diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2012-03-07 19:08:11 +0000 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2012-03-07 19:08:11 +0000 |
commit | 08456c61f6cd6dcb0d2c71f3ee86020283ce81e3 (patch) | |
tree | e6ff35636be5adb1b71088a6198b6e38a8c8775c /src/bpf.c | |
parent | 6ffeff86be670651bc30e3e34bd54818c4145db1 (diff) | |
download | dnsmasq-08456c61f6cd6dcb0d2c71f3ee86020283ce81e3.tar.gz |
Use getifaddrs to find interfaces on *BSD
Diffstat (limited to 'src/bpf.c')
-rw-r--r-- | src/bpf.c | 140 |
1 files changed, 46 insertions, 94 deletions
@@ -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 <sys/sysctl.h> #include <net/route.h> #include <net/if_dl.h> #include <netinet/if_ether.h> +#include <ifaddrs.h> #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); } |