Commit cc4baaab authored by Simon Kelley's avatar Simon Kelley

Fix DHCPv6 lease time calculation when client sends VL==0 or PL==0

parent 66409193
...@@ -54,13 +54,13 @@ static struct prefix_class *prefix_class_from_context(struct dhcp_context *conte ...@@ -54,13 +54,13 @@ static struct prefix_class *prefix_class_from_context(struct dhcp_context *conte
static void mark_context_used(struct state *state, struct dhcp_context *context, struct in6_addr *addr); static void mark_context_used(struct state *state, struct dhcp_context *context, 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 void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time, 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, int update_lease, time_t now); unsigned int *min_time, struct in6_addr *addr, int update_lease, 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 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 int add_local_addrs(struct dhcp_context *context);
static struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context, int do_refresh); static struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context, 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, unsigned int requested_time); unsigned int *preferred_timep, unsigned int lease_time);
#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))
...@@ -574,7 +574,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh ...@@ -574,7 +574,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
/* set unless we're sending a particular prefix-class, when we /* set unless we're sending a particular prefix-class, when we
want only dhcp-ranges with the correct tags set and not those without any tags. */ want only dhcp-ranges with the correct tags set and not those without any tags. */
int plain_range = 1; int plain_range = 1;
u32 lease_time, requested_time; u32 lease_time;
struct dhcp_lease *ltmp; struct dhcp_lease *ltmp;
struct in6_addr *req_addr; struct in6_addr *req_addr;
struct in6_addr addr; struct in6_addr addr;
...@@ -645,8 +645,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh ...@@ -645,8 +645,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) 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); req_addr = opt6_ptr(ia_option, 0);
requested_time = opt6_uint(ia_option, 16, 4);
if ((c = address6_valid(context, req_addr, solicit_tags, plain_range))) if ((c = address6_valid(context, req_addr, solicit_tags, plain_range)))
{ {
lease_time = c->lease_time; lease_time = c->lease_time;
...@@ -670,7 +669,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh ...@@ -670,7 +669,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA) if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c); state.send_prefix_class = prefix_class_from_context(c);
#endif #endif
add_address(&state, c, lease_time, requested_time, &min_time, req_addr, rapid_commit != NULL, now); add_address(&state, c, lease_time, ia_option, &min_time, req_addr, rapid_commit != NULL, now);
mark_context_used(&state, context, req_addr); mark_context_used(&state, context, req_addr);
get_context_tag(&state, c); get_context_tag(&state, c);
address_assigned = 1; address_assigned = 1;
...@@ -694,7 +693,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh ...@@ -694,7 +693,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA) if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c); state.send_prefix_class = prefix_class_from_context(c);
#endif #endif
add_address(&state, c, lease_time, lease_time, &min_time, &addr, rapid_commit != NULL, now); add_address(&state, c, lease_time, NULL, &min_time, &addr, rapid_commit != NULL, now);
mark_context_used(&state, context, &addr); mark_context_used(&state, context, &addr);
get_context_tag(&state, c); get_context_tag(&state, c);
address_assigned = 1; address_assigned = 1;
...@@ -711,7 +710,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh ...@@ -711,7 +710,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA) if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c); state.send_prefix_class = prefix_class_from_context(c);
#endif #endif
add_address(&state, c, c->lease_time, c->lease_time, &min_time, req_addr, rapid_commit != NULL, now); add_address(&state, c, c->lease_time, NULL, &min_time, req_addr, rapid_commit != NULL, now);
mark_context_used(&state, context, req_addr); mark_context_used(&state, context, req_addr);
get_context_tag(&state, c); get_context_tag(&state, c);
address_assigned = 1; address_assigned = 1;
...@@ -725,7 +724,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh ...@@ -725,7 +724,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA) if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c); state.send_prefix_class = prefix_class_from_context(c);
#endif #endif
add_address(&state, c, c->lease_time, c->lease_time, &min_time, &addr, rapid_commit != NULL, now); add_address(&state, c, c->lease_time, NULL, &min_time, &addr, rapid_commit != NULL, now);
mark_context_used(&state, context, &addr); mark_context_used(&state, context, &addr);
get_context_tag(&state, c); get_context_tag(&state, c);
address_assigned = 1; address_assigned = 1;
...@@ -788,7 +787,6 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh ...@@ -788,7 +787,6 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
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 = opt6_ptr(ia_option, 0); struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
u32 requested_time = opt6_uint(ia_option, 16, 4);
struct dhcp_context *dynamic, *c; struct dhcp_context *dynamic, *c;
unsigned int lease_time; unsigned int lease_time;
struct in6_addr addr; struct in6_addr addr;
...@@ -829,7 +827,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh ...@@ -829,7 +827,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA) if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c); state.send_prefix_class = prefix_class_from_context(c);
#endif #endif
add_address(&state, dynamic, lease_time, requested_time, &min_time, req_addr, 1, now); add_address(&state, dynamic, lease_time, ia_option, &min_time, req_addr, 1, now);
get_context_tag(&state, dynamic); get_context_tag(&state, dynamic);
address_assigned = 1; address_assigned = 1;
} }
...@@ -893,9 +891,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh ...@@ -893,9 +891,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
{ {
struct dhcp_lease *lease = NULL; struct dhcp_lease *lease = NULL;
struct in6_addr *req_addr = opt6_ptr(ia_option, 0); struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
u32 requested_time = opt6_uint(ia_option, 16, 4); unsigned int preferred_time = opt6_uint(ia_option, 16, 4);
unsigned int preferred_time = 0; /* in case renewal inappropriate */ unsigned int valid_time = opt6_uint(ia_option, 20, 4);
unsigned int valid_time = 0;
char *message = NULL; char *message = NULL;
struct dhcp_context *this_context; struct dhcp_context *this_context;
...@@ -915,6 +912,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh ...@@ -915,6 +912,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
put_opt6_short(DHCP6NOBINDING); put_opt6_short(DHCP6NOBINDING);
put_opt6_string(_("no binding found")); put_opt6_string(_("no binding found"));
end_opt6(o1); end_opt6(o1);
preferred_time = valid_time = 0;
break; break;
} }
...@@ -932,7 +931,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh ...@@ -932,7 +931,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
else else
lease_time = this_context->lease_time; lease_time = this_context->lease_time;
calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time, requested_time); calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time);
lease_set_expires(lease, valid_time, now); lease_set_expires(lease, valid_time, now);
if (state.ia_type == OPTION6_IA_NA && state.hostname) if (state.ia_type == OPTION6_IA_NA && state.hostname)
...@@ -949,8 +948,11 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh ...@@ -949,8 +948,11 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
message = _("deprecated"); message = _("deprecated");
} }
else else
message = _("address invalid"); {
preferred_time = valid_time = 0;
message = _("address invalid");
}
log6_packet(&state, "DHCPREPLY", req_addr, message); log6_packet(&state, "DHCPREPLY", req_addr, message);
o1 = new_opt6(OPTION6_IAADDR); o1 = new_opt6(OPTION6_IAADDR);
...@@ -1500,14 +1502,21 @@ static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz) ...@@ -1500,14 +1502,21 @@ static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
} }
} }
static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time, 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, int do_update, time_t now) unsigned int *min_time, struct in6_addr *addr, int do_update, time_t now)
{ {
unsigned int valid_time, preferred_time; unsigned int valid_time = 0, preferred_time = 0;
int o = new_opt6(OPTION6_IAADDR); int o = new_opt6(OPTION6_IAADDR);
struct dhcp_lease *lease; struct dhcp_lease *lease;
calculate_times(context, min_time, &valid_time, &preferred_time, lease_time, requested_time); /* get client requested times */
if (ia_option)
{
preferred_time = opt6_uint(ia_option, 16, 4);
valid_time = opt6_uint(ia_option, 20, 4);
}
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);
...@@ -1591,22 +1600,60 @@ static int check_address(struct state *state, struct in6_addr *addr) ...@@ -1591,22 +1600,60 @@ static int check_address(struct state *state, struct in6_addr *addr)
return 1; return 1;
} }
/* Calculate valid and preferred times to send in leases/renewals.
Inputs are:
*valid_timep, *preferred_timep - requested times from IAADDR options.
context->valid, context->preferred - times associated with subnet address on local interface.
context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range.
lease_time - configured time for context for individual client.
*min_time - smallest valid time sent so far.
Outputs are :
*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 requested_time) unsigned int *preferred_timep, unsigned int lease_time)
{ {
unsigned int preferred_time, valid_time; unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
unsigned int valid_time = lease_time, preferred_time = lease_time;
if (requested_time < 120u )
requested_time = 120u; /* sanity */ /* RFC 3315: "A server ignores the lifetimes set
if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time)) by the client if the preferred lifetime is greater than the valid
lease_time = requested_time; lifetime. */
if (req_preferred <= req_valid)
valid_time = (context->valid < lease_time) ? context->valid : lease_time; {
preferred_time = (context->preferred < lease_time) ? context->preferred : lease_time; if (req_preferred != 0)
{
/* 0 == "no preference from client" */
if (req_preferred < 120u)
req_preferred = 120u; /* sanity */
if (req_preferred < preferred_time)
preferred_time = req_preferred;
}
if (req_valid != 0)
/* 0 == "no preference from client" */
{
if (req_valid < 120u)
req_valid = 120u; /* sanity */
if (req_valid < valid_time)
valid_time = req_valid;
}
}
if (context->flags & CONTEXT_DEPRECATE) /* deprecate (preferred == 0) which configured, or when local address
is deprecated */
if ((context->flags & CONTEXT_DEPRECATE) || context->preferred == 0)
preferred_time = 0; preferred_time = 0;
if (preferred_time != 0 && preferred_time < *min_time) if (preferred_time != 0 && preferred_time < *min_time)
*min_time = preferred_time; *min_time = preferred_time;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment