Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

config: clamp configurable values to within sensible ranges #225

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 114 additions & 63 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <libubox/vlist.h>

#include "odhcpd.h"
#include "router.h"

static struct blob_buf b;
static int reload_pipe[2] = { -1, -1 };
Expand Down Expand Up @@ -255,8 +256,12 @@ static void set_interface_defaults(struct interface *iface)
iface->ra_flags = ND_RA_FLAG_OTHER;
iface->ra_slaac = true;
iface->ra_maxinterval = 600;
/*
* RFC4861: MinRtrAdvInterval: Default: 0.33 * MaxRtrAdvInterval If
* MaxRtrAdvInterval >= 9 seconds; otherwise, the Default is MaxRtrAdvInterval.
*/
iface->ra_mininterval = iface->ra_maxinterval/3;
iface->ra_lifetime = -1;
iface->ra_lifetime = 3 * iface->ra_maxinterval; /* RFC4861: AdvDefaultLifetime: Default: 3 * MaxRtrAdvInterval */
iface->ra_dns = true;
}

Expand Down Expand Up @@ -386,23 +391,19 @@ static void set_config(struct uci_section *s)
}
}

static double parse_leasetime(struct blob_attr *c) {
static uint32_t parse_leasetime(struct blob_attr *c) {
char *val = blobmsg_get_string(c), *endptr = NULL;
double time = strcmp(val, "infinite") ? strtod(val, &endptr) : UINT32_MAX;
uint32_t time = strcmp(val, "infinite") ? (uint32_t)strtod(val, &endptr) : UINT32_MAX;

if (time && endptr && endptr[0]) {
if (endptr[0] == 's')
time *= 1;
else if (endptr[0] == 'm')
time *= 60;
else if (endptr[0] == 'h')
time *= 3600;
else if (endptr[0] == 'd')
time *= 24 * 3600;
else if (endptr[0] == 'w')
time *= 7 * 24 * 3600;
else
goto err;
switch(endptr[0]) {
case 's': break; /* seconds */
case 'm': time *= 60; break; /* minutes */
case 'h': time *= 3600; break; /* hours */
case 'd': time *= 24 * 3600; break; /* days */
case 'w': time *= 7 * 24 * 3600; break; /* weeks */
default: goto err;
}
}

if (time < 60)
Expand All @@ -411,7 +412,7 @@ static double parse_leasetime(struct blob_attr *c) {
return time;

err:
return -1;
return 0;
}

static void free_lease(struct lease *l)
Expand Down Expand Up @@ -474,8 +475,8 @@ int set_lease_from_blobmsg(struct blob_attr *ba)
}

if ((c = tb[LEASE_ATTR_LEASETIME])) {
double time = parse_leasetime(c);
if (time < 0)
uint32_t time = parse_leasetime(c);
if (time == 0)
goto err;

l->leasetime = time;
Expand Down Expand Up @@ -953,9 +954,9 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
iface->no_dynamic_dhcp = !blobmsg_get_bool(c);

if ((c = tb[IFACE_ATTR_LEASETIME])) {
double time = parse_leasetime(c);
uint32_t time = parse_leasetime(c);

if (time >= 0)
if (time > 0)
iface->dhcp_leasetime = time;
else
syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
Expand All @@ -964,9 +965,9 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
}

if ((c = tb[IFACE_ATTR_PREFERRED_LIFETIME])) {
double time = parse_leasetime(c);
uint32_t time = parse_leasetime(c);

if (time >= 0)
if (time > 0)
iface->preferred_lifetime = time;
else
syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
Expand Down Expand Up @@ -1184,25 +1185,32 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr

if ((c = tb[IFACE_ATTR_DHCPV6_PD_MIN_LEN])) {
uint32_t pd_min_len = blobmsg_get_u32(c);
if (pd_min_len != 0 && pd_min_len <= PD_MIN_LEN_MAX)
iface->dhcpv6_pd_min_len = pd_min_len;
else
syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
iface_attrs[IFACE_ATTR_DHCPV6_PD_MIN_LEN].name, iface->name);
if (pd_min_len > PD_MIN_LEN_MAX)
iface->dhcpv6_pd_min_len = PD_MIN_LEN_MAX;
iface->dhcpv6_pd_min_len = pd_min_len;
if (pd_min_len >= PD_MIN_LEN_MAX)
syslog(LOG_ERR, "Clamped invalid %s value configured for interface '%s' to %d",
iface_attrs[IFACE_ATTR_DHCPV6_PD_MIN_LEN].name, iface->name, iface->dhcpv6_pd_min_len);
}

if ((c = tb[IFACE_ATTR_DHCPV6_NA]))
iface->dhcpv6_na = blobmsg_get_bool(c);

if ((c = tb[IFACE_ATTR_DHCPV6_HOSTID_LEN])) {
uint32_t hostid_len = blobmsg_get_u32(c);
uint32_t original_hostid_len, hostid_len;
original_hostid_len = hostid_len = blobmsg_get_u32(c);

if (hostid_len >= HOSTID_LEN_MIN && hostid_len <= HOSTID_LEN_MAX)
iface->dhcpv6_hostid_len = hostid_len;
else
syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
iface_attrs[IFACE_ATTR_DHCPV6_HOSTID_LEN].name, iface->name);
if (hostid_len < HOSTID_LEN_MIN)
hostid_len = HOSTID_LEN_MIN;
else if (hostid_len > HOSTID_LEN_MAX)
hostid_len = HOSTID_LEN_MAX;

iface->dhcpv6_hostid_len = hostid_len;

if (original_hostid_len != hostid_len) {
syslog(LOG_ERR, "Clamped invalid %s value configured for interface '%s' to %d",
iface_attrs[IFACE_ATTR_DHCPV6_HOSTID_LEN].name, iface->name, iface->dhcpv6_hostid_len);
}
}

if ((c = tb[IFACE_ATTR_RA_DEFAULT]))
Expand Down Expand Up @@ -1240,41 +1248,48 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
if ((c = tb[IFACE_ATTR_RA_REACHABLETIME])) {
uint32_t ra_reachabletime = blobmsg_get_u32(c);

if (ra_reachabletime <= 3600000)
iface->ra_reachabletime = ra_reachabletime;
else
syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
iface_attrs[IFACE_ATTR_RA_REACHABLETIME].name, iface->name);
/* rfc4861#section-6.2.1 : AdvReachableTime :
* MUST be no greater than 3,600,000 msec
*/
iface->ra_reachabletime = ra_reachabletime <= 3600000 ? ra_reachabletime : 3600000;
if(ra_reachabletime > 3600000)
syslog(LOG_ERR, "Clamped invalid %s value configured for interface '%s' to %d",
iface_attrs[IFACE_ATTR_RA_REACHABLETIME].name, iface->name, iface->ra_reachabletime);
}

if ((c = tb[IFACE_ATTR_RA_RETRANSTIME])) {
uint32_t ra_retranstime = blobmsg_get_u32(c);

if (ra_retranstime <= 60000)
iface->ra_retranstime = ra_retranstime;
else
syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
iface_attrs[IFACE_ATTR_RA_RETRANSTIME].name, iface->name);
iface->ra_retranstime = ra_retranstime <= 60000 ? ra_retranstime : 60000;
if (ra_retranstime > 60000)
syslog(LOG_ERR, "Clamped invalid %s value configured for interface '%s' to %d",
iface_attrs[IFACE_ATTR_RA_RETRANSTIME].name, iface->name, iface->ra_retranstime);
}

if ((c = tb[IFACE_ATTR_RA_HOPLIMIT])) {
uint32_t ra_hoplimit = blobmsg_get_u32(c);

if (ra_hoplimit <= 255)
iface->ra_hoplimit = ra_hoplimit;
else
syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
iface_attrs[IFACE_ATTR_RA_HOPLIMIT].name, iface->name);
/* rfc4861#section-6.2.1 : AdvCurHopLimit */
iface->ra_hoplimit = ra_hoplimit <= 255 ? ra_hoplimit : 255;
if(ra_hoplimit > 255)
syslog(LOG_ERR, "Clamped invalid %s value configured for interface '%s' to %d",
iface_attrs[IFACE_ATTR_RA_HOPLIMIT].name, iface->name, iface->ra_hoplimit);

}

if ((c = tb[IFACE_ATTR_RA_MTU])) {
uint32_t ra_mtu = blobmsg_get_u32(c);

if (ra_mtu >= 1280 || ra_mtu <= 65535)
iface->ra_mtu = ra_mtu;
else
syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
iface_attrs[IFACE_ATTR_RA_MTU].name, iface->name);
uint32_t original_ra_mtu, ra_mtu;
original_ra_mtu = ra_mtu = blobmsg_get_u32(c);
if (ra_mtu < 1280)
ra_mtu = 1280;
else if (ra_mtu > 65535)
ra_mtu = 65535;
iface->ra_mtu = ra_mtu;

if (original_ra_mtu != ra_mtu) {
syslog(LOG_ERR, "Clamped invalid %s value configured for interface '%s' to %d",
iface_attrs[IFACE_ATTR_RA_MTU].name, iface->name, iface->ra_mtu);
}
}

if ((c = tb[IFACE_ATTR_RA_SLAAC]))
Expand All @@ -1286,14 +1301,50 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
if ((c = tb[IFACE_ATTR_RA_ADVROUTER]))
iface->ra_advrouter = blobmsg_get_bool(c);

if ((c = tb[IFACE_ATTR_RA_MININTERVAL]))
iface->ra_mininterval = blobmsg_get_u32(c);

if ((c = tb[IFACE_ATTR_RA_MAXINTERVAL]))
iface->ra_maxinterval = blobmsg_get_u32(c);

if ((c = tb[IFACE_ATTR_RA_LIFETIME]))
iface->ra_lifetime = blobmsg_get_u32(c);
/*
* RFC4861: MaxRtrAdvInterval: MUST be no less than 4 seconds and no greater than 1800 seconds.
* RFC8319: MaxRtrAdvInterval: MUST be no less than 4 seconds and no greater than 65535 seconds.
* Default: 600 seconds
*/
if ((c = tb[IFACE_ATTR_RA_MAXINTERVAL])){
uint32_t ra_maxinterval = blobmsg_get_u32(c);
if (ra_maxinterval < 4)
ra_maxinterval = 4;
else if (ra_maxinterval > MaxRtrAdvInterval_CEILING)
ra_maxinterval = MaxRtrAdvInterval_CEILING;
iface->ra_maxinterval = ra_maxinterval;
}

/*
* RFC4861: MinRtrAdvInterval: MUST be no less than 3 seconds and no greater than .75 * MaxRtrAdvInterval.
* Default: 0.33 * MaxRtrAdvInterval If MaxRtrAdvInterval >= 9 seconds; otherwise, the
* Default is MaxRtrAdvInterval.
*/
if ((c = tb[IFACE_ATTR_RA_MININTERVAL])){
uint32_t ra_mininterval = blobmsg_get_u32(c);
if (ra_mininterval < MinRtrAdvInterval_FLOOR)
ra_mininterval = MinRtrAdvInterval_FLOOR; // clamp min
else if (ra_mininterval > (0.75 * iface->ra_maxinterval))
ra_mininterval = 0.75 * iface->ra_maxinterval; // clamp max
iface->ra_mininterval = ra_mininterval;
}

/*
* RFC4861: AdvDefaultLifetime: MUST be either zero or between MaxRtrAdvInterval and 9000 seconds.
* RFC8319: AdvDefaultLifetime: MUST be either zero or between MaxRtrAdvInterval and 65535 seconds.
* Default: 3 * MaxRtrAdvInterval
* i.e. 3 * 65535 => 65535 seconds.
*/
if ((c = tb[IFACE_ATTR_RA_LIFETIME])){
uint32_t ra_lifetime = blobmsg_get_u32(c);
if (ra_lifetime != 0){
if (ra_lifetime < iface->ra_maxinterval)
ra_lifetime = iface->ra_maxinterval; // clamp min
else if (ra_lifetime > AdvDefaultLifetime_CEILING)
ra_lifetime = AdvDefaultLifetime_CEILING; // clamp max
}
iface->ra_lifetime = ra_lifetime;
}

if ((c = tb[IFACE_ATTR_RA_USELEASETIME]))
iface->ra_useleasetime = blobmsg_get_bool(c);
Expand Down
6 changes: 3 additions & 3 deletions src/odhcpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,9 @@ struct interface {
struct in6_addr pio_filter_addr;
int default_router;
int route_preference;
int ra_maxinterval;
int ra_mininterval;
int ra_lifetime;
uint32_t ra_maxinterval;
uint32_t ra_mininterval;
uint32_t ra_lifetime;
uint32_t ra_reachabletime;
uint32_t ra_retranstime;
uint32_t ra_hoplimit;
Expand Down
25 changes: 6 additions & 19 deletions src/router.c
Original file line number Diff line number Diff line change
Expand Up @@ -350,16 +350,6 @@ static int calc_adv_interval(struct interface *iface, uint32_t lowest_found_life
if (*maxival > lowest_found_lifetime/3)
*maxival = lowest_found_lifetime/3;

if (*maxival > MaxRtrAdvInterval)
*maxival = MaxRtrAdvInterval;
else if (*maxival < 4)
*maxival = 4;

if (minival < MinRtrAdvInterval)
minival = MinRtrAdvInterval;
else if (minival > (*maxival * 3)/4)
minival = (*maxival >= 9 ? *maxival/3 : *maxival);

odhcpd_urandom(&msecs, sizeof(msecs));
msecs = (labs(msecs) % ((*maxival != minival) ? (*maxival - minival)*1000 : 500)) +
minival*1000;
Expand All @@ -376,15 +366,12 @@ static int calc_adv_interval(struct interface *iface, uint32_t lowest_found_life

static uint32_t calc_ra_lifetime(struct interface *iface, uint32_t maxival)
{
uint32_t lifetime = 3*maxival;

if (iface->ra_lifetime >= 0) {
lifetime = iface->ra_lifetime;
if (lifetime > 0 && lifetime < maxival)
lifetime = maxival;
else if (lifetime > 9000)
lifetime = 9000;
}
uint32_t lifetime = iface->ra_lifetime;

if (lifetime > 0 && lifetime < maxival)
lifetime = maxival;
else if (lifetime > RouterLifetime_MAX)
lifetime = RouterLifetime_MAX;

return lifetime;
}
Expand Down
26 changes: 24 additions & 2 deletions src/router.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,30 @@ struct icmpv6_opt {

#define MaxInitialRtrAdvInterval 16
#define MaxInitialRtAdvs 3
#define MaxRtrAdvInterval 1800
#define MinRtrAdvInterval 3
/* #define MaxRtrAdvInterval 1800 */
/* RFC8319 §4
This document updates §4.2 and 6.2.1 of [RFC4861] to change
the following router configuration variables.

In §6.2.1, inside the paragraph that defines
MaxRtrAdvInterval, change 1800 to 65535 seconds.

In §6.2.1, inside the paragraph that defines
AdvDefaultLifetime, change 9000 to 65535 seconds.
*/
#define MaxRtrAdvInterval_CEILING 65535
#define MinRtrAdvInterval_FLOOR 3
#define AdvDefaultLifetime_CEILING 65535
/* RFC8319 §4
This document updates §4.2 and 6.2.1 of [RFC4861] to change
the following router configuration variables.

In §4.2, inside the paragraph that defines Router Lifetime,
change 9000 to 65535 seconds.

Note: this is 16 bit Router Lifetime field in RA packets
*/
#define RouterLifetime_MAX 65535

#define ND_RA_FLAG_PROXY 0x4
#define ND_RA_PREF_HIGH (1 << 3)
Expand Down