diff options
Diffstat (limited to 'src/router.c')
-rw-r--r-- | src/router.c | 119 |
1 files changed, 73 insertions, 46 deletions
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] = { |