]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-radv: router lifetime must be 0 or between 4 seconds and 9000 seconds
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 24 Oct 2021 16:21:22 +0000 (01:21 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 27 Oct 2021 10:27:07 +0000 (19:27 +0900)
See RFC 4861 section 6.2.1.

src/libsystemd-network/radv-internal.h
src/libsystemd-network/sd-radv.c
src/libsystemd-network/test-ndisc-ra.c

index 6d8ad60b4834c7de334adb0639ccdd52d3a751c5..1f1c248c0a0263c9fecdc57c768043b1937380a9 100644 (file)
@@ -34,6 +34,8 @@
  * point-to-point link the peers may have enough information about the number and status of devices at
  * the other end so that advertisements are needed less frequently.
  * Default: 3 * MaxRtrAdvInterval */
+#define RADV_MIN_ROUTER_LIFETIME_USEC             (4 * USEC_PER_SEC)
+#define RADV_MAX_ROUTER_LIFETIME_USEC             (9000 * USEC_PER_SEC)
 #define RADV_DEFAULT_ROUTER_LIFETIME_USEC         (3 * RADV_DEFAULT_MAX_TIMEOUT_USEC)
 /* RFC 4861 section 10.
  * MAX_INITIAL_RTR_ADVERT_INTERVAL  16 seconds
index 0468b5268f20377a7a4dfc8d634e2e438e01d073..823b6f40e07bedd78a25c89a128c328e0fae64f5 100644 (file)
@@ -129,6 +129,12 @@ static sd_radv *radv_free(sd_radv *ra) {
 
 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv, sd_radv, radv_free);
 
+static bool router_lifetime_is_valid(usec_t lifetime_usec) {
+        return lifetime_usec == 0 ||
+                (lifetime_usec >= RADV_MIN_ROUTER_LIFETIME_USEC &&
+                 lifetime_usec <= RADV_MAX_ROUTER_LIFETIME_USEC);
+}
+
 static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_usec) {
         sd_radv_route_prefix *rt;
         sd_radv_prefix *p;
@@ -159,31 +165,24 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_us
                 .msg_namelen = sizeof(dst_addr),
                 .msg_iov = iov,
         };
-        uint16_t lifetime_sec;
         usec_t time_now;
         int r;
 
         assert(ra);
+        assert(router_lifetime_is_valid(lifetime_usec));
 
         r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
         if (r < 0)
                 return r;
 
-        /* a value of UINT16_MAX represents infinity, 0x0 means this host is not a router */
-        if (lifetime_usec == USEC_INFINITY)
-                lifetime_sec = UINT16_MAX;
-        else if (lifetime_usec > (UINT16_MAX - 1) * USEC_PER_SEC)
-                lifetime_sec = UINT16_MAX - 1;
-        else
-                lifetime_sec = DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC);
-
         if (dst && in6_addr_is_set(dst))
                 dst_addr.sin6_addr = *dst;
 
         adv.nd_ra_type = ND_ROUTER_ADVERT;
         adv.nd_ra_curhoplimit = ra->hop_limit;
         adv.nd_ra_flags_reserved = ra->flags;
-        adv.nd_ra_router_lifetime = htobe16(lifetime_sec);
+        assert_cc(RADV_MAX_ROUTER_LIFETIME_USEC <= UINT16_MAX * USEC_PER_SEC);
+        adv.nd_ra_router_lifetime = htobe16(DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC));
         iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv));
 
         /* MAC address is optional, either because the link does not use L2
@@ -504,11 +503,14 @@ _public_ int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t lifetime_usec) {
         if (ra->state != RADV_STATE_IDLE)
                 return -EBUSY;
 
+        if (!router_lifetime_is_valid(lifetime_usec))
+                return -EINVAL;
+
         /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the preference value MUST be set
          * to (00) by the sender..." */
         if (lifetime_usec == 0 &&
             (ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
-                return -ETIME;
+                return -EINVAL;
 
         ra->lifetime_usec = lifetime_usec;
 
index 4713bc99b5b47bf434b0107d8de263fe8c0c6ea8..45902862d3db6866b78d5503547b87db18aa92ca 100644 (file)
@@ -180,7 +180,9 @@ static void test_radv(void) {
 
         assert_se(sd_radv_set_router_lifetime(NULL, 0) < 0);
         assert_se(sd_radv_set_router_lifetime(ra, 0) >= 0);
-        assert_se(sd_radv_set_router_lifetime(ra, ~0) >= 0);
+        assert_se(sd_radv_set_router_lifetime(ra, USEC_INFINITY) < 0);
+        assert_se(sd_radv_set_router_lifetime(ra, USEC_PER_YEAR) < 0);
+        assert_se(sd_radv_set_router_lifetime(ra, 300 * USEC_PER_SEC) >= 0);
 
         assert_se(sd_radv_set_preference(NULL, 0) < 0);
         assert_se(sd_radv_set_preference(ra, SD_NDISC_PREFERENCE_LOW) >= 0);
@@ -189,7 +191,7 @@ static void test_radv(void) {
         assert_se(sd_radv_set_preference(ra, ~0) < 0);
 
         assert_se(sd_radv_set_preference(ra, SD_NDISC_PREFERENCE_HIGH) >= 0);
-        assert_se(sd_radv_set_router_lifetime(ra, 42000) >= 0);
+        assert_se(sd_radv_set_router_lifetime(ra, 300 * USEC_PER_SEC) >= 0);
         assert_se(sd_radv_set_router_lifetime(ra, 0) < 0);
         assert_se(sd_radv_set_preference(ra, SD_NDISC_PREFERENCE_MEDIUM) >= 0);
         assert_se(sd_radv_set_router_lifetime(ra, 0) >= 0);
@@ -308,7 +310,7 @@ static void test_ra(void) {
 
         assert_se(sd_radv_set_ifindex(ra, 42) >= 0);
         assert_se(sd_radv_set_mac(ra, &mac_addr) >= 0);
-        assert_se(sd_radv_set_router_lifetime(ra, 180) >= 0);
+        assert_se(sd_radv_set_router_lifetime(ra, 180 * USEC_PER_SEC) >= 0);
         assert_se(sd_radv_set_hop_limit(ra, 64) >= 0);
         assert_se(sd_radv_set_managed_information(ra, true) >= 0);
         assert_se(sd_radv_set_other_information(ra, true) >= 0);