mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
Implement dynamic interface discovery on *BSD
This commit is contained in:
@@ -1,3 +1,10 @@
|
|||||||
|
version 2.69
|
||||||
|
Implement dynamic interface discovery on *BSD. This allows
|
||||||
|
the contructor: syntax to be used in dhcp-range for DHCPv6
|
||||||
|
on the BSD platform. Thanks to Matthias Andree for
|
||||||
|
valuable research on how to implement this.
|
||||||
|
|
||||||
|
|
||||||
version 2.68
|
version 2.68
|
||||||
Use random addresses for DHCPv6 temporary address
|
Use random addresses for DHCPv6 temporary address
|
||||||
allocations, instead of algorithmically determined stable
|
allocations, instead of algorithmically determined stable
|
||||||
|
|||||||
106
src/bpf.c
106
src/bpf.c
@@ -19,9 +19,9 @@
|
|||||||
#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>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
|
#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>
|
||||||
@@ -29,7 +29,9 @@
|
|||||||
# include <net/if_var.h>
|
# include <net/if_var.h>
|
||||||
#endif
|
#endif
|
||||||
#include <netinet/in_var.h>
|
#include <netinet/in_var.h>
|
||||||
#include <netinet6/in6_var.h>
|
#ifdef HAVE_IPV6
|
||||||
|
# include <netinet6/in6_var.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SA_SIZE
|
#ifndef SA_SIZE
|
||||||
#define SA_SIZE(sa) \
|
#define SA_SIZE(sa) \
|
||||||
@@ -38,6 +40,13 @@
|
|||||||
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 struct 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];
|
||||||
@@ -88,7 +97,7 @@ 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)())
|
||||||
@@ -129,6 +138,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
{
|
{
|
||||||
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.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;
|
||||||
@@ -146,6 +159,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
int i, j, prefix = 0;
|
int i, j, prefix = 0;
|
||||||
u32 valid = 0xffffffff, preferred = 0xffffffff;
|
u32 valid = 0xffffffff, preferred = 0xffffffff;
|
||||||
int flags = 0;
|
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__)
|
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||||
struct in6_ifreq ifr6;
|
struct in6_ifreq ifr6;
|
||||||
|
|
||||||
@@ -226,7 +243,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
|
|
||||||
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)
|
||||||
@@ -345,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());
|
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
|
#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 */
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -720,7 +720,6 @@ void dhcp_construct_contexts(time_t now)
|
|||||||
|
|
||||||
if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
|
if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
|
||||||
{
|
{
|
||||||
|
|
||||||
if ((context->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) ||
|
if ((context->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) ||
|
||||||
option_bool(OPT_RA))
|
option_bool(OPT_RA))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ int main (int argc, char **argv)
|
|||||||
daemon->doing_dhcp6 = 1;
|
daemon->doing_dhcp6 = 1;
|
||||||
if (context->flags & CONTEXT_RA)
|
if (context->flags & CONTEXT_RA)
|
||||||
daemon->doing_ra = 1;
|
daemon->doing_ra = 1;
|
||||||
#ifndef HAVE_LINUX_NETWORK
|
#if !defined(HAVE_LINUX_NETWORK) && !defined(HAVE_BSD_NETWORK)
|
||||||
if (context->flags & CONTEXT_TEMPLATE)
|
if (context->flags & CONTEXT_TEMPLATE)
|
||||||
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
|
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
|
||||||
#endif
|
#endif
|
||||||
@@ -220,13 +220,15 @@ int main (int argc, char **argv)
|
|||||||
ipset_init();
|
ipset_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
netlink_init();
|
netlink_init();
|
||||||
|
#elif defined(HAVE_BSD_NETWORK)
|
||||||
if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
|
route_init();
|
||||||
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
|
||||||
|
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
|
||||||
|
|
||||||
if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
|
if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
|
||||||
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
||||||
|
|
||||||
@@ -808,11 +810,14 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
FD_SET(daemon->netlinkfd, &rset);
|
FD_SET(daemon->netlinkfd, &rset);
|
||||||
bump_maxfd(daemon->netlinkfd, &maxfd);
|
bump_maxfd(daemon->netlinkfd, &maxfd);
|
||||||
|
#elif defined(HAVE_BSD_NETWORK)
|
||||||
|
FD_SET(daemon->routefd, &rset);
|
||||||
|
bump_maxfd(daemon->routefd, &maxfd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FD_SET(piperead, &rset);
|
FD_SET(piperead, &rset);
|
||||||
bump_maxfd(piperead, &maxfd);
|
bump_maxfd(piperead, &maxfd);
|
||||||
|
|
||||||
@@ -867,9 +872,12 @@ int main (int argc, char **argv)
|
|||||||
warn_bound_listeners();
|
warn_bound_listeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||||
netlink_multicast(now);
|
netlink_multicast(now);
|
||||||
|
#elif defined(HAVE_BSD_NETWORK)
|
||||||
|
if (FD_ISSET(daemon->routefd, &rset))
|
||||||
|
route_sock(now);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Check for changes to resolv files once per second max. */
|
/* Check for changes to resolv files once per second max. */
|
||||||
|
|||||||
@@ -900,7 +900,7 @@ extern struct daemon {
|
|||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
int netlinkfd;
|
int netlinkfd;
|
||||||
#elif defined(HAVE_BSD_NETWORK)
|
#elif defined(HAVE_BSD_NETWORK)
|
||||||
int dhcp_raw_fd, dhcp_icmp_fd;
|
int dhcp_raw_fd, dhcp_icmp_fd, routefd;
|
||||||
#endif
|
#endif
|
||||||
struct iovec dhcp_packet;
|
struct iovec dhcp_packet;
|
||||||
char *dhcp_buff, *dhcp_buff2, *dhcp_buff3;
|
char *dhcp_buff, *dhcp_buff2, *dhcp_buff3;
|
||||||
@@ -1090,6 +1090,10 @@ int set_ipv6pktinfo(int fd);
|
|||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
void join_multicast(int dienow);
|
void join_multicast(int dienow);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_BSD_NETWORK)
|
||||||
|
void newaddress(time_t now);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* dhcp.c */
|
/* dhcp.c */
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
@@ -1177,6 +1181,8 @@ void netlink_multicast(time_t now);
|
|||||||
void init_bpf(void);
|
void init_bpf(void);
|
||||||
void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||||
struct in_addr iface_addr, struct ifreq *ifr);
|
struct in_addr iface_addr, struct ifreq *ifr);
|
||||||
|
void route_init(void);
|
||||||
|
void route_sock(time_t now);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* bpf.c or netlink.c */
|
/* bpf.c or netlink.c */
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ static struct iovec iov;
|
|||||||
static u32 netlink_pid;
|
static u32 netlink_pid;
|
||||||
|
|
||||||
static int nl_async(struct nlmsghdr *h);
|
static int nl_async(struct nlmsghdr *h);
|
||||||
static void nl_newaddress(time_t now);
|
|
||||||
|
|
||||||
void netlink_init(void)
|
void netlink_init(void)
|
||||||
{
|
{
|
||||||
@@ -203,7 +202,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
/* handle async new interface address arrivals, these have to be done
|
/* handle async new interface address arrivals, these have to be done
|
||||||
after we complete as we're not re-entrant */
|
after we complete as we're not re-entrant */
|
||||||
if (newaddr)
|
if (newaddr)
|
||||||
nl_newaddress(dnsmasq_time());
|
newaddress(dnsmasq_time());
|
||||||
|
|
||||||
return callback_ok;
|
return callback_ok;
|
||||||
}
|
}
|
||||||
@@ -351,7 +350,7 @@ void netlink_multicast(time_t now)
|
|||||||
fcntl(daemon->netlinkfd, F_SETFL, flags);
|
fcntl(daemon->netlinkfd, F_SETFL, flags);
|
||||||
|
|
||||||
if (newaddr)
|
if (newaddr)
|
||||||
nl_newaddress(now);
|
newaddress(now);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nl_async(struct nlmsghdr *h)
|
static int nl_async(struct nlmsghdr *h)
|
||||||
@@ -399,30 +398,6 @@ static int nl_async(struct nlmsghdr *h)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nl_newaddress(time_t now)
|
|
||||||
{
|
|
||||||
(void)now;
|
|
||||||
|
|
||||||
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
|
||||||
enumerate_interfaces(0);
|
|
||||||
|
|
||||||
if (option_bool(OPT_CLEVERBIND))
|
|
||||||
create_bound_listeners(0);
|
|
||||||
|
|
||||||
#ifdef HAVE_DHCP6
|
|
||||||
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
|
||||||
join_multicast(0);
|
|
||||||
|
|
||||||
if (daemon->doing_dhcp6 || daemon->doing_ra)
|
|
||||||
dhcp_construct_contexts(now);
|
|
||||||
|
|
||||||
if (daemon->doing_dhcp6)
|
|
||||||
lease_find_interfaces(now);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -489,7 +489,7 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
|
|||||||
addr.in6.sin6_scope_id = if_index;
|
addr.in6.sin6_scope_id = if_index;
|
||||||
else
|
else
|
||||||
addr.in6.sin6_scope_id = 0;
|
addr.in6.sin6_scope_id = 0;
|
||||||
|
|
||||||
return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, !!(flags & IFACE_TENTATIVE));
|
return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, !!(flags & IFACE_TENTATIVE));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -681,7 +681,7 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
|
|||||||
close (fd);
|
close (fd);
|
||||||
|
|
||||||
errno = errsav;
|
errno = errsav;
|
||||||
|
|
||||||
if (dienow)
|
if (dienow)
|
||||||
{
|
{
|
||||||
/* failure to bind addresses given by --listen-address at this point
|
/* failure to bind addresses given by --listen-address at this point
|
||||||
@@ -1470,7 +1470,31 @@ int reload_servers(char *fname)
|
|||||||
return gotone;
|
return gotone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_BSD_NETWORK)
|
||||||
|
/* Called when addresses are added or deleted from an interface */
|
||||||
|
void newaddress(time_t now)
|
||||||
|
{
|
||||||
|
(void)now;
|
||||||
|
|
||||||
|
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||||
|
enumerate_interfaces(0);
|
||||||
|
|
||||||
|
if (option_bool(OPT_CLEVERBIND))
|
||||||
|
create_bound_listeners(0);
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||||
|
join_multicast(0);
|
||||||
|
|
||||||
|
if (daemon->doing_dhcp6 || daemon->doing_ra)
|
||||||
|
dhcp_construct_contexts(now);
|
||||||
|
|
||||||
|
if (daemon->doing_dhcp6)
|
||||||
|
lease_find_interfaces(now);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user