From 25391a918f4b81ed4e4beb11ee3766fb66ea837b Mon Sep 17 00:00:00 2001 From: SATOH Fumiyasu Date: Sun, 26 Nov 2017 17:45:22 +0900 Subject: [PATCH] Fix getifaddrs() issues on AIX Based on fix from Miguel Sanders BUG: https://bugzilla.samba.org/show_bug.cgi?id=6970 --- lib/replace/getifaddrs.c | 141 ++++++++++++++++++++++++++++------------------- 1 file changed, 85 insertions(+), 56 deletions(-) diff --git a/lib/replace/getifaddrs.c b/lib/replace/getifaddrs.c index 9e377e5edc0..67810cf2c6c 100644 --- a/lib/replace/getifaddrs.c +++ b/lib/replace/getifaddrs.c @@ -282,94 +282,123 @@ int rep_getifaddrs(struct ifaddrs **ifap) #ifdef HAVE_IFACE_AIX /**************************************************************************** -this one is for AIX (tested on 4.2) +this one is for AIX (tested on 5.3 / 6.1 / 7.1) ****************************************************************************/ int rep_getifaddrs(struct ifaddrs **ifap) { - char buff[8192]; - int fd, i; + int ret, fd; struct ifconf ifc; - struct ifreq *ifr=NULL; - struct ifaddrs *curif; + struct ifaddrs *firstif = NULL; struct ifaddrs *lastif = NULL; + const uint8_t *current, *end; *ifap = NULL; + ifc.ifc_req = NULL; 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; + if (ioctl(fd, SIOCGSIZIFCONF, &ifc.ifc_len) != 0) { + ret = -1; + goto done; } - ifr = ifc.ifc_req; + ifc.ifc_req = (struct ifreq *)malloc(ifc.ifc_len); - /* Loop through interfaces */ - i = ifc.ifc_len; + if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { + ret = -1; + goto done; + } - while (i > 0) { - unsigned int inc; + current = (const uint8_t *)ifc.ifc_req; + end = current + ifc.ifc_len; - inc = ifr->ifr_addr.sa_len; + while (current < end) { + const struct ifreq *ifr = (const struct ifreq *)current; + struct sockaddr *sa = (struct sockaddr *)&(ifr->ifr_addr); + sa_family_t fam = ((struct sockaddr_in *)sa)->sin_family; + size_t inc; - if (ioctl(fd, SIOCGIFADDR, ifr) != 0) { - freeaddrinfo(*ifap); - return -1; + if (fam == AF_INET || fam == AF_INET6) { + struct ifaddrs *curif; + + curif = calloc(1, sizeof(struct ifaddrs)); + if (curif == NULL) { + ret = -1; + goto done; + } + if (lastif == NULL) { + firstif = curif; + } else { + lastif->ifa_next = curif; + } + + curif->ifa_name = strdup(ifr->ifr_name); + if (curif->ifa_name == NULL) { + ret = -1; + goto done; + } + curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr); + if (curif->ifa_addr == NULL) { + ret = -1; + goto done; + } + curif->ifa_dstaddr = NULL; + curif->ifa_data = NULL; + curif->ifa_netmask = NULL; + curif->ifa_next = NULL; + + if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { + ret = -1; + goto done; + } + + curif->ifa_flags = ifr->ifr_flags; + + if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { + ret = -1; + goto done; + } + + curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr); + if (curif->ifa_netmask == NULL) { + ret = -1; + goto done; + } + + lastif = curif; } - curif = calloc(1, sizeof(struct ifaddrs)); - if (lastif == NULL) { - *ifap = curif; - } else { - lastif->ifa_next = curif; - } - - curif->ifa_name = strdup(ifr->ifr_name); - curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr); - curif->ifa_dstaddr = NULL; - curif->ifa_data = NULL; - curif->ifa_netmask = NULL; - curif->ifa_next = NULL; - - if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { - freeaddrinfo(*ifap); - return -1; - } - - curif->ifa_flags = ifr->ifr_flags; - - if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { - freeaddrinfo(*ifap); - return -1; - } - - curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr); - - lastif = curif; - - 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. */ + * a zero length "link address", this does matter. + */ - if (inc < sizeof(ifr->ifr_addr)) + inc = ifr->ifr_addr.sa_len; + if (inc < sizeof(ifr->ifr_addr)) { inc = sizeof(ifr->ifr_addr); + } inc += IFNAMSIZ; - ifr = (struct ifreq*) (((char*) ifr) + inc); - i -= inc; + current += inc; } + *ifap = firstif; + firstif = NULL; + ret = 0; +done: + if (firstif != NULL) { + freeifaddrs(firstif); + } + if (ifc.ifc_req != NULL) { + free(ifc.ifc_req); + } close(fd); - return 0; + return ret; } #define _FOUND_IFACE_ANY -- 2.15.0