summaryrefslogtreecommitdiff
path: root/src/dhcp6.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dhcp6.c')
-rw-r--r--src/dhcp6.c87
1 files changed, 32 insertions, 55 deletions
diff --git a/src/dhcp6.c b/src/dhcp6.c
index 8286ff4..0853664 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -1,4 +1,4 @@
-/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
+/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,17 +27,10 @@ struct iface_param {
int ind, addr_match;
};
-struct mac_param {
- struct in6_addr *target;
- unsigned char *mac;
- unsigned int maclen;
-};
-
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam);
-static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv);
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
void dhcp6_init(void)
@@ -58,9 +51,9 @@ void dhcp6_init(void)
!set_ipv6pktinfo(fd))
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
- /* When bind-interfaces is set, there might be more than one dnmsasq
+ /* When bind-interfaces is set, there might be more than one dnsmasq
instance binding port 547. That's OK if they serve different networks.
- Need to set REUSEADDR|REUSEPORT to make this posible.
+ Need to set REUSEADDR|REUSEPORT to make this possible.
Handle the case that REUSEPORT is defined, but the kernel doesn't
support it. This handles the introduction of REUSEPORT on Linux. */
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
@@ -227,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;
}
@@ -257,16 +250,15 @@ 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
+ /* Receiving a packet from a host does not populate the neighbour
cache, so we send a neighbour discovery request if we can't
find the sender. Repeat a few times in case of packet loss. */
struct neigh_packet neigh;
- struct sockaddr_in6 addr;
- struct mac_param mac_param;
- int i;
+ union mysockaddr addr;
+ int i, maclen;
neigh.type = ND_NEIGHBOR_SOLICIT;
neigh.code = 0;
@@ -277,55 +269,31 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
- addr.sin6_len = sizeof(struct sockaddr_in6);
+ addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif
- addr.sin6_family = AF_INET6;
- addr.sin6_port = htons(IPPROTO_ICMPV6);
- addr.sin6_addr = *client;
- addr.sin6_scope_id = iface;
-
- mac_param.target = client;
- mac_param.maclen = 0;
- mac_param.mac = mac;
+ addr.in6.sin6_family = AF_INET6;
+ addr.in6.sin6_port = htons(IPPROTO_ICMPV6);
+ addr.in6.sin6_addr = *client;
+ addr.in6.sin6_scope_id = iface;
for (i = 0; i < 5; i++)
{
struct timespec ts;
- iface_enumerate(AF_UNSPEC, &mac_param, find_mac);
-
- if (mac_param.maclen != 0)
+ if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
break;
-
- sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct sockaddr *)&addr, sizeof(addr));
+
+ sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
ts.tv_sec = 0;
ts.tv_nsec = 100000000; /* 100ms */
nanosleep(&ts, NULL);
}
- *maclenp = mac_param.maclen;
+ *maclenp = maclen;
*mactypep = ARPHRD_ETHER;
}
-static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
-{
- struct mac_param *parm = parmv;
-
- if (family == AF_INET6 && IN6_ARE_ADDR_EQUAL(parm->target, (struct in6_addr *)addrp))
- {
- if (maclen <= DHCP_CHADDR_MAX)
- {
- parm->maclen = maclen;
- memcpy(parm->mac, mac, maclen);
- }
-
- return 0; /* found, abort */
- }
-
- return 1;
-}
-
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int flags, unsigned int preferred,
unsigned int valid, void *vparam)
@@ -376,7 +344,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
{
struct dhcp_context *tmp, **up;
- /* use interface values only for contructed contexts */
+ /* use interface values only for constructed contexts */
if (!(context->flags & CONTEXT_CONSTRUCTED))
preferred = valid = 0xffffffff;
else if (flags & IFACE_DEPRECATED)
@@ -452,7 +420,7 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
j = rand64();
else
for (j = iaid, i = 0; i < clid_len; i++)
- j += clid[i] + (j << 6) + (j << 16) - j;
+ j = clid[i] + (j << 6) + (j << 16) - j;
for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
for (c = context; c; c = c->current)
@@ -466,7 +434,16 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
/* seed is largest extant lease addr in this context */
start = lease_find_max_addr6(c) + serial;
else
- start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
+ {
+ u64 range = 1 + addr6part(&c->end6) - addr6part(&c->start6);
+ u64 offset = j + c->addr_epoch;
+
+ /* don't divide by zero if range is whole 2^64 */
+ if (range != 0)
+ offset = offset % range;
+
+ start = addr6part(&c->start6) + offset;
+ }
/* iterate until we find a free address. */
addr = start;
@@ -695,7 +672,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
/* address went, now it's back */
log_context(AF_INET6, context);
/* fast RAs for a while */
- ra_start_unsolicted(param->now, context);
+ ra_start_unsolicited(param->now, context);
param->newone = 1;
/* Add address to name again */
if (context->flags & CONTEXT_RA_NAME)
@@ -718,7 +695,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
context->next = daemon->dhcp6;
daemon->dhcp6 = context;
- ra_start_unsolicted(param->now, context);
+ ra_start_unsolicited(param->now, context);
/* we created a new one, need to call
lease_update_file to get periodic functions called */
param->newone = 1;
@@ -766,7 +743,7 @@ void dhcp_construct_contexts(time_t now)
/* maximum time is 2 hours, from RFC */
if (context->saved_valid > 7200) /* 2 hours */
context->saved_valid = 7200;
- ra_start_unsolicted(now, context);
+ ra_start_unsolicited(now, context);
param.newone = 1; /* include deletion */
if (context->flags & CONTEXT_RA_NAME)