"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/dhcp6.c" between
dnsmasq-2.80.tar.gz and dnsmasq-2.81.tar.xz

About: Dnsmasq is a lightweight caching DNS forwarder and DHCP server.

dhcp6.c  (dnsmasq-2.80):dhcp6.c  (dnsmasq-2.81.tar.xz)
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley /* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007. (at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
skipping to change at line 137 skipping to change at line 137
} p; } p;
p.c = CMSG_DATA(cmptr); p.c = CMSG_DATA(cmptr);
if_index = p.p->ipi6_ifindex; if_index = p.p->ipi6_ifindex;
dst_addr = p.p->ipi6_addr; dst_addr = p.p->ipi6_addr;
} }
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name)) if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
return; return;
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0) if ((port = relay_reply6(&from, sz, ifr.ifr_name)) != 0)
{
from.sin6_port = htons(port);
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
save_counter(-1), 0, (struct sockaddr *)&from,
sizeof(from))));
}
else
{ {
struct dhcp_bridge *bridge, *alias; struct dhcp_bridge *bridge, *alias;
for (tmp = daemon->if_except; tmp; tmp = tmp->next) for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name)) if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return; return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name)) if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return; return;
skipping to change at line 235 skipping to change at line 242
/* May have configured relay, but not DHCP server */ /* May have configured relay, but not DHCP server */
if (!daemon->doing_dhcp6) if (!daemon->doing_dhcp6)
return; return;
lease_prune(NULL, now); /* lose any expired leases */ lease_prune(NULL, now); /* lose any expired leases */
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback, port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
&parm.ll_addr, &parm.ula_addr, sz, &from.sin6_addr, now) ; &parm.ll_addr, &parm.ula_addr, sz, &from.sin6_addr, now) ;
/* The port in the source address of the original request should
be correct, but at least once client sends from the server port,
so we explicitly send to the client port to a client, and the
server port to a relay. */
if (port != 0)
{
from.sin6_port = htons(port);
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
save_counter(-1), 0, (struct sockaddr *)&from,
sizeof(from))));
}
/* These need to be called _after_ we send DHCPv6 packet, since lease_upda
te_file()
may trigger sending an RA packet, which overwrites our buffer. */
lease_update_file(now); lease_update_file(now);
lease_update_dns(0); lease_update_dns(0);
} }
/* The port in the source address of the original request should
be correct, but at least once client sends from the server port,
so we explicitly send to the client port to a client, and the
server port to a relay. */
if (port != 0)
{
from.sin6_port = htons(port);
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
save_counter(0), 0, (struct sockaddr *)&from,
sizeof(from))));
}
} }
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi gned int *maclenp, unsigned int *mactypep, time_t now) void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi gned int *maclenp, unsigned int *mactypep, time_t now)
{ {
/* Receiving 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 cache, so we send a neighbour discovery request if we can't
find the sender. Repeat a few times in case of packet loss. */ find the sender. Repeat a few times in case of packet loss. */
struct neigh_packet neigh; struct neigh_packet neigh;
union mysockaddr addr; union mysockaddr addr;
skipping to change at line 301 skipping to change at line 310
*maclenp = maclen; *maclenp = maclen;
*mactypep = ARPHRD_ETHER; *mactypep = ARPHRD_ETHER;
} }
static int complete_context6(struct in6_addr *local, int prefix, static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int flags, unsigned int pre ferred, int scope, int if_index, int flags, unsigned int pre ferred,
unsigned int valid, void *vparam) unsigned int valid, void *vparam)
{ {
struct dhcp_context *context; struct dhcp_context *context;
struct shared_network *share;
struct dhcp_relay *relay; struct dhcp_relay *relay;
struct iface_param *param = vparam; struct iface_param *param = vparam;
struct iname *tmp; struct iname *tmp;
(void)scope; /* warning */ (void)scope; /* warning */
if (if_index == param->ind) if (if_index != param->ind)
{ return 1;
if (IN6_IS_ADDR_LINKLOCAL(local))
param->ll_addr = *local;
else if (IN6_IS_ADDR_ULA(local))
param->ula_addr = *local;
if (!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
/* if we have --listen-address config, see if the
arrival interface has a matching address. */
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
param->addr_match = 1;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
param->fallback = *local;
for (context = daemon->dhcp6; context; context = context->next) if (IN6_IS_ADDR_LINKLOCAL(local))
{ param->ll_addr = *local;
if ((context->flags & CONTEXT_DHCP) && else if (IN6_IS_ADDR_ULA(local))
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) && param->ula_addr = *local;
prefix <= context->prefix &&
is_same_net6(local, &context->start6, context->prefix) &&
is_same_net6(local, &context->end6, context->prefix))
{
/* link it onto the current chain if we've not seen it before *
/
if (context->current == context)
{
struct dhcp_context *tmp, **up;
/* use interface values only for constructed contexts */
if (!(context->flags & CONTEXT_CONSTRUCTED))
preferred = valid = 0xffffffff;
else if (flags & IFACE_DEPRECATED)
preferred = 0;
if (context->flags & CONTEXT_DEPRECATE)
preferred = 0;
/* order chain, longest preferred time first */
for (up = &param->current, tmp = param->current; tmp; tmp =
tmp->current)
if (tmp->preferred <= preferred)
break;
else
up = &tmp->current;
context->current = *up;
*up = context;
context->local6 = *local;
context->preferred = preferred;
context->valid = valid;
}
}
}
}
for (relay = daemon->relay6; relay; relay = relay->next) if (IN6_IS_ADDR_LOOPBACK(local) ||
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr.addr6) && relay->current IN6_IS_ADDR_LINKLOCAL(local) ||
== relay && IN6_IS_ADDR_MULTICAST(local))
(IN6_IS_ADDR_UNSPECIFIED(&param->relay_local) || IN6_ARE_ADDR_EQUAL(l return 1;
ocal, &param->relay_local)))
/* if we have --listen-address config, see if the
arrival interface has a matching address. */
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
param->addr_match = 1;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
param->fallback = *local;
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_DHCP) &&
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix <= context->prefix &&
context->current == context)
{
if (is_same_net6(local, &context->start6, context->prefix) &&
is_same_net6(local, &context->end6, context->prefix))
{ {
relay->current = param->relay; struct dhcp_context *tmp, **up;
param->relay = relay;
param->relay_local = *local; /* use interface values only for constructed contexts */
if (!(context->flags & CONTEXT_CONSTRUCTED))
preferred = valid = 0xffffffff;
else if (flags & IFACE_DEPRECATED)
preferred = 0;
if (context->flags & CONTEXT_DEPRECATE)
preferred = 0;
/* order chain, longest preferred time first */
for (up = &param->current, tmp = param->current; tmp; tmp = tmp->curr
ent)
if (tmp->preferred <= preferred)
break;
else
up = &tmp->current;
context->current = *up;
*up = context;
context->local6 = *local;
context->preferred = preferred;
context->valid = valid;
} }
else
{
for (share = daemon->shared_networks; share; share = share->next)
{
/* IPv4 shared_address - ignore */
if (share->shared_addr.s_addr != 0)
continue;
} if (share->if_index != 0)
{
if (share->if_index != if_index)
continue;
}
else
{
if (!IN6_ARE_ADDR_EQUAL(&share->match_addr6, local))
continue;
}
if (is_same_net6(&share->shared_addr6, &context->start6, context-
>prefix) &&
is_same_net6(&share->shared_addr6, &context->end6, context->p
refix))
{
context->current = param->current;
param->current = context;
context->local6 = *local;
context->preferred = context->flags & CONTEXT_DEPRECATE ? 0 :
0xffffffff;
context->valid = 0xffffffff;
}
}
}
}
for (relay = daemon->relay6; relay; relay = relay->next)
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6) && relay->current == rela
y &&
(IN6_IS_ADDR_UNSPECIFIED(&param->relay_local) || IN6_ARE_ADDR_EQUAL(local
, &param->relay_local)))
{
relay->current = param->relay;
param->relay = relay;
param->relay_local = *local;
}
return 1; return 1;
} }
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr) struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, struct in6_addr *addr)
{ {
struct dhcp_config *config; struct dhcp_config *config;
for (config = configs; config; config = config->next) for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_ADDR6) && if (config->flags & CONFIG_ADDR6)
is_same_net6(&config->addr6, net, prefix) && {
(prefix == 128 || addr6part(&config->addr6) == addr)) struct addrlist *addr_list;
return config;
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
if ((!net || is_same_net6(&addr_list->addr.addr6, net, prefix) || ((add
r_list->flags & ADDRLIST_WILDCARD) && prefix == 64)) &&
is_same_net6(&addr_list->addr.addr6, addr, (addr_list->flags & ADDR
LIST_PREFIX) ? addr_list->prefixlen : 128))
return config;
}
return NULL; return NULL;
} }
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c har *clid, int clid_len, int temp_addr, struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c har *clid, int clid_len, int temp_addr,
int iaid, int serial, struct dhcp_netid *n etids, int plain_range, struct in6_addr *ans) unsigned int iaid, int serial, struct dhcp _netid *netids, int plain_range, struct in6_addr *ans)
{ {
/* Find a free address: exclude anything in use and anything allocated to /* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration. a particular hwaddr/clientid/hostname in our configuration.
Try to return from contexts which match netids first. Try to return from contexts which match netids first.
Note that we assume the address prefix lengths are 64 or greater, so we can Note that we assume the address prefix lengths are 64 or greater, so we can
get by with 64 bit arithmetic. get by with 64 bit arithmetic.
*/ */
u64 start, addr; u64 start, addr;
skipping to change at line 432 skipping to change at line 472
for (pass = 0; pass <= plain_range ? 1 : 0; pass++) for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
for (c = context; c; c = c->current) for (c = context; c; c = c->current)
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED)) if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED))
continue; continue;
else if (!match_netid(c->filter, netids, pass)) else if (!match_netid(c->filter, netids, pass))
continue; continue;
else else
{ {
if (!temp_addr && option_bool(OPT_CONSEC_ADDR)) if (!temp_addr && option_bool(OPT_CONSEC_ADDR))
/* seed is largest extant lease addr in this context */ {
start = lease_find_max_addr6(c) + serial; /* seed is largest extant lease addr in this context,
skip addresses equal to the number of addresses rejected
by clients. This should avoid the same client being offered the
same
address after it has rjected it. */
start = lease_find_max_addr6(c) + 1 + serial + c->addr_epoch;
if (c->addr_epoch)
c->addr_epoch--;
}
else else
{ {
u64 range = 1 + addr6part(&c->end6) - addr6part(&c->start6); u64 range = 1 + addr6part(&c->end6) - addr6part(&c->start6);
u64 offset = j + c->addr_epoch; u64 offset = j + c->addr_epoch;
/* don't divide by zero if range is whole 2^64 */ /* don't divide by zero if range is whole 2^64 */
if (range != 0) if (range != 0)
offset = offset % range; offset = offset % range;
start = addr6part(&c->start6) + offset; start = addr6part(&c->start6) + offset;
skipping to change at line 455 skipping to change at line 502
/* iterate until we find a free address. */ /* iterate until we find a free address. */
addr = start; addr = start;
do { do {
/* eliminate addresses in use by the server. */ /* eliminate addresses in use by the server. */
for (d = context; d; d = d->current) for (d = context; d; d = d->current)
if (addr == addr6part(&d->local6)) if (addr == addr6part(&d->local6))
break; break;
*ans = c->start6;
setaddr6part (ans, addr);
if (!d && if (!d &&
!lease6_find_by_addr(&c->start6, c->prefix, addr) && !lease6_find_by_addr(&c->start6, c->prefix, addr) &&
!config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix !config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix
, addr)) , ans))
{ return c;
*ans = c->start6;
setaddr6part (ans, addr);
return c;
}
addr++; addr++;
if (addr == addr6part(&c->end6) + 1) if (addr == addr6part(&c->end6) + 1)
addr = addr6part(&c->start6); addr = addr6part(&c->start6);
} while (addr != start); } while (addr != start);
} }
return NULL; return NULL;
skipping to change at line 517 skipping to change at line 563
struct dhcp_context *tmp; struct dhcp_context *tmp;
for (tmp = context; tmp; tmp = tmp->current) for (tmp = context; tmp; tmp = tmp->current)
if (is_same_net6(&tmp->start6, taddr, tmp->prefix) && if (is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
match_netid(tmp->filter, netids, plain_range)) match_netid(tmp->filter, netids, plain_range))
return tmp; return tmp;
return NULL; return NULL;
} }
int config_valid(struct dhcp_config *config, struct dhcp_context *context, struc
t in6_addr *addr)
{
if (!config || !(config->flags & CONFIG_ADDR6))
return 0;
if ((config->flags & CONFIG_WILDCARD) && context->prefix == 64)
{
*addr = context->start6;
setaddr6part(addr, addr6part(&config->addr6));
return 1;
}
if (is_same_net6(&context->start6, &config->addr6, context->prefix))
{
*addr = config->addr6;
return 1;
}
return 0;
}
void make_duid(time_t now) void make_duid(time_t now)
{ {
(void)now; (void)now;
if (daemon->duid_config) if (daemon->duid_config)
{ {
unsigned char *p; unsigned char *p;
daemon->duid = p = safe_malloc(daemon->duid_config_len + 6); daemon->duid = p = safe_malloc(daemon->duid_config_len + 6);
daemon->duid_len = daemon->duid_config_len + 6; daemon->duid_len = daemon->duid_config_len + 6;
skipping to change at line 618 skipping to change at line 643
int newone, newname; int newone, newname;
}; };
static int construct_worker(struct in6_addr *local, int prefix, static int construct_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int flags, int scope, int if_index, int flags,
int preferred, int valid, void *vparam) int preferred, int valid, void *vparam)
{ {
char ifrn_name[IFNAMSIZ]; char ifrn_name[IFNAMSIZ];
struct in6_addr start6, end6; struct in6_addr start6, end6;
struct dhcp_context *template, *context; struct dhcp_context *template, *context;
struct iname *tmp;
(void)scope; (void)scope;
(void)flags; (void)flags;
(void)valid; (void)valid;
(void)preferred; (void)preferred;
struct cparam *param = vparam; struct cparam *param = vparam;
if (IN6_IS_ADDR_LOOPBACK(local) || if (IN6_IS_ADDR_LOOPBACK(local) ||
IN6_IS_ADDR_LINKLOCAL(local) || IN6_IS_ADDR_LINKLOCAL(local) ||
IN6_IS_ADDR_MULTICAST(local)) IN6_IS_ADDR_MULTICAST(local))
return 1; return 1;
if (!(flags & IFACE_PERMANENT)) if (!(flags & IFACE_PERMANENT))
return 1; return 1;
if (flags & IFACE_DEPRECATED) if (flags & IFACE_DEPRECATED)
return 1; return 1;
if (!indextoname(daemon->icmp6fd, if_index, ifrn_name)) /* Ignore interfaces where we're not doing RA/DHCP6 */
return 0; if (!indextoname(daemon->icmp6fd, if_index, ifrn_name) ||
!iface_check(AF_LOCAL, NULL, ifrn_name, NULL))
return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifrn_name))
return 1;
for (template = daemon->dhcp6; template; template = template->next) for (template = daemon->dhcp6; template; template = template->next)
if (!(template->flags & (CONTEXT_TEMPLATE | CONTEXT_CONSTRUCTED))) if (!(template->flags & (CONTEXT_TEMPLATE | CONTEXT_CONSTRUCTED)))
{ {
/* non-template entries, just fill in interface and local addresses */ /* non-template entries, just fill in interface and local addresses */
if (prefix <= template->prefix && if (prefix <= template->prefix &&
is_same_net6(local, &template->start6, template->prefix) && is_same_net6(local, &template->start6, template->prefix) &&
is_same_net6(local, &template->end6, template->prefix)) is_same_net6(local, &template->end6, template->prefix))
{ {
/* First time found, do fast RA. */ /* First time found, do fast RA. */
if (template->if_index != if_index || !IN6_ARE_ADDR_EQUAL(&template-> local6, local)) if (template->if_index == 0)
{ {
ra_start_unsolicited(param->now, template); ra_start_unsolicited(param->now, template);
param->newone = 1; param->newone = 1;
} }
template->if_index = if_index; template->if_index = if_index;
template->local6 = *local; template->local6 = *local;
} }
} }
 End of changes. 22 change blocks. 
128 lines changed or deleted 165 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)