Commit 33702ab1 authored by Simon Kelley's avatar Simon Kelley

First complete version of DNS-client-id EDNS0 and ARP tracking code.

parent 11867dc2
......@@ -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 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
}
#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 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
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,13 +108,15 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
}
/* 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:
/* 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)
......@@ -136,46 +145,35 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy)
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);
}
}
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 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy)
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;
}
......@@ -337,7 +337,7 @@ HAVE_SOCKADDR_SA_LEN
#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
......
......@@ -220,7 +220,7 @@ void dhcp6_packet(time_t now)
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 dhcp6_packet(time_t now)
}
}
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 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi
{
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));
......
......@@ -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;
......
......@@ -245,8 +245,11 @@ int main (int argc, char **argv)
/* 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,7 +556,8 @@ int main (int argc, char **argv)
/* 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))
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
......@@ -914,9 +918,9 @@ int main (int argc, char **argv)
poll_listen(piperead, POLLIN);
#ifdef HAVE_DHCP
# ifdef HAVE_SCRIPT
#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,17 +928,18 @@ int main (int argc, char **argv)
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 */
set_log_writer();
......
......@@ -235,7 +235,8 @@ struct event_desc {
#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 @@ struct frec {
#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 @@ extern struct daemon {
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 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
#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 @@ void queue_script(int action, struct dhcp_lease *lease,
#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 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
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 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
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 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
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);
......@@ -2173,7 +2173,7 @@ int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
}
}
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;
......
......@@ -95,13 +95,6 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t
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,17 +201,52 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
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;
}
if ((maclen = find_mac(l3, mac, 1)) != 0)
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, now)) != 0)
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0);
return plen;
......@@ -296,7 +324,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
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 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
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;
}
......@@ -388,36 +388,27 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
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))
{
size_t new = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source);
if (new != plen)
edns0_len = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
if (edns0_len != plen)
{
plen = new;
plen = edns0_len;
forward->flags |= FREC_ADDED_PHEADER;
}
}
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;
}
if (subnet)
forward->flags |= FREC_HAS_SUBNET;
}
#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 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
}
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,15 +680,12 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
}
#ifdef HAVE_DNSSEC
if (bogusanswer && !(header->hb4 & HB4_CD))
{
if (!option_bool(OPT_DNSSEC_DEBUG))
if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
{
/* Bogus reply, turn into SERVFAIL */
SET_RCODE(header, SERVFAIL);
munged = 1;
}
}
if (option_bool(OPT_DNSSEC_VALID))
{
......@@ -802,7 +805,7 @@ void reply_query(int fd, int family, time_t now)
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 @@ void reply_query(int fd, int family, time_t now)
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 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
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 @@ unsigned char *tcp_request(int confd, time_t now,
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,18 +1628,12 @@ unsigned char *tcp_request(int confd, time_t now,
struct all_addr *addrp = NULL;
int type = 0;
char *domain = NULL;
size_t new_size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
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)
if (size != new_size)
{
size = new;
check_subnet = 1;
}
added_pheader = 1;
size = new_size;
}
if (gotname)
......@@ -1715,20 +1710,20 @@ unsigned char *tcp_request(int confd, time_t now,
}
#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
}
......
......@@ -219,6 +219,17 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
action_str = "tftp";
is6 = (data.flags != AF_INET);
}
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 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
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 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
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 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
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);
}
/* 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 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
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 @@ 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)
{
/* 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;
......
......@@ -154,6 +154,7 @@ struct myoption {
#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 @@ static const struct myoption opts[] =
{ "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 @@ static struct {
{ 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 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
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;
......
......@@ -130,7 +130,7 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
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 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
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 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer
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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment