mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
Cache access to the kernel's ARP table.
This commit is contained in:
2
Makefile
2
Makefile
@@ -74,7 +74,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
|||||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
||||||
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
||||||
poll.o rrfilter.o edns0.o
|
poll.o rrfilter.o edns0.o arp.o
|
||||||
|
|
||||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||||
dns-protocol.h radv-protocol.h ip6addr.h
|
dns-protocol.h radv-protocol.h ip6addr.h
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
|||||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||||
radv.c slaac.c auth.c ipset.c domain.c \
|
radv.c slaac.c auth.c ipset.c domain.c \
|
||||||
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
||||||
loop.c inotify.c poll.c rrfilter.c edns0.c
|
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c
|
||||||
|
|
||||||
LOCAL_MODULE := dnsmasq
|
LOCAL_MODULE := dnsmasq
|
||||||
|
|
||||||
|
|||||||
201
src/arp.c
Normal file
201
src/arp.c
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2015 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
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#define ARP_FREE 0
|
||||||
|
#define ARP_FOUND 1
|
||||||
|
#define ARP_NEW 2
|
||||||
|
#define ARP_EMPTY 3
|
||||||
|
|
||||||
|
struct arp_record {
|
||||||
|
short hwlen, status;
|
||||||
|
int family;
|
||||||
|
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||||
|
struct all_addr addr;
|
||||||
|
struct arp_record *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct arp_record *arps = NULL, *old = NULL;
|
||||||
|
|
||||||
|
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
|
||||||
|
{
|
||||||
|
int match = 0;
|
||||||
|
struct arp_record *arp;
|
||||||
|
|
||||||
|
if (maclen > DHCP_CHADDR_MAX)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Look for existing entry */
|
||||||
|
for (arp = arps; arp; arp = arp->next)
|
||||||
|
{
|
||||||
|
if (family != arp->family || arp->status == ARP_NEW)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (family == AF_INET)
|
||||||
|
{
|
||||||
|
if (arp->addr.addr.addr4.s_addr != ((struct in_addr *)addrp)->s_addr)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, (struct in6_addr *)addrp))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (arp->status != ARP_EMPTY && arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
|
||||||
|
arp->status = ARP_FOUND;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* existing address, MAC changed or arrived new. */
|
||||||
|
arp->status = ARP_NEW;
|
||||||
|
arp->hwlen = maclen;
|
||||||
|
arp->family = family;
|
||||||
|
memcpy(arp->hwaddr, mac, maclen);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!arp)
|
||||||
|
{
|
||||||
|
/* New entry */
|
||||||
|
if (old)
|
||||||
|
{
|
||||||
|
arp = old;
|
||||||
|
old = old->next;
|
||||||
|
}
|
||||||
|
else if (!(arp = whine_malloc(sizeof(struct arp_record))))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
arp->next = arps;
|
||||||
|
arps = arp;
|
||||||
|
arp->status = ARP_NEW;
|
||||||
|
arp->hwlen = maclen;
|
||||||
|
arp->family = family;
|
||||||
|
memcpy(arp->hwaddr, mac, maclen);
|
||||||
|
if (family == AF_INET)
|
||||||
|
arp->addr.addr.addr4.s_addr = ((struct in_addr *)addrp)->s_addr;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
memcpy(&arp->addr.addr.addr6, addrp, IN6ADDRSZ);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If in lazy mode, we cache absence of ARP entries. */
|
||||||
|
int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy)
|
||||||
|
{
|
||||||
|
struct arp_record *arp, **up;
|
||||||
|
int updated = 0;
|
||||||
|
|
||||||
|
again:
|
||||||
|
|
||||||
|
for (arp = arps; arp; arp = arp->next)
|
||||||
|
{
|
||||||
|
if (addr->sa.sa_family == arp->family)
|
||||||
|
{
|
||||||
|
if (arp->addr.addr.addr4.s_addr != addr->in.sin_addr.s_addr)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr->in6.sin6_addr))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Only accept poitive entries unless in lazy mode. */
|
||||||
|
if (arp->status != ARP_EMPTY || lazy || updated)
|
||||||
|
{
|
||||||
|
if (mac && arp->hwlen != 0)
|
||||||
|
memcpy(mac, arp->hwaddr, arp->hwlen);
|
||||||
|
return arp->hwlen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not found, try the kernel */
|
||||||
|
if (!updated)
|
||||||
|
{
|
||||||
|
updated = 1;
|
||||||
|
|
||||||
|
/* Mark all non-negative entries */
|
||||||
|
for (arp = arps, up = &arps; arp; arp = arp->next)
|
||||||
|
if (arp->status != ARP_EMPTY)
|
||||||
|
arp->status = ARP_FREE;
|
||||||
|
|
||||||
|
iface_enumerate(AF_UNSPEC, NULL, filter_mac);
|
||||||
|
|
||||||
|
/* Remove all unconfirmed entries to old list, announce new ones. */
|
||||||
|
for (arp = arps, up = &arps; arp; arp = arp->next)
|
||||||
|
if (arp->status == ARP_FREE)
|
||||||
|
{
|
||||||
|
*up = arp->next;
|
||||||
|
arp->next = old;
|
||||||
|
old = arp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
up = &arp->next;
|
||||||
|
if (arp->status == ARP_NEW)
|
||||||
|
{
|
||||||
|
char a[ADDRSTRLEN], m[ADDRSTRLEN];
|
||||||
|
union mysockaddr pa;
|
||||||
|
pa.sa.sa_family = arp->family;
|
||||||
|
pa.in.sin_addr.s_addr = arp->addr.addr.addr4.s_addr;
|
||||||
|
prettyprint_addr(&pa, a);
|
||||||
|
print_mac(m, arp->hwaddr, arp->hwlen);
|
||||||
|
my_syslog(LOG_INFO, _("new arp: %s %s"), a, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* record failure, so we don't consult the kernel each time
|
||||||
|
we're asked for this address */
|
||||||
|
if (old)
|
||||||
|
{
|
||||||
|
arp = old;
|
||||||
|
old = old->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
arp = whine_malloc(sizeof(struct arp_record));
|
||||||
|
|
||||||
|
if (arp)
|
||||||
|
{
|
||||||
|
arp->next = arps;
|
||||||
|
arps = arp;
|
||||||
|
arp->status = ARP_EMPTY;
|
||||||
|
arp->family = addr->sa.sa_family;
|
||||||
|
|
||||||
|
if (addr->sa.sa_family == AF_INET)
|
||||||
|
arp->addr.addr.addr4.s_addr = addr->in.sin_addr.s_addr;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
memcpy(&arp->addr.addr.addr6, &addr->in6.sin6_addr, IN6ADDRSZ);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
52
src/dhcp6.c
52
src/dhcp6.c
@@ -27,17 +27,10 @@ struct iface_param {
|
|||||||
int ind, addr_match;
|
int ind, addr_match;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mac_param {
|
|
||||||
struct in6_addr *target;
|
|
||||||
unsigned char *mac;
|
|
||||||
unsigned int maclen;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static int complete_context6(struct in6_addr *local, int prefix,
|
static int complete_context6(struct in6_addr *local, int prefix,
|
||||||
int scope, int if_index, int flags,
|
int scope, int if_index, int flags,
|
||||||
unsigned int preferred, unsigned int valid, void *vparam);
|
unsigned int preferred, unsigned int valid, void *vparam);
|
||||||
static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv);
|
|
||||||
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||||
|
|
||||||
void dhcp6_init(void)
|
void dhcp6_init(void)
|
||||||
@@ -264,9 +257,8 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi
|
|||||||
find the sender. Repeat a few times in case of packet loss. */
|
find the sender. Repeat a few times in case of packet loss. */
|
||||||
|
|
||||||
struct neigh_packet neigh;
|
struct neigh_packet neigh;
|
||||||
struct sockaddr_in6 addr;
|
union mysockaddr addr;
|
||||||
struct mac_param mac_param;
|
int i, maclen;
|
||||||
int i;
|
|
||||||
|
|
||||||
neigh.type = ND_NEIGHBOR_SOLICIT;
|
neigh.type = ND_NEIGHBOR_SOLICIT;
|
||||||
neigh.code = 0;
|
neigh.code = 0;
|
||||||
@@ -277,55 +269,31 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi
|
|||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
addr.sin6_len = sizeof(struct sockaddr_in6);
|
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||||
#endif
|
#endif
|
||||||
addr.sin6_family = AF_INET6;
|
addr.in6.sin6_family = AF_INET6;
|
||||||
addr.sin6_port = htons(IPPROTO_ICMPV6);
|
addr.in6.sin6_port = htons(IPPROTO_ICMPV6);
|
||||||
addr.sin6_addr = *client;
|
addr.in6.sin6_addr = *client;
|
||||||
addr.sin6_scope_id = iface;
|
addr.in6.sin6_scope_id = iface;
|
||||||
|
|
||||||
mac_param.target = client;
|
|
||||||
mac_param.maclen = 0;
|
|
||||||
mac_param.mac = mac;
|
|
||||||
|
|
||||||
for (i = 0; i < 5; i++)
|
for (i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
|
||||||
iface_enumerate(AF_UNSPEC, &mac_param, find_mac);
|
if ((maclen = find_mac(&addr, mac, 0)) != 0)
|
||||||
|
|
||||||
if (mac_param.maclen != 0)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct sockaddr *)&addr, sizeof(addr));
|
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
|
||||||
|
|
||||||
ts.tv_sec = 0;
|
ts.tv_sec = 0;
|
||||||
ts.tv_nsec = 100000000; /* 100ms */
|
ts.tv_nsec = 100000000; /* 100ms */
|
||||||
nanosleep(&ts, NULL);
|
nanosleep(&ts, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
*maclenp = mac_param.maclen;
|
*maclenp = maclen;
|
||||||
*mactypep = ARPHRD_ETHER;
|
*mactypep = ARPHRD_ETHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
|
|
||||||
{
|
|
||||||
struct mac_param *parm = parmv;
|
|
||||||
|
|
||||||
if (family == AF_INET6 && IN6_ARE_ADDR_EQUAL(parm->target, (struct in6_addr *)addrp))
|
|
||||||
{
|
|
||||||
if (maclen <= DHCP_CHADDR_MAX)
|
|
||||||
{
|
|
||||||
parm->maclen = maclen;
|
|
||||||
memcpy(parm->mac, mac, maclen);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0; /* found, abort */
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int complete_context6(struct in6_addr *local, int prefix,
|
static int complete_context6(struct in6_addr *local, int prefix,
|
||||||
int scope, int if_index, int flags, unsigned int preferred,
|
int scope, int if_index, int flags, unsigned int preferred,
|
||||||
unsigned int valid, void *vparam)
|
unsigned int valid, void *vparam)
|
||||||
|
|||||||
@@ -1516,3 +1516,7 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock
|
|||||||
size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
|
size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
|
||||||
size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
|
size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
|
||||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
|
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
|
||||||
|
|
||||||
|
/* arp.c */
|
||||||
|
int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy);
|
||||||
|
|
||||||
|
|||||||
37
src/edns0.c
37
src/edns0.c
@@ -213,42 +213,15 @@ size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
|
|||||||
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
|
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
|
|
||||||
{
|
|
||||||
struct macparm *parm = parmv;
|
|
||||||
int match = 0;
|
|
||||||
|
|
||||||
if (family == parm->l3->sa.sa_family)
|
|
||||||
{
|
|
||||||
if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
|
|
||||||
match = 1;
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
else
|
|
||||||
if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
|
|
||||||
match = 1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!match)
|
|
||||||
return 1; /* continue */
|
|
||||||
|
|
||||||
parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
|
|
||||||
|
|
||||||
return 0; /* done */
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
|
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
|
||||||
{
|
{
|
||||||
struct macparm parm;
|
int maclen;
|
||||||
|
unsigned char mac[DHCP_CHADDR_MAX];
|
||||||
|
|
||||||
parm.header = header;
|
if ((maclen = find_mac(l3, mac, 1)) != 0)
|
||||||
parm.limit = (unsigned char *)limit;
|
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0);
|
||||||
parm.plen = plen;
|
|
||||||
parm.l3 = l3;
|
|
||||||
|
|
||||||
iface_enumerate(AF_UNSPEC, &parm, filter_mac);
|
return plen;
|
||||||
|
|
||||||
return parm.plen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct subnet_opt {
|
struct subnet_opt {
|
||||||
|
|||||||
Reference in New Issue
Block a user