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 @@ ...@@ -16,26 +16,31 @@
#include "dnsmasq.h" #include "dnsmasq.h"
#define ARP_FREE 0 /* Time between forced re-loads from kernel. */
#define ARP_FOUND 1 #define INTERVAL 90
#define ARP_NEW 2
#define ARP_EMPTY 3 #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 { struct arp_record {
short hwlen, status; unsigned short hwlen, status;
int family; int family;
unsigned char hwaddr[DHCP_CHADDR_MAX]; unsigned char hwaddr[DHCP_CHADDR_MAX];
struct all_addr addr; struct all_addr addr;
struct arp_record *next; 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) static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
{ {
int match = 0;
struct arp_record *arp; struct arp_record *arp;
(void)parmv;
if (maclen > DHCP_CHADDR_MAX) if (maclen > DHCP_CHADDR_MAX)
return 1; return 1;
...@@ -58,16 +63,18 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p ...@@ -58,16 +63,18 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
} }
#endif #endif
if (arp->status != ARP_EMPTY && arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0) if (arp->status == ARP_EMPTY)
arp->status = ARP_FOUND;
else
{ {
/* existing address, MAC changed or arrived new. */ /* existing address, was negative. */
arp->status = ARP_NEW; arp->status = ARP_NEW;
arp->hwlen = maclen; arp->hwlen = maclen;
arp->family = family;
memcpy(arp->hwaddr, mac, maclen); 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; break;
} }
...@@ -75,10 +82,10 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p ...@@ -75,10 +82,10 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
if (!arp) if (!arp)
{ {
/* New entry */ /* New entry */
if (old) if (freelist)
{ {
arp = old; arp = freelist;
old = old->next; freelist = freelist->next;
} }
else if (!(arp = whine_malloc(sizeof(struct arp_record)))) else if (!(arp = whine_malloc(sizeof(struct arp_record))))
return 1; return 1;
...@@ -101,81 +108,72 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p ...@@ -101,81 +108,72 @@ 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. */ /* 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; struct arp_record *arp, **up;
int updated = 0; int updated = 0;
again: again:
for (arp = arps; arp; arp = arp->next) /* If the database is less then INTERVAL old, look in there */
{ if (difftime(now, last) < INTERVAL)
if (addr->sa.sa_family == arp->family) for (arp = arps; arp; arp = arp->next)
{ {
if (arp->addr.addr.addr4.s_addr != addr->in.sin_addr.s_addr) if (addr->sa.sa_family == arp->family)
continue; {
} if (arp->addr.addr.addr4.s_addr != addr->in.sin_addr.s_addr)
continue;
}
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else else
{ {
if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr->in6.sin6_addr)) if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr.addr6, &addr->in6.sin6_addr))
continue; continue;
} }
#endif #endif
/* Only accept poitive entries unless in lazy mode. */ /* Only accept poitive entries unless in lazy mode. */
if (arp->status != ARP_EMPTY || lazy || updated) if (arp->status != ARP_EMPTY || lazy || updated)
{ {
if (mac && arp->hwlen != 0) if (mac && arp->hwlen != 0)
memcpy(mac, arp->hwaddr, arp->hwlen); memcpy(mac, arp->hwaddr, arp->hwlen);
return arp->hwlen; return arp->hwlen;
} }
} }
/* Not found, try the kernel */ /* Not found, try the kernel */
if (!updated) if (!updated)
{ {
updated = 1; updated = 1;
last = now;
/* Mark all non-negative entries */ /* Mark all non-negative entries */
for (arp = arps, up = &arps; arp; arp = arp->next) for (arp = arps, up = &arps; arp; arp = arp->next)
if (arp->status != ARP_EMPTY) if (arp->status != ARP_EMPTY)
arp->status = ARP_FREE; arp->status = ARP_MARK;
iface_enumerate(AF_UNSPEC, NULL, filter_mac); 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) for (arp = arps, up = &arps; arp; arp = arp->next)
if (arp->status == ARP_FREE) if (arp->status == ARP_MARK)
{ {
*up = arp->next; *up = arp->next;
arp->next = old; arp->next = old;
old = arp; old = arp;
} }
else else
{ up = &arp->next;
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; goto again;
} }
/* record failure, so we don't consult the kernel each time /* record failure, so we don't consult the kernel each time
we're asked for this address */ we're asked for this address */
if (old) if (freelist)
{ {
arp = old; arp = freelist;
old = old->next; freelist = freelist->next;
} }
else else
arp = whine_malloc(sizeof(struct arp_record)); arp = whine_malloc(sizeof(struct arp_record));
...@@ -198,4 +196,36 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy) ...@@ -198,4 +196,36 @@ int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy)
return 0; 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 ...@@ -337,7 +337,7 @@ HAVE_SOCKADDR_SA_LEN
#define HAVE_DHCP #define HAVE_DHCP
#endif #endif
#if defined(NO_SCRIPT) || !defined(HAVE_DHCP) || defined(NO_FORK) #if defined(NO_SCRIPT) || defined(NO_FORK)
#undef HAVE_SCRIPT #undef HAVE_SCRIPT
#undef HAVE_LUASCRIPT #undef HAVE_LUASCRIPT
#endif #endif
......
...@@ -220,7 +220,7 @@ void dhcp6_packet(time_t now) ...@@ -220,7 +220,7 @@ void dhcp6_packet(time_t now)
inet_pton(AF_INET6, ALL_SERVERS, &all_servers); inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &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; return;
} }
...@@ -250,7 +250,7 @@ void dhcp6_packet(time_t now) ...@@ -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 /* Recieving a packet from a host does not populate the neighbour
cache, so we send a neighbour discovery request if we can't 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 ...@@ -280,7 +280,7 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi
{ {
struct timespec ts; struct timespec ts;
if ((maclen = find_mac(&addr, mac, 0)) != 0) if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
break; break;
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr)); sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
......
...@@ -77,6 +77,8 @@ ...@@ -77,6 +77,8 @@
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */ #define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */ #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 { struct dns_header {
u16 id; u16 id;
......
...@@ -245,8 +245,11 @@ int main (int argc, char **argv) ...@@ -245,8 +245,11 @@ int main (int argc, char **argv)
/* Note that order matters here, we must call lease_init before /* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked creating any file descriptors which shouldn't be leaked
to the lease-script init process. We need to call common_init to the lease-script init process. We need to call common_init
before lease_init to allocate buffers it uses.*/ before lease_init to allocate buffers it uses.
if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6) 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(); dhcp_common_init();
if (daemon->dhcp || daemon->doing_dhcp6) if (daemon->dhcp || daemon->doing_dhcp6)
...@@ -553,8 +556,9 @@ int main (int argc, char **argv) ...@@ -553,8 +556,9 @@ int main (int argc, char **argv)
/* if we are to run scripts, we need to fork a helper before dropping root. */ /* if we are to run scripts, we need to fork a helper before dropping root. */
daemon->helperfd = -1; daemon->helperfd = -1;
#ifdef HAVE_SCRIPT #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->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd); (daemon->lease_change_command || daemon->luascript))
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
#endif #endif
if (!option_bool(OPT_DEBUG) && getuid() == 0) if (!option_bool(OPT_DEBUG) && getuid() == 0)
...@@ -914,9 +918,9 @@ int main (int argc, char **argv) ...@@ -914,9 +918,9 @@ int main (int argc, char **argv)
poll_listen(piperead, POLLIN); 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_script_run(now)); while (helper_buf_empty() && do_arp_script_run());
# ifdef HAVE_TFTP # ifdef HAVE_TFTP
while (helper_buf_empty() && do_tftp_script_run()); while (helper_buf_empty() && do_tftp_script_run());
...@@ -924,16 +928,17 @@ int main (int argc, char **argv) ...@@ -924,16 +928,17 @@ int main (int argc, char **argv)
if (!helper_buf_empty()) if (!helper_buf_empty())
poll_listen(daemon->helperfd, POLLOUT); poll_listen(daemon->helperfd, POLLOUT);
# else #else
/* need this for other side-effects */ /* need this for other side-effects */
while (do_script_run(now)); while (do_script_run(now));
while (do_arp_script_run(now));
# ifdef HAVE_TFTP # ifdef HAVE_TFTP
while (do_tftp_script_run()); while (do_tftp_script_run());
# endif # endif
# endif
#endif #endif
/* must do this just before select(), when we know no /* must do this just before select(), when we know no
more calls to my_syslog() can occur */ more calls to my_syslog() can occur */
......
...@@ -235,7 +235,8 @@ struct event_desc { ...@@ -235,7 +235,8 @@ struct event_desc {
#define OPT_LOOP_DETECT 50 #define OPT_LOOP_DETECT 50
#define OPT_EXTRALOG 51 #define OPT_EXTRALOG 51
#define OPT_TFTP_NO_FAIL 52 #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 /* 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. */ not to occupy the same bits as priorities, no matter how syslog.h is set up. */
...@@ -633,6 +634,8 @@ struct frec { ...@@ -633,6 +634,8 @@ struct frec {
#define ACTION_OLD 3 #define ACTION_OLD 3
#define ACTION_ADD 4 #define ACTION_ADD 4
#define ACTION_TFTP 5 #define ACTION_TFTP 5
#define ACTION_ARP 6
#define ACTION_ARP_OLD 7
#define LEASE_NEW 1 /* newly created */ #define LEASE_NEW 1 /* newly created */
#define LEASE_CHANGED 2 /* modified */ #define LEASE_CHANGED 2 /* modified */
...@@ -948,6 +951,7 @@ extern struct daemon { ...@@ -948,6 +951,7 @@ extern struct daemon {
int cachesize, ftabsize; int cachesize, ftabsize;
int port, query_port, min_port; int port, query_port, min_port;
unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl; 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 hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6; struct dhcp_context *dhcp, *dhcp6;
struct ra_interface *ra_interfaces; struct ra_interface *ra_interfaces;
...@@ -1135,7 +1139,7 @@ int in_zone(struct auth_zone *zone, char *name, char **cut); ...@@ -1135,7 +1139,7 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
#endif #endif
/* dnssec.c */ /* 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_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_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, 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, ...@@ -1372,6 +1376,8 @@ void queue_script(int action, struct dhcp_lease *lease,
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer); void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer);
#endif #endif
void queue_arp(int action, unsigned char *mac, int maclen,
int family, struct all_addr *addr);
int helper_buf_empty(void); int helper_buf_empty(void);
#endif #endif
...@@ -1408,7 +1414,7 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct ...@@ -1408,7 +1414,7 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
void make_duid(time_t now); void make_duid(time_t now);
void dhcp_construct_contexts(time_t now); void dhcp_construct_contexts(time_t now);
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, 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 #endif
/* rfc3315.c */ /* rfc3315.c */
...@@ -1416,7 +1422,8 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, ...@@ -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, 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, 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); 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); unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
#endif #endif
...@@ -1512,11 +1519,11 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, ...@@ -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 *len, unsigned char **p, int *is_sign, int *is_last);
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 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); 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_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source); size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
size_t add_do_bit(struct dns_header *header, size_t plen, 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); int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
/* arp.c */ /* 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) ...@@ -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) int type, union mysockaddr *addr, int edns_pktsz)
{ {
unsigned char *p; unsigned char *p;
......
...@@ -94,13 +94,6 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t ...@@ -94,13 +94,6 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t
return ret; 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, 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) unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
...@@ -208,19 +201,54 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l ...@@ -208,19 +201,54 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
return p - (unsigned char *)header; 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); 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; int maclen;
unsigned char mac[DHCP_CHADDR_MAX]; 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); plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0);
return plen; return plen;
} }
...@@ -296,7 +324,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source) ...@@ -296,7 +324,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
return len + 4; 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 */ /* 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 ...@@ -344,3 +372,23 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
return 1; 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, ...@@ -388,36 +388,27 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (!flags && forward) if (!flags && forward)
{ {
struct server *firstsentto = start; struct server *firstsentto = start;
int forwarded = 0; int subnet, forwarded = 0;
size_t edns0_len; size_t edns0_len;
/* If a query is retried, use the log_id for the retry when logging the answer. */ /* If a query is retried, use the log_id for the retry when logging the answer. */
forward->log_id = daemon->log_id; 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);
{
size_t new = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source); if (edns0_len != plen)
if (new != plen)
{
plen = new;
forward->flags |= FREC_ADDED_PHEADER;
}
}
if (option_bool(OPT_CLIENT_SUBNET))
{ {
size_t new = add_source_addr(header, plen, ((char *) header) + PACKETSZ, &forward->source); plen = edns0_len;
if (new != plen) forward->flags |= FREC_ADDED_PHEADER;
{
plen = new; if (subnet)
forward->flags |= FREC_HAS_SUBNET | FREC_ADDED_PHEADER; forward->flags |= FREC_HAS_SUBNET;
}
} }
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID)) 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) if (new != plen)
forward->flags |= FREC_ADDED_PHEADER; forward->flags |= FREC_ADDED_PHEADER;
...@@ -607,15 +598,30 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server ...@@ -607,15 +598,30 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
} }
else else
{ {
unsigned short udpsz;
/* If upstream is advertising a larger UDP packet size /* If upstream is advertising a larger UDP packet size
than we allow, trim it so that we don't get overlarge than we allow, trim it so that we don't get overlarge
requests for the client. We can't do this for signed packets. */ requests for the client. We can't do this for signed packets. */
unsigned short udpsz;
unsigned char *psave = sizep;
GETSHORT(udpsz, sizep); GETSHORT(udpsz, sizep);
if (udpsz > daemon->edns_pktsz) 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 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server ...@@ -674,14 +680,11 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
} }
#ifdef HAVE_DNSSEC #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);
/* Bogus reply, turn into SERVFAIL */ munged = 1;
SET_RCODE(header, SERVFAIL);
munged = 1;
}
} }
if (option_bool(OPT_DNSSEC_VALID)) if (option_bool(OPT_DNSSEC_VALID))
...@@ -802,7 +805,7 @@ void reply_query(int fd, int family, time_t now) ...@@ -802,7 +805,7 @@ void reply_query(int fd, int family, time_t now)
if (forward->flags |= FREC_AD_QUESTION) if (forward->flags |= FREC_AD_QUESTION)
header->hb4 |= HB4_AD; header->hb4 |= HB4_AD;
if (forward->flags & FREC_DO_QUESTION) 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); forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
return; return;
} }
...@@ -927,13 +930,13 @@ void reply_query(int fd, int family, time_t now) ...@@ -927,13 +930,13 @@ void reply_query(int fd, int family, time_t now)
if (status == STAT_NEED_KEY) if (status == STAT_NEED_KEY)
{ {
new->flags |= FREC_DNSKEY_QUERY; 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); daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
} }
else else
{ {
new->flags |= FREC_DS_QUERY; 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); daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
} }
if ((hash = hash_questions(header, nn, daemon->namebuff))) 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 ...@@ -1434,7 +1437,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
break; 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); new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
*length = htons(m); *length = htons(m);
...@@ -1548,8 +1551,6 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -1548,8 +1551,6 @@ unsigned char *tcp_request(int confd, time_t now,
daemon->log_display_id = ++daemon->log_id; daemon->log_display_id = ++daemon->log_id;
daemon->log_source_addr = &peer_addr; daemon->log_source_addr = &peer_addr;
check_subnet = 0;
/* save state of "cd" flag in query */ /* save state of "cd" flag in query */
if ((checking_disabled = header->hb4 & HB4_CD)) if ((checking_disabled = header->hb4 & HB4_CD))
no_cache_dnssec = 1; no_cache_dnssec = 1;
...@@ -1627,20 +1628,14 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -1627,20 +1628,14 @@ unsigned char *tcp_request(int confd, time_t now,
struct all_addr *addrp = NULL; struct all_addr *addrp = NULL;
int type = 0; int type = 0;
char *domain = NULL; 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 (size != new_size)
if (option_bool(OPT_CLIENT_SUBNET))
{ {
size_t new = add_source_addr(header, size, ((char *) header) + 65536, &peer_addr); added_pheader = 1;
if (size != new) size = new_size;
{
size = new;
check_subnet = 1;
}
} }
if (gotname) if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
...@@ -1715,20 +1710,20 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -1715,20 +1710,20 @@ unsigned char *tcp_request(int confd, time_t now,
} }
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
added_pheader = 0;
if (option_bool(OPT_DNSSEC_VALID)) 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, /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
this allows it to select auth servers when one is returning bad data. */ this allows it to select auth servers when one is returning bad data. */
if (option_bool(OPT_DNSSEC_DEBUG)) if (option_bool(OPT_DNSSEC_DEBUG))
header->hb4 |= HB4_CD; header->hb4 |= HB4_CD;
if (size != new_size)
added_pheader = 1;
size = new_size;
} }
#endif #endif
} }
......
...@@ -219,7 +219,18 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) ...@@ -219,7 +219,18 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
action_str = "tftp"; action_str = "tftp";
is6 = (data.flags != AF_INET); 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; continue;
...@@ -321,6 +332,22 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) ...@@ -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 */ 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 else
{ {
lua_getglobal(lua, "lease"); /* function to call */ 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) ...@@ -478,7 +505,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue; continue;
} }
if (data.action != ACTION_TFTP) if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err); 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) ...@@ -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); my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
if (data.action == ACTION_OLD_HOSTNAME) if (data.action == ACTION_OLD_HOSTNAME)
hostname = NULL; 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 */ /* we need to have the event_fd around if exec fails */
if ((i = fcntl(event_fd, F_GETFD)) != -1) if ((i = fcntl(event_fd, F_GETFD)) != -1)
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC); 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) ...@@ -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) if (err == 0)
{ {
execl(daemon->lease_change_command, execl(daemon->lease_change_command,
p ? p+1 : daemon->lease_change_command, p ? p+1 : daemon->lease_change_command, action_str,
action_str, is6 ? daemon->packet : daemon->dhcp_buff, (is6 && data.action != ACTION_ARP) ? daemon->packet : daemon->dhcp_buff,
daemon->addrbuff, hostname, (char*)NULL); daemon->addrbuff, hostname, (char*)NULL);
err = errno; err = errno;
} }
...@@ -760,6 +786,30 @@ void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer) ...@@ -760,6 +786,30 @@ void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
} }
#endif #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) int helper_buf_empty(void)
{ {
return bytes_in_buf == 0; return bytes_in_buf == 0;
......
...@@ -154,6 +154,7 @@ struct myoption { ...@@ -154,6 +154,7 @@ struct myoption {
#define LOPT_HOST_INOTIFY 342 #define LOPT_HOST_INOTIFY 342
#define LOPT_DNSSEC_STAMP 343 #define LOPT_DNSSEC_STAMP 343
#define LOPT_TFTP_NO_FAIL 344 #define LOPT_TFTP_NO_FAIL 344
#define LOPT_DNS_CLIENT_ID 355
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
...@@ -281,6 +282,7 @@ static const struct myoption opts[] = ...@@ -281,6 +282,7 @@ static const struct myoption opts[] =
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND }, { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
{ "add-mac", 0, 0, LOPT_ADD_MAC }, { "add-mac", 0, 0, LOPT_ADD_MAC },
{ "add-subnet", 2, 0, LOPT_ADD_SBNET }, { "add-subnet", 2, 0, LOPT_ADD_SBNET },
{ "add-dns-client", 2, 0 , LOPT_DNS_CLIENT_ID },
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC }, { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR }, { "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
{ "conntrack", 0, 0, LOPT_CONNTRACK }, { "conntrack", 0, 0, LOPT_CONNTRACK },
...@@ -446,6 +448,7 @@ static struct { ...@@ -446,6 +448,7 @@ static struct {
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL }, { 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_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_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_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_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 }, { 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 ...@@ -2150,6 +2153,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
break; 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 */ case 'u': /* --user */
daemon->username = opt_string_alloc(arg); daemon->username = opt_string_alloc(arg);
break; break;
......
...@@ -130,7 +130,7 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, ...@@ -130,7 +130,7 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
MAC address from the local ND cache. */ MAC address from the local ND cache. */
if (!state->link_address) 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 else
{ {
struct dhcp_context *c; struct dhcp_context *c;
...@@ -2054,7 +2054,8 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size) ...@@ -2054,7 +2054,8 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
return ret; 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 */ /* ->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 ...@@ -2068,7 +2069,7 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer
unsigned char mac[DHCP_CHADDR_MAX]; unsigned char mac[DHCP_CHADDR_MAX];
inet_pton(AF_INET6, ALL_SERVERS, &multicast); 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 */ /* source address == relay address */
from.addr.addr6 = relay->local.addr.addr6; 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