/* * Example demonstrating a common pitfall with SIOCGIFCONF handling. */ #include <sys/sockio.h> #include <net/if.h> #include <malloc.h> #include <stdlib.h> #include <err.h> #include <ifaddrs.h> void gifconf(int); void gifaddrs(int); int main(void) { int s; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) err(EXIT_FAILURE, "socket"); gifconf(s); /* Old code often used SIOCGIFCONF ioctl */ gifaddrs(s); /* New code should use getifaddrs() */ close(s); return 0; } void gifconf(int s) { struct ifconf ifc; struct ifreq *inext, *iend, *icur; size_t size; size = 4096; ifc.ifc_len = size; if ((ifc.ifc_buf = malloc(ifc.ifc_len)) == NULL) err(EXIT_FAILURE, "malloc"); if (ioctl(s, SIOCGIFCONF, &ifc) == -1) err(EXIT_FAILURE, "SIOCGIFCONF"); if (ifc.ifc_len >= size) { /* realloc and try again */ errx(EXIT_FAILURE, "SIOCGIFCONF: buf too small"); } inext = ifc.ifc_req; iend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len); for (;;) { icur = inext; #if 0 /* * Broken code. This would happen to work for most cases * because previously: * * sizeof(struct sockaddr) + IFNAMSIZ == sizeof(struct ifreq) * * Under this scenario the two 'if' cases in the working * case below work out to the same thing. */ inext = (struct ifreq *) ((char *)inext + inext->ifr_addr.sa_len + IFNAMSIZ); #else /* This will work against old / new libsocket */ if (inext->ifr_addr.sa_len + IFNAMSIZ > sizeof(struct ifreq)) inext = (struct ifreq *) ((char *)inext + inext->ifr_addr.sa_len + IFNAMSIZ); else inext++; #endif if (inext > iend) break; /* process icur */ } free(ifc.ifc_buf); } void gifaddrs(int s) { struct ifaddrs *ifaddrs, *ifap; if (getifaddrs(&ifaddrs) == -1) err(EXIT_FAILURE, "getifaddrs"); for (ifap = ifaddrs; ifap != NULL; ifap = ifap->ifa_next) { continue; } freeifaddrs(ifaddrs); }
If you compile the test case against the old headers, the SIOCGIFCONF ioctl() will produce the expected results in all environments: old / new stack, old / new libc. If you compile it against the io-pkt headers, the SIOCGIFCONF command will work only with the io-pkt stack and the 6.4 libc. In either case, there's no dependency on any version of libsocket.
The getifaddrs() call will work everywhere and is recommended for new code.