void __ifreq (struct ifreq **ifreqs, int *num_ifs, int sockfd) { int fd = sockfd; struct ifconf ifc; int rq_len; int nifs; # define RQ_IFS 4 if (fd < 0) fd = __opensock (); if (fd < 0) { *num_ifs = 0; *ifreqs = NULL; return; } ifc.ifc_buf = NULL; rq_len = RQ_IFS * sizeof (struct ifreq) / 2; /* Doubled in the loop. */ do { ifc.ifc_len = rq_len *= 2; void *newp = realloc (ifc.ifc_buf, ifc.ifc_len); if (newp == NULL || __ioctl (fd, SIOCGIFCONF, &ifc) < 0) { free (ifc.ifc_buf); if (fd != sockfd) __close (fd); *num_ifs = 0; *ifreqs = NULL; return; } ifc.ifc_buf = newp; } while (rq_len < sizeof (struct ifreq) + ifc.ifc_len); if (fd != sockfd) __close (fd); #ifdef _HAVE_SA_LEN struct ifreq *ifr = *ifreqs; nifs = 0; while ((char *) ifr < ifc.ifc_buf + ifc.ifc_len) { ++nifs; ifr = __if_nextreq (ifr); if (ifr == NULL) break; } #else nifs = ifc.ifc_len / sizeof (struct ifreq); #endif *num_ifs = nifs; *ifreqs = realloc (ifc.ifc_buf, nifs * sizeof (struct ifreq)); }
/* Create a linked list of `struct ifaddrs' structures, one for each network interface on the host machine. If successful, store the list in *IFAP and return 0. On errors, return -1 and set `errno'. */ int getifaddrs (struct ifaddrs **ifap) { /* This implementation handles only IPv4 interfaces. The various ioctls below will only work on an AF_INET socket. Some different mechanism entirely must be used for IPv6. */ int fd = __socket (AF_INET, SOCK_DGRAM, 0); struct ifreq *ifreqs; int nifs; if (fd < 0) return -1; __ifreq (&ifreqs, &nifs, fd); if (ifreqs == NULL) /* XXX doesn't distinguish error vs none */ { __close (fd); return -1; } /* Now we have the list of interfaces and each one's address. Put it into the expected format and fill in the remaining details. */ if (nifs == 0) *ifap = NULL; else { struct { struct ifaddrs ia; struct sockaddr addr, netmask, broadaddr; char name[IF_NAMESIZE]; } *storage; struct ifreq *ifr; int i; storage = malloc (nifs * sizeof storage[0]); if (storage == NULL) { __close (fd); __if_freereq (ifreqs, nifs); return -1; } i = 0; ifr = ifreqs; do { /* Fill in pointers to the storage we've already allocated. */ storage[i].ia.ifa_next = &storage[i + 1].ia; storage[i].ia.ifa_addr = &storage[i].addr; /* Now copy the information we already have from SIOCGIFCONF. */ storage[i].ia.ifa_name = strncpy (storage[i].name, ifr->ifr_name, sizeof storage[i].name); storage[i].addr = ifr->ifr_addr; /* The SIOCGIFCONF call filled in only the name and address. Now we must also ask for the other information we need. */ if (__ioctl (fd, SIOCGIFFLAGS, ifr) < 0) break; storage[i].ia.ifa_flags = ifr->ifr_flags; ifr->ifr_addr = storage[i].addr; if (__ioctl (fd, SIOCGIFNETMASK, ifr) < 0) storage[i].ia.ifa_netmask = NULL; else { storage[i].ia.ifa_netmask = &storage[i].netmask; storage[i].netmask = ifr->ifr_netmask; } if (ifr->ifr_flags & IFF_BROADCAST) { ifr->ifr_addr = storage[i].addr; if (__ioctl (fd, SIOCGIFBRDADDR, ifr) < 0) storage[i].ia.ifa_broadaddr = NULL; { storage[i].ia.ifa_broadaddr = &storage[i].broadaddr; storage[i].broadaddr = ifr->ifr_broadaddr; } } else if (ifr->ifr_flags & IFF_POINTOPOINT) { ifr->ifr_addr = storage[i].addr; if (__ioctl (fd, SIOCGIFDSTADDR, ifr) < 0) storage[i].ia.ifa_broadaddr = NULL; else { storage[i].ia.ifa_broadaddr = &storage[i].broadaddr; storage[i].broadaddr = ifr->ifr_dstaddr; } } else storage[i].ia.ifa_broadaddr = NULL; storage[i].ia.ifa_data = NULL; /* Nothing here for now. */ ifr = __if_nextreq (ifr); } while (++i < nifs); if (i < nifs) /* Broke out early on error. */ { __close (fd); free (storage); __if_freereq (ifreqs, nifs); return -1; } storage[i - 1].ia.ifa_next = NULL; *ifap = &storage[0].ia; __close (fd); __if_freereq (ifreqs, nifs); } return 0; }
void __ifreq (struct ifreq **ifreqs, int *num_ifs, int sockfd) { int fd = sockfd; struct ifconf ifc; int rq_len; int nifs; char *ifstart; char *ifend; struct ifreq *ifr; /* FreeBSD has many interfaces, many of them are usually down. */ # define RQ_IFS 16 /* We have to assume all records are of limited size, so that we know when we can stop enlarging the buffer. */ # define RQ_MAXSIZE 256 if (fd < 0) fd = __opensock (); if (fd < 0) { *num_ifs = 0; *ifreqs = NULL; return; } ifc.ifc_buf = NULL; rq_len = RQ_IFS * sizeof (struct ifreq) + RQ_MAXSIZE; for (;;) { ifc.ifc_len = rq_len; ifc.ifc_buf = realloc (ifc.ifc_buf, ifc.ifc_len); if (ifc.ifc_buf == NULL || __ioctl (fd, SIOCGIFCONF, &ifc) < 0) { if (ifc.ifc_buf) free (ifc.ifc_buf); if (fd != sockfd) __close (fd); *num_ifs = 0; *ifreqs = NULL; return; } if (ifc.ifc_len + RQ_MAXSIZE <= rq_len) break; rq_len *= 2; } nifs = 0; ifstart = (char *) ifc.ifc_buf; ifend = ifstart + ifc.ifc_len; for (ifr = (struct ifreq *) ifstart; (char *) ifr < ifend; ifr = __if_nextreq (ifr)) nifs++; if (fd != sockfd) __close (fd); *num_ifs = nifs; *ifreqs = realloc (ifc.ifc_buf, ifc.ifc_len); }