mirror of
https://github.com/systemd/systemd
synced 2024-10-15 04:24:19 +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;
|
bool updated = false;
|
||||||
NDiscDNSSL *dnssl;
|
NDiscDNSSL *dnssl;
|
||||||
NDiscRDNSS *rdnss;
|
NDiscRDNSS *rdnss;
|
||||||
|
@ -1420,6 +1420,9 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) {
|
||||||
if (route->lifetime_usec > timestamp_usec)
|
if (route->lifetime_usec > timestamp_usec)
|
||||||
continue; /* the route is still valid */
|
continue; /* the route is still valid */
|
||||||
|
|
||||||
|
if (router && !in6_addr_equal(&route->provider.in6, router))
|
||||||
|
continue;
|
||||||
|
|
||||||
r = route_remove_and_cancel(route, link->manager);
|
r = route_remove_and_cancel(route, link->manager);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC route, ignoring: %m"));
|
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)
|
if (address->lifetime_valid_usec > timestamp_usec)
|
||||||
continue; /* the address is still valid */
|
continue; /* the address is still valid */
|
||||||
|
|
||||||
|
if (router && !in6_addr_equal(&address->provider.in6, router))
|
||||||
|
continue;
|
||||||
|
|
||||||
r = address_remove_and_cancel(address, link);
|
r = address_remove_and_cancel(address, link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC address, ignoring: %m"));
|
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)
|
if (rdnss->lifetime_usec > timestamp_usec)
|
||||||
continue; /* the DNS server is still valid */
|
continue; /* the DNS server is still valid */
|
||||||
|
|
||||||
|
if (router && !in6_addr_equal(&rdnss->router, router))
|
||||||
|
continue;
|
||||||
|
|
||||||
free(set_remove(link->ndisc_rdnss, rdnss));
|
free(set_remove(link->ndisc_rdnss, rdnss));
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
|
@ -1449,6 +1458,9 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) {
|
||||||
if (dnssl->lifetime_usec > timestamp_usec)
|
if (dnssl->lifetime_usec > timestamp_usec)
|
||||||
continue; /* the DNS domain is still valid */
|
continue; /* the DNS domain is still valid */
|
||||||
|
|
||||||
|
if (router && !in6_addr_equal(&dnssl->router, router))
|
||||||
|
continue;
|
||||||
|
|
||||||
free(set_remove(link->ndisc_dnssl, dnssl));
|
free(set_remove(link->ndisc_dnssl, dnssl));
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
|
@ -1457,6 +1469,9 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) {
|
||||||
if (cp->lifetime_usec > timestamp_usec)
|
if (cp->lifetime_usec > timestamp_usec)
|
||||||
continue; /* the captive portal is still valid */
|
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));
|
ndisc_captive_portal_free(set_remove(link->ndisc_captive_portals, cp));
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
|
@ -1465,6 +1480,9 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) {
|
||||||
if (p64->lifetime_usec > timestamp_usec)
|
if (p64->lifetime_usec > timestamp_usec)
|
||||||
continue; /* the pref64 prefix is still valid */
|
continue; /* the pref64 prefix is still valid */
|
||||||
|
|
||||||
|
if (router && !in6_addr_equal(&p64->router, router))
|
||||||
|
continue;
|
||||||
|
|
||||||
free(set_remove(link->ndisc_pref64, p64));
|
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 pref64 prefix is not exported through the state file, hence it is not necessary to set
|
||||||
* the 'updated' flag. */
|
* 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);
|
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);
|
(void) ndisc_setup_expire(link);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1635,7 +1653,7 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = ndisc_drop_outdated(link, timestamp_usec);
|
r = ndisc_drop_outdated(link, /* router = */ NULL, timestamp_usec);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1679,6 +1697,131 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||||
return 0;
|
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) {
|
static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata) {
|
||||||
Link *link = ASSERT_PTR(userdata);
|
Link *link = ASSERT_PTR(userdata);
|
||||||
int r;
|
int r;
|
||||||
|
@ -1696,6 +1839,14 @@ static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, void *message, v
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case SD_NDISC_EVENT_TIMEOUT:
|
||||||
log_link_debug(link, "NDisc handler get timeout event");
|
log_link_debug(link, "NDisc handler get timeout event");
|
||||||
if (link->ndisc_messages == 0) {
|
if (link->ndisc_messages == 0) {
|
||||||
|
@ -1825,7 +1976,7 @@ void ndisc_flush(Link *link) {
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
/* Remove all addresses, routes, RDNSS, DNSSL, and Captive Portal entries, without exception. */
|
/* 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_rdnss = set_free(link->ndisc_rdnss);
|
||||||
link->ndisc_dnssl = set_free(link->ndisc_dnssl);
|
link->ndisc_dnssl = set_free(link->ndisc_dnssl);
|
||||||
|
|
|
@ -6,3 +6,5 @@ Name=veth-peer
|
||||||
IPv6AcceptRA=no
|
IPv6AcceptRA=no
|
||||||
Address=2600::1/0
|
Address=2600::1/0
|
||||||
Address=192.168.5.1/24
|
Address=192.168.5.1/24
|
||||||
|
# To make the kernel send NA with IsRouter flag.
|
||||||
|
IPv6Forwarding=yes
|
||||||
|
|
Loading…
Reference in a new issue