static void connect_done(int unused_event, char *context) { SESSION *session = (SESSION *) context; int fd = vstream_fileno(session->stream); /* * Try again after some delay when the connection failed, in case they * run a Mickey Mouse protocol stack. */ if (socket_error(fd) < 0) { fail_connect(session); } else { non_blocking(fd, BLOCKING); /* Disable write events. */ event_disable_readwrite(fd); event_enable_read(fd, read_banner, (char *) session); dequeue_connect(session); /* Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. */ if (sa->sa_family == AF_INET #ifdef AF_INET6 || sa->sa_family == AF_INET6 #endif ) vstream_tweak_tcp(session->stream); } }
static SMTP_SESSION *smtp_connect_sock(int sock, struct sockaddr *sa, int salen, SMTP_ITERATOR *iter, DSN_BUF *why, int sess_flags) { int conn_stat; int saved_errno; VSTREAM *stream; time_t start_time; const char *name = STR(iter->host); const char *addr = STR(iter->addr); unsigned port = iter->port; start_time = time((time_t *) 0); if (var_smtp_conn_tmout > 0) { non_blocking(sock, NON_BLOCKING); conn_stat = timed_connect(sock, sa, salen, var_smtp_conn_tmout); saved_errno = errno; non_blocking(sock, BLOCKING); errno = saved_errno; } else { conn_stat = sane_connect(sock, sa, salen); } if (conn_stat < 0) { if (port) dsb_simple(why, "4.4.1", "connect to %s[%s]:%d: %m", name, addr, ntohs(port)); else dsb_simple(why, "4.4.1", "connect to %s[%s]: %m", name, addr); close(sock); return (0); } stream = vstream_fdopen(sock, O_RDWR); /* * Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. */ if (sa->sa_family == AF_INET #ifdef AF_INET6 || sa->sa_family == AF_INET6 #endif ) vstream_tweak_tcp(stream); /* * Bundle up what we have into a nice SMTP_SESSION object. */ return (smtp_session_alloc(stream, iter, start_time, sess_flags)); }
int vstream_tweak_sock(VSTREAM *fp) { SOCKADDR_STORAGE ss; struct sockaddr *sa = (struct sockaddr *) & ss; SOCKADDR_SIZE sa_length = sizeof(ss); int ret; /* * If the caller doesn't know if this socket is AF_LOCAL, AF_INET, etc., * figure it out for them. */ if ((ret = getsockname(vstream_fileno(fp), sa, &sa_length)) >= 0) { switch (sa->sa_family) { #ifdef AF_INET6 case AF_INET6: #endif case AF_INET: ret = vstream_tweak_tcp(fp); break; } } return (ret); }
static int smtpd_proxy_connect(SMTPD_STATE *state) { SMTPD_PROXY *proxy = state->proxy; int fd; char *lines; char *words; VSTRING *buf; int bad; char *word; static const NAME_CODE known_xforward_features[] = { XFORWARD_NAME, SMTPD_PROXY_XFORWARD_NAME, XFORWARD_ADDR, SMTPD_PROXY_XFORWARD_ADDR, XFORWARD_PORT, SMTPD_PROXY_XFORWARD_PORT, XFORWARD_PROTO, SMTPD_PROXY_XFORWARD_PROTO, XFORWARD_HELO, SMTPD_PROXY_XFORWARD_HELO, XFORWARD_IDENT, SMTPD_PROXY_XFORWARD_IDENT, XFORWARD_DOMAIN, SMTPD_PROXY_XFORWARD_DOMAIN, 0, 0, }; int server_xforward_features; int (*connect_fn) (const char *, int, int); const char *endpoint; /* * Find connection method (default inet) */ if (strncasecmp("unix:", proxy->service_name, 5) == 0) { endpoint = proxy->service_name + 5; connect_fn = unix_connect; } else { if (strncasecmp("inet:", proxy->service_name, 5) == 0) endpoint = proxy->service_name + 5; else endpoint = proxy->service_name; connect_fn = inet_connect; } /* * Connect to proxy. */ if ((fd = connect_fn(endpoint, BLOCKING, proxy->timeout)) < 0) { msg_warn("connect to proxy filter %s: %m", proxy->service_name); return (smtpd_proxy_rdwr_error(state, 0)); } proxy->service_stream = vstream_fdopen(fd, O_RDWR); /* Needed by our DATA-phase record emulation routines. */ vstream_control(proxy->service_stream, VSTREAM_CTL_CONTEXT, (char *) state, VSTREAM_CTL_END); /* Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. */ if (connect_fn == inet_connect) vstream_tweak_tcp(proxy->service_stream); smtp_timeout_setup(proxy->service_stream, proxy->timeout); /* * Get server greeting banner. * * If this fails then we have a problem because the proxy should always * accept our connection. Make up our own response instead of passing * back a negative greeting banner: the proxy open is delayed to the * point that the client expects a MAIL FROM or RCPT TO reply. */ if (smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK, SMTPD_PROXY_CONN_FMT)) { smtpd_proxy_fake_server_reply(state, CLEANUP_STAT_PROXY); smtpd_proxy_close(state); return (-1); } /* * Send our own EHLO command. If this fails then we have a problem * because the proxy should always accept our EHLO command. Make up our * own response instead of passing back a negative EHLO reply: the proxy * open is delayed to the point that the remote SMTP client expects a * MAIL FROM or RCPT TO reply. */ if (smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK, "EHLO %s", proxy->ehlo_name)) { smtpd_proxy_fake_server_reply(state, CLEANUP_STAT_PROXY); smtpd_proxy_close(state); return (-1); } /* * Parse the EHLO reply and see if we can forward logging information. */ server_xforward_features = 0; lines = STR(proxy->reply); while ((words = mystrtok(&lines, "\n")) != 0) { if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) { if (strcasecmp(word, XFORWARD_CMD) == 0) while ((word = mystrtok(&words, " \t")) != 0) server_xforward_features |= name_code(known_xforward_features, NAME_CODE_FLAG_NONE, word); } } /* * Send XFORWARD attributes. For robustness, explicitly specify what SMTP * session attributes are known and unknown. Make up our own response * instead of passing back a negative XFORWARD reply: the proxy open is * delayed to the point that the remote SMTP client expects a MAIL FROM * or RCPT TO reply. */ if (server_xforward_features) { buf = vstring_alloc(100); bad = (((server_xforward_features & SMTPD_PROXY_XFORWARD_NAME) && smtpd_proxy_xforward_send(state, buf, XFORWARD_NAME, IS_AVAIL_CLIENT_NAME(FORWARD_NAME(state)), FORWARD_NAME(state))) || ((server_xforward_features & SMTPD_PROXY_XFORWARD_ADDR) && smtpd_proxy_xforward_send(state, buf, XFORWARD_ADDR, IS_AVAIL_CLIENT_ADDR(FORWARD_ADDR(state)), FORWARD_ADDR(state))) || ((server_xforward_features & SMTPD_PROXY_XFORWARD_PORT) && smtpd_proxy_xforward_send(state, buf, XFORWARD_PORT, IS_AVAIL_CLIENT_PORT(FORWARD_PORT(state)), FORWARD_PORT(state))) || ((server_xforward_features & SMTPD_PROXY_XFORWARD_HELO) && smtpd_proxy_xforward_send(state, buf, XFORWARD_HELO, IS_AVAIL_CLIENT_HELO(FORWARD_HELO(state)), FORWARD_HELO(state))) || ((server_xforward_features & SMTPD_PROXY_XFORWARD_IDENT) && smtpd_proxy_xforward_send(state, buf, XFORWARD_IDENT, IS_AVAIL_CLIENT_IDENT(FORWARD_IDENT(state)), FORWARD_IDENT(state))) || ((server_xforward_features & SMTPD_PROXY_XFORWARD_PROTO) && smtpd_proxy_xforward_send(state, buf, XFORWARD_PROTO, IS_AVAIL_CLIENT_PROTO(FORWARD_PROTO(state)), FORWARD_PROTO(state))) || ((server_xforward_features & SMTPD_PROXY_XFORWARD_DOMAIN) && smtpd_proxy_xforward_send(state, buf, XFORWARD_DOMAIN, 1, STREQ(FORWARD_DOMAIN(state), MAIL_ATTR_RWR_LOCAL) ? XFORWARD_DOM_LOCAL : XFORWARD_DOM_REMOTE)) || smtpd_proxy_xforward_flush(state, buf)); vstring_free(buf); if (bad) { smtpd_proxy_fake_server_reply(state, CLEANUP_STAT_PROXY); smtpd_proxy_close(state); return (-1); } } /* * Pass-through the remote SMTP client's MAIL FROM command. If this * fails, then we have a problem because the proxy should always accept * any MAIL FROM command that was accepted by us. */ if (smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK, "%s", proxy->mail_from) != 0) { /* NOT: smtpd_proxy_fake_server_reply(state, CLEANUP_STAT_PROXY); */ smtpd_proxy_close(state); return (-1); } return (0); }