Skip to content

Commit d156688

Browse files
committed
refine ipv6 support
1 parent 543eacf commit d156688

File tree

2 files changed

+113
-71
lines changed

2 files changed

+113
-71
lines changed

PATCH/files/etc/hotplug.d/iface/99-odhcpd

+9-11
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@
44
[ "$ACTION" = ifupdate -a -z "$IFUPDATE_ADDRESSES" -a -z "$IFUPDATE_DATA" ] && exit 0
55

66
if echo "$INTERFACE" | grep -q "wan" && echo "$INTERFACE" | grep -qv "vap"; then
7-
logger -t odhcpd "Reloading odhcpd due to $ACTION of $INTERFACE ($DEVICE)"
8-
"/etc/init.d/odhcpd" restart
7+
IPV6_REGEX="\(\([0-9A-Fa-f]\{1,4\}:\)\{1,\}\)\(\([0-9A-Fa-f]\{1,4\}\)\{0,1\}\)\(\(:[0-9A-Fa-f]\{1,4\}\)\{1,\}\)"
8+
IPV6_ADDR="$(ip -6 addr show dev "$DEVICE" | grep inet6 | grep -m 1 -o "$IPV6_REGEX")"
9+
LOCK_FILE="/tmp/lock/odhcpd_hotplug_lock"
910

10-
IPV6_REGEX="\(\([0-9A-Fa-f]\{1,4\}:\)\{1,\}\)\(\([0-9A-Fa-f]\{1,4\}\)\{0,1\}\)\(\(:[0-9A-Fa-f]\{1,4\}\)\{1,\}\)"
11-
IPV6_ADDR="$(ip -6 addr show dev "$DEVICE" | grep inet6 | grep -m 1 -o "$IPV6_REGEX")"
12-
LOCK_FILE="/tmp/lock/odhcpd_hotplug_lock"
13-
14-
if [ -n "$IPV6_ADDR" ] && mkdir "$LOCK_FILE" 2>/dev/null; then
15-
"/sbin/ifup" lan
16-
[ -f '/etc/init.d/miniupnpd' ] && "/etc/init.d/miniupnpd" restart
17-
logger -t odhcpd "Reloading lan due to $ACTION of $INTERFACE ($DEVICE)"
18-
fi
11+
if [ -n "$IPV6_ADDR" ] && mkdir "$LOCK_FILE" 2>/dev/null; then
12+
[ -f '/etc/init.d/miniupnpd' ] && "/etc/init.d/miniupnpd" stop 2>&1
13+
"/sbin/ifup" lan 2>&1
14+
[ -f '/etc/init.d/miniupnpd' ] && "/etc/init.d/miniupnpd" start 2>&1 &
15+
logger -t odhcpd "Reloading lan due to $ACTION of $INTERFACE ($DEVICE)"
16+
fi
1917
fi

PATCH/odhcpd/001-config-allow-configuring-limit-of-min-and-max-value.patch

+104-60
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,189 @@
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>
23
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
56

67
---
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(-)
1213

1314
--- a/src/config.c
1415
+++ b/src/config.c
15-
@@ -92,6 +92,10 @@ enum {
16+
@@ -92,6 +92,8 @@ enum {
1617
IFACE_ATTR_NDPROXY_SLAVE,
1718
IFACE_ATTR_PREFIX_FILTER,
1819
IFACE_ATTR_PREFERRED_LIFETIME,
19-
+ IFACE_ATTR_MIN_PREFERRED_LIFETIME,
2020
+ IFACE_ATTR_MAX_PREFERRED_LIFETIME,
21-
+ IFACE_ATTR_MIN_VALID_LIFETIME,
2221
+ IFACE_ATTR_MAX_VALID_LIFETIME,
2322
IFACE_ATTR_NTP,
2423
IFACE_ATTR_MAX
2524
};
26-
@@ -145,6 +149,10 @@ static const struct blobmsg_policy iface
25+
@@ -145,6 +147,8 @@ static const struct blobmsg_policy iface
2726
[IFACE_ATTR_NDPROXY_SLAVE] = { .name = "ndproxy_slave", .type = BLOBMSG_TYPE_BOOL },
2827
[IFACE_ATTR_PREFIX_FILTER] = { .name = "prefix_filter", .type = BLOBMSG_TYPE_STRING },
2928
[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 },
3129
+ [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 },
3330
+ [IFACE_ATTR_MAX_VALID_LIFETIME] = { .name = "max_valid_lifetime", .type = BLOBMSG_TYPE_STRING },
3431
[IFACE_ATTR_NTP] = { .name = "ntp", .type = BLOBMSG_TYPE_ARRAY },
3532
};
3633

37-
@@ -648,6 +656,45 @@ int config_parse_interface(void *data, s
34+
@@ -648,6 +652,34 @@ int config_parse_interface(void *data, s
3835

3936
}
4037

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-
+
5138
+ if ((c = tb[IFACE_ATTR_MAX_PREFERRED_LIFETIME])) {
5239
+ double time = parse_leasetime(c);
5340
+
54-
+ if (time >= 0)
41+
+ if (time >= 0) {
5542
+ iface->max_preferred_lifetime = time;
56-
+ else
43+
+ } else {
44+
+ iface->max_preferred_lifetime = ND_PREFERRED_LIMIT;
5745
+ syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
5846
+ 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;
6850
+ }
6951
+
7052
+ if ((c = tb[IFACE_ATTR_MAX_VALID_LIFETIME])) {
7153
+ double time = parse_leasetime(c);
7254
+
73-
+ if (time >= 0)
55+
+ if (time >= 0) {
7456
+ iface->max_valid_lifetime = time;
75-
+ else
57+
+ } else {
58+
+ iface->max_valid_lifetime = ND_VALID_LIMIT;
7659
+ syslog(LOG_ERR, "Invalid %s value configured for interface '%s'",
7760
+ iface_attrs[IFACE_ATTR_MAX_VALID_LIFETIME].name, iface->name);
61+
+ }
62+
+ } else {
63+
+ iface->max_valid_lifetime = ND_VALID_LIMIT;
7864
+ }
7965
+
8066
if ((c = tb[IFACE_ATTR_START])) {
8167
iface->dhcpv4_start.s_addr = htonl(blobmsg_get_u32(c));
8268
iface->dhcpv4_end.s_addr = htonl(ntohl(iface->dhcpv4_start.s_addr) +
8369
--- a/src/dhcpv6-ia.c
8470
+++ 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
8672
}
8773
}
8874

8975
+ if (pref) {
90-
+ if (iface->min_preferred_lifetime)
91-
+ pref = max(pref, iface->min_preferred_lifetime);
9276
+ if (iface->max_preferred_lifetime)
9377
+ pref = min(pref, iface->max_preferred_lifetime);
9478
+ }
9579
+ if (valid) {
96-
+ if (iface->min_valid_lifetime)
97-
+ valid = max(valid, iface->min_valid_lifetime);
9880
+ if (iface->max_valid_lifetime)
9981
+ valid = min(valid, iface->max_valid_lifetime);
100-
+
101-
+ if (!pref)
102-
+ pref = valid;
10382
+ }
10483
+
10584
if (!INFINITE_VALID(a->valid_until))
10685
/* UINT32_MAX is considered as infinite leasetime */
10786
a->valid_until = (valid == UINT32_MAX) ? 0 : valid + now;
10887
--- a/src/odhcpd.h
10988
+++ 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 {
111101
uint32_t ra_hoplimit;
112102
int ra_mtu;
113103
uint32_t preferred_lifetime;
114-
+ uint32_t min_preferred_lifetime;
115104
+ uint32_t max_preferred_lifetime;
116-
+ uint32_t min_valid_lifetime;
117105
+ uint32_t max_valid_lifetime;
118106

119107
// DHCP
120108
uint32_t dhcp_leasetime;
121109
--- a/src/router.c
122110
+++ 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);
124124

125+
+ if (valid < max_prefix_vlt)
126+
+ max_prefix_vlt = valid;
127+
+
125128
if (iface->ra_useleasetime && valid > iface->dhcp_leasetime)
126129
valid = iface->dhcp_leasetime;
127-
+
128-
+ if (!preferred)
129-
+ preferred = valid;
130-
+ }
131-
+
130+
}
131+
132132
+ if (preferred) {
133-
+ if (iface->min_preferred_lifetime)
134-
+ preferred = max(preferred, iface->min_preferred_lifetime);
135133
+ if (iface->max_preferred_lifetime)
136134
+ preferred = min(preferred, iface->max_preferred_lifetime);
137135
+ }
138136
+ if (valid) {
139-
+ if (iface->min_valid_lifetime)
140-
+ valid = max(valid, iface->min_valid_lifetime);
141137
+ if (iface->max_valid_lifetime)
142138
+ 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!");
143172
}
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;
144189

145-
if (minvalid > valid)

0 commit comments

Comments
 (0)