version 1.1.1.3, 2016/11/02 09:57:01
|
version 1.1.1.4, 2021/03/17 00:56:46
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2016 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 40 static u32 netlink_pid;
|
Line 49 static u32 netlink_pid;
|
|
|
static void 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 149 int iface_enumerate(int family, void *parm, int (*call
|
Line 165 int iface_enumerate(int family, void *parm, int (*call
|
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 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 */ |
nl_async(h); |
nl_async(h); |
} |
} |
|
else if (h->nlmsg_seq != seq) |
|
{ |
|
/* May be part of incomplete response to previous request after |
|
ENOBUFS. Drop it. */ |
|
continue; |
|
} |
else if (h->nlmsg_type == NLMSG_DONE) |
else if (h->nlmsg_type == NLMSG_DONE) |
return callback_ok; |
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) |
Line 229 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 264 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 357 static void nl_async(struct nlmsghdr *h)
|
Line 377 static void 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 || |
| rtm->rtm_table == RT_TABLE_LOCAL)) |
queue_event(EVENT_NEWROUTE); |
queue_event(EVENT_NEWROUTE); |
} |
} |
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) |
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) |