mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
import of dnsmasq-2.27.tar.gz
This commit is contained in:
114
src/netlink.c
114
src/netlink.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2006 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
|
||||
@@ -10,8 +10,6 @@
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_RTNETLINK
|
||||
@@ -20,35 +18,74 @@
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
int netlink_init(void)
|
||||
static struct iovec iov[1];
|
||||
|
||||
void netlink_init(struct daemon *daemon)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
daemon->netlinkfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
|
||||
if (sock < 0)
|
||||
return -1; /* no kernel support */
|
||||
if (daemon->netlinkfd < 0)
|
||||
return; /* no kernel support */
|
||||
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pad = 0;
|
||||
addr.nl_pid = getpid();
|
||||
addr.nl_groups = 0;
|
||||
#ifdef HAVE_IPV6
|
||||
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
|
||||
#else
|
||||
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
|
||||
#endif
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
||||
if (bind(daemon->netlinkfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
||||
die(_("cannot bind netlink socket: %s"), NULL);
|
||||
|
||||
return sock;
|
||||
|
||||
iov[0].iov_len = 200;
|
||||
iov[0].iov_base = safe_malloc(iov[0].iov_len);
|
||||
}
|
||||
|
||||
static ssize_t netlink_recv(struct daemon *daemon)
|
||||
{
|
||||
struct msghdr msg;
|
||||
ssize_t rc;
|
||||
|
||||
/* We borrow the DNS packet buffer here. (The DHCP one already has a packet in it)
|
||||
Since it's used only within this routine, that's fine, just remember
|
||||
that calling icmp_echo() will trash it */
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
retry:
|
||||
while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK)) == -1 && retry_send());
|
||||
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
|
||||
if (msg.msg_flags & MSG_TRUNC)
|
||||
{
|
||||
size_t newsz = iov[0].iov_len + 100;
|
||||
void *new = realloc(iov[0].iov_base, newsz);
|
||||
if (!new)
|
||||
return -1;
|
||||
iov[0].iov_len = newsz;
|
||||
iov[0].iov_base = new;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && retry_send());
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int netlink_process(struct daemon *daemon, int index, struct in_addr relay,
|
||||
struct in_addr primary, struct dhcp_context **retp)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
struct nlmsghdr *h;
|
||||
int len, found_primary = 0;
|
||||
int found_primary = 0;
|
||||
ssize_t len;
|
||||
struct dhcp_context *ret = NULL;
|
||||
static unsigned int seq = 0;
|
||||
|
||||
@@ -88,17 +125,11 @@ int netlink_process(struct daemon *daemon, int index, struct in_addr relay,
|
||||
}
|
||||
|
||||
get_next:
|
||||
while((len = recvfrom(daemon->netlinkfd, daemon->packet, daemon->packet_buff_sz,
|
||||
MSG_WAITALL, NULL, 0)) == -1 && retry_send());
|
||||
|
||||
if (len == -1)
|
||||
if ((len = netlink_recv(daemon)) == -1)
|
||||
return 0;
|
||||
|
||||
h = (struct nlmsghdr *)daemon->packet;
|
||||
|
||||
while (NLMSG_OK(h, (unsigned int)len))
|
||||
for (h = (struct nlmsghdr *)iov[0].iov_base; NLMSG_OK(h, (unsigned int)len); h = NLMSG_NEXT(h, len))
|
||||
{
|
||||
|
||||
if (h->nlmsg_seq != seq)
|
||||
goto get_next;
|
||||
|
||||
@@ -110,8 +141,7 @@ int netlink_process(struct daemon *daemon, int index, struct in_addr relay,
|
||||
|
||||
if (h->nlmsg_type == RTM_NEWADDR)
|
||||
{
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||
if (ifa->ifa_index == index && ifa->ifa_family == AF_INET)
|
||||
{
|
||||
struct rtattr *rta = IFA_RTA(ifa);
|
||||
@@ -140,15 +170,43 @@ int netlink_process(struct daemon *daemon, int index, struct in_addr relay,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h = NLMSG_NEXT(h, len);
|
||||
}
|
||||
|
||||
*retp = ret;
|
||||
|
||||
return found_primary;
|
||||
}
|
||||
|
||||
|
||||
/* We arrange to receive netlink multicast messages whenever the network config changes.
|
||||
If this happens and we still have a DNS packet in the buffer, we re-send it.
|
||||
This helps on DoD links, where frequently the packet which triggers dialling is
|
||||
a DNS query, which then gets lost. By re-sending, we can avoid the lookup
|
||||
failing. */
|
||||
void netlink_multicast(struct daemon *daemon)
|
||||
{
|
||||
ssize_t len;
|
||||
struct nlmsghdr *h;
|
||||
|
||||
if ((len = netlink_recv(daemon)) == -1)
|
||||
return;
|
||||
|
||||
if (!daemon->srv_save)
|
||||
return;
|
||||
|
||||
for (h = (struct nlmsghdr *)iov[0].iov_base; NLMSG_OK(h, (unsigned int)len); h = NLMSG_NEXT(h, len))
|
||||
{
|
||||
if (h->nlmsg_type == NLMSG_DONE || h->nlmsg_type == NLMSG_ERROR)
|
||||
break;
|
||||
|
||||
if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_NEWROUTE)
|
||||
{
|
||||
while(sendto(daemon->srv_save->sfd->fd, daemon->packet, daemon->packet_len, 0,
|
||||
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user