X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/ec4b68e5d820109e5954329013a911d4032bc4dc..e9477a08d2d1f528b1f127f1d563d77e2cf24a22:/src/src/ip.c diff --git a/src/src/ip.c b/src/src/ip.c index b0c98878b..ca5ca9b2b 100644 --- a/src/src/ip.c +++ b/src/src/ip.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2009 */ +/* Copyright (c) University of Cambridge 1995 - 2014 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for doing things with sockets. With the advent of IPv6 this has @@ -172,7 +172,7 @@ Arguments: af AF_INET6 or AF_INET for the socket type address the remote address, in text form port the remote port - timeout a timeout + timeout a timeout (zero for indefinite timeout) Returns: 0 on success; -1 on failure, with errno set */ @@ -249,6 +249,111 @@ return -1; +/************************************************* +* Create connected socket to remote host * +*************************************************/ + +/* Create a socket and connect to host (name or number, ipv6 ok) + at one of port-range. + +Arguments: + type SOCK_DGRAM or SOCK_STREAM + af AF_INET6 or AF_INET for the socket type + address the remote address, in text form + portlo,porthi the remote port range + timeout a timeout + connhost if not NULL, host_item filled in with connection details + errstr pointer for allocated string on error + +Return: + socket fd, or -1 on failure (having allocated an error string) +*/ +int +ip_connectedsocket(int type, const uschar * hostname, int portlo, int porthi, + int timeout, host_item * connhost, uschar ** errstr) +{ +int namelen, port; +host_item shost; +host_item *h; +int af = 0, fd, fd4 = -1, fd6 = -1; + +shost.next = NULL; +shost.address = NULL; +shost.port = portlo; +shost.mx = -1; + +namelen = Ustrlen(hostname); + +/* Anything enclosed in [] must be an IP address. */ + +if (hostname[0] == '[' && + hostname[namelen - 1] == ']') + { + uschar * host = string_copy(hostname); + host[namelen - 1] = 0; + host++; + if (string_is_ip_address(host, NULL) == 0) + { + *errstr = string_sprintf("malformed IP address \"%s\"", hostname); + return -1; + } + shost.name = shost.address = host; + } + +/* Otherwise check for an unadorned IP address */ + +else if (string_is_ip_address(hostname, NULL) != 0) + shost.name = shost.address = string_copy(hostname); + +/* Otherwise lookup IP address(es) from the name */ + +else + { + shost.name = string_copy(hostname); + if (host_find_byname(&shost, NULL, HOST_FIND_QUALIFY_SINGLE, NULL, + FALSE) != HOST_FOUND) + { + *errstr = string_sprintf("no IP address found for host %s", shost.name); + return -1; + } + } + +/* Try to connect to the server - test each IP till one works */ + +for (h = &shost; h != NULL; h = h->next) + { + fd = (Ustrchr(h->address, ':') != 0) + ? (fd6 < 0) ? (fd6 = ip_socket(type, af = AF_INET6)) : fd6 + : (fd4 < 0) ? (fd4 = ip_socket(type, af = AF_INET )) : fd4; + + if (fd < 0) + { + *errstr = string_sprintf("failed to create socket: %s", strerror(errno)); + goto bad; + } + + for(port = portlo; port <= porthi; port++) + if (ip_connect(fd, af, h->address, port, timeout) == 0) + { + if (fd != fd6) close(fd6); + if (fd != fd4) close(fd4); + if (connhost) { + h->port = port; + *connhost = *h; + connhost->next = NULL; + } + return fd; + } + } + +*errstr = string_sprintf("failed to connect to any address for %s: %s", + hostname, strerror(errno)); + +bad: + close(fd4); close(fd6); return -1; +} + + /************************************************* * Set keepalive on a socket * *************************************************/ @@ -298,7 +403,7 @@ ip_recv(int sock, uschar *buffer, int buffsize, int timeout) { fd_set select_inset; struct timeval tv; -int start_recv = time(NULL); +time_t start_recv = time(NULL); int rc; /* Wait until the socket is ready */ @@ -464,11 +569,13 @@ if (af == AF_INET) *level = IPPROTO_IP; *optname = IP_TOS; } +#if HAVE_IPV6 && defined(IPV6_TCLASS) else if (af == AF_INET6) { *level = IPPROTO_IPV6; *optname = IPV6_TCLASS; } +#endif else { DEBUG(D_transport)