--- embedaddon/dnsmasq/src/bpf.c 2013/07/29 19:37:40 1.1.1.1 +++ embedaddon/dnsmasq/src/bpf.c 2014/06/15 16:31:38 1.1.1.2 @@ -1,4 +1,4 @@ -/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley +/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,12 +19,19 @@ #if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) #include -#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) #include #include +#include #include #include #include +#if defined(__FreeBSD__) +# include +#endif +#include +#ifdef HAVE_IPV6 +# include +#endif #ifndef SA_SIZE #define SA_SIZE(sa) \ @@ -33,6 +40,13 @@ 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) #endif +#ifdef HAVE_BSD_NETWORK +static int del_family = 0; +static struct all_addr del_addr; +#endif + +#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) + int arp_enumerate(void *parm, int (*callback)()) { int mib[6]; @@ -83,13 +97,13 @@ int arp_enumerate(void *parm, int (*callback)()) return 1; } -#endif +#endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */ int iface_enumerate(int family, void *parm, int (*callback)()) { struct ifaddrs *head, *addrs; - int errsav, ret = 0; + int errsav, fd = -1, ret = 0; if (family == AF_UNSPEC) #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) @@ -105,25 +119,35 @@ int iface_enumerate(int family, void *parm, int (*call if (getifaddrs(&head) == -1) return 0; +#if defined(HAVE_BSD_NETWORK) && defined(HAVE_IPV6) + if (family == AF_INET6) + fd = socket(PF_INET6, SOCK_DGRAM, 0); +#endif + for (addrs = head; addrs; addrs = addrs->ifa_next) { if (addrs->ifa_addr->sa_family == family) { int iface_index = if_nametoindex(addrs->ifa_name); - if (iface_index == 0 || !addrs->ifa_addr || !addrs->ifa_netmask) + if (iface_index == 0 || !addrs->ifa_addr || + (!addrs->ifa_netmask && family != AF_LINK)) continue; if (family == AF_INET) { struct in_addr addr, netmask, broadcast; addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr; +#ifdef HAVE_BSD_NETWORK + if (del_family == AF_INET && del_addr.addr.addr4.s_addr == addr.s_addr) + continue; +#endif netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr; if (addrs->ifa_broadaddr) broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr; else broadcast.s_addr = 0; - if (!((*callback)(addr, iface_index, netmask, broadcast, parm))) + if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm))) goto err; } #ifdef HAVE_IPV6 @@ -133,11 +157,50 @@ int iface_enumerate(int family, void *parm, int (*call 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; + u32 valid = 0xffffffff, preferred = 0xffffffff; + int flags = 0; +#ifdef HAVE_BSD_NETWORK + if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr.addr6, addr)) + continue; +#endif +#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) + struct in6_ifreq ifr6; + + memset(&ifr6, 0, sizeof(ifr6)); + strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name)); + ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr); + if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1) + { + if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE) + flags |= IFACE_TENTATIVE; + + if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED) + flags |= IFACE_DEPRECATED; + +#ifdef IN6_IFF_TEMPORARY + if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY))) + flags |= IFACE_PERMANENT; +#endif + +#ifdef IN6_IFF_PRIVACY + if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY))) + flags |= IFACE_PERMANENT; +#endif + } + + ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr); + if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1) + { + valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime; + preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime; + } +#endif + 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) @@ -148,13 +211,14 @@ int iface_enumerate(int family, void *parm, int (*call { addr->s6_addr[2] = 0; addr->s6_addr[3] = 0; - } - - /* preferred and valid times == forever until we known how to dtermine them. */ - if (!((*callback)(addr, prefix, scope_id, iface_index, 0, -1, -1, parm))) - goto err; - } -#endif + } + + if (!((*callback)(addr, prefix, scope_id, iface_index, flags, + (int) preferred, (int)valid, parm))) + goto err; + } +#endif /* HAVE_IPV6 */ + #ifdef HAVE_DHCP6 else if (family == AF_LINK) { @@ -172,12 +236,14 @@ int iface_enumerate(int family, void *parm, int (*call err: errsav = errno; - freeifaddrs(head); + freeifaddrs(head); + if (fd != -1) + close(fd); errno = errsav; return ret; } -#endif +#endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */ #if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) @@ -296,6 +362,87 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send()); } +#endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */ + + +#ifdef HAVE_BSD_NETWORK + +void route_init(void) +{ + /* AF_UNSPEC: all addr families */ + daemon->routefd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); + + if (daemon->routefd == -1 || !fix_fd(daemon->routefd)) + die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET); +} + +void route_sock(time_t now) +{ + struct if_msghdr *msg; + int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0); + + if (rc < 4) + return; + + msg = (struct if_msghdr *)daemon->packet; + + if (rc < msg->ifm_msglen) + return; + + if (msg->ifm_version != RTM_VERSION) + { + static int warned = 0; + if (!warned) + { + my_syslog(LOG_WARNING, _("Unknown protocol version from route socket")); + warned = 1; + } + } + else if (msg->ifm_type == RTM_NEWADDR) + { + del_family = 0; + newaddress(now); + } + else if (msg->ifm_type == RTM_DELADDR) + { + /* There's a race in the kernel, such that if we run iface_enumerate() immediately + we get a DELADDR event, the deleted address still appears. Here we store the deleted address + in a static variable, and omit it from the set returned by iface_enumerate() */ + int mask = ((struct ifa_msghdr *)msg)->ifam_addrs; + int maskvec[] = { RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_GENMASK, + RTA_IFP, RTA_IFA, RTA_AUTHOR, RTA_BRD }; + int of; + unsigned int i; + + for (i = 0, of = sizeof(struct ifa_msghdr); of < rc && i < sizeof(maskvec)/sizeof(maskvec[0]); i++) + if (mask & maskvec[i]) + { + struct sockaddr *sa = (struct sockaddr *)((char *)msg + of); + size_t diff = (sa->sa_len != 0) ? sa->sa_len : sizeof(long); + + if (maskvec[i] == RTA_IFA) + { + del_family = sa->sa_family; + if (del_family == AF_INET) + del_addr.addr.addr4 = ((struct sockaddr_in *)sa)->sin_addr; +#ifdef HAVE_IPV6 + else if (del_family == AF_INET6) + del_addr.addr.addr6 = ((struct sockaddr_in6 *)sa)->sin6_addr; #endif + else + del_family = 0; + } + + of += diff; + /* round up as needed */ + if (diff & (sizeof(long) - 1)) + of += sizeof(long) - (diff & (sizeof(long) - 1)); + } + + newaddress(now); + } +} + +#endif /* HAVE_BSD_NETWORK */