"Fossies" - the Fresh Open Source Software Archive  

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

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

rfc3315.c  (dnsmasq-2.80):rfc3315.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 23 skipping to change at line 23
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
struct state { struct state {
unsigned char *clid; unsigned char *clid;
int clid_len, iaid, ia_type, interface, hostname_auth, lease_allocate; int clid_len, ia_type, interface, hostname_auth, lease_allocate;
char *client_hostname, *hostname, *domain, *send_domain; char *client_hostname, *hostname, *domain, *send_domain;
struct dhcp_context *context; struct dhcp_context *context;
struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr; struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;
unsigned int xid, fqdn_flags; unsigned int xid, fqdn_flags, iaid;
char *iface_name; char *iface_name;
void *packet_options, *end; void *packet_options, *end;
struct dhcp_netid *tags, *context_tags; struct dhcp_netid *tags, *context_tags;
unsigned char mac[DHCP_CHADDR_MAX]; unsigned char mac[DHCP_CHADDR_MAX];
unsigned int mac_len, mac_type; unsigned int mac_len, mac_type;
#ifdef OPTION6_PREFIX_CLASS
struct prefix_class *send_prefix_class;
#endif
}; };
static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
struct in6_addr *client_addr, int is_unicast, time_t now); struct in6_addr *client_addr, int is_unicast, time_t now);
static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ t sz, int is_unicast, time_t now); static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ t sz, int is_unicast, time_t now);
static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op ts); static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op ts);
static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string); static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, c har *string); static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, c har *string);
static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize); static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
static void *opt6_next(void *opts, void *end); static void *opt6_next(void *opts, void *end);
static unsigned int opt6_uint(unsigned char *opt, int offset, int size); static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
static void get_context_tag(struct state *state, struct dhcp_context *context); static void get_context_tag(struct state *state, struct dhcp_context *context);
static int check_ia(struct state *state, void *opt, void **endp, void **ia_optio n); static int check_ia(struct state *state, void *opt, void **endp, void **ia_optio n);
static int build_ia(struct state *state, int *t1cntr); static int build_ia(struct state *state, int *t1cntr);
static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz); static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
#ifdef OPTION6_PREFIX_CLASS
static struct prefix_class *prefix_class_from_context(struct dhcp_context *conte
xt);
#endif
static void mark_context_used(struct state *state, struct in6_addr *addr); static void mark_context_used(struct state *state, struct in6_addr *addr);
static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr ); static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr );
static int check_address(struct state *state, struct in6_addr *addr); static int check_address(struct state *state, struct in6_addr *addr);
static int config_valid(struct dhcp_config *config, struct dhcp_context *context
, struct in6_addr *addr, struct state *state, time_t now);
static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_c
ontext *context, struct in6_addr *addr);
static void add_address(struct state *state, struct dhcp_context *context, unsig ned int lease_time, void *ia_option, static void add_address(struct state *state, struct dhcp_context *context, unsig ned int lease_time, void *ia_option,
unsigned int *min_time, struct in6_addr *addr, time_t now ); unsigned int *min_time, struct in6_addr *addr, time_t now );
static void update_leases(struct state *state, struct dhcp_context *context, str uct in6_addr *addr, unsigned int lease_time, time_t now); static void update_leases(struct state *state, struct dhcp_context *context, str uct in6_addr *addr, unsigned int lease_time, time_t now);
static int add_local_addrs(struct dhcp_context *context); static int add_local_addrs(struct dhcp_context *context);
static struct dhcp_netid *add_options(struct state *state, int do_refresh); static struct dhcp_netid *add_options(struct state *state, int do_refresh);
static void calculate_times(struct dhcp_context *context, unsigned int *min_time , unsigned int *valid_timep, static void calculate_times(struct dhcp_context *context, unsigned int *min_time , unsigned int *valid_timep,
unsigned int *preferred_timep, unsigned int lease_tim e); unsigned int *preferred_timep, unsigned int lease_tim e);
#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2))) #define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
#define opt6_type(opt) (opt6_uint(opt, -4, 2)) #define opt6_type(opt) (opt6_uint(opt, -4, 2))
skipping to change at line 135 skipping to change at line 131
Recalculate the available contexts using that information. Recalculate the available contexts using that information.
link_address == NULL means there's no relay in use, so we try and find the client's link_address == NULL means there's no relay in use, so we try and find the client's
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, now); 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;
struct shared_network *share = NULL;
state->context = NULL; state->context = NULL;
if (!IN6_IS_ADDR_LOOPBACK(state->link_address) && if (!IN6_IS_ADDR_LOOPBACK(state->link_address) &&
!IN6_IS_ADDR_LINKLOCAL(state->link_address) && !IN6_IS_ADDR_LINKLOCAL(state->link_address) &&
!IN6_IS_ADDR_MULTICAST(state->link_address)) !IN6_IS_ADDR_MULTICAST(state->link_address))
for (c = daemon->dhcp6; c; c = c->next) for (c = daemon->dhcp6; c; c = c->next)
if ((c->flags & CONTEXT_DHCP) && {
!(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) && for (share = daemon->shared_networks; share; share = share->next)
is_same_net6(state->link_address, &c->start6, c->prefix) && {
is_same_net6(state->link_address, &c->end6, c->prefix)) if (share->shared_addr.s_addr != 0)
{ continue;
c->preferred = c->valid = 0xffffffff;
c->current = state->context; if (share->if_index != 0 ||
state->context = c; !IN6_ARE_ADDR_EQUAL(state->link_address, &share->match_ad
} dr6))
continue;
if ((c->flags & CONTEXT_DHCP) &&
!(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
is_same_net6(&share->shared_addr6, &c->start6, c->prefix)
&&
is_same_net6(&share->shared_addr6, &c->end6, c->prefix))
break;
}
if (share ||
((c->flags & CONTEXT_DHCP) &&
!(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
is_same_net6(state->link_address, &c->start6, c->prefix) &&
is_same_net6(state->link_address, &c->end6, c->prefix)))
{
c->preferred = c->valid = 0xffffffff;
c->current = state->context;
state->context = c;
}
}
if (!state->context) if (!state->context)
{ {
inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRL EN); inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRL EN);
my_syslog(MS_DHCP | LOG_WARNING, my_syslog(MS_DHCP | LOG_WARNING,
_("no address range available for DHCPv6 request from rel ay at %s"), _("no address range available for DHCPv6 request from rel ay at %s"),
daemon->addrbuff); daemon->addrbuff);
return 0; return 0;
} }
} }
skipping to change at line 220 skipping to change at line 236
state->mac_type = opt6_uint(opt, 0, 2); state->mac_type = opt6_uint(opt, 0, 2);
state->mac_len = opt6_len(opt) - 2; state->mac_len = opt6_len(opt) - 2;
memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len); memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
} }
for (opt = opts; opt; opt = opt6_next(opt, end)) for (opt = opts; opt; opt = opt6_next(opt, end))
{ {
if (opt6_ptr(opt, 0) + opt6_len(opt) > end) if (opt6_ptr(opt, 0) + opt6_len(opt) > end)
return 0; return 0;
int o = new_opt6(opt6_type(opt)); /* Don't copy MAC address into reply. */
if (opt6_type(opt) == OPTION6_RELAY_MSG) if (opt6_type(opt) != OPTION6_CLIENT_MAC)
{ {
struct in6_addr align; int o = new_opt6(opt6_type(opt));
/* the packet data is unaligned, copy to aligned storage */ if (opt6_type(opt) == OPTION6_RELAY_MSG)
memcpy(&align, inbuff + 2, IN6ADDRSZ); {
state->link_address = &align; struct in6_addr align;
/* zero is_unicast since that is now known to refer to the /* the packet data is unaligned, copy to aligned storage */
relayed packet, not the original sent by the client */ memcpy(&align, inbuff + 2, IN6ADDRSZ);
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_a state->link_address = &align;
ddr, 0, now)) /* zero is_unicast since that is now known to refer to the
return 0; relayed packet, not the original sent by the client */
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), clie
nt_addr, 0, now))
return 0;
}
else
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
end_opt6(o);
} }
else if (opt6_type(opt) != OPTION6_CLIENT_MAC)
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
end_opt6(o);
} }
return 1; return 1;
} }
static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ t sz, int is_unicast, time_t now) static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ t sz, int is_unicast, time_t now)
{ {
void *opt; void *opt;
int i, o, o1, start_opts; int i, o, o1, start_opts;
struct dhcp_opt *opt_cfg; struct dhcp_opt *opt_cfg;
struct dhcp_netid *tagif; struct dhcp_netid *tagif;
struct dhcp_config *config = NULL; struct dhcp_config *config = NULL;
struct dhcp_netid known_id, iface_id, v6_id; struct dhcp_netid known_id, iface_id, v6_id;
unsigned char *outmsgtypep; unsigned char *outmsgtypep;
struct dhcp_vendor *vendor; struct dhcp_vendor *vendor;
struct dhcp_context *context_tmp; struct dhcp_context *context_tmp;
struct dhcp_mac *mac_opt; struct dhcp_mac *mac_opt;
unsigned int ignore = 0; unsigned int ignore = 0;
#ifdef OPTION6_PREFIX_CLASS
struct prefix_class *p;
int dump_all_prefix_classes = 0;
#endif
state->packet_options = inbuff + 4; state->packet_options = inbuff + 4;
state->end = inbuff + sz; state->end = inbuff + sz;
state->clid = NULL; state->clid = NULL;
state->clid_len = 0; state->clid_len = 0;
state->lease_allocate = 0; state->lease_allocate = 0;
state->context_tags = NULL; state->context_tags = NULL;
state->domain = NULL; state->domain = NULL;
state->send_domain = NULL; state->send_domain = NULL;
state->hostname_auth = 0; state->hostname_auth = 0;
state->hostname = NULL; state->hostname = NULL;
state->client_hostname = NULL; state->client_hostname = NULL;
state->fqdn_flags = 0x01; /* default to send if we receive no FQDN option */ state->fqdn_flags = 0x01; /* default to send if we receive no FQDN option */
#ifdef OPTION6_PREFIX_CLASS
state->send_prefix_class = NULL;
#endif
/* set tag with name == interface */ /* set tag with name == interface */
iface_id.net = state->iface_name; iface_id.net = state->iface_name;
iface_id.next = state->tags; iface_id.next = state->tags;
state->tags = &iface_id; state->tags = &iface_id;
/* set tag "dhcpv6" */ /* set tag "dhcpv6" */
v6_id.net = "dhcpv6"; v6_id.net = "dhcpv6";
v6_id.next = state->tags; v6_id.next = state->tags;
state->tags = &v6_id; state->tags = &v6_id;
skipping to change at line 478 skipping to change at line 491
op += (*op)+1; op += (*op)+1;
*(pq++) = '.'; *(pq++) = '.';
} }
if (pq != daemon->dhcp_buff) if (pq != daemon->dhcp_buff)
pq--; pq--;
*pq = 0; *pq = 0;
if (legal_hostname(daemon->dhcp_buff)) if (legal_hostname(daemon->dhcp_buff))
{ {
struct dhcp_match_name *m;
size_t nl = strlen(daemon->dhcp_buff);
state->client_hostname = daemon->dhcp_buff; state->client_hostname = daemon->dhcp_buff;
if (option_bool(OPT_LOG_OPTS)) if (option_bool(OPT_LOG_OPTS))
my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state->xid, state->client_hostname); my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state->xid, state->client_hostname);
for (m = daemon->dhcp_name_match; m; m = m->next)
{
size_t ml = strlen(m->name);
char save = 0;
if (nl < ml)
continue;
if (nl > ml)
{
save = state->client_hostname[ml];
state->client_hostname[ml] = 0;
}
if (hostname_isequal(state->client_hostname, m->name) &&
(save == 0 || m->wildcard))
{
m->netid->next = state->tags;
state->tags = m->netid;
}
if (save != 0)
state->client_hostname[ml] = save;
}
} }
} }
} }
if (state->clid) if (state->clid &&
(config = find_config(daemon->dhcp_conf, state->context, state->clid, stat
e->clid_len,
state->mac, state->mac_len, state->mac_type, NULL, ru
n_tag_if(state->tags))) &&
have_config(config, CONFIG_NAME))
{ {
config = find_config(daemon->dhcp_conf, state->context, state->clid, state state->hostname = config->hostname;
->clid_len, state->mac, state->mac_len, state->mac_type, NULL); state->domain = config->domain;
state->hostname_auth = 1;
}
else if (state->client_hostname)
{
state->domain = strip_hostname(state->client_hostname);
if (have_config(config, CONFIG_NAME)) if (strlen(state->client_hostname) != 0)
{
state->hostname = config->hostname;
state->domain = config->domain;
state->hostname_auth = 1;
}
else if (state->client_hostname)
{ {
struct dhcp_match_name *m; state->hostname = state->client_hostname;
size_t nl;
state->domain = strip_hostname(state->client_hostname);
nl = strlen(state->client_hostname);
if (strlen(state->client_hostname) != 0) if (!config)
{ {
state->hostname = state->client_hostname; /* Search again now we have a hostname.
Only accept configs without CLID here, (it won't match)
if (!config) to avoid impersonation by name. */
{ struct dhcp_config *new = find_config(daemon->dhcp_conf, state->con
/* Search again now we have a hostname. text, NULL, 0, NULL, 0, 0, state->hostname, run_tag_if(state->tags));
Only accept configs without CLID here, (it won't match) if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
to avoid impersonation by name. */ config = new;
struct dhcp_config *new = find_config(daemon->dhcp_conf, state-
>context, NULL, 0, NULL, 0, 0, state->hostname);
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
config = new;
}
for (m = daemon->dhcp_name_match; m; m = m->next)
{
size_t ml = strlen(m->name);
char save = 0;
if (nl < ml)
continue;
if (nl > ml)
{
save = state->client_hostname[ml];
state->client_hostname[ml] = 0;
}
if (hostname_isequal(state->client_hostname, m->name) &&
(save == 0 || m->wildcard))
{
m->netid->next = state->tags;
state->tags = m->netid;
}
if (save != 0)
state->client_hostname[ml] = save;
}
} }
} }
} }
if (config) if (config)
{ {
struct dhcp_netid_list *list; struct dhcp_netid_list *list;
for (list = config->netid; list; list = list->next) for (list = config->netid; list; list = list->next)
{ {
skipping to change at line 563 skipping to change at line 574
/* set "known" tag for known hosts */ /* set "known" tag for known hosts */
known_id.net = "known"; known_id.net = "known";
known_id.next = state->tags; known_id.next = state->tags;
state->tags = &known_id; state->tags = &known_id;
if (have_config(config, CONFIG_DISABLE)) if (have_config(config, CONFIG_DISABLE))
ignore = 1; ignore = 1;
} }
else if (state->clid && else if (state->clid &&
find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, sta find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len,
te->mac, state->mac_len, state->mac_type, NULL)) state->mac, state->mac_len, state->mac_type, NULL, run_tag
_if(state->tags)))
{ {
known_id.net = "known-othernet"; known_id.net = "known-othernet";
known_id.next = state->tags; known_id.next = state->tags;
state->tags = &known_id; state->tags = &known_id;
} }
#ifdef OPTION6_PREFIX_CLASS
/* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6RE
QUEST))
{
void *oro;
if ((oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0)))
for (i = 0; i < opt6_len(oro) - 1; i += 2)
if (opt6_uint(oro, i, 2) == OPTION6_PREFIX_CLASS)
{
dump_all_prefix_classes = 1;
break;
}
if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes)
/* Add the tags associated with prefix classes so we can use the DHCP ran
ges.
Not done for SOLICIT as we add them one-at-time. */
for (p = daemon->prefix_classes; p ; p = p->next)
{
p->tag.next = state->tags;
state->tags = &p->tag;
}
}
#endif
tagif = run_tag_if(state->tags); tagif = run_tag_if(state->tags);
/* if all the netids in the ignore list are present, ignore this client */ /* if all the netids in the ignore list are present, ignore this client */
if (daemon->dhcp_ignore) if (daemon->dhcp_ignore)
{ {
struct dhcp_netid_list *id_list; struct dhcp_netid_list *id_list;
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next) for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
if (match_netid(id_list->list, tagif, 0)) if (match_netid(id_list->list, tagif, 0))
ignore = 1; ignore = 1;
skipping to change at line 676 skipping to change at line 663
struct dhcp_lease *ltmp; struct dhcp_lease *ltmp;
struct in6_addr req_addr, addr; struct in6_addr req_addr, addr;
if (!check_ia(state, opt, &ia_end, &ia_option)) if (!check_ia(state, opt, &ia_end, &ia_option))
continue; continue;
/* reset USED bits in contexts - one address per prefix per IAID */ /* reset USED bits in contexts - one address per prefix per IAID */
for (c = state->context; c; c = c->current) for (c = state->context; c; c = c->current)
c->flags &= ~CONTEXT_USED; c->flags &= ~CONTEXT_USED;
#ifdef OPTION6_PREFIX_CLASS
if (daemon->prefix_classes && state->ia_type == OPTION6_IA_NA)
{
void *prefix_opt;
int prefix_class;
if (dump_all_prefix_classes)
/* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix cla
sses */
plain_range = 0;
else
{
if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION
6_PREFIX_CLASS, 2)))
{
prefix_class = opt6_uint(prefix_opt, 0, 2);
for (p = daemon->prefix_classes; p ; p = p->next)
if (p->class == prefix_class)
break;
if (!p)
my_syslog(MS_DHCP | LOG_WARNING, _("unknown prefix-clas
s %d"), prefix_class);
else
{
/* add tag to list, and exclude undecorated dhcp-rang
es */
p->tag.next = state->tags;
solicit_tags = run_tag_if(&p->tag);
plain_range = 0;
state->send_prefix_class = p;
}
}
else
{
/* client didn't ask for a prefix class, lets see if we c
an find one. */
for (p = daemon->prefix_classes; p ; p = p->next)
{
p->tag.next = NULL;
if (match_netid(&p->tag, solicit_tags, 1))
break;
}
if (p)
{
plain_range = 0;
state->send_prefix_class = p;
}
}
if (p && option_bool(OPT_LOG_OPTS))
my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s",
state->xid, p->class, p->tag.net);
}
}
#endif
o = build_ia(state, &t1cntr); o = build_ia(state, &t1cntr);
if (address_assigned) if (address_assigned)
address_assigned = 2; address_assigned = 2;
for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(o pt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(o pt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{ {
/* worry about alignment here. */ /* worry about alignment here. */
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
if ((c = address6_valid(state->context, &req_addr, solicit_tags, plain_range))) if ((c = address6_valid(state->context, &req_addr, solicit_tags, plain_range)))
{ {
lease_time = c->lease_time; lease_time = c->lease_time;
/* If the client asks for an address on the same network as a configured address, /* If the client asks for an address on the same network as a configured address,
offer the configured address instead, to make moving to ne wly-configured offer the configured address instead, to make moving to ne wly-configured
addresses automatic. */ addresses automatic. */
if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c , &addr) && check_address(state, &addr)) if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c , &addr, state, now))
{ {
req_addr = addr; req_addr = addr;
mark_config_used(c, &addr); mark_config_used(c, &addr);
if (have_config(config, CONFIG_TIME)) if (have_config(config, CONFIG_TIME))
lease_time = config->lease_time; lease_time = config->lease_time;
} }
else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range))) else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
continue; /* not an address we're allowed */ continue; /* not an address we're allowed */
else if (!check_address(state, &req_addr)) else if (!check_address(state, &req_addr))
continue; /* address leased elsewhere */ continue; /* address leased elsewhere */
/* add address to output packet */ /* add address to output packet */
#ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_N
A)
state->send_prefix_class = prefix_class_from_context(c);
#endif
add_address(state, c, lease_time, ia_option, &min_time, &req_ addr, now); add_address(state, c, lease_time, ia_option, &min_time, &req_ addr, now);
mark_context_used(state, &req_addr); mark_context_used(state, &req_addr);
get_context_tag(state, c); get_context_tag(state, c);
address_assigned = 1; address_assigned = 1;
} }
} }
/* Suggest configured address(es) */ /* Suggest configured address(es) */
for (c = state->context; c; c = c->current) for (c = state->context; c; c = c->current)
if (!(c->flags & CONTEXT_CONF_USED) && if (!(c->flags & CONTEXT_CONF_USED) &&
match_netid(c->filter, solicit_tags, plain_range) && match_netid(c->filter, solicit_tags, plain_range) &&
config_valid(config, c, &addr) && config_valid(config, c, &addr, state, now))
check_address(state, &addr))
{ {
mark_config_used(state->context, &addr); mark_config_used(state->context, &addr);
if (have_config(config, CONFIG_TIME)) if (have_config(config, CONFIG_TIME))
lease_time = config->lease_time; lease_time = config->lease_time;
else else
lease_time = c->lease_time; lease_time = c->lease_time;
/* add address to output packet */ /* add address to output packet */
#ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
state->send_prefix_class = prefix_class_from_context(c);
#endif
add_address(state, c, lease_time, NULL, &min_time, &addr, now); add_address(state, c, lease_time, NULL, &min_time, &addr, now);
mark_context_used(state, &addr); mark_context_used(state, &addr);
get_context_tag(state, c); get_context_tag(state, c);
address_assigned = 1; address_assigned = 1;
} }
/* return addresses for existing leases */ /* return addresses for existing leases */
ltmp = NULL; ltmp = NULL;
while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_ IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid))) while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_ IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid)))
{ {
req_addr = ltmp->addr6; req_addr = ltmp->addr6;
if ((c = address6_available(state->context, &req_addr, solicit_ta gs, plain_range))) if ((c = address6_available(state->context, &req_addr, solicit_ta gs, plain_range)))
{ {
#ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_N
A)
state->send_prefix_class = prefix_class_from_context(c);
#endif
add_address(state, c, c->lease_time, NULL, &min_time, &req_ad dr, now); add_address(state, c, c->lease_time, NULL, &min_time, &req_ad dr, now);
mark_context_used(state, &req_addr); mark_context_used(state, &req_addr);
get_context_tag(state, c); get_context_tag(state, c);
address_assigned = 1; address_assigned = 1;
} }
} }
/* Return addresses for all valid contexts which don't yet have one * / /* Return addresses for all valid contexts which don't yet have one * /
while ((c = address6_allocate(state->context, state->clid, state->cli d_len, state->ia_type == OPTION6_IA_TA, while ((c = address6_allocate(state->context, state->clid, state->cli d_len, state->ia_type == OPTION6_IA_TA,
state->iaid, ia_counter, solicit_tags, plain_range, &addr))) state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
{ {
#ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
state->send_prefix_class = prefix_class_from_context(c);
#endif
add_address(state, c, c->lease_time, NULL, &min_time, &addr, now) ; add_address(state, c, c->lease_time, NULL, &min_time, &addr, now) ;
mark_context_used(state, &addr); mark_context_used(state, &addr);
get_context_tag(state, c); get_context_tag(state, c);
address_assigned = 1; address_assigned = 1;
} }
if (address_assigned != 1) if (address_assigned != 1)
{ {
/* If the server will not assign any addresses to any IAs in a /* If the server will not assign any addresses to any IAs in a
subsequent Request from the client, the server MUST send an Ad vertise subsequent Request from the client, the server MUST send an Ad vertise
skipping to change at line 923 skipping to change at line 840
goto request_no_address; goto request_no_address;
} }
o = build_ia(state, &t1cntr); o = build_ia(state, &t1cntr);
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{ {
struct in6_addr req_addr; struct in6_addr req_addr;
struct dhcp_context *dynamic, *c; struct dhcp_context *dynamic, *c;
unsigned int lease_time; unsigned int lease_time;
struct in6_addr addr;
int config_ok = 0; int config_ok = 0;
/* align. */ /* align. */
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
if ((c = address6_valid(state->context, &req_addr, tagif, 1))) if ((c = address6_valid(state->context, &req_addr, tagif, 1)))
config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUA L(&addr, &req_addr); config_ok = (config_implies(config, c, &req_addr) != NULL);
if ((dynamic = address6_available(state->context, &req_addr, tagi f, 1)) || c) if ((dynamic = address6_available(state->context, &req_addr, tagi f, 1)) || c)
{ {
if (!dynamic && !config_ok) if (!dynamic && !config_ok)
{ {
/* Static range, not configured. */ /* Static range, not configured. */
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOADDRS); put_opt6_short(DHCP6NOADDRS);
put_opt6_string(_("address unavailable")); put_opt6_string(_("address unavailable"));
end_opt6(o1); end_opt6(o1);
skipping to change at line 960 skipping to change at line 876
else else
{ {
if (!dynamic) if (!dynamic)
dynamic = c; dynamic = c;
lease_time = dynamic->lease_time; lease_time = dynamic->lease_time;
if (config_ok && have_config(config, CONFIG_TIME)) if (config_ok && have_config(config, CONFIG_TIME))
lease_time = config->lease_time; lease_time = config->lease_time;
#ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state->ia_type == OPTION6_
IA_NA)
state->send_prefix_class = prefix_class_from_context(c)
;
#endif
add_address(state, dynamic, lease_time, ia_option, &min_t ime, &req_addr, now); add_address(state, dynamic, lease_time, ia_option, &min_t ime, &req_addr, now);
get_context_tag(state, dynamic); get_context_tag(state, dynamic);
address_assigned = 1; address_assigned = 1;
} }
} }
else else
{ {
/* requested address not on the correct link */ /* requested address not on the correct link */
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOTONLINK); put_opt6_short(DHCP6NOTONLINK);
skipping to change at line 1058 skipping to change at line 970
put_opt6_string(_("no binding found")); put_opt6_string(_("no binding found"));
end_opt6(o1); end_opt6(o1);
preferred_time = valid_time = 0; preferred_time = valid_time = 0;
break; break;
} }
if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) || if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
(this_context = address6_valid(state->context, &req_addr, tag if, 1))) (this_context = address6_valid(state->context, &req_addr, tag if, 1)))
{ {
struct in6_addr addr;
unsigned int lease_time; unsigned int lease_time;
get_context_tag(state, this_context); get_context_tag(state, this_context);
if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR _EQUAL(&addr, &req_addr) && have_config(config, CONFIG_TIME)) if (config_implies(config, this_context, &req_addr) && have_c onfig(config, CONFIG_TIME))
lease_time = config->lease_time; lease_time = config->lease_time;
else else
lease_time = this_context->lease_time; lease_time = this_context->lease_time;
calculate_times(this_context, &min_time, &valid_time, &prefer red_time, lease_time); calculate_times(this_context, &min_time, &valid_time, &prefer red_time, lease_time);
lease_set_expires(lease, valid_time, now); lease_set_expires(lease, valid_time, now);
/* Update MAC record in case it's new information. */ /* Update MAC record in case it's new information. */
if (state->mac_len != 0) if (state->mac_len != 0)
lease_set_hwaddr(lease, state->mac, state->clid, state->mac _len, state->mac_type, state->clid_len, now, 0); lease_set_hwaddr(lease, state->mac, state->clid, state->mac _len, state->mac_type, state->clid_len, now, 0);
skipping to change at line 1270 skipping to change at line 1181
{ {
void *ia_option, *ia_end; void *ia_option, *ia_end;
int made_ia = 0; int made_ia = 0;
for (check_ia(state, opt, &ia_end, &ia_option); for (check_ia(state, opt, &ia_end, &ia_option);
ia_option; ia_option;
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTI ON6_IAADDR, 24)) ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTI ON6_IAADDR, 24))
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
struct in6_addr addr; struct in6_addr addr;
struct addrlist *addr_list;
/* align */ /* align */
memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&conf ig->addr6, &addr)) if ((addr_list = config_implies(config, state->context, &addr)))
{ {
prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF); prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN); inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static add ress %s for %s"), my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static add ress %s for %s"),
daemon->addrbuff, daemon->dhcp_buff3); daemon->addrbuff, daemon->dhcp_buff3);
config->flags |= CONFIG_DECLINED; addr_list->flags |= ADDRLIST_DECLINED;
config->decline_time = now; addr_list->decline_time = now;
} }
else else
/* make sure this host gets a different address next time. */ /* make sure this host gets a different address next time. */
for (context_tmp = state->context; context_tmp; context_tmp = c ontext_tmp->current) for (context_tmp = state->context; context_tmp; context_tmp = c ontext_tmp->current)
context_tmp->addr_epoch++; context_tmp->addr_epoch++;
if ((lease = lease6_find(state->clid, state->clid_len, state->ia_ type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, if ((lease = lease6_find(state->clid, state->clid_len, state->ia_ type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
state->iaid, &addr))) state->iaid, &addr)))
lease_prune(lease, now); lease_prune(lease, now);
else else
skipping to change at line 1394 skipping to change at line 1306
(IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state- >ll_addr))) (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state- >ll_addr)))
len -= IN6ADDRSZ; len -= IN6ADDRSZ;
if (len != 0) if (len != 0)
{ {
o = new_opt6(opt_cfg->opt); o = new_opt6(opt_cfg->opt);
for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++) for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
{ {
struct in6_addr *p = NULL;
if (IN6_IS_ADDR_UNSPECIFIED(a)) if (IN6_IS_ADDR_UNSPECIFIED(a))
{ {
if (!add_local_addrs(state->context)) if (!add_local_addrs(state->context))
put_opt6(state->fallback, IN6ADDRSZ); p = state->fallback;
} }
else if (IN6_IS_ADDR_ULA_ZERO(a)) else if (IN6_IS_ADDR_ULA_ZERO(a))
{ {
if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
put_opt6(state->ula_addr, IN6ADDRSZ); p = state->ula_addr;
} }
else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a)) else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
{ {
if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)) if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
put_opt6(state->ll_addr, IN6ADDRSZ); p = state->ll_addr;
} }
else else
put_opt6(a, IN6ADDRSZ); p = a;
if (!p)
continue;
else if (opt_cfg->opt == OPTION6_NTP_SERVER)
{
if (IN6_IS_ADDR_MULTICAST(p))
o1 = new_opt6(NTP_SUBOPTION_MC_ADDR);
else
o1 = new_opt6(NTP_SUBOPTION_SRV_ADDR);
put_opt6(p, IN6ADDRSZ);
end_opt6(o1);
}
else
put_opt6(p, IN6ADDRSZ);
} }
end_opt6(o); end_opt6(o);
} }
} }
else else
{ {
o = new_opt6(opt_cfg->opt); o = new_opt6(opt_cfg->opt);
if (opt_cfg->val) if (opt_cfg->val)
put_opt6(opt_cfg->val, opt_cfg->len); put_opt6(opt_cfg->val, opt_cfg->len);
skipping to change at line 1601 skipping to change at line 1529
for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->n ext) for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->n ext)
if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0 )) if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0 ))
break; break;
if (id_list) if (id_list)
state->hostname = NULL; state->hostname = NULL;
} }
} }
} }
#ifdef OPTION6_PREFIX_CLASS
static struct prefix_class *prefix_class_from_context(struct dhcp_context *conte
xt)
{
struct prefix_class *p;
struct dhcp_netid *t;
for (p = daemon->prefix_classes; p ; p = p->next)
for (t = context->filter; t; t = t->next)
if (strcmp(p->tag.net, t->net) == 0)
return p;
return NULL;
}
#endif
static int check_ia(struct state *state, void *opt, void **endp, void **ia_optio n) static int check_ia(struct state *state, void *opt, void **endp, void **ia_optio n)
{ {
state->ia_type = opt6_type(opt); state->ia_type = opt6_type(opt);
*ia_option = NULL; *ia_option = NULL;
if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA) if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
return 0; return 0;
if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12) if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
return 0; return 0;
skipping to change at line 1699 skipping to change at line 1612
{ {
preferred_time = opt6_uint(ia_option, 16, 4); preferred_time = opt6_uint(ia_option, 16, 4);
valid_time = opt6_uint(ia_option, 20, 4); valid_time = opt6_uint(ia_option, 20, 4);
} }
calculate_times(context, min_time, &valid_time, &preferred_time, lease_time); calculate_times(context, min_time, &valid_time, &preferred_time, lease_time);
put_opt6(addr, sizeof(*addr)); put_opt6(addr, sizeof(*addr));
put_opt6_long(preferred_time); put_opt6_long(preferred_time);
put_opt6_long(valid_time); put_opt6_long(valid_time);
#ifdef OPTION6_PREFIX_CLASS
if (state->send_prefix_class)
{
int o1 = new_opt6(OPTION6_PREFIX_CLASS);
put_opt6_short(state->send_prefix_class->class);
end_opt6(o1);
}
#endif
end_opt6(o); end_opt6(o);
if (state->lease_allocate) if (state->lease_allocate)
update_leases(state, context, addr, valid_time, now); update_leases(state, context, addr, valid_time, now);
if ((lease = lease6_find_by_addr(addr, 128, 0))) if ((lease = lease6_find_by_addr(addr, 128, 0)))
lease->flags |= LEASE_USED; lease->flags |= LEASE_USED;
/* get tags from context if we've not used it before */ /* get tags from context if we've not used it before */
if (context->netid.next == &context->netid && context->netid.net) if (context->netid.next == &context->netid && context->netid.net)
skipping to change at line 1744 skipping to change at line 1647
log6_quiet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname); log6_quiet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
} }
static void mark_context_used(struct state *state, struct in6_addr *addr) static void mark_context_used(struct state *state, struct in6_addr *addr)
{ {
struct dhcp_context *context; struct dhcp_context *context;
/* Mark that we have an address for this prefix. */ /* Mark that we have an address for this prefix. */
#ifdef OPTION6_PREFIX_CLASS
for (context = state->context; context; context = context->current)
if (is_same_net6(addr, &context->start6, context->prefix) &&
(!state->send_prefix_class || state->send_prefix_class == prefix_class_fr
om_context(context)))
context->flags |= CONTEXT_USED;
#else
for (context = state->context; context; context = context->current) for (context = state->context; context; context = context->current)
if (is_same_net6(addr, &context->start6, context->prefix)) if (is_same_net6(addr, &context->start6, context->prefix))
context->flags |= CONTEXT_USED; context->flags |= CONTEXT_USED;
#endif
} }
static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr ) static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr )
{ {
for (; context; context = context->current) for (; context; context = context->current)
if (is_same_net6(addr, &context->start6, context->prefix)) if (is_same_net6(addr, &context->start6, context->prefix))
context->flags |= CONTEXT_CONF_USED; context->flags |= CONTEXT_CONF_USED;
} }
/* make sure address not leased to another CLID/IAID */ /* make sure address not leased to another CLID/IAID */
skipping to change at line 1779 skipping to change at line 1675
return 1; return 1;
if (lease->clid_len != state->clid_len || if (lease->clid_len != state->clid_len ||
memcmp(lease->clid, state->clid, state->clid_len) != 0 || memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
lease->iaid != state->iaid) lease->iaid != state->iaid)
return 0; return 0;
return 1; return 1;
} }
/* return true of *addr could have been generated from config. */
static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_c
ontext *context, struct in6_addr *addr)
{
int prefix;
struct in6_addr wild_addr;
struct addrlist *addr_list;
if (!config || !(config->flags & CONFIG_ADDR6))
return NULL;
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
{
prefix = (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128
;
wild_addr = addr_list->addr.addr6;
if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
{
wild_addr = context->start6;
setaddr6part(&wild_addr, addr6part(&addr_list->addr.addr6));
}
else if (!is_same_net6(&context->start6, addr, context->prefix))
continue;
if (is_same_net6(&wild_addr, addr, prefix))
return addr_list;
}
return NULL;
}
static int config_valid(struct dhcp_config *config, struct dhcp_context *context
, struct in6_addr *addr, struct state *state, time_t now)
{
u64 addrpart, i, addresses;
struct addrlist *addr_list;
if (!config || !(config->flags & CONFIG_ADDR6))
return 0;
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
if (!(addr_list->flags & ADDRLIST_DECLINED) ||
difftime(now, addr_list->decline_time) >= (float)DECLINE_BACKOFF)
{
addrpart = addr6part(&addr_list->addr.addr6);
addresses = 1;
if (addr_list->flags & ADDRLIST_PREFIX)
addresses = (u64)1<<(128-addr_list->prefixlen);
if ((addr_list->flags & ADDRLIST_WILDCARD))
{
if (context->prefix != 64)
continue;
*addr = context->start6;
}
else if (is_same_net6(&context->start6, &addr_list->addr.addr6, context->
prefix))
*addr = addr_list->addr.addr6;
else
continue;
for (i = 0 ; i < addresses; i++)
{
setaddr6part(addr, addrpart+i);
if (check_address(state, addr))
return 1;
}
}
return 0;
}
/* Calculate valid and preferred times to send in leases/renewals. /* Calculate valid and preferred times to send in leases/renewals.
Inputs are: Inputs are:
*valid_timep, *preferred_timep - requested times from IAADDR options. *valid_timep, *preferred_timep - requested times from IAADDR options.
context->valid, context->preferred - times associated with subnet address on local interface. context->valid, context->preferred - times associated with subnet address on local interface.
context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range. context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range.
lease_time - configured time for context for individual client. lease_time - configured time for context for individual client.
*min_time - smallest valid time sent so far. *min_time - smallest valid time sent so far.
skipping to change at line 1977 skipping to change at line 1945
struct in6_addr addr; struct in6_addr addr;
/* align */ /* align */
memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ); memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ);
inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN); inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
sprintf(daemon->namebuff, "%s PL=%u VL=%u", sprintf(daemon->namebuff, "%s PL=%u VL=%u",
daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4)) ; daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4)) ;
optname = "iaaddr"; optname = "iaaddr";
ia_options = opt6_ptr(opt, 24); ia_options = opt6_ptr(opt, 24);
} }
#ifdef OPTION6_PREFIX_CLASS
else if (type == OPTION6_PREFIX_CLASS)
{
optname = "prefix-class";
sprintf(daemon->namebuff, "class=%u", opt6_uint(opt, 0, 2));
}
#endif
else if (type == OPTION6_STATUS_CODE) else if (type == OPTION6_STATUS_CODE)
{ {
int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2)); int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2); memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
daemon->namebuff[len + opt6_len(opt) - 2] = 0; daemon->namebuff[len + opt6_len(opt) - 2] = 0;
optname = "status"; optname = "status";
} }
else else
{ {
/* account for flag byte on FQDN */ /* account for flag byte on FQDN */
skipping to change at line 2108 skipping to change at line 2069
ret = (ret << 8) | *p++; ret = (ret << 8) | *p++;
return ret; return ret;
} }
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
struct in6_addr *peer_address, u32 scope_id, time_t now) 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 */
struct all_addr from; union all_addr from;
unsigned char *header; unsigned char *header;
unsigned char *inbuff = daemon->dhcp_packet.iov_base; unsigned char *inbuff = daemon->dhcp_packet.iov_base;
int msg_type = *inbuff; int msg_type = *inbuff;
int hopcount; int hopcount;
struct in6_addr multicast; struct in6_addr multicast;
unsigned int maclen, mactype; unsigned int maclen, mactype;
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, now); 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.addr6 = relay->local.addr6;
/* Get hop count from nested relayed message */ /* Get hop count from nested relayed message */
if (msg_type == DHCP6RELAYFORW) if (msg_type == DHCP6RELAYFORW)
hopcount = *((unsigned char *)inbuff+1) + 1; hopcount = *((unsigned char *)inbuff+1) + 1;
else else
hopcount = 0; hopcount = 0;
/* RFC 3315 HOP_COUNT_LIMIT */ /* RFC 3315 HOP_COUNT_LIMIT */
if (hopcount > 32) if (hopcount > 32)
return; return;
reset_counter(); reset_counter();
if ((header = put_opt6(NULL, 34))) if ((header = put_opt6(NULL, 34)))
{ {
int o; int o;
header[0] = DHCP6RELAYFORW; header[0] = DHCP6RELAYFORW;
header[1] = hopcount; header[1] = hopcount;
memcpy(&header[2], &relay->local.addr.addr6, IN6ADDRSZ); memcpy(&header[2], &relay->local.addr6, IN6ADDRSZ);
memcpy(&header[18], peer_address, IN6ADDRSZ); memcpy(&header[18], peer_address, IN6ADDRSZ);
/* RFC-6939 */ /* RFC-6939 */
if (maclen != 0) if (maclen != 0)
{ {
o = new_opt6(OPTION6_CLIENT_MAC); o = new_opt6(OPTION6_CLIENT_MAC);
put_opt6_short(mactype); put_opt6_short(mactype);
put_opt6(mac, maclen); put_opt6(mac, maclen);
end_opt6(o); end_opt6(o);
} }
o = new_opt6(OPTION6_RELAY_MSG); o = new_opt6(OPTION6_RELAY_MSG);
put_opt6(inbuff, sz); put_opt6(inbuff, sz);
end_opt6(o); end_opt6(o);
for (; relay; relay = relay->current) for (; relay; relay = relay->current)
{ {
union mysockaddr to; union mysockaddr to;
to.sa.sa_family = AF_INET6; to.sa.sa_family = AF_INET6;
to.in6.sin6_addr = relay->server.addr.addr6; to.in6.sin6_addr = relay->server.addr6;
to.in6.sin6_port = htons(DHCPV6_SERVER_PORT); to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
to.in6.sin6_flowinfo = 0; to.in6.sin6_flowinfo = 0;
to.in6.sin6_scope_id = 0; to.in6.sin6_scope_id = 0;
if (IN6_ARE_ADDR_EQUAL(&relay->server.addr.addr6, &multicast)) if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
{ {
int multicast_iface; int multicast_iface;
if (!relay->interface || strchr(relay->interface, '*') || if (!relay->interface || strchr(relay->interface, '*') ||
(multicast_iface = if_nametoindex(relay->interface)) == 0 || (multicast_iface = if_nametoindex(relay->interface)) == 0 ||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &m ulticast_iface, sizeof(multicast_iface)) == -1) setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &m ulticast_iface, sizeof(multicast_iface)) == -1)
my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface")); my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
} }
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter( -1), &to, &from, 0); send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter( -1), &to, &from, 0);
skipping to change at line 2206 skipping to change at line 2167
/* must have at least msg_type+hopcount+link_address+peer_address+minimal size option /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */ which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
if (sz < 38 || *inbuff != DHCP6RELAYREPL) if (sz < 38 || *inbuff != DHCP6RELAYREPL)
return 0; return 0;
memcpy(&link, &inbuff[2], IN6ADDRSZ); memcpy(&link, &inbuff[2], IN6ADDRSZ);
for (relay = daemon->relay6; relay; relay = relay->next) for (relay = daemon->relay6; relay; relay = relay->next)
if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr.addr6) && if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr6) &&
(!relay->interface || wildcard_match(relay->interface, arrival_interface) )) (!relay->interface || wildcard_match(relay->interface, arrival_interface) ))
break; break;
reset_counter(); reset_counter();
if (relay) if (relay)
{ {
void *opt, *opts = inbuff + 34; void *opt, *opts = inbuff + 34;
void *end = inbuff + sz; void *end = inbuff + sz;
for (opt = opts; opt; opt = opt6_next(opt, end)) for (opt = opts; opt; opt = opt6_next(opt, end))
 End of changes. 57 change blocks. 
266 lines changed or deleted 221 lines changed or added

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