From 7649fc8140cebacaa7bef71d80c010d31e89c32c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 9 Jun 2017 16:55:08 +0200 Subject: [PATCH] Fix getifaddrs() issues on AIX Based on fix from Miguel Sanders BUG: https://bugzilla.samba.org/show_bug.cgi?id=6970 Signed-off-by: Stefan Metzmacher Reviewed-by: Björn Jacke --- lib/replace/getifaddrs.c | 127 ++++++++++++++++++++++++++++------------------ 1 file changed, 77 insertions(+), 50 deletions(-) diff --git a/lib/replace/getifaddrs.c b/lib/replace/getifaddrs.c index c2d20f8..300b442 100644 --- a/lib/replace/getifaddrs.c +++ b/lib/replace/getifaddrs.c @@ -282,16 +282,15 @@ 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 fd, size; 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; @@ -299,77 +298,105 @@ int rep_getifaddrs(struct ifaddrs **ifap) return -1; } - ifc.ifc_len = sizeof(buff); - ifc.ifc_buf = buff; + if (ioctl(fd, SIOCGSIZIFCONF, &size) != 0) { + ret = -1; + goto done; + } + + ifc.ifc_len = size; + ifc.ifc_req = (struct ifreq *)malloc(size); if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { - close(fd); - return -1; + ret = -1; + goto done; } - ifr = ifc.ifc_req; + current = (const uint8_t *)ifc.ifc_req; + end = current + ifc.ifc_len; - /* Loop through interfaces */ - i = ifc.ifc_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; - while (i > 0) { - unsigned int inc; + if (fam == AF_INET || fam == AF_INET6) { + struct ifaddrs *curif; - inc = ifr->ifr_addr.sa_len; - - if (ioctl(fd, SIOCGIFADDR, ifr) != 0) { - freeaddrinfo(*ifap); - return -1; - } + curif = calloc(1, sizeof(struct ifaddrs)); + if (curif == NULL) { + ret = -1; + goto done; + } + if (lastif == NULL) { + firstif = curif; + } else { + lastif->ifa_next = curif; + } - curif = calloc(1, sizeof(struct ifaddrs)); - if (lastif == NULL) { - *ifap = 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_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; + curif->ifa_flags = ifr->ifr_flags; - if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { - freeaddrinfo(*ifap); - return -1; - } + if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { + ret = -1; + goto done; + } - curif->ifa_flags = ifr->ifr_flags; + curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr); + if (curif->ifa_netmask == NULL) { + ret = -1; + goto done; + } - if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { - freeaddrinfo(*ifap); - return -1; + lastif = curif; } - 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) { + freeaddrinfo(firstif); + } + free(ifc.ifc_req); close(fd); - return 0; + return ret; } #define _FOUND_IFACE_ANY -- 1.7.9.5