From 08456c61f6cd6dcb0d2c71f3ee86020283ce81e3 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Wed, 7 Mar 2012 19:08:11 +0000 Subject: Use getifaddrs to find interfaces on *BSD --- src/bpf.c | 140 +++++++++++++++++++++----------------------------------------- 1 file changed, 46 insertions(+), 94 deletions(-) diff --git a/src/bpf.c b/src/bpf.c index 9619764..ded0c71 100644 --- a/src/bpf.c +++ b/src/bpf.c @@ -18,22 +18,12 @@ #if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) -static struct iovec ifconf = { - .iov_base = NULL, - .iov_len = 0 -}; - -static struct iovec ifreq = { - .iov_base = NULL, - .iov_len = 0 -}; - #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) - #include #include #include #include +#include #ifndef SA_SIZE #define SA_SIZE(sa) \ @@ -50,8 +40,12 @@ int arp_enumerate(void *parm, int (*callback)()) struct rt_msghdr *rtm; struct sockaddr_inarp *sin2; struct sockaddr_dl *sdl; + struct iovec buff; int rc; - + + buff.iov_base = NULL; + buff.iov_len = 0 + mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; @@ -67,9 +61,9 @@ int arp_enumerate(void *parm, int (*callback)()) while (1) { - if (!expand_buf(&ifconf, needed)) + if (!expand_buf(&buff, needed)) return 0; - if ((rc = sysctl(mib, 6, ifconf.iov_base, &needed, NULL, 0)) == 0 || + if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 || errno != ENOMEM) break; needed += needed / 8; @@ -77,7 +71,7 @@ int arp_enumerate(void *parm, int (*callback)()) if (rc == -1) return 0; - for (next = ifconf.iov_base ; next < (char *)ifconf.iov_base + needed; next += rtm->rtm_msglen) + for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; sin2 = (struct sockaddr_inarp *)(rtm + 1); @@ -88,18 +82,12 @@ int arp_enumerate(void *parm, int (*callback)()) return 1; } - #endif int iface_enumerate(int family, void *parm, int (*callback)()) { - char *ptr; - struct ifreq *ifr; - struct ifconf ifc; - int fd, errsav, ret = 0; - int lastlen = 0; - size_t len = 0; + struct ifaddrs *head, *addrs; if (family == AF_UNSPEC) #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) @@ -112,95 +100,62 @@ int iface_enumerate(int family, void *parm, int (*callback)()) if (family == AF_LOCAL) family = AF_LINK; - if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) + if (getifaddrs(&head) == -1) return 0; - - while(1) + + for (addrs = head; addrs; addrs = addrs->ifa_next) { - len += 10*sizeof(struct ifreq); - - if (!expand_buf(&ifconf, len)) - goto err; - - ifc.ifc_len = len; - ifc.ifc_buf = ifconf.iov_base; - - if (ioctl(fd, SIOCGIFCONF, &ifc) == -1) - { - if (errno != EINVAL || lastlen != 0) - goto err; - } - else + if (addrs->ifa_addr.sa_family == family) { - if (ifc.ifc_len == lastlen) - break; /* got a big enough buffer now */ - lastlen = ifc.ifc_len; - } - } - - for (ptr = ifc.ifc_buf; ptr < (char *)(ifc.ifc_buf + ifc.ifc_len); ptr += len) - { - /* subsequent entries may not be aligned, so copy into - an aligned buffer to avoid nasty complaints about - unaligned accesses. */ + int iface_index = if_nametoindex(addrs->ifa_name); - len = sizeof(struct ifreq); - -#ifdef HAVE_SOCKADDR_SA_LEN - ifr = (struct ifreq *)ptr; - if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru)) - len = ifr->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru); -#endif - - if (!expand_buf(&ifreq, len)) - goto err; + if (iface_index == 0) + continue; - ifr = (struct ifreq *)ifreq.iov_base; - memcpy(ifr, ptr, len); - - if (ifr->ifr_addr.sa_family == family) - { if (family == AF_INET) { struct in_addr addr, netmask, broadcast; - broadcast.s_addr = 0; - addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr; - if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1) - continue; - netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr; - if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1) - broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr; - if (!((*callback)(addr, - (int)if_nametoindex(ifr->ifr_name), - netmask, broadcast, - parm))) + addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr; + netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr; + broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr; + if (!((*callback)(addr, iface_index, netmask, broadcast, parm))) goto err; } #ifdef HAVE_IPV6 else if (family == AF_INET6) { - struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr; + struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr; + unsigned char *netmask = &(unisgned char *) addrs->ifa_netmask)->sin6_addr; + int scope_id = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id; + int i, j, prefix = 0; + + for (i = 0; i < IN6_ADDRSZ; i++, prefix += 8) + if (netmask[i] != 0xff) + break; + + if (i != IN6_ADDRSZ && netmask[i]) + for (j = 7; j > 0; j--, prefix++) + if ((netmask[i] & (1 << j)) == 0) + break; + /* voodoo to clear interface field in address */ if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr)) { addr->s6_addr[2] = 0; addr->s6_addr[3] = 0; } - /* We have no way to determine the prefix, so we assume it's 64 for now....... */ - if (!((*callback)(addr, 64, - (int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id, - (int)if_nametoindex(ifr->ifr_name), 0, - parm))) + + if (!((*callback)(addr, prefix, scope_id, iface_index, 0, parm))) goto err; - } + } #endif #ifdef HAVE_DHCP6 else if (family == AF_LINK) { /* Assume ethernet again here */ - struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr; - if (sdl->sdl_alen != 0 && !((*callback)((int)if_nametoindex(ifr->ifr_name), - ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm))) + struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifa->ifr_addr; + if (sdl->sdl_alen != 0 && + !((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm))) goto err; } #endif @@ -211,7 +166,7 @@ int iface_enumerate(int family, void *parm, int (*callback)()) err: errsav = errno; - close(fd); + freeifaddrs(head); errno = errsav; return ret; @@ -228,13 +183,10 @@ void init_bpf(void) while (1) { - /* useful size which happens to be sufficient */ - if (expand_buf(&ifreq, sizeof(struct ifreq))) - { - sprintf(ifreq.iov_base, "/dev/bpf%d", i++); - if ((daemon->dhcp_raw_fd = open(ifreq.iov_base, O_RDWR, 0)) != -1) - return; - } + sprintf(daemon->dhcp_buff, "/dev/bpf%d", i++); + if ((daemon->dhcp_raw_fd = open(daemon->dhcp_buff, O_RDWR, 0)) != -1) + return; + if (errno != EBUSY) die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET); } -- cgit v1.2.1 From 96fafe2ed60892612dfeecca933fb066935ca0dd Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Wed, 7 Mar 2012 20:25:39 +0000 Subject: Fixed typos and tested. --- src/bpf.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/bpf.c b/src/bpf.c index ded0c71..72cf526 100644 --- a/src/bpf.c +++ b/src/bpf.c @@ -44,7 +44,7 @@ int arp_enumerate(void *parm, int (*callback)()) int rc; buff.iov_base = NULL; - buff.iov_len = 0 + buff.iov_len = 0; mib[0] = CTL_NET; mib[1] = PF_ROUTE; @@ -88,7 +88,8 @@ int arp_enumerate(void *parm, int (*callback)()) int iface_enumerate(int family, void *parm, int (*callback)()) { struct ifaddrs *head, *addrs; - + int errsav, ret = 0; + if (family == AF_UNSPEC) #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) return arp_enumerate(parm, callback); @@ -105,7 +106,7 @@ int iface_enumerate(int family, void *parm, int (*callback)()) for (addrs = head; addrs; addrs = addrs->ifa_next) { - if (addrs->ifa_addr.sa_family == family) + if (addrs->ifa_addr->sa_family == family) { int iface_index = if_nametoindex(addrs->ifa_name); @@ -125,15 +126,15 @@ int iface_enumerate(int family, void *parm, int (*callback)()) else if (family == AF_INET6) { struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr; - unsigned char *netmask = &(unisgned char *) addrs->ifa_netmask)->sin6_addr; - int scope_id = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id; + unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr; + int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id; int i, j, prefix = 0; - for (i = 0; i < IN6_ADDRSZ; i++, prefix += 8) + for (i = 0; i < IN6ADDRSZ; i++, prefix += 8) if (netmask[i] != 0xff) break; - if (i != IN6_ADDRSZ && netmask[i]) + if (i != IN6ADDRSZ && netmask[i]) for (j = 7; j > 0; j--, prefix++) if ((netmask[i] & (1 << j)) == 0) break; @@ -153,7 +154,7 @@ int iface_enumerate(int family, void *parm, int (*callback)()) else if (family == AF_LINK) { /* Assume ethernet again here */ - struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifa->ifr_addr; + struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr; if (sdl->sdl_alen != 0 && !((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm))) goto err; -- cgit v1.2.1