mirror of
https://github.com/systemd/systemd
synced 2024-07-21 10:17:21 +00:00
netowrk/ndisc: drop NDisc configurations when received NA without Router flag
Closes #28421.
This commit is contained in:
parent
ecab9b6040
commit
87a33c0740
|
@ -1391,7 +1391,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, const struct in6_addr *router, usec_t timestamp_usec) {
|
||||
bool updated = false;
|
||||
NDiscDNSSL *dnssl;
|
||||
NDiscRDNSS *rdnss;
|
||||
|
@ -1420,6 +1420,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;
|
||||
|
||||
r = route_remove_and_cancel(route, link->manager);
|
||||
if (r < 0)
|
||||
RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC route, ignoring: %m"));
|
||||
|
@ -1432,6 +1435,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;
|
||||
|
||||
r = address_remove_and_cancel(address, link);
|
||||
if (r < 0)
|
||||
RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC address, ignoring: %m"));
|
||||
|
@ -1441,6 +1447,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;
|
||||
}
|
||||
|
@ -1449,6 +1458,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;
|
||||
}
|
||||
|
@ -1457,6 +1469,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;
|
||||
}
|
||||
|
@ -1465,6 +1480,9 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) {
|
|||
if (p64->lifetime_usec > timestamp_usec)
|
||||
continue; /* the pref64 prefix is still valid */
|
||||
|
||||
if (router && !in6_addr_equal(&p64->router, router))
|
||||
continue;
|
||||
|
||||
free(set_remove(link->ndisc_pref64, p64));
|
||||
/* The pref64 prefix is not exported through the state file, hence it is not necessary to set
|
||||
* the 'updated' flag. */
|
||||
|
@ -1486,7 +1504,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, /* router = */ NULL, now_usec);
|
||||
(void) ndisc_setup_expire(link);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1635,7 +1653,7 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ndisc_drop_outdated(link, timestamp_usec);
|
||||
r = ndisc_drop_outdated(link, /* router = */ NULL, timestamp_usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -1679,6 +1697,131 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_neighbor_handle_non_router_message(Link *link, sd_ndisc_neighbor *na) {
|
||||
struct in6_addr address;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(na);
|
||||
|
||||
/* Received Neighbor Advertisement message without Router flag. The node might have been a router,
|
||||
* and now it is not. Let's drop all configurations based on RAs sent from the node. */
|
||||
|
||||
r = sd_ndisc_neighbor_get_target_address(na, &address);
|
||||
if (r == -ENODATA)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) ndisc_drop_outdated(link, /* router = */ &address, /* timestamp_usec = */ USEC_INFINITY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_neighbor_handle_router_message(Link *link, sd_ndisc_neighbor *na) {
|
||||
struct in6_addr current_address, original_address;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(na);
|
||||
|
||||
/* Received Neighbor Advertisement message with Router flag. If the router address is changed, update
|
||||
* the provider field of configurations. */
|
||||
|
||||
r = sd_ndisc_neighbor_get_sender_address(na, ¤t_address);
|
||||
if (r == -ENODATA)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ndisc_neighbor_get_target_address(na, &original_address);
|
||||
if (r == -ENODATA)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (in6_addr_equal(¤t_address, &original_address))
|
||||
return 0; /* the router address is not changed */
|
||||
|
||||
Route *route;
|
||||
SET_FOREACH(route, link->manager->routes) {
|
||||
if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
|
||||
continue;
|
||||
|
||||
if (route->nexthop.ifindex != link->ifindex)
|
||||
continue;
|
||||
|
||||
if (!in6_addr_equal(&route->provider.in6, &original_address))
|
||||
continue;
|
||||
|
||||
route->provider.in6 = current_address;
|
||||
}
|
||||
|
||||
Address *address;
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
|
||||
continue;
|
||||
|
||||
if (!in6_addr_equal(&address->provider.in6, &original_address))
|
||||
continue;
|
||||
|
||||
address->provider.in6 = current_address;
|
||||
}
|
||||
|
||||
NDiscRDNSS *rdnss;
|
||||
SET_FOREACH(rdnss, link->ndisc_rdnss) {
|
||||
if (!in6_addr_equal(&rdnss->router, &original_address))
|
||||
continue;
|
||||
|
||||
rdnss->router = current_address;
|
||||
}
|
||||
|
||||
NDiscDNSSL *dnssl;
|
||||
SET_FOREACH(dnssl, link->ndisc_dnssl) {
|
||||
if (!in6_addr_equal(&dnssl->router, &original_address))
|
||||
continue;
|
||||
|
||||
dnssl->router = current_address;
|
||||
}
|
||||
|
||||
NDiscCaptivePortal *cp;
|
||||
SET_FOREACH(cp, link->ndisc_captive_portals) {
|
||||
if (!in6_addr_equal(&cp->router, &original_address))
|
||||
continue;
|
||||
|
||||
cp->router = current_address;
|
||||
}
|
||||
|
||||
NDiscPREF64 *p64;
|
||||
SET_FOREACH(p64, link->ndisc_pref64) {
|
||||
if (!in6_addr_equal(&p64->router, &original_address))
|
||||
continue;
|
||||
|
||||
p64->router = current_address;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_neighbor_handler(Link *link, sd_ndisc_neighbor *na) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(na);
|
||||
|
||||
r = sd_ndisc_neighbor_is_router(na);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
r = ndisc_neighbor_handle_non_router_message(link, na);
|
||||
else
|
||||
r = ndisc_neighbor_handle_router_message(link, na);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata) {
|
||||
Link *link = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
@ -1696,6 +1839,14 @@ static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, void *message, v
|
|||
}
|
||||
break;
|
||||
|
||||
case SD_NDISC_EVENT_NEIGHBOR:
|
||||
r = ndisc_neighbor_handler(link, ASSERT_PTR(message));
|
||||
if (r < 0 && r != -EBADMSG) {
|
||||
link_enter_failed(link);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case SD_NDISC_EVENT_TIMEOUT:
|
||||
log_link_debug(link, "NDisc handler get timeout event");
|
||||
if (link->ndisc_messages == 0) {
|
||||
|
@ -1825,7 +1976,7 @@ void ndisc_flush(Link *link) {
|
|||
assert(link);
|
||||
|
||||
/* Remove all addresses, routes, RDNSS, DNSSL, and Captive Portal entries, without exception. */
|
||||
(void) ndisc_drop_outdated(link, /* timestamp_usec = */ USEC_INFINITY);
|
||||
(void) ndisc_drop_outdated(link, /* router = */ NULL, /* timestamp_usec = */ USEC_INFINITY);
|
||||
|
||||
link->ndisc_rdnss = set_free(link->ndisc_rdnss);
|
||||
link->ndisc_dnssl = set_free(link->ndisc_dnssl);
|
||||
|
|
|
@ -6,3 +6,5 @@ Name=veth-peer
|
|||
IPv6AcceptRA=no
|
||||
Address=2600::1/0
|
||||
Address=192.168.5.1/24
|
||||
# To make the kernel send NA with IsRouter flag.
|
||||
IPv6Forwarding=yes
|
||||
|
|
Loading…
Reference in a new issue