First complete version of DNS-client-id EDNS0 and ARP tracking code.
diff --git a/src/arp.c b/src/arp.c
index b624dac..f41cdec 100644
--- a/src/arp.c
+++ b/src/arp.c
@@ -16,26 +16,31 @@
#include "dnsmasq.h"
-#define ARP_FREE 0
-#define ARP_FOUND 1
-#define ARP_NEW 2
-#define ARP_EMPTY 3
+/* Time between forced re-loads from kernel. */
+#define INTERVAL 90
+
+#define ARP_MARK 0
+#define ARP_FOUND 1 /* Confirmed */
+#define ARP_NEW 2 /* Newly created */
+#define ARP_EMPTY 3 /* No MAC addr */
struct arp_record {
- short hwlen, status;
+ unsigned 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 struct arp_record *arps = NULL, *old = NULL, *freelist = NULL;
+static time_t last = 0;
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
{
- int match = 0;
struct arp_record *arp;
+ (void)parmv;
+
if (maclen > DHCP_CHADDR_MAX)
return 1;
@@ -58,16 +63,18 @@
}
#endif
- if (arp->status != ARP_EMPTY && arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
- arp->status = ARP_FOUND;
- else
+ if (arp->status == ARP_EMPTY)
{
- /* existing address, MAC changed or arrived new. */
+ /* existing address, was negative. */
arp->status = ARP_NEW;
arp->hwlen = maclen;
- arp->family = family;
memcpy(arp->hwaddr, mac, maclen);
}
+ else if (arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
+ /* Existing entry matches - confirm. */
+ arp->status = ARP_FOUND;
+ else
+ continue;
break;
}
@@ -75,10 +82,10 @@
if (!arp)
{
/* New entry */
- if (old)
+ if (freelist)
{
- arp = old;
- old = old->next;
+ arp = freelist;
+ freelist = freelist->next;
}
else if (!(arp = whine_malloc(sizeof(struct arp_record))))
return 1;
@@ -101,81 +108,72 @@
}
/* If in lazy mode, we cache absence of ARP entries. */
-int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy)
+int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
{
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;
- }
+ /* If the database is less then INTERVAL old, look in there */
+ if (difftime(now, last) < INTERVAL)
+ 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;
- }
+ 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;
- }
- }
-
+
+ /* 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;
-
+ last = now;
+
/* Mark all non-negative entries */
for (arp = arps, up = &arps; arp; arp = arp->next)
if (arp->status != ARP_EMPTY)
- arp->status = ARP_FREE;
+ arp->status = ARP_MARK;
iface_enumerate(AF_UNSPEC, NULL, filter_mac);
- /* Remove all unconfirmed entries to old list, announce new ones. */
+ /* Remove all unconfirmed entries to old list. */
for (arp = arps, up = &arps; arp; arp = arp->next)
- if (arp->status == ARP_FREE)
+ if (arp->status == ARP_MARK)
{
*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);
- }
- }
-
+ up = &arp->next;
+
goto again;
}
/* record failure, so we don't consult the kernel each time
we're asked for this address */
- if (old)
+ if (freelist)
{
- arp = old;
- old = old->next;
+ arp = freelist;
+ freelist = freelist->next;
}
else
arp = whine_malloc(sizeof(struct arp_record));
@@ -198,4 +196,36 @@
return 0;
}
+int do_arp_script_run(void)
+{
+ struct arp_record *arp;
+
+ /* Notify any which went, then move to free list */
+ if (old)
+ {
+#ifdef HAVE_SCRIPT
+ if (option_bool(OPT_DNS_CLIENT))
+ queue_arp(ACTION_ARP_OLD, old->hwaddr, old->hwlen, old->family, &old->addr);
+#endif
+ arp = old;
+ old = arp->next;
+ arp->next = freelist;
+ freelist = arp;
+ return 1;
+ }
+
+ for (arp = arps; arp; arp = arp->next)
+ if (arp->status == ARP_NEW)
+ {
+#ifdef HAVE_SCRIPT
+ if (option_bool(OPT_DNS_CLIENT))
+ queue_arp(ACTION_ARP, arp->hwaddr, arp->hwlen, arp->family, &arp->addr);
+#endif
+ arp->status = ARP_FOUND;
+ return 1;
+ }
+
+ return 0;
+}
+
diff --git a/src/config.h b/src/config.h
index f75fe9d..309be6b 100644
--- a/src/config.h
+++ b/src/config.h
@@ -337,7 +337,7 @@
#define HAVE_DHCP
#endif
-#if defined(NO_SCRIPT) || !defined(HAVE_DHCP) || defined(NO_FORK)
+#if defined(NO_SCRIPT) || defined(NO_FORK)
#undef HAVE_SCRIPT
#undef HAVE_LUASCRIPT
#endif
diff --git a/src/dhcp6.c b/src/dhcp6.c
index 7b1a7c7..0e2e171 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -220,7 +220,7 @@
inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
- relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id);
+ relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id, now);
return;
}
@@ -250,7 +250,7 @@
}
}
-void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep)
+void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep, time_t now)
{
/* Recieving a packet from a host does not populate the neighbour
cache, so we send a neighbour discovery request if we can't
@@ -280,7 +280,7 @@
{
struct timespec ts;
- if ((maclen = find_mac(&addr, mac, 0)) != 0)
+ if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
break;
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
diff --git a/src/dns-protocol.h b/src/dns-protocol.h
index 6cf5158..addfa9e 100644
--- a/src/dns-protocol.h
+++ b/src/dns-protocol.h
@@ -77,6 +77,8 @@
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
+#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary assignment */
+#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
struct dns_header {
u16 id;
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 45761cc..229693f 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -245,8 +245,11 @@
/* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked
to the lease-script init process. We need to call common_init
- before lease_init to allocate buffers it uses.*/
- if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
+ before lease_init to allocate buffers it uses.
+ The script subsystrm relies on DHCP buffers, hence the last two
+ conditions below. */
+ if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 ||
+ daemon->relay6 || option_bool(OPT_TFTP) || option_bool(OPT_ADD_MAC))
{
dhcp_common_init();
if (daemon->dhcp || daemon->doing_dhcp6)
@@ -553,8 +556,9 @@
/* if we are to run scripts, we need to fork a helper before dropping root. */
daemon->helperfd = -1;
#ifdef HAVE_SCRIPT
- if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
- daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
+ if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_bool(OPT_ADD_MAC)) &&
+ (daemon->lease_change_command || daemon->luascript))
+ daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
#endif
if (!option_bool(OPT_DEBUG) && getuid() == 0)
@@ -914,9 +918,9 @@
poll_listen(piperead, POLLIN);
-#ifdef HAVE_DHCP
-# ifdef HAVE_SCRIPT
- while (helper_buf_empty() && do_script_run(now));
+#ifdef HAVE_SCRIPT
+ while (helper_buf_empty() && do_script_run(now));
+ while (helper_buf_empty() && do_arp_script_run());
# ifdef HAVE_TFTP
while (helper_buf_empty() && do_tftp_script_run());
@@ -924,16 +928,17 @@
if (!helper_buf_empty())
poll_listen(daemon->helperfd, POLLOUT);
-# else
+#else
/* need this for other side-effects */
while (do_script_run(now));
+ while (do_arp_script_run(now));
# ifdef HAVE_TFTP
while (do_tftp_script_run());
# endif
-# endif
#endif
+
/* must do this just before select(), when we know no
more calls to my_syslog() can occur */
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 4459594..fec0f8d 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -235,7 +235,8 @@
#define OPT_LOOP_DETECT 50
#define OPT_EXTRALOG 51
#define OPT_TFTP_NO_FAIL 52
-#define OPT_LAST 53
+#define OPT_DNS_CLIENT 53
+#define OPT_LAST 54
/* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
@@ -633,6 +634,8 @@
#define ACTION_OLD 3
#define ACTION_ADD 4
#define ACTION_TFTP 5
+#define ACTION_ARP 6
+#define ACTION_ARP_OLD 7
#define LEASE_NEW 1 /* newly created */
#define LEASE_CHANGED 2 /* modified */
@@ -948,6 +951,7 @@
int cachesize, ftabsize;
int port, query_port, min_port;
unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl;
+ char *dns_client_id;
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6;
struct ra_interface *ra_interfaces;
@@ -1135,7 +1139,7 @@
#endif
/* dnssec.c */
-size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr, int edns_pktsz);
+size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class, int type, union mysockaddr *addr, int edns_pktsz);
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class,
@@ -1372,6 +1376,8 @@
#ifdef HAVE_TFTP
void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer);
#endif
+void queue_arp(int action, unsigned char *mac, int maclen,
+ int family, struct all_addr *addr);
int helper_buf_empty(void);
#endif
@@ -1408,7 +1414,7 @@
void make_duid(time_t now);
void dhcp_construct_contexts(time_t now);
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
- unsigned int *maclenp, unsigned int *mactypep);
+ unsigned int *maclenp, unsigned int *mactypep, time_t now);
#endif
/* rfc3315.c */
@@ -1416,7 +1422,8 @@
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
size_t sz, struct in6_addr *client_addr, time_t now);
-void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id);
+void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address,
+ u32 scope_id, time_t now);
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
#endif
@@ -1512,11 +1519,11 @@
size_t *len, unsigned char **p, int *is_sign, int *is_last);
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
-size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
-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, unsigned char *limit);
+size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
+ union mysockaddr *source, time_t now, int *check_subnet);
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);
-
+int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now);
+int do_arp_script_run(void);
diff --git a/src/dnssec.c b/src/dnssec.c
index ed2d3fe..918a2dc 100644
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -2173,7 +2173,7 @@
}
}
-size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class,
+size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class,
int type, union mysockaddr *addr, int edns_pktsz)
{
unsigned char *p;
diff --git a/src/edns0.c b/src/edns0.c
index 9d8c0b9..12e0210 100644
--- a/src/edns0.c
+++ b/src/edns0.c
@@ -94,13 +94,6 @@
return ret;
}
-
-struct macparm {
- unsigned char *limit;
- struct dns_header *header;
- size_t plen;
- union mysockaddr *l3;
-};
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
@@ -208,19 +201,54 @@
return p - (unsigned char *)header;
}
-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, unsigned char *limit)
{
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
}
-size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
+static unsigned char char64(unsigned char c)
+{
+ return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c & 0x3f];
+}
+
+static void encoder(unsigned char *in, char *out)
+{
+ out[0] = char64(in[0]>>2);
+ out[1] = char64((in[0]<<4) | (in[1]>>4));
+ out[2] = char64((in[1]<<2) | (in[2]>>6));
+ out[3] = char64(in[2]);
+}
+
+static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
+{
+ int maclen;
+ unsigned char mac[DHCP_CHADDR_MAX];
+ char encode[8]; /* handle 6 byte MACs */
+
+ if ((maclen = find_mac(l3, mac, 1, now)) == 6)
+ {
+ encoder(mac, encode);
+ encoder(mac+3, encode+4);
+
+ plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, 8, 0);
+ }
+
+ if (daemon->dns_client_id)
+ plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
+ (unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0);
+
+ return plen;
+}
+
+
+static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
{
int maclen;
unsigned char mac[DHCP_CHADDR_MAX];
- if ((maclen = find_mac(l3, mac, 1)) != 0)
+ if ((maclen = find_mac(l3, mac, 1, now)) != 0)
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0);
-
+
return plen;
}
@@ -296,7 +324,7 @@
return len + 4;
}
-size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
+static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source)
{
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
@@ -344,3 +372,23 @@
return 1;
}
+
+size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
+ union mysockaddr *source, time_t now, int *check_subnet)
+{
+ *check_subnet = 0;
+
+ if (option_bool(OPT_ADD_MAC))
+ plen = add_mac(header, plen, limit, source, now);
+
+ if (option_bool(OPT_DNS_CLIENT))
+ plen = add_dns_client(header, plen, limit, source, now);
+
+ if (option_bool(OPT_CLIENT_SUBNET))
+ {
+ plen = add_source_addr(header, plen, limit, source);
+ *check_subnet = 1;
+ }
+
+ return plen;
+}
diff --git a/src/forward.c b/src/forward.c
index c0e4d9a..911f46e 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -388,36 +388,27 @@
if (!flags && forward)
{
struct server *firstsentto = start;
- int forwarded = 0;
+ int subnet, forwarded = 0;
size_t edns0_len;
/* If a query is retried, use the log_id for the retry when logging the answer. */
forward->log_id = daemon->log_id;
- if (option_bool(OPT_ADD_MAC))
+ edns0_len = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
+
+ if (edns0_len != plen)
{
- size_t new = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source);
- if (new != plen)
- {
- plen = new;
- forward->flags |= FREC_ADDED_PHEADER;
- }
+ plen = edns0_len;
+ forward->flags |= FREC_ADDED_PHEADER;
+
+ if (subnet)
+ forward->flags |= FREC_HAS_SUBNET;
}
-
- if (option_bool(OPT_CLIENT_SUBNET))
- {
- size_t new = add_source_addr(header, plen, ((char *) header) + PACKETSZ, &forward->source);
- if (new != plen)
- {
- plen = new;
- forward->flags |= FREC_HAS_SUBNET | FREC_ADDED_PHEADER;
- }
- }
-
+
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID))
{
- size_t new = add_do_bit(header, plen, ((char *) header) + PACKETSZ);
+ size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
if (new != plen)
forward->flags |= FREC_ADDED_PHEADER;
@@ -607,15 +598,30 @@
}
else
{
+ unsigned short udpsz;
+
/* If upstream is advertising a larger UDP packet size
than we allow, trim it so that we don't get overlarge
requests for the client. We can't do this for signed packets. */
- unsigned short udpsz;
- unsigned char *psave = sizep;
-
GETSHORT(udpsz, sizep);
if (udpsz > daemon->edns_pktsz)
- PUTSHORT(daemon->edns_pktsz, psave);
+ {
+ sizep -= 2;
+ PUTSHORT(daemon->edns_pktsz, sizep);
+ }
+
+#ifdef HAVE_DNSSEC
+ /* If the client didn't set the do bit, but we did, reset it. */
+ if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
+ {
+ unsigned short flags;
+ sizep += 2; /* skip RCODE */
+ GETSHORT(flags, sizep);
+ flags &= ~0x8000;
+ sizep -= 2;
+ PUTSHORT(flags, sizep);
+ }
+#endif
}
}
}
@@ -674,14 +680,11 @@
}
#ifdef HAVE_DNSSEC
- if (bogusanswer && !(header->hb4 & HB4_CD))
+ if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
{
- if (!option_bool(OPT_DNSSEC_DEBUG))
- {
- /* Bogus reply, turn into SERVFAIL */
- SET_RCODE(header, SERVFAIL);
- munged = 1;
- }
+ /* Bogus reply, turn into SERVFAIL */
+ SET_RCODE(header, SERVFAIL);
+ munged = 1;
}
if (option_bool(OPT_DNSSEC_VALID))
@@ -802,7 +805,7 @@
if (forward->flags |= FREC_AD_QUESTION)
header->hb4 |= HB4_AD;
if (forward->flags & FREC_DO_QUESTION)
- add_do_bit(header, nn, (char *)pheader + plen);
+ add_do_bit(header, nn, (unsigned char *)pheader + plen);
forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
return;
}
@@ -927,13 +930,13 @@
if (status == STAT_NEED_KEY)
{
new->flags |= FREC_DNSKEY_QUERY;
- nn = dnssec_generate_query(header, ((char *) header) + server->edns_pktsz,
+ nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
}
else
{
new->flags |= FREC_DS_QUERY;
- nn = dnssec_generate_query(header,((char *) header) + server->edns_pktsz,
+ nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
}
if ((hash = hash_questions(header, nn, daemon->namebuff)))
@@ -1434,7 +1437,7 @@
break;
}
- m = dnssec_generate_query(new_header, ((char *) new_header) + 65536, keyname, class,
+ m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
*length = htons(m);
@@ -1548,8 +1551,6 @@
daemon->log_display_id = ++daemon->log_id;
daemon->log_source_addr = &peer_addr;
- check_subnet = 0;
-
/* save state of "cd" flag in query */
if ((checking_disabled = header->hb4 & HB4_CD))
no_cache_dnssec = 1;
@@ -1627,20 +1628,14 @@
struct all_addr *addrp = NULL;
int type = 0;
char *domain = NULL;
-
- if (option_bool(OPT_ADD_MAC))
- size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
-
- if (option_bool(OPT_CLIENT_SUBNET))
- {
- size_t new = add_source_addr(header, size, ((char *) header) + 65536, &peer_addr);
- if (size != new)
- {
- size = new;
- check_subnet = 1;
- }
- }
+ size_t new_size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
+ if (size != new_size)
+ {
+ added_pheader = 1;
+ size = new_size;
+ }
+
if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
@@ -1715,20 +1710,20 @@
}
#ifdef HAVE_DNSSEC
- added_pheader = 0;
if (option_bool(OPT_DNSSEC_VALID))
{
- size_t new_size = add_do_bit(header, size, ((char *) header) + 65536);
+ new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
+
+ if (size != new_size)
+ {
+ added_pheader = 1;
+ size = new_size;
+ }
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
this allows it to select auth servers when one is returning bad data. */
if (option_bool(OPT_DNSSEC_DEBUG))
header->hb4 |= HB4_CD;
-
- if (size != new_size)
- added_pheader = 1;
-
- size = new_size;
}
#endif
}
diff --git a/src/helper.c b/src/helper.c
index 1fee72d..517cfd9 100644
--- a/src/helper.c
+++ b/src/helper.c
@@ -219,7 +219,18 @@
action_str = "tftp";
is6 = (data.flags != AF_INET);
}
- else
+ else if (data.action == ACTION_ARP)
+ {
+ action_str = "arp";
+ is6 = (data.flags != AF_INET);
+ }
+ else if (data.action == ACTION_ARP_OLD)
+ {
+ action_str = "arp-old";
+ is6 = (data.flags != AF_INET);
+ data.action = ACTION_ARP;
+ }
+ else
continue;
@@ -321,6 +332,22 @@
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
}
}
+ else if (data.action == ACTION_ARP)
+ {
+ lua_getglobal(lua, "arp");
+ if (lua_type(lua, -1) != LUA_TFUNCTION)
+ lua_pop(lua, 1); /* arp function optional */
+ else
+ {
+ lua_pushstring(lua, action_str); /* arg1 - action */
+ lua_newtable(lua); /* arg2 - data table */
+ lua_pushstring(lua, daemon->addrbuff);
+ lua_setfield(lua, -2, "client_address");
+ lua_pushstring(lua, daemon->dhcp_buff);
+ lua_setfield(lua, -2, "mac_address");
+ lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
+ }
+ }
else
{
lua_getglobal(lua, "lease"); /* function to call */
@@ -478,7 +505,7 @@
continue;
}
- if (data.action != ACTION_TFTP)
+ if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
{
#ifdef HAVE_DHCP6
my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
@@ -550,10 +577,9 @@
my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
if (data.action == ACTION_OLD_HOSTNAME)
hostname = NULL;
- }
-
- my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
-
+
+ my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
+ }
/* we need to have the event_fd around if exec fails */
if ((i = fcntl(event_fd, F_GETFD)) != -1)
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
@@ -563,8 +589,8 @@
if (err == 0)
{
execl(daemon->lease_change_command,
- p ? p+1 : daemon->lease_change_command,
- action_str, is6 ? daemon->packet : daemon->dhcp_buff,
+ p ? p+1 : daemon->lease_change_command, action_str,
+ (is6 && data.action != ACTION_ARP) ? daemon->packet : daemon->dhcp_buff,
daemon->addrbuff, hostname, (char*)NULL);
err = errno;
}
@@ -760,6 +786,30 @@
}
#endif
+void queue_arp(int action, unsigned char *mac, int maclen, int family, struct all_addr *addr)
+{
+ /* no script */
+ if (daemon->helperfd == -1)
+ return;
+
+ buff_alloc(sizeof(struct script_data));
+ memset(buf, 0, sizeof(struct script_data));
+
+ buf->action = action;
+ buf->hwaddr_len = maclen;
+ buf->hwaddr_type = ARPHRD_ETHER;
+ if ((buf->flags = family) == AF_INET)
+ buf->addr = addr->addr.addr4;
+#ifdef HAVE_IPV6
+ else
+ buf->addr6 = addr->addr.addr6;
+#endif
+
+ memcpy(buf->hwaddr, mac, maclen);
+
+ bytes_in_buf = sizeof(struct script_data);
+}
+
int helper_buf_empty(void)
{
return bytes_in_buf == 0;
diff --git a/src/option.c b/src/option.c
index 71beb98..f359bc5 100644
--- a/src/option.c
+++ b/src/option.c
@@ -154,6 +154,7 @@
#define LOPT_HOST_INOTIFY 342
#define LOPT_DNSSEC_STAMP 343
#define LOPT_TFTP_NO_FAIL 344
+#define LOPT_DNS_CLIENT_ID 355
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -281,6 +282,7 @@
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
{ "add-mac", 0, 0, LOPT_ADD_MAC },
{ "add-subnet", 2, 0, LOPT_ADD_SBNET },
+ { "add-dns-client", 2, 0 , LOPT_DNS_CLIENT_ID },
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC },
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
{ "conntrack", 0, 0, LOPT_CONNTRACK },
@@ -446,6 +448,7 @@
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
+ { LOPT_DNS_CLIENT_ID, ARG_ONE, "<proxyname>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
{ LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
@@ -2150,6 +2153,12 @@
}
break;
+ case LOPT_DNS_CLIENT_ID: /* --add-dns-client */
+ set_option_bool(OPT_DNS_CLIENT);
+ if (arg)
+ daemon->dns_client_id = opt_string_alloc(arg);
+ break;
+
case 'u': /* --user */
daemon->username = opt_string_alloc(arg);
break;
diff --git a/src/rfc3315.c b/src/rfc3315.c
index 3ed8623..31bb41b 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -130,7 +130,7 @@
MAC address from the local ND cache. */
if (!state->link_address)
- get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type);
+ get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type, now);
else
{
struct dhcp_context *c;
@@ -2054,7 +2054,8 @@
return ret;
}
-void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id)
+void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
+ struct in6_addr *peer_address, u32 scope_id, time_t now)
{
/* ->local is same value for all relays on ->current chain */
@@ -2068,7 +2069,7 @@
unsigned char mac[DHCP_CHADDR_MAX];
inet_pton(AF_INET6, ALL_SERVERS, &multicast);
- get_client_mac(peer_address, scope_id, mac, &maclen, &mactype);
+ get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
/* source address == relay address */
from.addr.addr6 = relay->local.addr.addr6;