version 1.1.1.2, 2014/06/15 16:31:38
|
version 1.1.1.4, 2021/03/17 00:56:46
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2014 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 22
|
Line 22
|
#include <linux/netlink.h> |
#include <linux/netlink.h> |
#include <linux/rtnetlink.h> |
#include <linux/rtnetlink.h> |
|
|
|
/* Blergh. Radv does this, so that's our excuse. */ |
|
#ifndef SOL_NETLINK |
|
#define SOL_NETLINK 270 |
|
#endif |
|
|
|
#ifndef NETLINK_NO_ENOBUFS |
|
#define NETLINK_NO_ENOBUFS 5 |
|
#endif |
|
|
/* linux 2.6.19 buggers up the headers, patch it up here. */ |
/* linux 2.6.19 buggers up the headers, patch it up here. */ |
#ifndef IFA_RTA |
#ifndef IFA_RTA |
# define IFA_RTA(r) \ |
# define IFA_RTA(r) \ |
Line 38
|
Line 47
|
static struct iovec iov; |
static struct iovec iov; |
static u32 netlink_pid; |
static u32 netlink_pid; |
|
|
static int nl_async(struct nlmsghdr *h); | static void nl_async(struct nlmsghdr *h); |
|
|
void netlink_init(void) | char *netlink_init(void) |
{ |
{ |
struct sockaddr_nl addr; |
struct sockaddr_nl addr; |
socklen_t slen = sizeof(addr); |
socklen_t slen = sizeof(addr); |
|
int opt = 1; |
|
|
addr.nl_family = AF_NETLINK; |
addr.nl_family = AF_NETLINK; |
addr.nl_pad = 0; |
addr.nl_pad = 0; |
Line 51 void netlink_init(void)
|
Line 61 void netlink_init(void)
|
addr.nl_groups = RTMGRP_IPV4_ROUTE; |
addr.nl_groups = RTMGRP_IPV4_ROUTE; |
if (option_bool(OPT_CLEVERBIND)) |
if (option_bool(OPT_CLEVERBIND)) |
addr.nl_groups |= RTMGRP_IPV4_IFADDR; |
addr.nl_groups |= RTMGRP_IPV4_IFADDR; |
#ifdef HAVE_IPV6 |
|
addr.nl_groups |= RTMGRP_IPV6_ROUTE; |
addr.nl_groups |= RTMGRP_IPV6_ROUTE; |
if (option_bool(OPT_CLEVERBIND)) |
if (option_bool(OPT_CLEVERBIND)) |
addr.nl_groups |= RTMGRP_IPV6_IFADDR; |
addr.nl_groups |= RTMGRP_IPV6_IFADDR; |
#endif | |
#ifdef HAVE_DHCP6 |
#ifdef HAVE_DHCP6 |
if (daemon->doing_ra || daemon->doing_dhcp6) |
if (daemon->doing_ra || daemon->doing_dhcp6) |
addr.nl_groups |= RTMGRP_IPV6_IFADDR; |
addr.nl_groups |= RTMGRP_IPV6_IFADDR; |
Line 73 void netlink_init(void)
|
Line 82 void netlink_init(void)
|
} |
} |
|
|
if (daemon->netlinkfd == -1 || |
if (daemon->netlinkfd == -1 || |
getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == 1) | getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == -1) |
die(_("cannot create netlink socket: %s"), NULL, EC_MISC); |
die(_("cannot create netlink socket: %s"), NULL, EC_MISC); |
| |
| |
/* save pid assigned by bind() and retrieved by getsockname() */ |
/* save pid assigned by bind() and retrieved by getsockname() */ |
netlink_pid = addr.nl_pid; |
netlink_pid = addr.nl_pid; |
|
|
iov.iov_len = 100; |
iov.iov_len = 100; |
iov.iov_base = safe_malloc(iov.iov_len); |
iov.iov_base = safe_malloc(iov.iov_len); |
|
|
|
if (daemon->kernel_version >= KERNEL_VERSION(2,6,30) && |
|
setsockopt(daemon->netlinkfd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(opt)) == -1) |
|
return _("warning: failed to set NETLINK_NO_ENOBUFS on netlink socket"); |
|
|
|
return NULL; |
} |
} |
|
|
static ssize_t netlink_recv(void) |
static ssize_t netlink_recv(void) |
Line 142 int iface_enumerate(int family, void *parm, int (*call
|
Line 158 int iface_enumerate(int family, void *parm, int (*call
|
struct nlmsghdr *h; |
struct nlmsghdr *h; |
ssize_t len; |
ssize_t len; |
static unsigned int seq = 0; |
static unsigned int seq = 0; |
int callback_ok = 1, newaddr = 0; | int callback_ok = 1; |
|
|
struct { |
struct { |
struct nlmsghdr nlh; |
struct nlmsghdr nlh; |
struct rtgenmsg g; |
struct rtgenmsg g; |
} req; |
} req; |
|
|
|
memset(&req, 0, sizeof(req)); |
|
memset(&addr, 0, sizeof(addr)); |
|
|
addr.nl_family = AF_NETLINK; |
addr.nl_family = AF_NETLINK; |
addr.nl_pad = 0; |
|
addr.nl_groups = 0; |
|
addr.nl_pid = 0; /* address to kernel */ |
|
|
|
again: |
again: |
if (family == AF_UNSPEC) |
if (family == AF_UNSPEC) |
Line 169 int iface_enumerate(int family, void *parm, int (*call
|
Line 185 int iface_enumerate(int family, void *parm, int (*call
|
req.g.rtgen_family = family; |
req.g.rtgen_family = family; |
|
|
/* Don't block in recvfrom if send fails */ |
/* Don't block in recvfrom if send fails */ |
while((len = sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0, | while(retry_send(sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0, |
(struct sockaddr *)&addr, sizeof(addr))) == -1 && retry_send()); | (struct sockaddr *)&addr, sizeof(addr)))); |
| |
if (len == -1) | if (errno != 0) |
return 0; |
return 0; |
|
|
while (1) |
while (1) |
Line 188 int iface_enumerate(int family, void *parm, int (*call
|
Line 204 int iface_enumerate(int family, void *parm, int (*call
|
} |
} |
|
|
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len)) |
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len)) |
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR) | if (h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR) |
{ |
{ |
/* May be multicast arriving async */ |
/* May be multicast arriving async */ |
if (nl_async(h)) | nl_async(h); |
{ | |
newaddr = 1; | |
enumerate_interfaces(1); /* reset */ | |
} | |
} |
} |
else if (h->nlmsg_type == NLMSG_DONE) | else if (h->nlmsg_seq != seq) |
{ |
{ |
/* handle async new interface address arrivals, these have to be done | /* May be part of incomplete response to previous request after |
after we complete as we're not re-entrant */ | ENOBUFS. Drop it. */ |
if (newaddr) | continue; |
newaddress(dnsmasq_time()); | |
| |
return callback_ok; | |
} |
} |
|
else if (h->nlmsg_type == NLMSG_DONE) |
|
return callback_ok; |
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL) |
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL) |
{ |
{ |
struct ifaddrmsg *ifa = NLMSG_DATA(h); |
struct ifaddrmsg *ifa = NLMSG_DATA(h); |
Line 219 int iface_enumerate(int family, void *parm, int (*call
|
Line 230 int iface_enumerate(int family, void *parm, int (*call
|
struct in_addr netmask, addr, broadcast; |
struct in_addr netmask, addr, broadcast; |
char *label = NULL; |
char *label = NULL; |
|
|
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen)); | netmask.s_addr = htonl(~(in_addr_t)0 << (32 - ifa->ifa_prefixlen)); |
| |
addr.s_addr = 0; |
addr.s_addr = 0; |
broadcast.s_addr = 0; |
broadcast.s_addr = 0; |
|
|
Line 239 int iface_enumerate(int family, void *parm, int (*call
|
Line 251 int iface_enumerate(int family, void *parm, int (*call
|
if (!((*callback)(addr, ifa->ifa_index, label, netmask, broadcast, parm))) |
if (!((*callback)(addr, ifa->ifa_index, label, netmask, broadcast, parm))) |
callback_ok = 0; |
callback_ok = 0; |
} |
} |
#ifdef HAVE_IPV6 |
|
else if (ifa->ifa_family == AF_INET6) |
else if (ifa->ifa_family == AF_INET6) |
{ |
{ |
struct in6_addr *addrp = NULL; |
struct in6_addr *addrp = NULL; |
Line 274 int iface_enumerate(int family, void *parm, int (*call
|
Line 285 int iface_enumerate(int family, void *parm, int (*call
|
(int) preferred, (int)valid, parm))) |
(int) preferred, (int)valid, parm))) |
callback_ok = 0; |
callback_ok = 0; |
} |
} |
#endif |
|
} |
} |
} |
} |
else if (h->nlmsg_type == RTM_NEWNEIGH && family == AF_UNSPEC) |
else if (h->nlmsg_type == RTM_NEWNEIGH && family == AF_UNSPEC) |
Line 298 int iface_enumerate(int family, void *parm, int (*call
|
Line 308 int iface_enumerate(int family, void *parm, int (*call
|
rta = RTA_NEXT(rta, len1); |
rta = RTA_NEXT(rta, len1); |
} |
} |
|
|
if (inaddr && mac && callback_ok) | if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) && |
| inaddr && mac && callback_ok) |
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm))) |
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm))) |
callback_ok = 0; |
callback_ok = 0; |
} |
} |
Line 330 int iface_enumerate(int family, void *parm, int (*call
|
Line 341 int iface_enumerate(int family, void *parm, int (*call
|
} |
} |
} |
} |
|
|
void netlink_multicast(time_t now) | void netlink_multicast(void) |
{ |
{ |
ssize_t len; |
ssize_t len; |
struct nlmsghdr *h; |
struct nlmsghdr *h; |
int flags, newaddr = 0; | int flags; |
|
|
/* don't risk blocking reading netlink messages here. */ |
/* don't risk blocking reading netlink messages here. */ |
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 || |
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 || |
Line 343 void netlink_multicast(time_t now)
|
Line 354 void netlink_multicast(time_t now)
|
|
|
if ((len = netlink_recv()) != -1) |
if ((len = netlink_recv()) != -1) |
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len)) |
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len)) |
if (nl_async(h)) | nl_async(h); |
newaddr = 1; | |
|
|
/* restore non-blocking status */ |
/* restore non-blocking status */ |
fcntl(daemon->netlinkfd, F_SETFL, flags); |
fcntl(daemon->netlinkfd, F_SETFL, flags); |
|
|
if (newaddr) |
|
newaddress(now); |
|
} |
} |
|
|
static int nl_async(struct nlmsghdr *h) | static void nl_async(struct nlmsghdr *h) |
{ |
{ |
if (h->nlmsg_type == NLMSG_ERROR) |
if (h->nlmsg_type == NLMSG_ERROR) |
{ |
{ |
struct nlmsgerr *err = NLMSG_DATA(h); |
struct nlmsgerr *err = NLMSG_DATA(h); |
if (err->error != 0) |
if (err->error != 0) |
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error))); |
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error))); |
return 0; |
|
} |
} |
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE) |
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE) |
{ |
{ |
Line 371 static int nl_async(struct nlmsghdr *h)
|
Line 377 static int nl_async(struct nlmsghdr *h)
|
failing. */ |
failing. */ |
struct rtmsg *rtm = NLMSG_DATA(h); |
struct rtmsg *rtm = NLMSG_DATA(h); |
|
|
if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK) | if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK && |
{ | (rtm->rtm_table == RT_TABLE_MAIN || |
/* Force re-reading resolv file right now, for luck. */ | rtm->rtm_table == RT_TABLE_LOCAL)) |
daemon->last_resolv = 0; | queue_event(EVENT_NEWROUTE); |
| |
if (daemon->srv_save) | |
{ | |
int fd; | |
| |
if (daemon->srv_save->sfd) | |
fd = daemon->srv_save->sfd->fd; | |
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0) | |
fd = daemon->rfd_save->fd; | |
else | |
return 0; | |
| |
while(sendto(fd, daemon->packet, daemon->packet_len, 0, | |
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send()); | |
} | |
} | |
return 0; | |
} |
} |
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) |
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) |
return 1; /* clever bind mode - rescan */ | queue_event(EVENT_NEWADDR); |
| |
return 0; | |
} |
} |
#endif |
#endif |
|
|