|
1 |
| -From 4c2bb6b71b0b7d4d9a2ca5796b320aaa4516c1bb Mon Sep 17 00:00:00 2001 |
| 1 | +From 8a8150f045ed73e15c77c38be4b90999024f6d17 Mon Sep 17 00:00:00 2001 |
| 2 | +From: skbeh <60107333+skbeh@users.noreply.github.com> |
2 | 3 | Date: Sat, 16 Sep 2023 15:04:12 +0000
|
3 |
| -Subject: [PATCH] config: allow configuring limit of min and max value for |
4 |
| - preferred and valid lifetime |
| 4 | +Subject: [PATCH] config: allow configuring max limit for preferred and valid |
| 5 | + lifetime |
5 | 6 |
|
6 | 7 | ---
|
7 |
| - src/config.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ |
8 |
| - src/dhcpv6-ia.c | 16 ++++++++++++++++ |
9 |
| - src/odhcpd.h | 4 ++++ |
10 |
| - src/router.c | 16 ++++++++++++++++ |
11 |
| - 4 files changed, 83 insertions(+) |
| 8 | + src/config.c | 32 ++++++++++++++++++++++++++++++++ |
| 9 | + src/dhcpv6-ia.c | 9 +++++++++ |
| 10 | + src/odhcpd.h | 6 ++++++ |
| 11 | + src/router.c | 35 +++++++++++++++++++++++++++-------- |
| 12 | + 4 files changed, 74 insertions(+), 8 deletions(-) |
12 | 13 |
|
13 | 14 | --- a/src/config.c
|
14 | 15 | +++ b/src/config.c
|
15 |
| -@@ -92,6 +92,10 @@ enum { |
| 16 | +@@ -92,6 +92,8 @@ enum { |
16 | 17 | IFACE_ATTR_NDPROXY_SLAVE,
|
17 | 18 | IFACE_ATTR_PREFIX_FILTER,
|
18 | 19 | IFACE_ATTR_PREFERRED_LIFETIME,
|
19 |
| -+ IFACE_ATTR_MIN_PREFERRED_LIFETIME, |
20 | 20 | + IFACE_ATTR_MAX_PREFERRED_LIFETIME,
|
21 |
| -+ IFACE_ATTR_MIN_VALID_LIFETIME, |
22 | 21 | + IFACE_ATTR_MAX_VALID_LIFETIME,
|
23 | 22 | IFACE_ATTR_NTP,
|
24 | 23 | IFACE_ATTR_MAX
|
25 | 24 | };
|
26 |
| -@@ -145,6 +149,10 @@ static const struct blobmsg_policy iface |
| 25 | +@@ -145,6 +147,8 @@ static const struct blobmsg_policy iface |
27 | 26 | [IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL },
|
28 | 27 | [IFACE_ATTR_PREFIX_FILTER] = { .name = "prefix_filter", .type = BLOBMSG_TYPE_STRING },
|
29 | 28 | [IFACE_ATTR_PREFERRED_LIFETIME] = { .name = "preferred_lifetime", .type = BLOBMSG_TYPE_STRING },
|
30 |
| -+ [IFACE_ATTR_MIN_PREFERRED_LIFETIME] = { .name = "min_preferred_lifetime", .type = BLOBMSG_TYPE_STRING }, |
31 | 29 | + [IFACE_ATTR_MAX_PREFERRED_LIFETIME] = { .name = "max_preferred_lifetime", .type = BLOBMSG_TYPE_STRING },
|
32 |
| -+ [IFACE_ATTR_MIN_VALID_LIFETIME] = { .name = "min_valid_lifetime", .type = BLOBMSG_TYPE_STRING }, |
33 | 30 | + [IFACE_ATTR_MAX_VALID_LIFETIME] = { .name = "max_valid_lifetime", .type = BLOBMSG_TYPE_STRING },
|
34 | 31 | [IFACE_ATTR_NTP] = { .name = "ntp", .type = BLOBMSG_TYPE_ARRAY },
|
35 | 32 | };
|
36 | 33 |
|
37 |
| -@@ -648,6 +656,45 @@ int config_parse_interface(void *data, s |
| 34 | +@@ -648,6 +652,34 @@ int config_parse_interface(void *data, s |
38 | 35 |
|
39 | 36 | }
|
40 | 37 |
|
41 |
| -+ if ((c = tb[IFACE_ATTR_MIN_PREFERRED_LIFETIME])) { |
42 |
| -+ double time = parse_leasetime(c); |
43 |
| -+ |
44 |
| -+ if (time >= 0) |
45 |
| -+ iface->min_preferred_lifetime = time; |
46 |
| -+ else |
47 |
| -+ syslog(LOG_ERR, "Invalid %s value configured for interface '%s'", |
48 |
| -+ iface_attrs[IFACE_ATTR_MIN_PREFERRED_LIFETIME].name, iface->name); |
49 |
| -+ } |
50 |
| -+ |
51 | 38 | + if ((c = tb[IFACE_ATTR_MAX_PREFERRED_LIFETIME])) {
|
52 | 39 | + double time = parse_leasetime(c);
|
53 | 40 | +
|
54 |
| -+ if (time >= 0) |
| 41 | ++ if (time >= 0) { |
55 | 42 | + iface->max_preferred_lifetime = time;
|
56 |
| -+ else |
| 43 | ++ } else { |
| 44 | ++ iface->max_preferred_lifetime = ND_PREFERRED_LIMIT; |
57 | 45 | + syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
|
58 | 46 | + iface_attrs[IFACE_ATTR_MAX_PREFERRED_LIFETIME].name, iface->name);
|
59 |
| -+ } |
60 |
| -+ if ((c = tb[IFACE_ATTR_MIN_VALID_LIFETIME])) { |
61 |
| -+ double time = parse_leasetime(c); |
62 |
| -+ |
63 |
| -+ if (time >= 0) |
64 |
| -+ iface->min_valid_lifetime = time; |
65 |
| -+ else |
66 |
| -+ syslog(LOG_ERR, "Invalid %s value configured for interface '%s'", |
67 |
| -+ iface_attrs[IFACE_ATTR_MIN_VALID_LIFETIME].name, iface->name); |
| 47 | ++ } |
| 48 | ++ } else { |
| 49 | ++ iface->max_preferred_lifetime = ND_PREFERRED_LIMIT; |
68 | 50 | + }
|
69 | 51 | +
|
70 | 52 | + if ((c = tb[IFACE_ATTR_MAX_VALID_LIFETIME])) {
|
71 | 53 | + double time = parse_leasetime(c);
|
72 | 54 | +
|
73 |
| -+ if (time >= 0) |
| 55 | ++ if (time >= 0) { |
74 | 56 | + iface->max_valid_lifetime = time;
|
75 |
| -+ else |
| 57 | ++ } else { |
| 58 | ++ iface->max_valid_lifetime = ND_VALID_LIMIT; |
76 | 59 | + syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
|
77 | 60 | + iface_attrs[IFACE_ATTR_MAX_VALID_LIFETIME].name, iface->name);
|
| 61 | ++ } |
| 62 | ++ } else { |
| 63 | ++ iface->max_valid_lifetime = ND_VALID_LIMIT; |
78 | 64 | + }
|
79 | 65 | +
|
80 | 66 | if ((c = tb[IFACE_ATTR_START])) {
|
81 | 67 | iface->dhcpv4_start.s_addr = htonl(blobmsg_get_u32(c));
|
82 | 68 | iface->dhcpv4_end.s_addr = htonl(ntohl(iface->dhcpv4_start.s_addr) +
|
83 | 69 | --- a/src/dhcpv6-ia.c
|
84 | 70 | +++ b/src/dhcpv6-ia.c
|
85 |
| -@@ -1027,6 +1027,22 @@ static size_t build_ia(uint8_t *buf, siz |
| 71 | +@@ -1027,6 +1027,15 @@ static size_t build_ia(uint8_t *buf, siz |
86 | 72 | }
|
87 | 73 | }
|
88 | 74 |
|
89 | 75 | + if (pref) {
|
90 |
| -+ if (iface->min_preferred_lifetime) |
91 |
| -+ pref = max(pref, iface->min_preferred_lifetime); |
92 | 76 | + if (iface->max_preferred_lifetime)
|
93 | 77 | + pref = min(pref, iface->max_preferred_lifetime);
|
94 | 78 | + }
|
95 | 79 | + if (valid) {
|
96 |
| -+ if (iface->min_valid_lifetime) |
97 |
| -+ valid = max(valid, iface->min_valid_lifetime); |
98 | 80 | + if (iface->max_valid_lifetime)
|
99 | 81 | + valid = min(valid, iface->max_valid_lifetime);
|
100 |
| -+ |
101 |
| -+ if (!pref) |
102 |
| -+ pref = valid; |
103 | 82 | + }
|
104 | 83 | +
|
105 | 84 | if (!INFINITE_VALID(a->valid_until))
|
106 | 85 | /* UINT32_MAX is considered as infinite leasetime */
|
107 | 86 | a->valid_until = (valid == UINT32_MAX) ? 0 : valid + now;
|
108 | 87 | --- a/src/odhcpd.h
|
109 | 88 | +++ b/src/odhcpd.h
|
110 |
| -@@ -319,6 +319,10 @@ struct interface { |
| 89 | +@@ -37,6 +37,10 @@ |
| 90 | + // RFC 8781 defines PREF64 option |
| 91 | + #define ND_OPT_PREF64 38 |
| 92 | + |
| 93 | ++// RFC9096 defines recommended option lifetimes configuration values |
| 94 | ++#define ND_PREFERRED_LIMIT 2700 |
| 95 | ++#define ND_VALID_LIMIT 5400 |
| 96 | ++ |
| 97 | + #define INFINITE_VALID(x) ((x) == 0) |
| 98 | + |
| 99 | + #define _unused __attribute__((unused)) |
| 100 | +@@ -319,6 +323,8 @@ struct interface { |
111 | 101 | uint32_t ra_hoplimit;
|
112 | 102 | int ra_mtu;
|
113 | 103 | uint32_t preferred_lifetime;
|
114 |
| -+ uint32_t min_preferred_lifetime; |
115 | 104 | + uint32_t max_preferred_lifetime;
|
116 |
| -+ uint32_t min_valid_lifetime; |
117 | 105 | + uint32_t max_valid_lifetime;
|
118 | 106 |
|
119 | 107 | // DHCP
|
120 | 108 | uint32_t dhcp_leasetime;
|
121 | 109 | --- a/src/router.c
|
122 | 110 | +++ b/src/router.c
|
123 |
| -@@ -600,6 +600,22 @@ static int send_router_advert(struct int |
| 111 | +@@ -452,7 +452,8 @@ static int send_router_advert(struct int |
| 112 | + size_t dns_sz = 0, search_sz = 0, pref64_sz = 0; |
| 113 | + size_t pfxs_cnt = 0, routes_cnt = 0; |
| 114 | + ssize_t valid_addr_cnt = 0, invalid_addr_cnt = 0; |
| 115 | +- uint32_t minvalid = UINT32_MAX, maxival, lifetime; |
| 116 | ++ uint32_t minvalid = UINT32_MAX, maxival, lifetime, max_prefix_vlt = ND_VALID_LIMIT; |
| 117 | ++ uint32_t calculated_ra_lifetime; |
| 118 | + int msecs, mtu = iface->ra_mtu, hlim = iface->ra_hoplimit; |
| 119 | + bool default_route = false; |
| 120 | + bool valid_prefix = false; |
| 121 | +@@ -598,10 +599,22 @@ static int send_router_advert(struct int |
| 122 | + if (addr->valid > (uint32_t)now) { |
| 123 | + valid = TIME_LEFT(addr->valid, now); |
124 | 124 |
|
| 125 | ++ if (valid < max_prefix_vlt) |
| 126 | ++ max_prefix_vlt = valid; |
| 127 | ++ |
125 | 128 | if (iface->ra_useleasetime && valid > iface->dhcp_leasetime)
|
126 | 129 | valid = iface->dhcp_leasetime;
|
127 |
| -+ |
128 |
| -+ if (!preferred) |
129 |
| -+ preferred = valid; |
130 |
| -+ } |
131 |
| -+ |
| 130 | + } |
| 131 | + |
132 | 132 | + if (preferred) {
|
133 |
| -+ if (iface->min_preferred_lifetime) |
134 |
| -+ preferred = max(preferred, iface->min_preferred_lifetime); |
135 | 133 | + if (iface->max_preferred_lifetime)
|
136 | 134 | + preferred = min(preferred, iface->max_preferred_lifetime);
|
137 | 135 | + }
|
138 | 136 | + if (valid) {
|
139 |
| -+ if (iface->min_valid_lifetime) |
140 |
| -+ valid = max(valid, iface->min_valid_lifetime); |
141 | 137 | + if (iface->max_valid_lifetime)
|
142 | 138 | + valid = min(valid, iface->max_valid_lifetime);
|
| 139 | ++ } |
| 140 | ++ |
| 141 | + if (minvalid > valid) |
| 142 | + minvalid = valid; |
| 143 | + |
| 144 | +@@ -629,24 +642,30 @@ static int send_router_advert(struct int |
| 145 | + |
| 146 | + /* Calculate periodic transmit */ |
| 147 | + msecs = calc_adv_interval(iface, minvalid, &maxival); |
| 148 | +- lifetime = calc_ra_lifetime(iface, maxival); |
| 149 | ++ calculated_ra_lifetime = calc_ra_lifetime(iface, maxival); |
| 150 | ++ lifetime = min(calculated_ra_lifetime, max_prefix_vlt); |
| 151 | + |
| 152 | + if (!iface->have_link_local) { |
| 153 | + syslog(LOG_NOTICE, "Skip sending a RA on %s as no link local address is available", iface->name); |
| 154 | + goto out; |
| 155 | + } |
| 156 | + |
| 157 | +- if (default_route && valid_prefix) { |
| 158 | +- adv.h.nd_ra_router_lifetime = htons(lifetime < UINT16_MAX ? lifetime : UINT16_MAX); |
| 159 | +- } else { |
| 160 | ++ /* RFC9096: CE routers SHOULD set the "Router Lifetime" of Router Advertisement (RA) messages to ND_PREFERRED_LIMIT. */ |
| 161 | ++ adv.h.nd_ra_router_lifetime = ND_PREFERRED_LIMIT; |
| 162 | ++ if (!(default_route && valid_prefix)) { |
| 163 | + adv.h.nd_ra_router_lifetime = 0; |
| 164 | + |
| 165 | + if (default_route) { |
| 166 | + syslog(LOG_WARNING, "A default route is present but there is no public prefix " |
| 167 | +- "on %s thus we don't announce a default route by overriding ra_lifetime!", iface->name); |
| 168 | ++ "on %s thus we don't announce a default route by setting ra_lifetime to zero!", iface->name); |
| 169 | + } else { |
| 170 | +- syslog(LOG_WARNING, "No default route present, overriding ra_lifetime!"); |
| 171 | ++ syslog(LOG_WARNING, "No default route present, setting ra_lifetime to zero!"); |
143 | 172 | }
|
| 173 | ++ } else if (iface->ra_lifetime >= 0) { |
| 174 | ++ adv.h.nd_ra_router_lifetime = calculated_ra_lifetime; |
| 175 | ++ if (calculated_ra_lifetime == 0) |
| 176 | ++ syslog(LOG_WARNING, "A default route is present and there is public prefix " |
| 177 | ++ "but ra_lifetime on iface was set to zero, setting ra_lifetime to zero!"); |
| 178 | + } |
| 179 | + |
| 180 | + syslog(LOG_DEBUG, "Using a RA lifetime of %d seconds on %s", ntohs(adv.h.nd_ra_router_lifetime), iface->name); |
| 181 | +@@ -710,7 +729,7 @@ static int send_router_advert(struct int |
| 182 | + |
| 183 | + if (iface->pref64_length) { |
| 184 | + /* RFC 8781 § 4.1 rounding up lifetime to multiply of 8 */ |
| 185 | +- uint16_t pref64_lifetime = lifetime < (UINT16_MAX - 7) ? lifetime + 7 : UINT16_MAX; |
| 186 | ++ uint16_t pref64_lifetime = lifetime < (UINT16_MAX - 7) ? lifetime + 7 : (UINT16_MAX - 7); |
| 187 | + uint8_t prefix_length_code; |
| 188 | + uint32_t mask_a1, mask_a2; |
144 | 189 |
|
145 |
| - if (minvalid > valid) |
|
0 commit comments