From f44eebd1bab9327c5dd3a281196bd07192134d3b Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Sat, 22 Jul 2023 23:38:47 +0530 Subject: [PATCH 1/2] network: ndisc - Also fill router preference --- src/network/networkd-ndisc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 7570d37662..61776d3c26 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -448,10 +448,10 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) { _cleanup_(route_freep) Route *route = NULL; + unsigned prefixlen, preference; usec_t timestamp_usec; uint32_t lifetime_sec; struct in6_addr prefix; - unsigned prefixlen; int r; assert(link); @@ -477,6 +477,11 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) { if (r < 0) return log_link_warning_errno(link, r, "Failed to get prefix length: %m"); + /* Prefix Information option does not have preference, hence we use the 'main' preference here */ + r = sd_ndisc_router_get_preference(rt, &preference); + if (r < 0) + log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m"); + r = route_new(&route); if (r < 0) return log_oom(); @@ -484,6 +489,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) { route->family = AF_INET6; route->dst.in6 = prefix; route->dst_prefixlen = prefixlen; + route->pref = preference; route->lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec); r = ndisc_request_route(TAKE_PTR(route), link, rt); From 4ccd48cb2693a3603f14a30b6286228597285d92 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Wed, 26 Jul 2023 15:14:13 +0530 Subject: [PATCH 2/2] network: ndisc - drop routes of lifetime 0 A Lifetime of 0 indicates that the router is not a default router anymore and associated default route should be discarded from host's routing table. https://datatracker.ietf.org/doc/html/rfc4861 ``` Router Lifetime 16-bit unsigned integer. The lifetime associated with the default router in units of seconds. The field can contain values up to 65535 and receivers should handle any value, while the sending rules in Section 6 limit the lifetime to 9000 seconds. A Lifetime of 0 indicates that the router is not a default router and SHOULD NOT appear on the default router list. The Router Lifetime applies only to the router's usefulness as a default router; it does not apply to information contained in other message fields or options. Options that need time limits for their information include their own lifetime fields. ``` --- src/network/networkd-ndisc.c | 40 ++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 61776d3c26..c6ca7f95e2 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -978,7 +978,7 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) { } } -static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) { +static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec, const struct in6_addr *router) { bool updated = false; NDiscDNSSL *dnssl; NDiscRDNSS *rdnss; @@ -1002,6 +1002,9 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) { if (route->lifetime_usec >= timestamp_usec) continue; /* the route is still valid */ + if (router && !in6_addr_equal(&route->provider.in6, router)) + continue; + k = route_remove_and_drop(route); if (k < 0) r = log_link_warning_errno(link, k, "Failed to remove outdated SLAAC route, ignoring: %m"); @@ -1014,6 +1017,9 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) { if (address->lifetime_valid_usec >= timestamp_usec) continue; /* the address is still valid */ + if (router && !in6_addr_equal(&address->provider.in6, router)) + continue; + k = address_remove_and_drop(address); if (k < 0) r = log_link_warning_errno(link, k, "Failed to remove outdated SLAAC address, ignoring: %m"); @@ -1023,6 +1029,9 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) { if (rdnss->lifetime_usec >= timestamp_usec) continue; /* the DNS server is still valid */ + if (router && !in6_addr_equal(&rdnss->router, router)) + continue; + free(set_remove(link->ndisc_rdnss, rdnss)); updated = true; } @@ -1031,6 +1040,9 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) { if (dnssl->lifetime_usec >= timestamp_usec) continue; /* the DNS domain is still valid */ + if (router && !in6_addr_equal(&dnssl->router, router)) + continue; + free(set_remove(link->ndisc_dnssl, dnssl)); updated = true; } @@ -1039,6 +1051,9 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) { if (cp->lifetime_usec >= timestamp_usec) continue; /* the captive portal is still valid */ + if (router && !in6_addr_equal(&cp->router, router)) + continue; + ndisc_captive_portal_free(set_remove(link->ndisc_captive_portals, cp)); updated = true; } @@ -1059,7 +1074,7 @@ static int ndisc_expire_handler(sd_event_source *s, uint64_t usec, void *userdat assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0); - (void) ndisc_drop_outdated(link, now_usec); + (void) ndisc_drop_outdated(link, now_usec, NULL); (void) ndisc_setup_expire(link); return 0; } @@ -1160,6 +1175,7 @@ static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) { } static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) { + uint16_t router_lifetime_sec; struct in6_addr router; usec_t timestamp_usec; int r; @@ -1192,12 +1208,28 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) { log_link_debug(link, "Received RA without timestamp, ignoring."); return 0; } + + r = ndisc_drop_outdated(link, timestamp_usec, NULL); if (r < 0) return r; - r = ndisc_drop_outdated(link, timestamp_usec); + r = sd_ndisc_router_get_lifetime(rt, &router_lifetime_sec); if (r < 0) - return r; + return log_link_warning_errno(link, r, "Failed to get lifetime of RA message: %m"); + + /* https://datatracker.ietf.org/doc/html/rfc4861 + * Router Lifetime: A Lifetime of 0 indicates that the router is not a default router + * and SHOULD NOT appear on the default router list. + */ + if (router_lifetime_sec == 0) { + log_link_debug(link, "Received RA with lifetime = 0, dropping configurations."); + + r = ndisc_drop_outdated(link, USEC_INFINITY, &router); + if (r < 0) + log_link_warning_errno(link, r, "Failed to process RA with zero lifetime, ignoring: %m"); + + return 0; + } r = ndisc_start_dhcp6_client(link, rt); if (r < 0)