diff options
-rw-r--r-- | README | 3 | ||||
-rw-r--r-- | src/config.c | 14 | ||||
-rw-r--r-- | src/dhcpv6-ia.c | 25 | ||||
-rw-r--r-- | src/odhcpd.h | 1 |
4 files changed, 43 insertions, 0 deletions
@@ -101,6 +101,9 @@ dhcpv6_na bool 1 DHCPv6 stateful addressing hands out IA_NA - Internet Address - Network Address dhcpv6_pd bool 1 DHCPv6 stateful addressing hands out IA_PD - Internet Address - Prefix Delegation +dhcpv6_pd_min_len integer - Minimum prefix length to delegate with IA_PD + (value is adjusted if needed to be greater + than the interface prefix length). Range [1,62] router list <local address> Routers to announce accepts IPv4 only dns list <local address> DNS servers to announce diff --git a/src/config.c b/src/config.c index d7cd5dd..e631814 100644 --- a/src/config.c +++ b/src/config.c @@ -39,6 +39,8 @@ struct config config = {.legacy = false, .main_dhcpv4 = false, #define HOSTID_LEN_MAX 64 #define HOSTID_LEN_DEFAULT HOSTID_LEN_MIN +#define PD_MIN_LEN_MAX (64-2) // must delegate at least 2 bits of prefix + #define OAF_DHCPV6 (OAF_DHCPV6_NA | OAF_DHCPV6_PD) enum { @@ -64,6 +66,7 @@ enum { IFACE_ATTR_DHCPV6_RAW, IFACE_ATTR_DHCPV6_ASSIGNALL, IFACE_ATTR_DHCPV6_PD, + IFACE_ATTR_DHCPV6_PD_MIN_LEN, IFACE_ATTR_DHCPV6_NA, IFACE_ATTR_DHCPV6_HOSTID_LEN, IFACE_ATTR_RA_DEFAULT, @@ -116,6 +119,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { [IFACE_ATTR_DHCPV6_RAW] = { .name = "dhcpv6_raw", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_DHCPV6_ASSIGNALL] = { .name ="dhcpv6_assignall", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_DHCPV6_PD] = { .name = "dhcpv6_pd", .type = BLOBMSG_TYPE_BOOL }, + [IFACE_ATTR_DHCPV6_PD_MIN_LEN] = { .name = "dhcpv6_pd_min_len", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_DHCPV6_NA] = { .name = "dhcpv6_na", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_DHCPV6_HOSTID_LEN] = { .name = "dhcpv6_hostidlength", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_PD_MANAGER] = { .name = "pd_manager", .type = BLOBMSG_TYPE_STRING }, @@ -214,6 +218,7 @@ static void set_interface_defaults(struct interface *iface) iface->dhcpv4_end.s_addr = htonl(START_DEFAULT + LIMIT_DEFAULT - 1); iface->dhcpv6_assignall = true; iface->dhcpv6_pd = true; + iface->dhcpv6_pd_min_len = 0; iface->dhcpv6_na = true; iface->dhcpv6_hostid_len = HOSTID_LEN_DEFAULT; iface->dns_service = true; @@ -851,6 +856,15 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr if ((c = tb[IFACE_ATTR_DHCPV6_PD])) iface->dhcpv6_pd = blobmsg_get_bool(c); + 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 ((c = tb[IFACE_ATTR_DHCPV6_NA])) iface->dhcpv6_na = blobmsg_get_bool(c); diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index 99fd2fd..41c9f30 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -1332,6 +1332,31 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac if (reqlen > 64) reqlen = 64; + + /* + * A requesting router can include a desired prefix length for its + * delegation. The delegating router (us) is not required to honor + * the hint (RFC3633, section 11.2, we MAY choose to use the + * information in the option; RFC8168, section 3.2 has several SHOULDs + * about desired choices for selecting a prefix to delegate). + * + * We support a policy setting to conserve prefix space, which purposely + * assigns prefixes that might not match the requesting router's hint. + * + * If the minimum prefix length is set in this interface's + * configuration, we use it as a floor for the requested (hinted) + * prefix length. This allows us to conserve prefix space so that + * any single router can't grab too much of it. Consider if we have + * an interface with a /56 prefix. A requesting router could ask for + * a /58 and take 1/4 of our total address space. But if we set a + * minimum of /60, we can limit each requesting router to get only + * 1/16 of our total address space. + */ + if (iface->dhcpv6_pd_min_len && reqlen < iface->dhcpv6_pd_min_len) { + syslog(LOG_INFO, "clamping requested PD from %d to %d", + reqlen, iface->dhcpv6_pd_min_len); + reqlen = iface->dhcpv6_pd_min_len; + } } else if (is_na) { uint8_t *sdata; uint16_t stype, slen; diff --git a/src/odhcpd.h b/src/odhcpd.h index 8ab51dc..08b4920 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -350,6 +350,7 @@ struct interface { bool dhcpv6_pd; bool dhcpv6_na; uint32_t dhcpv6_hostid_len; + uint32_t dhcpv6_pd_min_len; // minimum delegated prefix length char *upstream; size_t upstream_len; |