version 1.1, 2013/07/29 19:37:40
|
version 1.1.1.4, 2021/03/17 00:56:46
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2021 Simon Kelley |
|
|
This program is free software; you can redistribute it and/or modify |
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 |
it under the terms of the GNU General Public License as published by |
Line 19
|
Line 19
|
#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) |
#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) |
#include <ifaddrs.h> |
#include <ifaddrs.h> |
|
|
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) |
|
#include <sys/param.h> |
#include <sys/param.h> |
|
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) |
#include <sys/sysctl.h> |
#include <sys/sysctl.h> |
|
#endif |
|
#include <net/if.h> |
#include <net/route.h> |
#include <net/route.h> |
#include <net/if_dl.h> |
#include <net/if_dl.h> |
#include <netinet/if_ether.h> |
#include <netinet/if_ether.h> |
|
#if defined(__FreeBSD__) |
|
# include <net/if_var.h> |
|
#endif |
|
#include <netinet/in_var.h> |
|
#include <netinet6/in6_var.h> |
|
|
#ifndef SA_SIZE |
#ifndef SA_SIZE |
#define SA_SIZE(sa) \ |
#define SA_SIZE(sa) \ |
Line 33
|
Line 40
|
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) |
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) |
#endif |
#endif |
|
|
|
#ifdef HAVE_BSD_NETWORK |
|
static int del_family = 0; |
|
static union all_addr del_addr; |
|
#endif |
|
|
|
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) |
|
|
int arp_enumerate(void *parm, int (*callback)()) |
int arp_enumerate(void *parm, int (*callback)()) |
{ |
{ |
int mib[6]; |
int mib[6]; |
Line 83 int arp_enumerate(void *parm, int (*callback)())
|
Line 97 int arp_enumerate(void *parm, int (*callback)())
|
|
|
return 1; |
return 1; |
} |
} |
#endif | #endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */ |
|
|
|
|
int iface_enumerate(int family, void *parm, int (*callback)()) |
int iface_enumerate(int family, void *parm, int (*callback)()) |
{ |
{ |
struct ifaddrs *head, *addrs; |
struct ifaddrs *head, *addrs; |
int errsav, ret = 0; | int errsave, fd = -1, ret = 0; |
|
|
if (family == AF_UNSPEC) |
if (family == AF_UNSPEC) |
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) |
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) |
Line 105 int iface_enumerate(int family, void *parm, int (*call
|
Line 119 int iface_enumerate(int family, void *parm, int (*call
|
if (getifaddrs(&head) == -1) |
if (getifaddrs(&head) == -1) |
return 0; |
return 0; |
|
|
|
#if defined(HAVE_BSD_NETWORK) |
|
if (family == AF_INET6) |
|
fd = socket(PF_INET6, SOCK_DGRAM, 0); |
|
#endif |
|
|
for (addrs = head; addrs; addrs = addrs->ifa_next) |
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); |
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; |
continue; |
|
|
if (family == AF_INET) |
if (family == AF_INET) |
{ |
{ |
struct in_addr addr, netmask, broadcast; |
struct in_addr addr, netmask, broadcast; |
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr; |
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr; |
|
#ifdef HAVE_BSD_NETWORK |
|
if (del_family == AF_INET && del_addr.addr4.s_addr == addr.s_addr) |
|
continue; |
|
#endif |
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr; |
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr; |
if (addrs->ifa_broadaddr) |
if (addrs->ifa_broadaddr) |
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr; |
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr; |
else |
else |
broadcast.s_addr = 0; |
broadcast.s_addr = 0; |
if (!((*callback)(addr, iface_index, netmask, broadcast, parm))) | if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm))) |
goto err; |
goto err; |
} |
} |
#ifdef HAVE_IPV6 |
|
else if (family == AF_INET6) |
else if (family == AF_INET6) |
{ |
{ |
struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_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; |
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 scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id; |
int i, j, prefix = 0; |
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.addr6, addr)) |
|
continue; |
|
#endif |
|
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) |
|
struct in6_ifreq ifr6; |
|
|
|
memset(&ifr6, 0, sizeof(ifr6)); |
|
safe_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) |
for (i = 0; i < IN6ADDRSZ; i++, prefix += 8) |
if (netmask[i] != 0xff) |
if (netmask[i] != 0xff) |
break; |
break; |
| |
if (i != IN6ADDRSZ && netmask[i]) |
if (i != IN6ADDRSZ && netmask[i]) |
for (j = 7; j > 0; j--, prefix++) |
for (j = 7; j > 0; j--, prefix++) |
if ((netmask[i] & (1 << j)) == 0) |
if ((netmask[i] & (1 << j)) == 0) |
Line 148 int iface_enumerate(int family, void *parm, int (*call
|
Line 210 int iface_enumerate(int family, void *parm, int (*call
|
{ |
{ |
addr->s6_addr[2] = 0; |
addr->s6_addr[2] = 0; |
addr->s6_addr[3] = 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, flags, |
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, -1, -1, parm))) | (int) preferred, (int)valid, parm))) |
goto err; | goto err; |
} | } |
#endif | |
#ifdef HAVE_DHCP6 |
#ifdef HAVE_DHCP6 |
else if (family == AF_LINK) |
else if (family == AF_LINK) |
{ |
{ |
Line 171 int iface_enumerate(int family, void *parm, int (*call
|
Line 233 int iface_enumerate(int family, void *parm, int (*call
|
ret = 1; |
ret = 1; |
|
|
err: |
err: |
errsav = errno; | errsave = errno; |
freeifaddrs(head); | freeifaddrs(head); |
errno = errsav; | if (fd != -1) |
| close(fd); |
| errno = errsave; |
|
|
return ret; |
return ret; |
} |
} |
#endif | #endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */ |
|
|
|
|
#if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) |
#if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) |
Line 293 void send_via_bpf(struct dhcp_packet *mess, size_t len
|
Line 357 void send_via_bpf(struct dhcp_packet *mess, size_t len
|
iov[3].iov_base = mess; |
iov[3].iov_base = mess; |
iov[3].iov_len = len; |
iov[3].iov_len = len; |
|
|
while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send()); | while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4))); |
} |
} |
|
|
#endif | #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(void) |
| { |
| 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; |
| queue_event(EVENT_NEWADDR); |
| } |
| 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.addr4 = ((struct sockaddr_in *)sa)->sin_addr; |
| else if (del_family == AF_INET6) |
| del_addr.addr6 = ((struct sockaddr_in6 *)sa)->sin6_addr; |
| else |
| del_family = 0; |
| } |
| |
| of += diff; |
| /* round up as needed */ |
| if (diff & (sizeof(long) - 1)) |
| of += sizeof(long) - (diff & (sizeof(long) - 1)); |
| } |
| |
| queue_event(EVENT_NEWADDR); |
| } |
| } |
| |
| #endif /* HAVE_BSD_NETWORK */ |
|
|
|
|