static SMTP_SESSION *smtp_connect_unix(const char *addr, DSN_BUF *why, int sess_flags) { const char *myname = "smtp_connect_unix"; struct sockaddr_un sock_un; int len = strlen(addr); int sock; dsb_reset(why); /* Paranoia */ /* * Sanity checks. */ if (len >= (int) sizeof(sock_un.sun_path)) { msg_warn("unix-domain name too long: %s", addr); dsb_simple(why, "4.3.5", "Server configuration error"); return (0); } /* * Initialize. */ memset((char *) &sock_un, 0, sizeof(sock_un)); sock_un.sun_family = AF_UNIX; #ifdef HAS_SUN_LEN sock_un.sun_len = len + 1; #endif memcpy(sock_un.sun_path, addr, len + 1); /* * Create a client socket. */ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) msg_fatal("%s: socket: %m", myname); /* * Connect to the server. */ if (msg_verbose) msg_info("%s: trying: %s...", myname, addr); return (smtp_connect_sock(sock, (struct sockaddr *) & sock_un, sizeof(sock_un), var_myhostname, addr, 0, addr, why, sess_flags)); }
static SMTP_SESSION *smtp_connect_addr(SMTP_ITERATOR *iter, DSN_BUF *why, int sess_flags) { const char *myname = "smtp_connect_addr"; struct sockaddr_storage ss; /* remote */ struct sockaddr *sa = (struct sockaddr *) &ss; SOCKADDR_SIZE salen = sizeof(ss); MAI_HOSTADDR_STR hostaddr; DNS_RR *addr = iter->rr; unsigned port = iter->port; int sock; char *bind_addr; char *bind_var; dsb_reset(why); /* Paranoia */ /* * Sanity checks. */ if (dns_rr_to_sa(addr, port, sa, &salen) != 0) { msg_warn("%s: skip address type %s: %m", myname, dns_strtype(addr->type)); dsb_simple(why, "4.4.0", "network address conversion failed: %m"); return (0); } /* * Initialize. */ if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) msg_fatal("%s: socket: %m", myname); if (inet_windowsize > 0) set_inet_windowsize(sock, inet_windowsize); /* * Allow the sysadmin to specify the source address, for example, as "-o * smtp_bind_address=x.x.x.x" in the master.cf file. */ #ifdef HAS_IPV6 if (sa->sa_family == AF_INET6) { bind_addr = var_smtp_bind_addr6; bind_var = VAR_LMTP_SMTP(BIND_ADDR6); } else #endif if (sa->sa_family == AF_INET) { bind_addr = var_smtp_bind_addr; bind_var = VAR_LMTP_SMTP(BIND_ADDR); } else bind_var = bind_addr = ""; if (*bind_addr) { int aierr; struct addrinfo *res0; if ((aierr = hostaddr_to_sockaddr(bind_addr, (char *) 0, 0, &res0)) != 0) msg_fatal("%s: bad %s parameter: %s: %s", myname, bind_var, bind_addr, MAI_STRERROR(aierr)); if (bind(sock, res0->ai_addr, res0->ai_addrlen) < 0) msg_warn("%s: bind %s: %m", myname, bind_addr); else if (msg_verbose) msg_info("%s: bind %s", myname, bind_addr); freeaddrinfo(res0); } /* * When running as a virtual host, bind to the virtual interface so that * the mail appears to come from the "right" machine address. * * XXX The IPv6 patch expands the null host (as client endpoint) and uses * the result as the loopback address list. */ else { int count = 0; struct sockaddr *own_addr = 0; INET_ADDR_LIST *addr_list = own_inet_addr_list(); struct sockaddr_storage *s; for (s = addr_list->addrs; s < addr_list->addrs + addr_list->used; s++) { if (SOCK_ADDR_FAMILY(s) == sa->sa_family) { if (count++ > 0) break; own_addr = SOCK_ADDR_PTR(s); } } if (count == 1 && !sock_addr_in_loopback(own_addr)) { if (bind(sock, own_addr, SOCK_ADDR_LEN(own_addr)) < 0) { SOCKADDR_TO_HOSTADDR(own_addr, SOCK_ADDR_LEN(own_addr), &hostaddr, (MAI_SERVPORT_STR *) 0, 0); msg_warn("%s: bind %s: %m", myname, hostaddr.buf); } else if (msg_verbose) { SOCKADDR_TO_HOSTADDR(own_addr, SOCK_ADDR_LEN(own_addr), &hostaddr, (MAI_SERVPORT_STR *) 0, 0); msg_info("%s: bind %s", myname, hostaddr.buf); } } } /* * Connect to the server. */ if (msg_verbose) msg_info("%s: trying: %s[%s] port %d...", myname, STR(iter->host), STR(iter->addr), ntohs(port)); return (smtp_connect_sock(sock, sa, salen, iter, why, sess_flags)); }