summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2012-03-07 20:26:23 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2012-03-07 20:26:23 +0000
commite28d2e2b778d06da717ba4c1d8219512b1a6ca72 (patch)
treec7c1c8313c437cca9176a073040aa0651036fd92
parentc81d390f84182f6565454afce8ff6e7244f6760e (diff)
parent96fafe2ed60892612dfeecca933fb066935ca0dd (diff)
downloaddnsmasq-e28d2e2b778d06da717ba4c1d8219512b1a6ca72.tar.gz
Merge branch 'getifaddrs'
-rw-r--r--src/bpf.c143
1 files changed, 48 insertions, 95 deletions
diff --git a/src/bpf.c b/src/bpf.c
index 9619764..72cf526 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,19 +82,14 @@ 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;
+ int errsav, ret = 0;
+
if (family == AF_UNSPEC)
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
return arp_enumerate(parm, callback);
@@ -112,95 +101,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 = (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 < IN6ADDRSZ; i++, prefix += 8)
+ if (netmask[i] != 0xff)
+ break;
+
+ if (i != IN6ADDRSZ && 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 *) addrs->ifa_addr;
+ if (sdl->sdl_alen != 0 &&
+ !((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
goto err;
}
#endif
@@ -211,7 +167,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
err:
errsav = errno;
- close(fd);
+ freeifaddrs(head);
errno = errsav;
return ret;
@@ -228,13 +184,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);
}