X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/c988f1f4faa9f679f79beddf3c14676c5dcb8e28..261dc43e32f6039781ca92535e56f5caaa68b809:/src/src/os.c diff --git a/src/src/os.c b/src/src/os.c index 7ca0fdabd..b8d369307 100644 --- a/src/src/os.c +++ b/src/src/os.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/os.c,v 1.2 2005/01/04 10:00:42 ph10 Exp $ */ +/* $Cambridge: exim/src/src/os.c,v 1.8 2009/11/16 19:50:37 nm4 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* Copyright (c) University of Cambridge 1995 - 2009 */ /* See the file NOTICE for conditions of use and distribution. */ #ifdef STAND_ALONE @@ -463,6 +463,75 @@ calls the common function; on Linux it calls the Linux function. This function finds the addresses of all the running interfaces on the machine. A chain of blocks containing the textual form of the addresses is returned. +getifaddrs() provides a sane consistent way to query this on modern OSs, +otherwise fall back to a maze of twisty ioctl() calls + +Arguments: none +Returns: a chain of ip_address_items, each pointing to a textual + version of an IP address, with the port field set to zero +*/ + + +#ifndef NO_FIND_INTERFACES + +#ifdef HAVE_GETIFADDRS + +#include + +ip_address_item * +os_common_find_running_interfaces(void) +{ +struct ifaddrs *ifalist = NULL; +ip_address_item *yield = NULL; +ip_address_item *last = NULL; +ip_address_item *next; + +if (getifaddrs(&ifalist) != 0) + log_write(0, LOG_PANIC_DIE, "Unable to call getifaddrs: %d %s", + errno, strerror(errno)); + +struct ifaddrs *ifa; +for (ifa = ifalist; ifa != NULL; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr->sa_family != AF_INET +#if HAVE_IPV6 + && ifa->ifa_addr->sa_family != AF_INET6 +#endif /* HAVE_IPV6 */ + ) + continue; + + if ( !(ifa->ifa_flags & IFF_UP) ) /* Only want 'UP' interfaces */ + continue; + + /* Create a data block for the address, fill in the data, and put it on the + chain. */ + + next = store_get(sizeof(ip_address_item)); + next->next = NULL; + next->port = 0; + (void)host_ntoa(-1, ifa->ifa_addr, next->address, NULL); + + if (yield == NULL) + yield = last = next; + else + { + last->next = next; + last = next; + } + + DEBUG(D_interface) debug_printf("Actual local interface address is %s (%s)\n", + last->address, ifa->ifa_name); + } + +/* free the list of addresses, and return the chain of data blocks. */ + +freeifaddrs (ifalist); +return yield; +} + +#else /* HAVE_GETIFADDRS */ + +/* Problems: (1) Solaris 2 has the SIOGIFNUM call to get the number of interfaces, but @@ -486,15 +555,8 @@ Problems: the former, calling the latter does no harm, but it causes grief on Linux and BSD systems in the case of IP aliasing, so a means of cutting it out is provided. - -Arguments: none -Returns: a chain of ip_address_items, each pointing to a textual - version of an IP address, with the port field set to zero */ - -#ifndef NO_FIND_INTERFACES - /* If there is IPv6 support, and SIOCGLIFCONF is defined, define macros to use these new, longer versions of the old IPv4 interfaces. Otherwise, define the macros to use the historical versions. */ @@ -556,7 +618,7 @@ char *cp; char buf[MAX_INTERFACES*sizeof(struct V_ifreq)]; struct sockaddr *addrp; size_t len = 0; -char addrbuf[256]; +char addrbuf[512]; /* We have to create a socket in order to do ioctls on it to find out what we want to know. */ @@ -661,8 +723,9 @@ for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len) if ((ifreq.V_ifr_flags & IFF_UP) == 0) continue; /* On some operating systems we have to get the IP address of the interface - by another call. On others, it's already there, but we must reinstate the - data in ifreq, because SIOCGIFFLAGS may wreck it. */ + by another call. On others, it's already there, but we must copy the full + length because we only copied the basic length above, and anyway, + GIFFLAGS may have wrecked the data. */ #ifndef SIOCGIFCONF_GIVES_ADDR if (ioctl(vs, V_GIFADDR, (char *)&ifreq) < 0) @@ -671,8 +734,8 @@ for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len) addrp = &ifreq.V_ifr_addr; #else - memcpy((char *)&ifreq, cp, sizeof(ifreq)); - memcpy(addrbuf, (char *)&(ifreq.V_ifr_addr), len - sizeof(ifreq.V_ifr_name)); + memcpy(addrbuf, cp + offsetof(struct V_ifreq, V_ifr_addr), + len - sizeof(ifreq.V_ifr_name)); addrp = (struct sockaddr *)addrbuf; #endif @@ -696,10 +759,12 @@ for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len) /* Close the socket, and return the chain of data blocks. */ -close(vs); +(void)close(vs); return yield; } +#endif /* HAVE_GETIFADDRS */ + #else /* NO_FIND_INTERFACES */ /* Some experimental or developing OS (e.g. GNU/Hurd) do not have the ioctls,