summaryrefslogtreecommitdiff
path: root/src/bpf.c
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2012-03-07 19:08:11 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2012-03-07 19:08:11 +0000
commit08456c61f6cd6dcb0d2c71f3ee86020283ce81e3 (patch)
treee6ff35636be5adb1b71088a6198b6e38a8c8775c /src/bpf.c
parent6ffeff86be670651bc30e3e34bd54818c4145db1 (diff)
downloaddnsmasq-08456c61f6cd6dcb0d2c71f3ee86020283ce81e3.tar.gz
Use getifaddrs to find interfaces on *BSD
Diffstat (limited to 'src/bpf.c')
-rw-r--r--src/bpf.c140
1 files 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 <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);
}