it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-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);
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_opts);
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 void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
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 int check_address(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 int check_address(struct state *state, struct in6_addr *addr);
-static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
+static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
unsigned int *min_time, struct in6_addr *addr, time_t now);
static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
static int add_local_addrs(struct dhcp_context *context);
static struct dhcp_netid *add_options(struct state *state, int do_refresh);
unsigned int *min_time, struct in6_addr *addr, time_t now);
static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
static int add_local_addrs(struct dhcp_context *context);
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_time);
#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
unsigned int *preferred_timep, unsigned int lease_time);
#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
#define opt6_user_vendor_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2+(i)]))
#define opt6_user_vendor_len(opt) ((int)(opt6_uint(opt, -4, 2)))
#define opt6_user_vendor_next(opt, end) (opt6_next(((void *) opt) - 2, end))
#define opt6_user_vendor_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2+(i)]))
#define opt6_user_vendor_len(opt) ((int)(opt6_uint(opt, -4, 2)))
#define opt6_user_vendor_next(opt, end) (opt6_next(((void *) opt) - 2, end))
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,
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,
/* Mark these so we only match each at most once, to avoid tangled linked lists */
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
vendor->netid.next = &vendor->netid;
/* Mark these so we only match each at most once, to avoid tangled linked lists */
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
vendor->netid.next = &vendor->netid;
- if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr,
+ if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr,
IN6_IS_ADDR_MULTICAST(client_addr), now))
return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
IN6_IS_ADDR_MULTICAST(client_addr), now))
return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
-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,
/* if not an encaplsulated relayed message, just do the stuff */
if (msg_type != DHCP6RELAYFORW)
{
/* if not an encaplsulated relayed message, just do the stuff */
if (msg_type != DHCP6RELAYFORW)
{
innermost nested RELAYFORW message, which is where we find the
address of the network on which we can allocate an address.
innermost nested RELAYFORW message, which is where we find the
address of the network on which we can allocate an address.
if (!state->link_address)
get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type);
else
{
struct dhcp_context *c;
state->context = NULL;
if (!state->link_address)
get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type);
else
{
struct dhcp_context *c;
state->context = NULL;
if (!IN6_IS_ADDR_LOOPBACK(state->link_address) &&
!IN6_IS_ADDR_LINKLOCAL(state->link_address) &&
!IN6_IS_ADDR_MULTICAST(state->link_address))
if (!IN6_IS_ADDR_LOOPBACK(state->link_address) &&
!IN6_IS_ADDR_LINKLOCAL(state->link_address) &&
!IN6_IS_ADDR_MULTICAST(state->link_address))
- inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
- my_syslog(MS_DHCP | LOG_WARNING,
+ inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
+ my_syslog(MS_DHCP | LOG_WARNING,
/* copy header stuff into reply message and set type to reply */
if (!(outmsgtypep = put_opt6(inbuff, 34)))
return 0;
/* copy header stuff into reply message and set type to reply */
if (!(outmsgtypep = put_opt6(inbuff, 34)))
return 0;
if (vendor->match_type == MATCH_SUBSCRIBER)
mopt = OPTION6_SUBSCRIBER_ID;
else if (vendor->match_type == MATCH_REMOTE)
if (vendor->match_type == MATCH_SUBSCRIBER)
mopt = OPTION6_SUBSCRIBER_ID;
else if (vendor->match_type == MATCH_REMOTE)
/* RFC-6939 */
if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))
{
/* RFC-6939 */
if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))
{
state->mac_type = opt6_uint(opt, 0, 2);
state->mac_len = opt6_len(opt) - 2;
memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
}
state->mac_type = opt6_uint(opt, 0, 2);
state->mac_len = opt6_len(opt) - 2;
memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
}
for (opt = opts; opt; opt = opt6_next(opt, end))
{
int o = new_opt6(opt6_type(opt));
for (opt = opts; opt; opt = opt6_next(opt, end))
{
int o = new_opt6(opt6_type(opt));
relayed packet, not the original sent by the client */
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
return 0;
}
else if (opt6_type(opt) != OPTION6_CLIENT_MAC)
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
relayed packet, not the original sent by the client */
if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
return 0;
}
else if (opt6_type(opt) != OPTION6_CLIENT_MAC)
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
/* set tag with name == interface */
iface_id.net = state->iface_name;
iface_id.next = state->tags;
/* set tag with name == interface */
iface_id.net = state->iface_name;
iface_id.next = state->tags;
return 0;
start_opts = save_counter(-1);
state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
return 0;
start_opts = save_counter(-1);
state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
mark them as unused so we don't link one twice and break the list */
for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
{
mark them as unused so we don't link one twice and break the list */
for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
{
- inet_ntop(AF_INET6, &context_tmp->start6, daemon->dhcp_buff, ADDRSTRLEN);
- inet_ntop(AF_INET6, &context_tmp->end6, daemon->dhcp_buff2, ADDRSTRLEN);
+ inet_ntop(AF_INET6, &context_tmp->start6, daemon->dhcp_buff, ADDRSTRLEN);
+ inet_ntop(AF_INET6, &context_tmp->end6, daemon->dhcp_buff2, ADDRSTRLEN);
if (context_tmp->flags & (CONTEXT_STATIC))
my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCPv6 subnet: %s/%d"),
state->xid, daemon->dhcp_buff, context_tmp->prefix);
else
if (context_tmp->flags & (CONTEXT_STATIC))
my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCPv6 subnet: %s/%d"),
state->xid, daemon->dhcp_buff, context_tmp->prefix);
else
opt6_len(opt) != daemon->duid_len ||
memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
return 0;
opt6_len(opt) != daemon->duid_len ||
memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
return 0;
o = new_opt6(OPTION6_SERVER_ID);
put_opt6(daemon->duid, daemon->duid_len);
end_opt6(o);
if (is_unicast &&
(msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
o = new_opt6(OPTION6_SERVER_ID);
put_opt6(daemon->duid, daemon->duid_len);
end_opt6(o);
if (is_unicast &&
(msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
*outmsgtypep = DHCP6REPLY;
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6USEMULTI);
*outmsgtypep = DHCP6REPLY;
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6USEMULTI);
if (vendor->match_type == MATCH_VENDOR)
mopt = OPTION6_VENDOR_CLASS;
else if (vendor->match_type == MATCH_USER)
if (vendor->match_type == MATCH_VENDOR)
mopt = OPTION6_VENDOR_CLASS;
else if (vendor->match_type == MATCH_USER)
/* Note that format if user/vendor classes is different to DHCP options - no option types. */
for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_user_vendor_next(enc_opt, enc_end))
for (i = 0; i <= (opt6_user_vendor_len(enc_opt) - vendor->len); i++)
/* Note that format if user/vendor classes is different to DHCP options - no option types. */
for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_user_vendor_next(enc_opt, enc_end))
for (i = 0; i <= (opt6_user_vendor_len(enc_opt) - vendor->len); i++)
if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), state->xid, opt6_uint(opt, 0, 4));
if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), state->xid, opt6_uint(opt, 0, 4));
- Otherwise assume the option is an array, and look for a matching element.
- If no data given, existance of the option is enough. This code handles
+ Otherwise assume the option is an array, and look for a matching element.
+ If no data given, existance of the option is enough. This code handles
if (opt_cfg->flags & DHOPT_RFC3925)
{
for (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_OPTS, 4);
if (opt_cfg->flags & DHOPT_RFC3925)
{
for (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_OPTS, 4);
for (vopt = opt6_find(opt6_ptr(opt, 4), vend, opt_cfg->opt, 0);
vopt;
vopt = opt6_find(opt6_next(vopt, vend), vend, opt_cfg->opt, 0))
for (vopt = opt6_find(opt6_ptr(opt, 4), vend, opt_cfg->opt, 0);
vopt;
vopt = opt6_find(opt6_next(vopt, vend), vend, opt_cfg->opt, 0))
{
if (!(opt = opt6_find(state->packet_options, state->end, opt_cfg->opt, 1)))
continue;
{
if (!(opt = opt6_find(state->packet_options, state->end, opt_cfg->opt, 1)))
continue;
match = match_bytes(opt_cfg, opt6_ptr(opt, 0), opt6_len(opt));
match = match_bytes(opt_cfg, opt6_ptr(opt, 0), opt6_len(opt));
if ((opt = opt6_find(state->packet_options, state->end, OPTION6_FQDN, 1)))
{
/* RFC4704 refers */
int len = opt6_len(opt) - 1;
if ((opt = opt6_find(state->packet_options, state->end, OPTION6_FQDN, 1)))
{
/* RFC4704 refers */
int len = opt6_len(opt) - 1;
/* Always force update, since the client has no way to do it itself. */
if (!option_bool(OPT_FQDN_UPDATE) && !(state->fqdn_flags & 0x01))
state->fqdn_flags |= 0x03;
/* Always force update, since the client has no way to do it itself. */
if (!option_bool(OPT_FQDN_UPDATE) && !(state->fqdn_flags & 0x01))
state->fqdn_flags |= 0x03;
state->fqdn_flags &= ~0x04;
if (len != 0 && len < 255)
{
unsigned char *pp, *op = opt6_ptr(opt, 1);
char *pq = daemon->dhcp_buff;
state->fqdn_flags &= ~0x04;
if (len != 0 && len < 255)
{
unsigned char *pp, *op = opt6_ptr(opt, 1);
char *pq = daemon->dhcp_buff;
if (legal_hostname(daemon->dhcp_buff))
{
state->client_hostname = daemon->dhcp_buff;
if (option_bool(OPT_LOG_OPTS))
if (legal_hostname(daemon->dhcp_buff))
{
state->client_hostname = daemon->dhcp_buff;
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);
if (state->clid)
{
config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL);
if (state->clid)
{
config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL);
if (have_config(config, CONFIG_NAME))
{
state->hostname = config->hostname;
if (have_config(config, CONFIG_NAME))
{
state->hostname = config->hostname;
Only accept configs without CLID here, (it won't match)
to avoid impersonation by name. */
struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname);
Only accept configs without CLID here, (it won't match)
to avoid impersonation by name. */
struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname);
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)
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)
if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes)
/* Add the tags associated with prefix classes so we can use the DHCP ranges.
Not done for SOLICIT as we add them one-at-time. */
if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes)
/* Add the tags associated with prefix classes so we can use the DHCP ranges.
Not done for SOLICIT as we add them one-at-time. */
/* if all the netids in the ignore list are present, ignore this client */
if (daemon->dhcp_ignore)
{
struct dhcp_netid_list *id_list;
/* if all the netids in the ignore list are present, ignore this client */
if (daemon->dhcp_ignore)
{
struct dhcp_netid_list *id_list;
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
if (match_netid(id_list->list, tagif, 0))
ignore = 1;
}
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
if (match_netid(id_list->list, tagif, 0))
ignore = 1;
}
/* if all the netids in the ignore_name list are present, ignore client-supplied name */
if (!state->hostname_auth)
{
struct dhcp_netid_list *id_list;
/* if all the netids in the ignore_name list are present, ignore client-supplied name */
if (!state->hostname_auth)
{
struct dhcp_netid_list *id_list;
for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
if ((!id_list->list) || match_netid(id_list->list, tagif, 0))
break;
if (id_list)
state->hostname = NULL;
}
for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
if ((!id_list->list) || match_netid(id_list->list, tagif, 0))
break;
if (id_list)
state->hostname = NULL;
}
case DHCP6SOLICIT:
{
int address_assigned = 0;
/* tags without all prefix-class tags */
struct dhcp_netid *solicit_tags;
struct dhcp_context *c;
case DHCP6SOLICIT:
{
int address_assigned = 0;
/* tags without all prefix-class tags */
struct dhcp_netid *solicit_tags;
struct dhcp_context *c;
if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))
{
*outmsgtypep = DHCP6REPLY;
if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))
{
*outmsgtypep = DHCP6REPLY;
log6_quiet(state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
request_no_address:
solicit_tags = tagif;
log6_quiet(state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
request_no_address:
solicit_tags = tagif;
c->flags &= ~CONTEXT_CONF_USED;
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
c->flags &= ~CONTEXT_CONF_USED;
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
void *ia_option, *ia_end;
unsigned int min_time = 0xffffffff;
int t1cntr;
void *ia_option, *ia_end;
unsigned int min_time = 0xffffffff;
int t1cntr;
if (!check_ia(state, opt, &ia_end, &ia_option))
continue;
if (!check_ia(state, opt, &ia_end, &ia_option))
continue;
/* reset USED bits in contexts - one address per prefix per IAID */
for (c = state->context; c; c = c->current)
c->flags &= ~CONTEXT_USED;
/* reset USED bits in contexts - one address per prefix per IAID */
for (c = state->context; c; c = c->current)
c->flags &= ~CONTEXT_USED;
if (dump_all_prefix_classes)
/* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
plain_range = 0;
if (dump_all_prefix_classes)
/* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
plain_range = 0;
if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))
{
if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))
{
- my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s", state->xid, p->class, p->tag.net);
+ my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s", state->xid, p->class, p->tag.net);
for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
req_addr = opt6_ptr(ia_option, 0);
for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
req_addr = opt6_ptr(ia_option, 0);
if ((c = address6_valid(state->context, req_addr, solicit_tags, plain_range)))
{
lease_time = c->lease_time;
if ((c = address6_valid(state->context, req_addr, solicit_tags, plain_range)))
{
lease_time = c->lease_time;
offer the configured address instead, to make moving to newly-configured
addresses automatic. */
if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
offer the configured address instead, to make moving to newly-configured
addresses automatic. */
if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
continue; /* not an address we're allowed */
else if (!check_address(state, req_addr))
continue; /* address leased elsewhere */
continue; /* not an address we're allowed */
else if (!check_address(state, req_addr))
continue; /* address leased elsewhere */
/* 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);
/* 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);
add_address(state, c, lease_time, ia_option, &min_time, req_addr, now);
mark_context_used(state, req_addr);
get_context_tag(state, c);
address_assigned = 1;
}
}
add_address(state, c, lease_time, ia_option, &min_time, req_addr, now);
mark_context_used(state, req_addr);
get_context_tag(state, c);
address_assigned = 1;
}
}
if (!(c->flags & CONTEXT_CONF_USED) &&
match_netid(c->filter, solicit_tags, plain_range) &&
if (!(c->flags & CONTEXT_CONF_USED) &&
match_netid(c->filter, solicit_tags, plain_range) &&
check_address(state, &addr))
{
mark_config_used(state->context, &addr);
check_address(state, &addr))
{
mark_config_used(state->context, &addr);
/* return addresses for existing leases */
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)))
/* return addresses for existing leases */
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)))
/* Return addresses for all valid contexts which don't yet have one */
while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->ia_type == OPTION6_IA_TA,
state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
/* Return addresses for all valid contexts which don't yet have one */
while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->ia_type == OPTION6_IA_TA,
state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
/* If the server cannot assign any addresses to an IA in the message
from the client, the server MUST include the IA in the Reply message
with no addresses in the IA and a Status Code option in the IA
/* If the server cannot assign any addresses to an IA in the message
from the client, the server MUST include the IA in the Reply message
with no addresses in the IA and a Status Code option in the IA
{
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6SUCCESS);
put_opt6_string(_("success"));
end_opt6(o1);
{
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6SUCCESS);
put_opt6_string(_("success"));
end_opt6(o1);
/* If --dhcp-authoritative is set, we can tell client not to wait for
other possible servers */
o = new_opt6(OPTION6_PREFERENCE);
/* If --dhcp-authoritative is set, we can tell client not to wait for
other possible servers */
o = new_opt6(OPTION6_PREFERENCE);
/* no address, return error */
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOADDRS);
/* no address, return error */
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOADDRS);
state->lease_allocate = 1;
log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
state->lease_allocate = 1;
log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
void *ia_option, *ia_end;
unsigned int min_time = 0xffffffff;
int t1cntr;
void *ia_option, *ia_end;
unsigned int min_time = 0xffffffff;
int t1cntr;
if (!check_ia(state, opt, &ia_end, &ia_option))
continue;
if (!check_ia(state, opt, &ia_end, &ia_option))
continue;
/* If we get a request with a IA_*A without addresses, treat it exactly like
a SOLICT with rapid commit set. */
save_counter(start);
/* If we get a request with a IA_*A without addresses, treat it exactly like
a SOLICT with rapid commit set. */
save_counter(start);
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
if ((c = address6_valid(state->context, req_addr, tagif, 1)))
config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
if ((c = address6_valid(state->context, req_addr, tagif, 1)))
config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c)
{
if (!dynamic && !config_ok)
if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c)
{
if (!dynamic && !config_ok)
if (config_ok && have_config(config, CONFIG_TIME))
lease_time = config->lease_time;
if (config_ok && have_config(config, CONFIG_TIME))
lease_time = config->lease_time;
/* no address, return error */
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOADDRS);
/* no address, return error */
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOADDRS);
log6_quiet(state, "DHCPRENEW", NULL, NULL);
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
log6_quiet(state, "DHCPRENEW", NULL, NULL);
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
void *ia_option, *ia_end;
unsigned int min_time = 0xffffffff;
int t1cntr, iacntr;
void *ia_option, *ia_end;
unsigned int min_time = 0xffffffff;
int t1cntr, iacntr;
if (!check_ia(state, opt, &ia_end, &ia_option))
continue;
if (!check_ia(state, opt, &ia_end, &ia_option))
continue;
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
struct dhcp_lease *lease = NULL;
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
struct dhcp_lease *lease = NULL;
unsigned int valid_time = opt6_uint(ia_option, 20, 4);
char *message = NULL;
struct dhcp_context *this_context;
unsigned int valid_time = opt6_uint(ia_option, 20, 4);
char *message = NULL;
struct dhcp_context *this_context;
log6_packet(state, "DHCPREPLY", req_addr, _("lease not found"));
log6_packet(state, "DHCPREPLY", req_addr, _("lease not found"));
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING);
put_opt6_string(_("no binding found"));
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING);
put_opt6_string(_("no binding found"));
if ((this_context = address6_available(state->context, req_addr, tagif, 1)) ||
(this_context = address6_valid(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, tagif, 1)))
{
if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
lease_time = config->lease_time;
if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
lease_time = config->lease_time;
-
- calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time);
-
+
+ calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time);
+
lease_set_expires(lease, valid_time, now);
/* Update MAC record in case it's new information. */
if (state->mac_len != 0)
lease_set_expires(lease, valid_time, now);
/* Update MAC record in case it's new information. */
if (state->mac_len != 0)
- lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
+ lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
- log6_packet(state, "DHCPREPLY", req_addr, message);
+ log6_packet(state, "DHCPREPLY", req_addr, message);
else
log6_quiet(state, "DHCPREPLY", req_addr, message);
else
log6_quiet(state, "DHCPREPLY", req_addr, message);
o1 = new_opt6(OPTION6_IAADDR);
put_opt6(req_addr, sizeof(*req_addr));
put_opt6_long(preferred_time);
put_opt6_long(valid_time);
end_opt6(o1);
}
o1 = new_opt6(OPTION6_IAADDR);
put_opt6(req_addr, sizeof(*req_addr));
put_opt6_long(preferred_time);
put_opt6_long(valid_time);
end_opt6(o1);
}
log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
{
void *ia_option, *ia_end;
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
{
void *ia_option, *ia_end;
for (check_ia(state, opt, &ia_end, &ia_option);
ia_option;
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
for (check_ia(state, opt, &ia_end, &ia_option);
ia_option;
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
if (!address6_valid(state->context, req_addr, tagif, 1))
{
o1 = new_opt6(OPTION6_STATUS_CODE);
if (!address6_valid(state->context, req_addr, tagif, 1))
{
o1 = new_opt6(OPTION6_STATUS_CODE);
good_addr = 1;
log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);
}
good_addr = 1;
log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);
}
unqualified configured domain, if any. */
if (state->hostname_auth)
state->send_domain = state->domain;
unqualified configured domain, if any. */
if (state->hostname_auth)
state->send_domain = state->domain;
for (check_ia(state, opt, &ia_end, &ia_option);
ia_option;
for (check_ia(state, opt, &ia_end, &ia_option);
ia_option;
- ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
+ ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
state->iaid, opt6_ptr(ia_option, 0))))
lease_prune(lease, now);
if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
state->iaid, opt6_ptr(ia_option, 0))))
lease_prune(lease, now);
o1 = new_opt6(OPTION6_IAADDR);
put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
put_opt6_long(0);
o1 = new_opt6(OPTION6_IAADDR);
put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
put_opt6_long(0);
if (made_ia)
{
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING);
put_opt6_string(_("no binding found"));
end_opt6(o1);
if (made_ia)
{
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING);
put_opt6_string(_("no binding found"));
end_opt6(o1);
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6SUCCESS);
put_opt6_string(_("release received"));
end_opt6(o1);
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6SUCCESS);
put_opt6_string(_("release received"));
end_opt6(o1);
log6_quiet(state, "DHCPDECLINE", NULL, NULL);
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
{
void *ia_option, *ia_end;
int made_ia = 0;
log6_quiet(state, "DHCPDECLINE", NULL, NULL);
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
{
void *ia_option, *ia_end;
int made_ia = 0;
for (check_ia(state, opt, &ia_end, &ia_option);
ia_option;
for (check_ia(state, opt, &ia_end, &ia_option);
ia_option;
- ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
+ ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
struct dhcp_lease *lease;
struct in6_addr *addrp = opt6_ptr(ia_option, 0);
{
struct dhcp_lease *lease;
struct in6_addr *addrp = opt6_ptr(ia_option, 0);
{
prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);
{
prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);
daemon->addrbuff, daemon->dhcp_buff3);
config->flags |= CONFIG_DECLINED;
config->decline_time = now;
daemon->addrbuff, daemon->dhcp_buff3);
config->flags |= CONFIG_DECLINED;
config->decline_time = now;
/* make sure this host gets a different address next time. */
for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
context_tmp->addr_epoch++;
/* make sure this host gets a different address next time. */
for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
context_tmp->addr_epoch++;
if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
state->iaid, opt6_ptr(ia_option, 0))))
lease_prune(lease, now);
if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
state->iaid, opt6_ptr(ia_option, 0))))
lease_prune(lease, now);
o1 = new_opt6(OPTION6_IAADDR);
put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
put_opt6_long(0);
o1 = new_opt6(OPTION6_IAADDR);
put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
put_opt6_long(0);
if (made_ia)
{
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING);
put_opt6_string(_("no binding found"));
end_opt6(o1);
if (made_ia)
{
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING);
put_opt6_string(_("no binding found"));
end_opt6(o1);
log_tags(tagif, state->xid);
log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
log_tags(tagif, state->xid);
log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
int i, o, o1;
oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
int i, o, o1;
oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
{
/* netids match and not encapsulated? */
if (!(opt_cfg->flags & DHOPT_TAGOK))
continue;
for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
{
/* netids match and not encapsulated? */
if (!(opt_cfg->flags & DHOPT_TAGOK))
continue;
if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
{
for (i = 0; i < opt6_len(oro) - 1; i += 2)
if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
break;
if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
{
for (i = 0; i < opt6_len(oro) - 1; i += 2)
if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
break;
j < opt_cfg->len; j += IN6ADDRSZ, a++)
if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
(IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)))
len -= IN6ADDRSZ;
j < opt_cfg->len; j += IN6ADDRSZ, a++)
if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
(IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)))
len -= IN6ADDRSZ;
for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
{
if (IN6_IS_ADDR_UNSPECIFIED(a))
for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
{
if (IN6_IS_ADDR_UNSPECIFIED(a))
if (daemon->port == NAMESERVER_PORT && !done_dns)
{
o = new_opt6(OPTION6_DNS_SERVER);
if (!add_local_addrs(state->context))
put_opt6(state->fallback, IN6ADDRSZ);
if (daemon->port == NAMESERVER_PORT && !done_dns)
{
o = new_opt6(OPTION6_DNS_SERVER);
if (!add_local_addrs(state->context))
put_opt6(state->fallback, IN6ADDRSZ);
/* handle vendor-identifying vendor-encapsulated options,
dhcp-option = vi-encap:13,17,....... */
for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
/* handle vendor-identifying vendor-encapsulated options,
dhcp-option = vi-encap:13,17,....... */
for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
if (oro)
for (i = 0; i < opt6_len(oro) - 1; i += 2)
if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
do_encap = 1;
if (oro)
for (i = 0; i < opt6_len(oro) - 1; i += 2)
if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
do_encap = 1;
oc->flags |= DHOPT_ENCAP_DONE;
if (match_netid(oc->netid, tagif, 1))
{
oc->flags |= DHOPT_ENCAP_DONE;
if (match_netid(oc->netid, tagif, 1))
{
{
char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
{
char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
(i > opt6_len(oro) - 3) ? "" : ", ");
if ( i > opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
{
(i > opt6_len(oro) - 3) ? "" : ", ");
if ( i > opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
{
my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
}
}
my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
}
}
for (; context; context = context->current)
if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
{
for (; context; context = context->current)
if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
{
if ((c->flags & CONTEXT_USED) &&
IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
break;
if ((c->flags & CONTEXT_USED) &&
IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
break;
for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
break;
for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
break;
#ifdef OPTION6_PREFIX_CLASS
static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)
{
struct prefix_class *p;
struct dhcp_netid *t;
#ifdef OPTION6_PREFIX_CLASS
static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)
{
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;
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;
*endp = opt6_ptr(opt, opt6_len(opt));
state->iaid = opt6_uint(opt, 0, 4);
*ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
*endp = opt6_ptr(opt, opt6_len(opt));
state->iaid = opt6_uint(opt, 0, 4);
*ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
static int build_ia(struct state *state, int *t1cntr)
{
int o = new_opt6(state->ia_type);
static int build_ia(struct state *state, int *t1cntr)
{
int o = new_opt6(state->ia_type);
if (state->ia_type == OPTION6_IA_NA)
{
/* save pointer */
*t1cntr = save_counter(-1);
/* so we can fill these in later */
put_opt6_long(0);
if (state->ia_type == OPTION6_IA_NA)
{
/* save pointer */
*t1cntr = save_counter(-1);
/* so we can fill these in later */
put_opt6_long(0);
t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
put_opt6_long(t1);
put_opt6_long(t2);
save_counter(sav);
t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
put_opt6_long(t1);
put_opt6_long(t2);
save_counter(sav);
-static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
+static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
unsigned int *min_time, struct in6_addr *addr, time_t now)
{
unsigned int valid_time = 0, preferred_time = 0;
unsigned int *min_time, struct in6_addr *addr, time_t now)
{
unsigned int valid_time = 0, preferred_time = 0;
- 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_long(preferred_time);
put_opt6(addr, sizeof(*addr));
put_opt6_long(preferred_time);
if (state->lease_allocate)
update_leases(state, context, addr, valid_time, now);
if (state->lease_allocate)
update_leases(state, context, addr, valid_time, now);
for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
break;
for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
break;
/* make sure address not leased to another CLID/IAID */
static int check_address(struct state *state, struct in6_addr *addr)
/* make sure address not leased to another CLID/IAID */
static int check_address(struct state *state, struct in6_addr *addr)
struct dhcp_lease *lease;
if (!(lease = lease6_find_by_addr(addr, 128, 0)))
return 1;
struct dhcp_lease *lease;
if (!(lease = lease6_find_by_addr(addr, 128, 0)))
return 1;
memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
lease->iaid != state->iaid)
return 0;
memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
lease->iaid != state->iaid)
return 0;
*valid_timep, *preferred_timep - times to be send in IAADDR option.
*min_time - smallest valid time sent so far, to calculate T1 and T2.
*valid_timep, *preferred_timep - times to be send in IAADDR option.
*min_time - smallest valid time sent so far, to calculate T1 and T2.
-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_time)
{
unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
unsigned int valid_time = lease_time, preferred_time = lease_time;
unsigned int *preferred_timep, unsigned int lease_time)
{
unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
unsigned int valid_time = lease_time, preferred_time = lease_time;
/* RFC 3315: "A server ignores the lifetimes set
by the client if the preferred lifetime is greater than the valid
lifetime. */
/* RFC 3315: "A server ignores the lifetimes set
by the client if the preferred lifetime is greater than the valid
lifetime. */
/* 0 == "no preference from client" */
if (req_preferred < 120u)
req_preferred = 120u; /* sanity */
/* 0 == "no preference from client" */
if (req_preferred < 120u)
req_preferred = 120u; /* sanity */
lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
lease_set_interface(lease, state->interface, now);
if (state->hostname && state->ia_type == OPTION6_IA_NA)
lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
lease_set_interface(lease, state->interface, now);
if (state->hostname && state->ia_type == OPTION6_IA_NA)
state->send_domain = addr_domain;
lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
}
state->send_domain = addr_domain;
lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
}
if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
{
void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
{
void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
/* send enterprise number first */
sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
/* send enterprise number first */
sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
{
lease->vendorclass_count++;
lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
}
}
for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
{
lease->vendorclass_count++;
lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
}
}
-
- lease_add_extradata(lease, (unsigned char *)state->client_hostname,
- state->client_hostname ? strlen(state->client_hostname) : 0, 0);
-
+
+ lease_add_extradata(lease, (unsigned char *)state->client_hostname,
+ state->client_hostname ? strlen(state->client_hostname) : 0, 0);
+
/* space-concat tag set */
if (!tagif && !context->netid.net)
lease_add_extradata(lease, NULL, 0, 0);
/* space-concat tag set */
if (!tagif && !context->netid.net)
lease_add_extradata(lease, NULL, 0, 0);
{
if (context->netid.net)
lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
{
if (context->netid.net)
lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
- lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
+ lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
if (state->link_address)
inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
if (state->link_address)
inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
{
void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
{
void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
}
}
lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
}
}
static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
{
void *opt;
char *desc = nest ? "nest" : "sent";
static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
{
void *opt;
char *desc = nest ? "nest" : "sent";
for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
{
int type = opt6_type(opt);
void *ia_options = NULL;
char *optname;
for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
{
int type = opt6_type(opt);
void *ia_options = NULL;
char *optname;
if (type == OPTION6_IA_NA)
{
sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
if (type == OPTION6_IA_NA)
{
sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
else if (type == OPTION6_IAADDR)
{
inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);
else if (type == OPTION6_IAADDR)
{
inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);
daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
optname = "iaaddr";
ia_options = opt6_ptr(opt, 24);
daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
optname = "iaaddr";
ia_options = opt6_ptr(opt, 24);
int offset = type == OPTION6_FQDN ? 1 : 0;
optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
}
int offset = type == OPTION6_FQDN ? 1 : 0;
optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
}
xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
if (ia_options)
log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
}
if (ia_options)
log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
}
static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string)
{
if (option_bool(OPT_LOG_OPTS) || !option_bool(OPT_QUIET_DHCP6))
static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string)
{
if (option_bool(OPT_LOG_OPTS) || !option_bool(OPT_QUIET_DHCP6))
if(option_bool(OPT_LOG_OPTS))
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
if(option_bool(OPT_LOG_OPTS))
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id)
{
/* ->local is same value for all relays on ->current chain */
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id)
{
/* ->local is same value for all relays on ->current chain */
header[1] = hopcount;
memcpy(&header[2], &relay->local.addr.addr6, IN6ADDRSZ);
memcpy(&header[18], peer_address, IN6ADDRSZ);
header[1] = hopcount;
memcpy(&header[2], &relay->local.addr.addr6, IN6ADDRSZ);
memcpy(&header[18], peer_address, IN6ADDRSZ);
to.sa.sa_family = AF_INET6;
to.in6.sin6_addr = relay->server.addr.addr6;
to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
to.sa.sa_family = AF_INET6;
to.in6.sin6_addr = relay->server.addr.addr6;
to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
}
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
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(0), &to, &from, 0);
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(0), &to, &from, 0);
if (option_bool(OPT_LOG_OPTS))
{
inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
if (option_bool(OPT_LOG_OPTS))
{
inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
/* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
/* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
for (relay = daemon->relay6; relay; relay = relay->next)
if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr.addr6) &&
(!relay->interface || wildcard_match(relay->interface, arrival_interface)))
break;
for (relay = daemon->relay6; relay; relay = relay->next)
if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr.addr6) &&
(!relay->interface || wildcard_match(relay->interface, arrival_interface)))
break;
{
int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
{
int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
peer->sin6_scope_id = relay->iface_index;
return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
}
peer->sin6_scope_id = relay->iface_index;
return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
}