diff options
-rw-r--r-- | README | 6 | ||||
-rw-r--r-- | src/config.c | 13 | ||||
-rw-r--r-- | src/odhcpd.h | 3 | ||||
-rw-r--r-- | src/router.c | 119 | ||||
-rw-r--r-- | src/router.h | 2 |
5 files changed, 96 insertions, 47 deletions
@@ -105,6 +105,12 @@ ra_management integer 1 RA management mode ra_offlink bool 0 Announce prefixes off-link ra_preference string medium Route(r) preference [medium|high|low] +ra_maxinterval integer 600 Maximum time allowed between + sending unsolicited RA +ra_mininterval integer 200 Minimum time allowed between + sending unsolicited RA +ra_lifetime integer 1800 Value to be placed in Router + Lifetime field of RA ndproxy_routing bool 1 Learn routes from NDP ndproxy_slave bool 0 NDProxy external slave diff --git a/src/config.c b/src/config.c index 69a3ad1..b621c75 100644 --- a/src/config.c +++ b/src/config.c @@ -45,7 +45,9 @@ enum { IFACE_ATTR_RA_OFFLINK, IFACE_ATTR_RA_PREFERENCE, IFACE_ATTR_RA_ADVROUTER, + IFACE_ATTR_RA_MININTERVAL, IFACE_ATTR_RA_MAXINTERVAL, + IFACE_ATTR_RA_LIFETIME, IFACE_ATTR_PD_MANAGER, IFACE_ATTR_PD_CER, IFACE_ATTR_NDPROXY_ROUTING, @@ -80,7 +82,9 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { [IFACE_ATTR_RA_OFFLINK] = { .name = "ra_offlink", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_RA_PREFERENCE] = { .name = "ra_preference", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_RA_ADVROUTER] = { .name = "ra_advrouter", .type = BLOBMSG_TYPE_BOOL }, + [IFACE_ATTR_RA_MININTERVAL] = { .name = "ra_mininterval", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_RA_MAXINTERVAL] = { .name = "ra_maxinterval", .type = BLOBMSG_TYPE_INT32 }, + [IFACE_ATTR_RA_LIFETIME] = { .name = "ra_lifetime", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_NDPROXY_ROUTING] = { .name = "ndproxy_routing", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL }, }; @@ -188,6 +192,9 @@ static void set_interface_defaults(struct interface *iface) { iface->managed = 1; iface->learn_routes = 1; + iface->ra_maxinterval = 600; + iface->ra_mininterval = iface->ra_maxinterval/3; + iface->ra_lifetime = -1; } static void clean_interface(struct interface *iface) @@ -584,9 +591,15 @@ 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); + if ((c = tb[IFACE_ATTR_RA_PREFERENCE])) { const char *prio = blobmsg_get_string(c); diff --git a/src/odhcpd.h b/src/odhcpd.h index 8db3e7d..a88eb08 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -152,11 +152,14 @@ struct interface { bool ra_advrouter; bool no_dynamic_dhcp; + // RA int learn_routes; int default_router; int managed; int route_preference; int ra_maxinterval; + int ra_mininterval; + int ra_lifetime; // DHCPv4 struct in_addr dhcpv4_start; diff --git a/src/router.c b/src/router.c index 36267be..4ab06b6 100644 --- a/src/router.c +++ b/src/router.c @@ -211,6 +211,48 @@ static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len) return found_default; } +static int calc_adv_interval(struct interface *iface, uint32_t minvalid, + uint32_t *maxival) +{ + uint32_t minival = iface->ra_mininterval; + int msecs; + + *maxival = iface->ra_maxinterval; + + if (*maxival > minvalid/3) + *maxival = minvalid/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)*1000)) + minival*1000; + + return msecs; +} + +static uint16_t calc_ra_lifetime(struct interface *iface, uint32_t maxival) +{ + uint16_t lifetime = 3*maxival; + + if (iface->ra_lifetime >= 0) { + lifetime = iface->ra_lifetime; + if (lifetime < maxival) + lifetime = maxival; + else if (lifetime > 9000) + lifetime = 9000; + } + + return lifetime; +} + // Router Advert server mode static uint64_t send_router_advert(struct interface *iface, const struct in6_addr *from) { @@ -250,7 +292,9 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add // If not currently shutting down struct odhcpd_ipaddr addrs[RELAYD_MAX_ADDRS]; ssize_t ipcnt = 0; - int64_t minvalid = INT64_MAX; + uint32_t minvalid = UINT32_MAX; + bool default_route = false; + bool valid_prefix = false; // If not shutdown if (iface->timer_rs.cb) { @@ -258,13 +302,13 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add memcpy(addrs, iface->ia_addr, ipcnt * sizeof(*addrs)); // Check default route - if (iface->default_router > 1) - adv.h.nd_ra_router_lifetime = htons(iface->default_router); - else if (parse_routes(addrs, ipcnt)) - adv.h.nd_ra_router_lifetime = htons(1); + if (iface->default_router) { + default_route = true; - syslog(LOG_INFO, "Initial RA router lifetime %d, %d address(es) available on %s", - ntohs(adv.h.nd_ra_router_lifetime), (int)ipcnt, iface->ifname); + if (iface->default_router > 1) + valid_prefix = true; + } else if (parse_routes(addrs, ipcnt)) + default_route = true; } // Construct Prefix Information options @@ -303,19 +347,11 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add } if (addr->preferred > (uint32_t)now && - minvalid > 1000LL * TIME_LEFT(addr->valid, now)) - minvalid = 1000LL * TIME_LEFT(addr->valid, now); - - uint32_t this_lifetime = TIME_LEFT(addr->valid, now); - if (this_lifetime > UINT16_MAX) - this_lifetime = UINT16_MAX; - if ((!IN6_IS_ADDR_ULA(&addr->addr) || iface->default_router) - && adv.h.nd_ra_router_lifetime - && ntohs(adv.h.nd_ra_router_lifetime) < this_lifetime) { - adv.h.nd_ra_router_lifetime = htons(this_lifetime); - - syslog(LOG_INFO, "Updating RA router lifetime to %d on %s", this_lifetime, iface->ifname); - } + minvalid > TIME_LEFT(addr->valid, now)) + minvalid = TIME_LEFT(addr->valid, now); + + if (!IN6_IS_ADDR_ULA(&addr->addr) || iface->default_router) + valid_prefix = true; odhcpd_bmemcpy(&p->nd_opt_pi_prefix, &addr->addr, (iface->ra_advrouter) ? 128 : addr->prefix); @@ -336,11 +372,22 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add p->nd_opt_pi_valid_time = 0; } - if (!iface->default_router && adv.h.nd_ra_router_lifetime == htons(1)) { - syslog(LOG_WARNING, "A default route is present but there is no public prefix " - "on %s thus we don't announce a default route!", iface->ifname); + // Calculate periodic transmit + uint32_t maxival; + int msecs = calc_adv_interval(iface, minvalid, &maxival); + + if (default_route) { + if (!valid_prefix) { + syslog(LOG_WARNING, "A default route is present but there is no public prefix " + "on %s thus we don't announce a default route!", iface->ifname); + adv.h.nd_ra_router_lifetime = 0; + } else + adv.h.nd_ra_router_lifetime = htons(calc_ra_lifetime(iface, maxival)); + + } else adv.h.nd_ra_router_lifetime = 0; - } + + syslog(LOG_INFO, "Using a RA lifetime of %d seconds on %s", ntohs(adv.h.nd_ra_router_lifetime), iface->ifname); // DNS Recursive DNS if (iface->dns_cnt > 0) { @@ -433,33 +480,13 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add ++routes_cnt; } - // Calculate periodic transmit - int msecs = 0; - uint32_t maxival = iface->ra_maxinterval * 1000; - uint32_t minival; - - if (maxival < 4000 || maxival > MaxRtrAdvInterval * 1000) - maxival = MaxRtrAdvInterval * 1000; - - if (maxival > minvalid / 3) { - maxival = minvalid / 3; - - if (maxival < 4000) - maxival = 4000; - } - - minival = (maxival * 3) / 4; - - search->lifetime = htonl(maxival / 100); + search->lifetime = htonl(maxival*10); dns.lifetime = search->lifetime; - odhcpd_urandom(&msecs, sizeof(msecs)); - msecs = (labs(msecs) % (maxival - minival)) + minival; - struct icmpv6_opt adv_interval = { .type = ND_OPT_RTR_ADV_INTERVAL, .len = 1, - .data = {0, 0, maxival >> 24, maxival >> 16, maxival >> 8, maxival} + .data = {0, 0, (maxival*1000) >> 24, (maxival*1000) >> 16, (maxival*1000) >> 8, maxival*1000} }; struct iovec iov[RA_IOV_LEN] = { diff --git a/src/router.h b/src/router.h index 546af3e..bdfe52c 100644 --- a/src/router.h +++ b/src/router.h @@ -30,8 +30,8 @@ struct icmpv6_opt { (void*)(opt + opt->len) <= (void*)(end); opt += opt->len) -#define MaxValidTime 65535 #define MaxRtrAdvInterval 1800 +#define MinRtrAdvInterval 3 #define ND_RA_FLAG_PROXY 0x4 #define ND_RA_PREF_HIGH (1 << 3) |