]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: ndisc - drop routes of lifetime 0 28496/head
authorSusant Sahani <ssahani@gmail.com>
Wed, 26 Jul 2023 09:44:13 +0000 (15:14 +0530)
committerSusant Sahani <ssahani@gmail.com>
Tue, 22 Aug 2023 15:58:11 +0000 (21:28 +0530)
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

index 61776d3c262fc43d34263dcecbb7c4dbce59fd28..c6ca7f95e2d3664f5956908423c1c9d4432d6fe2 100644 (file)
@@ -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)