X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source3%2Flib%2Finterfaces.c;h=4567fe457b83b0cc083aa22006606dc4d513ff37;hb=5209a846a9157e649fcdcb561f7eaf19c8c0e465;hp=122101cdc996abc7131248a24ec31e2988f9849a;hpb=70b416a1742e28b43cf82511277b57ff04affece;p=tprouty%2Fsamba.git diff --git a/source3/lib/interfaces.c b/source3/lib/interfaces.c index 122101cdc9..4567fe457b 100644 --- a/source3/lib/interfaces.c +++ b/source3/lib/interfaces.c @@ -84,423 +84,185 @@ #include #endif +#define SOCKET_WRAPPER_NOT_REPLACE #include "interfaces.h" +#include "../replace/replace.h" /**************************************************************************** - Try the "standard" getifaddrs/freeifaddrs interfaces. - Also gets IPv6 interfaces. + Utility functions. ****************************************************************************/ -#if HAVE_IFACE_GETIFADDRS /**************************************************************************** - Get the netmask address for a local interface. + Create a struct sockaddr_storage with the netmask bits set to 1. ****************************************************************************/ -static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) +bool make_netmask(struct sockaddr_storage *pss_out, + const struct sockaddr_storage *pss_in, + unsigned long masklen) { - struct ifaddrs *iflist = NULL; - struct ifaddrs *ifptr = NULL; - int total = 0; - size_t copy_size; - - if (getifaddrs(&iflist) < 0) { - return -1; - } - - /* Loop through interfaces, looking for given IP address */ - for (ifptr = iflist, total = 0; - ifptr != NULL && total < max_interfaces; - ifptr = ifptr->ifa_next) { - - memset(&ifaces[total], '\0', sizeof(ifaces[total])); - - copy_size = sizeof(struct sockaddr_in); - - if (!ifptr->ifa_addr || !ifptr->ifa_netmask) { - continue; + *pss_out = *pss_in; + /* Now apply masklen bits of mask. */ +#if defined(HAVE_IPV6) + if (pss_in->ss_family == AF_INET6) { + char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr; + unsigned int i; + + if (masklen > 128) { + return false; } - - ifaces[total].flags = ifptr->ifa_flags; - - /* Check the interface is up. */ - if (!(ifaces[total].flags & IFF_UP)) { - continue; + for (i = 0; masklen >= 8; masklen -= 8, i++) { + *p++ = 0xff; } - -#ifdef AF_INET6 - if (ifptr->ifa_addr->sa_family == AF_INET6) { - copy_size = sizeof(struct sockaddr_in6); + /* Deal with the partial byte. */ + *p++ &= (0xff & ~(0xff>>masklen)); + i++; + for (;i < sizeof(struct in6_addr); i++) { + *p++ = '\0'; } + return true; + } #endif - - memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size); - memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size); - - if ((ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) && - ifptr->ifa_broadaddr) { - memcpy(&ifaces[total].bcast, - ifptr->ifa_broadaddr, - copy_size); - } else if ((ifaces[total].flags & IFF_POINTOPOINT) && - ifptr->ifa_dstaddr ) { - memcpy(&ifaces[total].bcast, - ifptr->ifa_dstaddr, - copy_size); - } else { - continue; + if (pss_in->ss_family == AF_INET) { + if (masklen > 32) { + return false; } - - strncpy(ifaces[total].name, ifptr->ifa_name, - sizeof(ifaces[total].name)-1); - ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; - total++; + ((struct sockaddr_in *)pss_out)->sin_addr.s_addr = + htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL)); + return true; } - - freeifaddrs(iflist); - - return total; + return false; } -#define _FOUND_IFACE_ANY -#endif /* HAVE_IFACE_GETIFADDRS */ -#if HAVE_IFACE_IFCONF - -/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1 - V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2. - - It probably also works on any BSD style system. */ - /**************************************************************************** - Get the netmask address for a local interface. + Create a struct sockaddr_storage set to the broadcast or network adress from + an incoming sockaddr_storage. ****************************************************************************/ -static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) +static void make_bcast_or_net(struct sockaddr_storage *pss_out, + const struct sockaddr_storage *pss_in, + const struct sockaddr_storage *nmask, + bool make_bcast_p) { - struct ifconf ifc; - char buff[8192]; - int fd, i, n; - struct ifreq *ifr=NULL; - int total = 0; - - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - return -1; + unsigned int i = 0, len = 0; + char *pmask = NULL; + char *p = NULL; + *pss_out = *pss_in; + + /* Set all zero netmask bits to 1. */ +#if defined(HAVE_IPV6) + if (pss_in->ss_family == AF_INET6) { + p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr; + pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr; + len = 16; } - - ifc.ifc_len = sizeof(buff); - ifc.ifc_buf = buff; - - if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { - close(fd); - return -1; +#endif + if (pss_in->ss_family == AF_INET) { + p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr; + pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr; + len = 4; } - ifr = ifc.ifc_req; - - n = ifc.ifc_len / sizeof(struct ifreq); - - /* Loop through interfaces, looking for given IP address */ - for (i=n-1;i>=0 && total < max_interfaces;i--) { - - memset(&ifaces[total], '\0', sizeof(ifaces[total])); - - /* Check the interface is up. */ - if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) { - continue; - } - - ifaces[total].flags = ifr[i].ifr_flags; - - if (!(flags & IFF_UP)) { - continue; - } - - if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) { - continue; - } - - strncpy(ifaces[total].name, ifr[i].ifr_name, - sizeof(ifaces[total].name)-1); - ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; - - memcpy(&ifaces[total].ip, &ifr[i].ifr_addr, - sizeof(struct sockaddr_in)); - - if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) { - continue; - } - - memcpy(&ifaces[total].netmask, &ifr[i].ifr_netmask, - sizeof(struct sockaddr_in)); - - if (ifaces[total].flags & IFF_BROADCAST) { - if (ioctl(fd, SIOCGIFBRDADDR, &ifr[i]) != 0) { - continue; - } - memcpy(&ifaces[total].bcast, &ifr[i].ifr_broadaddr, - sizeof(struct sockaddr_in)); - } else if (ifaces[total].flags & IFF_POINTOPOINT) { - if (ioctl(fd, SIOCGIFDSTADDR, &ifr[i]) != 0) { - continue; - } - memcpy(&ifaces[total].bcast, &ifr[i].ifr_dstaddr, - sizeof(struct sockaddr_in)); + for (i = 0; i < len; i++, p++, pmask++) { + if (make_bcast_p) { + *p = (*p & *pmask) | (*pmask ^ 0xff); } else { - continue; + /* make_net */ + *p = (*p & *pmask); } - - total++; } +} - close(fd); - - return total; +void make_bcast(struct sockaddr_storage *pss_out, + const struct sockaddr_storage *pss_in, + const struct sockaddr_storage *nmask) +{ + make_bcast_or_net(pss_out, pss_in, nmask, true); } -#define _FOUND_IFACE_ANY -#endif /* HAVE_IFACE_IFCONF */ -#ifdef HAVE_IFACE_IFREQ +void make_net(struct sockaddr_storage *pss_out, + const struct sockaddr_storage *pss_in, + const struct sockaddr_storage *nmask) +{ + make_bcast_or_net(pss_out, pss_in, nmask, false); +} -#ifndef I_STR -#include -#endif +/**************************************************************************** + Try the "standard" getifaddrs/freeifaddrs interfaces. + Also gets IPv6 interfaces. +****************************************************************************/ /**************************************************************************** - This should cover most of the streams based systems. - Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code. + Get the netmask address for a local interface. ****************************************************************************/ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) { - struct ifreq ifreq; - struct strioctl strioctl; - char buff[8192]; - int fd, i, n; - struct ifreq *ifr=NULL; + struct ifaddrs *iflist = NULL; + struct ifaddrs *ifptr = NULL; int total = 0; + size_t copy_size; - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - return -1; - } - - strioctl.ic_cmd = SIOCGIFCONF; - strioctl.ic_dp = buff; - strioctl.ic_len = sizeof(buff); - if (ioctl(fd, I_STR, &strioctl) < 0) { - close(fd); + if (getifaddrs(&iflist) < 0) { return -1; } - /* we can ignore the possible sizeof(int) here as the resulting - number of interface structures won't change */ - n = strioctl.ic_len / sizeof(struct ifreq); - - /* we will assume that the kernel returns the length as an int - at the start of the buffer if the offered size is a - multiple of the structure size plus an int */ - if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) { - ifr = (struct ifreq *)(buff + sizeof(int)); - } else { - ifr = (struct ifreq *)buff; - } - - /* Loop through interfaces */ - - for (i = 0; iifa_next) { memset(&ifaces[total], '\0', sizeof(ifaces[total])); - ifreq = ifr[i]; + copy_size = sizeof(struct sockaddr_in); - strioctl.ic_cmd = SIOCGIFFLAGS; - strioctl.ic_dp = (char *)&ifreq; - strioctl.ic_len = sizeof(struct ifreq); - if (ioctl(fd, I_STR, &strioctl) != 0) { + if (!ifptr->ifa_addr || !ifptr->ifa_netmask) { continue; } - ifaces[total].flags = ifreq.ifr_flags; + ifaces[total].flags = ifptr->ifa_flags; + /* Check the interface is up. */ if (!(ifaces[total].flags & IFF_UP)) { continue; } - strioctl.ic_cmd = SIOCGIFADDR; - strioctl.ic_dp = (char *)&ifreq; - strioctl.ic_len = sizeof(struct ifreq); - if (ioctl(fd, I_STR, &strioctl) != 0) { - continue; - } - - strncpy(ifaces[total].name, iname, - sizeof(ifaces[total].name)-1); - ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; - - memcpy(&ifaces[total].ip, &ifreq.ifr_addr, - sizeof(struct sockaddr_in)); - - strioctl.ic_cmd = SIOCGIFNETMASK; - strioctl.ic_dp = (char *)&ifreq; - strioctl.ic_len = sizeof(struct ifreq); - if (ioctl(fd, I_STR, &strioctl) != 0) { - continue; +#if defined(HAVE_IPV6) + if (ifptr->ifa_addr->sa_family == AF_INET6) { + copy_size = sizeof(struct sockaddr_in6); } +#endif - memcpy(&ifaces[total].netmask, &ifreq.ifr_addr, - sizeof(struct sockaddr_in)); + memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size); + memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size); - if (ifaces[total].flags & IFF_BROADCAST) { - strioctl.ic_cmd = SIOCGIFBRDADDR; - strioctl.ic_dp = (char *)&ifreq; - strioctl.ic_len = sizeof(struct ifreq); - if (ioctl(fd, I_STR, &strioctl) != 0) { - continue; - } - memcpy(&ifaces[total].bcast, &ifreq.ifr_broadaddr, - sizeof(struct sockaddr_in)); - } else if (ifaces[total].flags & IFF_POINTOPOINT) { - strioctl.ic_cmd = SIOCGIFDSTADDR; - strioctl.ic_dp = (char *)&ifreq; - strioctl.ic_len = sizeof(struct ifreq); - if (ioctl(fd, I_STR, &strioctl) != 0) { - continue; - } - memcpy(&ifaces[total].bcast, &ifreq.ifr_dstaddr, - sizeof(struct sockaddr_in)); + if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) { + make_bcast(&ifaces[total].bcast, + &ifaces[total].ip, + &ifaces[total].netmask); + } else if ((ifaces[total].flags & IFF_POINTOPOINT) && + ifptr->ifa_dstaddr ) { + memcpy(&ifaces[total].bcast, + ifptr->ifa_dstaddr, + copy_size); } else { continue; } + strlcpy(ifaces[total].name, ifptr->ifa_name, + sizeof(ifaces[total].name)); total++; } - close(fd); - - return total; -} - -#define _FOUND_IFACE_ANY -#endif /* HAVE_IFACE_IFREQ */ -#ifdef HAVE_IFACE_AIX - -/**************************************************************************** - This one is for AIX (tested on 4.2). -****************************************************************************/ - -static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) -{ - char buff[8192]; - int fd, i; - struct ifconf ifc; - struct ifreq *ifr=NULL; - int total = 0; - - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - return -1; - } - - - ifc.ifc_len = sizeof(buff); - ifc.ifc_buf = buff; - - if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { - close(fd); - return -1; - } - - ifr = ifc.ifc_req; - - /* Loop through interfaces */ - i = ifc.ifc_len; - - while (i > 0 && total < max_interfaces) { - uint_t inc; - - memset(&ifaces[total], '\0', sizeof(ifaces[total])); - - inc = ifr->ifr_addr.sa_len; - - if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { - goto next; - } - - ifaces[total].flags = ifr->ifr_flags; - - if (!(ifaces[total].flags & IFF_UP)) { - goto next; - } - - if (ioctl(fd, SIOCGIFADDR, ifr) != 0) { - goto next; - } - - memcpy(&ifaces[total].ip, &ifr->ifr_addr, - sizeof(struct sockaddr_in)); - - strncpy(ifaces[total].name, ifr->ifr_name, - sizeof(ifaces[total].name)-1); - ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; - - if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { - goto next; - } - - memcpy(&ifaces[total].netmask, &ifr->ifr_addr, - sizeof(struct sockaddr_in)); - - if (ifaces[total].flags & IFF_BROADCAST) { - if (ioctl(fd, SIOCGIFBRDADDR, &ifr[i]) != 0) { - continue; - } - memcpy(&ifaces[total].bcast, &ifr[i].ifr_broadaddr, - sizeof(struct sockaddr_in)); - } else if (ifaces[total].flags & IFF_POINTOPOINT) { - if (ioctl(fd, SIOCGIFDSTADDR, &ifr[i]) != 0) { - continue; - } - memcpy(&ifaces[total].bcast, &ifr[i].ifr_dstaddr, - sizeof(struct sockaddr_in)); - } else { - continue; - } - - - total++; - - next: - /* - * Patch from Archie Cobbs (archie@whistle.com). The - * addresses in the SIOCGIFCONF interface list have a - * minimum size. Usually this doesn't matter, but if - * your machine has tunnel interfaces, etc. that have - * a zero length "link address", this does matter. */ - - if (inc < sizeof(ifr->ifr_addr)) - inc = sizeof(ifr->ifr_addr); - inc += IFNAMSIZ; - - ifr = (struct ifreq*) (((char*) ifr) + inc); - i -= inc; - } + freeifaddrs(iflist); - close(fd); return total; } -#define _FOUND_IFACE_ANY -#endif /* HAVE_IFACE_AIX */ -#ifndef _FOUND_IFACE_ANY -static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) -{ - return -1; -} -#endif - - static int iface_comp(struct iface_struct *i1, struct iface_struct *i2) { int r; -#ifdef AF_INET6 +#if defined(HAVE_IPV6) /* * If we have IPv6 - sort these interfaces lower * than any IPv4 ones. @@ -536,7 +298,12 @@ static int iface_comp(struct iface_struct *i1, struct iface_struct *i2) } #endif - if (i1->ip.ss_family == AF_INET) { + /* AIX uses __ss_family instead of ss_family inside of + sockaddr_storage. Instead of trying to figure out which field to + use, we can just cast it to a sockaddr. + */ + + if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) { struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip; struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip; @@ -582,44 +349,3 @@ int get_interfaces(struct iface_struct *ifaces, int max_interfaces) return total; } - -#ifdef AUTOCONF_TEST -/* this is the autoconf driver to test get_interfaces() */ - - int main() -{ - struct iface_struct ifaces[MAX_INTERFACES]; - int total = get_interfaces(ifaces, MAX_INTERFACES); - int i; - - printf("got %d interfaces:\n", total); - if (total <= 0) { - exit(1); - } - - for (i=0;i