summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorÁlvaro Fernández Rojas2025-11-28 09:39:42 +0000
committerÁlvaro Fernández Rojas2025-12-02 19:29:29 +0000
commitd970ae0ca4a32c017241bdf2b9ad41303cb6b7bf (patch)
tree024ae2e6584c27913ddfe10a66bbf83def33271c
parent63f040e88b122b6dcd17a8c48699de5169c863dd (diff)
router: improve RA PIO search logic
We need to properly handle when the user modifies the prefix length assigned to an interface by: - Checking if the prefix matches the address taking into account: - The biggest length of address and PIO. - A minimum PIO of /64. - Updating addresses and lengths for existing PIOs. Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
-rw-r--r--src/router.c32
1 files changed, 27 insertions, 5 deletions
diff --git a/src/router.c b/src/router.c
index 4fe8ccf..31a4c33 100644
--- a/src/router.c
+++ b/src/router.c
@@ -449,14 +449,20 @@ struct nd_opt_capt_portal {
};
/* IPv6 RA PIOs */
+inline static int router_compare_pio_addr(const struct ra_pio *pio, const struct odhcpd_ipaddr *addr)
+{
+ uint8_t cmp_len = max(64, max(pio->length, addr->prefix_len));
+
+ return odhcpd_bmemcmp(&pio->prefix, &addr->addr.in6, cmp_len);
+}
+
static struct ra_pio *router_find_ra_pio(struct interface *iface,
struct odhcpd_ipaddr *addr)
{
for (size_t i = 0; i < iface->pio_cnt; i++) {
struct ra_pio *cur_pio = &iface->pios[i];
- if (addr->prefix_len == cur_pio->length &&
- !odhcpd_bmemcmp(&addr->addr.in6, &cur_pio->prefix, cur_pio->length))
+ if (!router_compare_pio_addr(cur_pio, addr))
return cur_pio;
}
@@ -471,6 +477,23 @@ static void router_add_ra_pio(struct interface *iface,
pio = router_find_ra_pio(iface, addr);
if (pio) {
+ if (memcmp(&pio->prefix, &addr->addr.in6, sizeof(struct in6_addr)) != 0 ||
+ pio->length != addr->prefix_len)
+ {
+ char new_ipv6_str[INET6_ADDRSTRLEN];
+
+ iface->pio_update = true;
+ warn("rfc9096: %s: changed %s/%u -> %s/%u",
+ iface->ifname,
+ inet_ntop(AF_INET6, &pio->prefix, ipv6_str, sizeof(ipv6_str)),
+ pio->length,
+ inet_ntop(AF_INET6, &addr->addr.in6, new_ipv6_str, sizeof(new_ipv6_str)),
+ addr->prefix_len);
+
+ memcpy(&pio->prefix, &addr->addr.in6, sizeof(struct in6_addr));
+ pio->length = addr->prefix_len;
+ }
+
if (pio->lifetime) {
pio->lifetime = 0;
@@ -492,7 +515,7 @@ static void router_add_ra_pio(struct interface *iface,
pio = &iface->pios[iface->pio_cnt];
iface->pio_cnt++;
- memcpy(&pio->prefix, &addr->addr.in6, sizeof(pio->prefix));
+ memcpy(&pio->prefix, &addr->addr.in6, sizeof(struct in6_addr));
pio->length = addr->prefix_len;
pio->lifetime = 0;
@@ -659,8 +682,7 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr
for (size_t j = 0; j < valid_addr_cnt; j++) {
struct odhcpd_ipaddr *cur_addr = &addrs[j];
- if (cur_pio->length == cur_addr->prefix_len &&
- !odhcpd_bmemcmp(&cur_pio->prefix, &cur_addr->addr.in6, cur_pio->length)) {
+ if (!router_compare_pio_addr(cur_pio, cur_addr)) {
pio_found = true;
break;
}