From ca34b434812f30989aa7d181e7e433815cb70dda Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 14 Feb 2024 18:11:06 +0900 Subject: [PATCH 1/7] sd-ndisc: split sd-ndisc.h into small pieces --- src/libsystemd-network/meson.build | 2 +- ...ndisc-router.h => ndisc-router-internal.h} | 0 .../{ndisc-router.c => sd-ndisc-router.c} | 2 +- src/libsystemd-network/sd-ndisc.c | 2 +- src/systemd/meson.build | 2 + src/systemd/sd-ndisc-protocol.h | 50 ++++++++++ src/systemd/sd-ndisc-router.h | 94 +++++++++++++++++++ src/systemd/sd-ndisc.h | 87 +---------------- 8 files changed, 152 insertions(+), 87 deletions(-) rename src/libsystemd-network/{ndisc-router.h => ndisc-router-internal.h} (100%) rename src/libsystemd-network/{ndisc-router.c => sd-ndisc-router.c} (99%) create mode 100644 src/systemd/sd-ndisc-protocol.h create mode 100644 src/systemd/sd-ndisc-router.h diff --git a/src/libsystemd-network/meson.build b/src/libsystemd-network/meson.build index 277935296f..301a4d5c5c 100644 --- a/src/libsystemd-network/meson.build +++ b/src/libsystemd-network/meson.build @@ -12,7 +12,6 @@ sources = files( 'lldp-neighbor.c', 'lldp-network.c', 'ndisc-protocol.c', - 'ndisc-router.c', 'network-common.c', 'network-internal.c', 'sd-dhcp-client-id.c', @@ -28,6 +27,7 @@ sources = files( 'sd-lldp-rx.c', 'sd-lldp-tx.c', 'sd-ndisc.c', + 'sd-ndisc-router.c', 'sd-radv.c', ) diff --git a/src/libsystemd-network/ndisc-router.h b/src/libsystemd-network/ndisc-router-internal.h similarity index 100% rename from src/libsystemd-network/ndisc-router.h rename to src/libsystemd-network/ndisc-router-internal.h diff --git a/src/libsystemd-network/ndisc-router.c b/src/libsystemd-network/sd-ndisc-router.c similarity index 99% rename from src/libsystemd-network/ndisc-router.c rename to src/libsystemd-network/sd-ndisc-router.c index e50a0b966b..fa22368c8f 100644 --- a/src/libsystemd-network/ndisc-router.c +++ b/src/libsystemd-network/sd-ndisc-router.c @@ -15,7 +15,7 @@ #include "missing_network.h" #include "ndisc-internal.h" #include "ndisc-protocol.h" -#include "ndisc-router.h" +#include "ndisc-router-internal.h" #include "strv.h" DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router, sd_ndisc_router, mfree); diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 1beed5d0ce..fe81794e3d 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -15,7 +15,7 @@ #include "in-addr-util.h" #include "memory-util.h" #include "ndisc-internal.h" -#include "ndisc-router.h" +#include "ndisc-router-internal.h" #include "network-common.h" #include "random-util.h" #include "socket-util.h" diff --git a/src/systemd/meson.build b/src/systemd/meson.build index 76d87cc9d4..d50edb413f 100644 --- a/src/systemd/meson.build +++ b/src/systemd/meson.build @@ -38,6 +38,8 @@ _not_installed_headers = [ 'sd-lldp-tx.h', 'sd-lldp.h', 'sd-ndisc.h', + 'sd-ndisc-protocol.h', + 'sd-ndisc-router.h', 'sd-netlink.h', 'sd-network.h', 'sd-radv.h', diff --git a/src/systemd/sd-ndisc-protocol.h b/src/systemd/sd-ndisc-protocol.h new file mode 100644 index 0000000000..93c5d20861 --- /dev/null +++ b/src/systemd/sd-ndisc-protocol.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#ifndef foosdndiscprotocolfoo +#define foosdndiscprotocolfoo + +/*** + Copyright © 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +/* Neighbor Discovery Options, RFC 4861, Section 4.6 and + * https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */ +enum { + SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1, + SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2, + SD_NDISC_OPTION_PREFIX_INFORMATION = 3, + SD_NDISC_OPTION_MTU = 5, + SD_NDISC_OPTION_ROUTE_INFORMATION = 24, + SD_NDISC_OPTION_RDNSS = 25, + SD_NDISC_OPTION_FLAGS_EXTENSION = 26, + SD_NDISC_OPTION_DNSSL = 31, + SD_NDISC_OPTION_CAPTIVE_PORTAL = 37, + SD_NDISC_OPTION_PREF64 = 38 +}; + +/* Route preference, RFC 4191, Section 2.1 */ +enum { + SD_NDISC_PREFERENCE_LOW = 3U, + SD_NDISC_PREFERENCE_MEDIUM = 0U, + SD_NDISC_PREFERENCE_HIGH = 1U +}; + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-ndisc-router.h b/src/systemd/sd-ndisc-router.h new file mode 100644 index 0000000000..1445939b1d --- /dev/null +++ b/src/systemd/sd-ndisc-router.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#ifndef foosdndiscrouterfoo +#define foosdndiscrouterfoo + +/*** + Copyright © 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +typedef struct sd_ndisc_router sd_ndisc_router; + +sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt); +sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref); + +int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret); +int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); +int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size); + +int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret); +int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret); +int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret); +int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret); +int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret); +int sd_ndisc_router_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); +int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret); +int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret); + +/* Generic option access */ +int sd_ndisc_router_option_rewind(sd_ndisc_router *rt); +int sd_ndisc_router_option_next(sd_ndisc_router *rt); +int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret); +int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type); +int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size); + +/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */ +int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint64_t *ret); +int sd_ndisc_router_prefix_get_valid_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); +int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint64_t *ret); +int sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); +int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret); +int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret); +int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret); + +/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */ +int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint64_t *ret); +int sd_ndisc_router_route_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); +int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret); +int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret); +int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret); + +/* Specific option access: SD_NDISC_OPTION_RDNSS */ +int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret); +int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint64_t *ret); +int sd_ndisc_router_rdnss_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); + +/* Specific option access: SD_NDISC_OPTION_DNSSL */ +int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret); +int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint64_t *ret); +int sd_ndisc_router_dnssl_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); + +/* Specific option access: SD_NDISC_OPTION_CAPTIVE_PORTAL */ +int sd_ndisc_router_captive_portal_get_uri(sd_ndisc_router *rt, const char **ret, size_t *ret_size); + +/* Specific option access: SD_NDISC_OPTION_PREF64 */ +int sd_ndisc_router_prefix64_get_prefix(sd_ndisc_router *rt, struct in6_addr *ret); +int sd_ndisc_router_prefix64_get_prefixlen(sd_ndisc_router *rt, unsigned *ret); +int sd_ndisc_router_prefix64_get_lifetime(sd_ndisc_router *rt, uint64_t *ret); +int sd_ndisc_router_prefix64_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h index a5ccd5f644..c348e505ed 100644 --- a/src/systemd/sd-ndisc.h +++ b/src/systemd/sd-ndisc.h @@ -26,35 +26,14 @@ #include #include "sd-event.h" +#include "sd-ndisc-protocol.h" +#include "sd-ndisc-router.h" #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; -/* Neighbor Discovery Options, RFC 4861, Section 4.6 and - * https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */ -enum { - SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1, - SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2, - SD_NDISC_OPTION_PREFIX_INFORMATION = 3, - SD_NDISC_OPTION_MTU = 5, - SD_NDISC_OPTION_ROUTE_INFORMATION = 24, - SD_NDISC_OPTION_RDNSS = 25, - SD_NDISC_OPTION_FLAGS_EXTENSION = 26, - SD_NDISC_OPTION_DNSSL = 31, - SD_NDISC_OPTION_CAPTIVE_PORTAL = 37, - SD_NDISC_OPTION_PREF64 = 38 -}; - -/* Route preference, RFC 4191, Section 2.1 */ -enum { - SD_NDISC_PREFERENCE_LOW = 3U, - SD_NDISC_PREFERENCE_MEDIUM = 0U, - SD_NDISC_PREFERENCE_HIGH = 1U -}; - typedef struct sd_ndisc sd_ndisc; -typedef struct sd_ndisc_router sd_ndisc_router; __extension__ typedef enum sd_ndisc_event_t { SD_NDISC_EVENT_TIMEOUT, @@ -69,6 +48,7 @@ typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndi int sd_ndisc_new(sd_ndisc **ret); sd_ndisc *sd_ndisc_ref(sd_ndisc *nd); sd_ndisc *sd_ndisc_unref(sd_ndisc *nd); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref); int sd_ndisc_start(sd_ndisc *nd); int sd_ndisc_stop(sd_ndisc *nd); @@ -83,67 +63,6 @@ int sd_ndisc_set_ifname(sd_ndisc *nd, const char *interface_name); int sd_ndisc_get_ifname(sd_ndisc *nd, const char **ret); int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); -sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt); -sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt); - -int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret); -int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); -int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size); - -int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret); -int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret); -int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret); -int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret); -int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret); -int sd_ndisc_router_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); -int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret); -int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret); - -/* Generic option access */ -int sd_ndisc_router_option_rewind(sd_ndisc_router *rt); -int sd_ndisc_router_option_next(sd_ndisc_router *rt); -int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret); -int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type); -int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size); - -/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */ -int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint64_t *ret); -int sd_ndisc_router_prefix_get_valid_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); -int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint64_t *ret); -int sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); -int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret); -int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret); -int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret); - -/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */ -int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint64_t *ret); -int sd_ndisc_router_route_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); -int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret); -int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret); -int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret); - -/* Specific option access: SD_NDISC_OPTION_RDNSS */ -int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret); -int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint64_t *ret); -int sd_ndisc_router_rdnss_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); - -/* Specific option access: SD_NDISC_OPTION_DNSSL */ -int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret); -int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint64_t *ret); -int sd_ndisc_router_dnssl_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); - -/* Specific option access: SD_NDISC_OPTION_CAPTIVE_PORTAL */ -int sd_ndisc_router_captive_portal_get_uri(sd_ndisc_router *rt, const char **ret, size_t *ret_size); - -/* Specific option access: SD_NDISC_OPTION_PREF64 */ -int sd_ndisc_router_prefix64_get_prefix(sd_ndisc_router *rt, struct in6_addr *ret); -int sd_ndisc_router_prefix64_get_prefixlen(sd_ndisc_router *rt, unsigned *ret); -int sd_ndisc_router_prefix64_get_lifetime(sd_ndisc_router *rt, uint64_t *ret); -int sd_ndisc_router_prefix64_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref); -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref); - _SD_END_DECLARATIONS; #endif From 787e71e432abf6134257875ba3bee55b1c747a29 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 14 Feb 2024 15:43:27 +0900 Subject: [PATCH 2/7] sd-ndisc: introduce sd_ndisc_is_running() --- src/libsystemd-network/sd-ndisc.c | 17 ++++++++++++----- src/systemd/sd-ndisc.h | 1 + 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index fe81794e3d..0b5626670b 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -42,6 +42,13 @@ static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event_t event, sd_ndisc_rou ndisc->callback(ndisc, event, rt, ndisc->userdata); } +int sd_ndisc_is_running(sd_ndisc *nd) { + if (!nd) + return false; + + return sd_event_source_get_enabled(nd->recv_event_source, NULL) > 0; +} + int sd_ndisc_set_callback( sd_ndisc *nd, sd_ndisc_callback_t callback, @@ -58,7 +65,7 @@ int sd_ndisc_set_callback( int sd_ndisc_set_ifindex(sd_ndisc *nd, int ifindex) { assert_return(nd, -EINVAL); assert_return(ifindex > 0, -EINVAL); - assert_return(nd->fd < 0, -EBUSY); + assert_return(!sd_ndisc_is_running(nd), -EBUSY); nd->ifindex = ifindex; return 0; @@ -104,7 +111,7 @@ int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) { int r; assert_return(nd, -EINVAL); - assert_return(nd->fd < 0, -EBUSY); + assert_return(!sd_ndisc_is_running(nd), -EBUSY); assert_return(!nd->event, -EBUSY); if (event) @@ -123,7 +130,7 @@ int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) { int sd_ndisc_detach_event(sd_ndisc *nd) { assert_return(nd, -EINVAL); - assert_return(nd->fd < 0, -EBUSY); + assert_return(!sd_ndisc_is_running(nd), -EBUSY); nd->event = sd_event_unref(nd->event); return 0; @@ -316,7 +323,7 @@ int sd_ndisc_stop(sd_ndisc *nd) { if (!nd) return 0; - if (nd->fd < 0) + if (!sd_ndisc_is_running(nd)) return 0; log_ndisc(nd, "Stopping IPv6 Router Solicitation client"); @@ -333,7 +340,7 @@ int sd_ndisc_start(sd_ndisc *nd) { assert_return(nd->event, -EINVAL); assert_return(nd->ifindex > 0, -EINVAL); - if (nd->fd >= 0) + if (sd_ndisc_is_running(nd)) return 0; assert(!nd->recv_event_source); diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h index c348e505ed..1bc7c73889 100644 --- a/src/systemd/sd-ndisc.h +++ b/src/systemd/sd-ndisc.h @@ -52,6 +52,7 @@ _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref); int sd_ndisc_start(sd_ndisc *nd); int sd_ndisc_stop(sd_ndisc *nd); +int sd_ndisc_is_running(sd_ndisc *nd); int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority); int sd_ndisc_detach_event(sd_ndisc *nd); From 828b5dbf2ff7a31816da66b6b1196b41e04c3fa1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 19 Feb 2024 10:00:33 +0900 Subject: [PATCH 3/7] sd-ndisc: allow to call sd_ndisc_router_get_lifetime() with NULL for 'ret' --- src/libsystemd-network/sd-ndisc-router.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libsystemd-network/sd-ndisc-router.c b/src/libsystemd-network/sd-ndisc-router.c index fa22368c8f..536ee8cdf2 100644 --- a/src/libsystemd-network/sd-ndisc-router.c +++ b/src/libsystemd-network/sd-ndisc-router.c @@ -303,10 +303,11 @@ int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret) { int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret) { assert_return(rt, -EINVAL); - assert_return(ret, -EINVAL); - *ret = rt->lifetime_usec; - return 0; + if (ret) + *ret = rt->lifetime_usec; + + return rt->lifetime_usec > 0; /* Indicate if the router is still valid or not. */ } int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret) { From 479d3e1994a2e4ff7070dc2a0cb1615af7120b0c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 19 Feb 2024 10:35:48 +0900 Subject: [PATCH 4/7] network/ndisc: drop configurations when received RA with zero lifetime --- src/network/networkd-ndisc.c | 127 +++++++++++++++++++++++++++++------ 1 file changed, 108 insertions(+), 19 deletions(-) diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index f9fb7e207b..bf67cb63bf 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -273,6 +273,39 @@ static int ndisc_request_route(Route *route, Link *link, sd_ndisc_router *rt) { return 0; } +static int ndisc_remove_route(Route *route, Link *link) { + int r; + + assert(route); + assert(link); + assert(link->manager); + + ndisc_set_route_priority(link, route); + + if (!route->table_set) + route->table = link_get_ipv6_accept_ra_route_table(link); + + r = route_adjust_nexthops(route, link); + if (r < 0) + return r; + + if (route->pref_set) { + ndisc_set_route_priority(link, route); + return route_remove_and_cancel(route, link->manager); + } + + uint8_t pref; + FOREACH_ARGUMENT(pref, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_MEDIUM, SD_NDISC_PREFERENCE_HIGH) { + route->pref = pref; + ndisc_set_route_priority(link, route); + r = route_remove_and_cancel(route, link->manager); + if (r < 0) + return r; + } + + return 0; +} + static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) { int r; @@ -340,6 +373,55 @@ static int ndisc_request_address(Address *address, Link *link, sd_ndisc_router * return 0; } +static int ndisc_router_drop_default(Link *link, sd_ndisc_router *rt) { + _cleanup_(route_unrefp) Route *route = NULL; + struct in6_addr gateway; + int r; + + assert(link); + assert(link->network); + assert(rt); + + r = sd_ndisc_router_get_address(rt, &gateway); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to get router address from RA: %m"); + + r = route_new(&route); + if (r < 0) + return log_oom(); + + route->family = AF_INET6; + route->nexthop.family = AF_INET6; + route->nexthop.gw.in6 = gateway; + + r = ndisc_remove_route(route, link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to remove the default gateway configured by RA: %m"); + + Route *route_gw; + HASHMAP_FOREACH(route_gw, link->network->routes_by_section) { + _cleanup_(route_unrefp) Route *tmp = NULL; + + if (!route_gw->gateway_from_dhcp_or_ra) + continue; + + if (route_gw->nexthop.family != AF_INET6) + continue; + + r = route_dup(route_gw, NULL, &tmp); + if (r < 0) + return r; + + tmp->nexthop.gw.in6 = gateway; + + r = ndisc_remove_route(tmp, link); + if (r < 0) + return log_link_warning_errno(link, r, "Could not remove semi-static gateway: %m"); + } + + return 0; +} + static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { usec_t lifetime_usec; struct in6_addr gateway; @@ -350,6 +432,13 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { assert(link->network); assert(rt); + /* If the router lifetime is zero, the router should not be used as the default gateway. */ + r = sd_ndisc_router_get_lifetime(rt, NULL); + if (r < 0) + return r; + if (r == 0) + return ndisc_router_drop_default(link, rt); + if (!link->network->ipv6_accept_ra_use_gateway && hashmap_isempty(link->network->routes_by_section)) return 0; @@ -578,9 +667,22 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r address->lifetime_valid_usec = lifetime_valid_usec; address->lifetime_preferred_usec = lifetime_preferred_usec; - r = ndisc_request_address(address, link, rt); - if (r < 0) - return log_link_warning_errno(link, r, "Could not request SLAAC address: %m"); + /* draft-ietf-6man-slaac-renum-07 section 4.2 + * https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-07#section-4.2 + * + * If the advertised prefix is equal to the prefix of an address configured by stateless + * autoconfiguration in the list, the valid lifetime and the preferred lifetime of the + * address should be updated by processing the Valid Lifetime and the Preferred Lifetime + * (respectively) in the received advertisement. */ + if (lifetime_valid_usec == 0) { + r = address_remove_and_cancel(address, link); + if (r < 0) + return log_link_warning_errno(link, r, "Could not remove SLAAC address: %m"); + } else { + r = ndisc_request_address(address, link, rt); + if (r < 0) + return log_link_warning_errno(link, r, "Could not request SLAAC address: %m"); + } } return 0; @@ -636,7 +738,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) { static int ndisc_router_drop_onlink_prefix(Link *link, sd_ndisc_router *rt) { _cleanup_(route_unrefp) Route *route = NULL; - unsigned prefixlen, preference; + unsigned prefixlen; struct in6_addr prefix; usec_t lifetime_usec; int r; @@ -669,11 +771,6 @@ static int ndisc_router_drop_onlink_prefix(Link *link, sd_ndisc_router *rt) { if (r < 0) return log_link_warning_errno(link, r, "Failed to get prefix length: %m"); - /* Prefix Information option does not have preference, hence we use the 'main' preference here */ - r = sd_ndisc_router_get_preference(rt, &preference); - if (r < 0) - return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m"); - r = route_new(&route); if (r < 0) return log_oom(); @@ -681,16 +778,8 @@ static int ndisc_router_drop_onlink_prefix(Link *link, sd_ndisc_router *rt) { route->family = AF_INET6; route->dst.in6 = prefix; route->dst_prefixlen = prefixlen; - route->table = link_get_ipv6_accept_ra_route_table(link); - route->pref = preference; - ndisc_set_route_priority(link, route); - route->protocol = RTPROT_RA; - r = route_adjust_nexthops(route, link); - if (r < 0) - return r; - - r = route_remove_and_cancel(route, link->manager); + r = ndisc_remove_route(route, link); if (r < 0) return log_link_warning_errno(link, r, "Could not remove prefix route: %m"); @@ -715,7 +804,7 @@ static int ndisc_router_process_prefix(Link *link, sd_ndisc_router *rt) { * A router SHOULD NOT send a prefix option for the link-local prefix and a host SHOULD ignore such * a prefix option. */ if (in6_addr_is_link_local(&a)) { - log_link_debug(link, "Received link-local prefix, ignoring autonomous prefix."); + log_link_debug(link, "Received link-local prefix, ignoring prefix."); return 0; } From ffef01acddcac27caaef02f7f28bff03d7799e5e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 19 Feb 2024 10:37:23 +0900 Subject: [PATCH 5/7] network/ndisc: ignore most fields of RA header when lifetime is zero --- src/network/networkd-ndisc.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index bf67cb63bf..99271aa3fd 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -518,6 +518,11 @@ static int ndisc_router_process_icmp6_ratelimit(Link *link, sd_ndisc_router *rt) if (!link->network->ipv6_accept_ra_use_icmp6_ratelimit) return 0; + /* Ignore the icmp6 ratelimit field of the RA header if the lifetime is zero. */ + r = sd_ndisc_router_get_lifetime(rt, NULL); + if (r <= 0) + return r; + r = sd_ndisc_router_get_icmp6_ratelimit(rt, &icmp6_ratelimit); if (r < 0) return log_link_warning_errno(link, r, "Failed to get ICMP6 ratelimit from RA: %m"); @@ -550,6 +555,11 @@ static int ndisc_router_process_retransmission_time(Link *link, sd_ndisc_router if (!link->network->ipv6_accept_ra_use_retransmission_time) return 0; + /* Ignore the retransmission time field of the RA header if the lifetime is zero. */ + r = sd_ndisc_router_get_lifetime(rt, NULL); + if (r <= 0) + return r; + r = sd_ndisc_router_get_retransmission_time(rt, &retrans_time); if (r < 0) return log_link_warning_errno(link, r, "Failed to get retransmission time from RA: %m"); @@ -567,8 +577,7 @@ static int ndisc_router_process_retransmission_time(Link *link, sd_ndisc_router /* Set the retransmission time for Neighbor Solicitations. */ r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", (uint32_t) msec); if (r < 0) - log_link_warning_errno( - link, r, "Failed to apply neighbor retransmission time (%"PRIu64"), ignoring: %m", msec); + log_link_warning_errno(link, r, "Failed to apply neighbor retransmission time (%"PRIu64"), ignoring: %m", msec); return 0; } @@ -584,6 +593,11 @@ static int ndisc_router_process_hop_limit(Link *link, sd_ndisc_router *rt) { if (!link->network->ipv6_accept_ra_use_hop_limit) return 0; + /* Ignore the hop limit field of the RA header if the lifetime is zero. */ + r = sd_ndisc_router_get_lifetime(rt, NULL); + if (r <= 0) + return r; + r = sd_ndisc_router_get_hop_limit(rt, &hop_limit); if (r < 0) return log_link_warning_errno(link, r, "Failed to get hop limit from RA: %m"); @@ -1551,6 +1565,12 @@ static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) { assert(link); assert(link->network); + /* Do not start DHCPv6 client if the router lifetime is zero, as the message sent as a signal of + * that the router is e.g. shutting down, revoked, etc,. */ + r = sd_ndisc_router_get_lifetime(rt, NULL); + if (r <= 0) + return r; + switch (link->network->ipv6_accept_ra_start_dhcp6_client) { case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO: return 0; From a68f007a23607ce182556d7673899c7fd9a16362 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 20 Feb 2024 15:10:59 +0900 Subject: [PATCH 6/7] sd-ndisc: introduce sd_ndisc_router_get_reachable_time() --- src/libsystemd-network/ndisc-router-internal.h | 1 + src/libsystemd-network/sd-ndisc-router.c | 9 +++++++++ src/systemd/sd-ndisc-router.h | 1 + 3 files changed, 11 insertions(+) diff --git a/src/libsystemd-network/ndisc-router-internal.h b/src/libsystemd-network/ndisc-router-internal.h index 63d4f90ba9..5bd9a65dd2 100644 --- a/src/libsystemd-network/ndisc-router-internal.h +++ b/src/libsystemd-network/ndisc-router-internal.h @@ -24,6 +24,7 @@ struct sd_ndisc_router { uint64_t flags; unsigned preference; uint64_t lifetime_usec; + usec_t reachable_time_usec; usec_t retransmission_time_usec; uint8_t hop_limit; diff --git a/src/libsystemd-network/sd-ndisc-router.c b/src/libsystemd-network/sd-ndisc-router.c index 536ee8cdf2..b90fb77cd8 100644 --- a/src/libsystemd-network/sd-ndisc-router.c +++ b/src/libsystemd-network/sd-ndisc-router.c @@ -145,6 +145,7 @@ int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) { rt->flags = a->nd_ra_flags_reserved; /* the first 8 bits */ rt->lifetime_usec = be16_sec_to_usec(a->nd_ra_router_lifetime, /* max_as_infinity = */ false); rt->icmp6_ratelimit_usec = be32_msec_to_usec(a->nd_ra_retransmit, /* max_as_infinity = */ false); + rt->reachable_time_usec = be32_msec_to_usec(a->nd_ra_reachable, /* mas_as_infinity = */ false); rt->retransmission_time_usec = be32_msec_to_usec(a->nd_ra_retransmit, /* max_as_infinity = */ false); rt->preference = (rt->flags >> 3) & 3; @@ -277,6 +278,14 @@ int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) { return 0; } +int sd_ndisc_router_get_reachable_time(sd_ndisc_router *rt, uint64_t *ret) { + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + *ret = rt->reachable_time_usec; + return 0; +} + int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret) { assert_return(rt, -EINVAL); assert_return(ret, -EINVAL); diff --git a/src/systemd/sd-ndisc-router.h b/src/systemd/sd-ndisc-router.h index 1445939b1d..7f1a0229e8 100644 --- a/src/systemd/sd-ndisc-router.h +++ b/src/systemd/sd-ndisc-router.h @@ -44,6 +44,7 @@ int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret); int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret); int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret); int sd_ndisc_router_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); +int sd_ndisc_router_get_reachable_time(sd_ndisc_router *rt, uint64_t *ret); int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret); int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret); From 1452d49741e8ba2a01ec34240f6af84ebb9d358c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 20 Feb 2024 15:24:09 +0900 Subject: [PATCH 7/7] network/ndisc: set IPv6 neighbor reachable time Closes #31402. --- man/systemd.network.xml | 11 +++++++ src/network/networkd-ndisc.c | 42 ++++++++++++++++++++++++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.c | 1 + src/network/networkd-network.h | 1 + 5 files changed, 56 insertions(+) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index b739e709f5..32de0ce844 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -3347,6 +3347,17 @@ Token=prefixstable:2002:da8:1:: + + UseReachableTime= + + Takes a boolean. When true, the reachable time received in the Router Advertisement will be + set on the interface receiving the advertisement. It is used as the base timespan of the validity + of a neighbor entry. Defaults to true. + + + + + UseRetransmissionTime= diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 99271aa3fd..d110482c00 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -544,6 +544,44 @@ static int ndisc_router_process_icmp6_ratelimit(Link *link, sd_ndisc_router *rt) return 0; } +static int ndisc_router_process_reachable_time(Link *link, sd_ndisc_router *rt) { + usec_t reachable_time, msec; + int r; + + assert(link); + assert(link->network); + assert(rt); + + if (!link->network->ipv6_accept_ra_use_reachable_time) + return 0; + + /* Ignore the reachable time field of the RA header if the lifetime is zero. */ + r = sd_ndisc_router_get_lifetime(rt, NULL); + if (r <= 0) + return r; + + r = sd_ndisc_router_get_reachable_time(rt, &reachable_time); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to get reachable time from RA: %m"); + + /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */ + if (!timestamp_is_set(reachable_time)) + return 0; + + msec = DIV_ROUND_UP(reachable_time, USEC_PER_MSEC); + if (msec <= 0 || msec > UINT32_MAX) { + log_link_debug(link, "Failed to get reachable time from RA - out of range (%"PRIu64"), ignoring", msec); + return 0; + } + + /* Set the reachable time for Neighbor Solicitations. */ + r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "base_reachable_time_ms", (uint32_t) msec); + if (r < 0) + log_link_warning_errno(link, r, "Failed to apply neighbor reachable time (%"PRIu64"), ignoring: %m", msec); + + return 0; +} + static int ndisc_router_process_retransmission_time(Link *link, sd_ndisc_router *rt) { usec_t retrans_time, msec; int r; @@ -1660,6 +1698,10 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) { if (r < 0) return r; + r = ndisc_router_process_reachable_time(link, rt); + if (r < 0) + return r; + r = ndisc_router_process_retransmission_time(link, rt); if (r < 0) return r; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index ce37450938..a196da7f0f 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -298,6 +298,7 @@ IPv6AcceptRA.UseDNS, config_parse_bool, IPv6AcceptRA.UseDomains, config_parse_ipv6_accept_ra_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains) IPv6AcceptRA.UseMTU, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_mtu) IPv6AcceptRA.UseHopLimit, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_hop_limit) +IPv6AcceptRA.UseReachableTime, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_reachable_time) IPv6AcceptRA.UseRetransmissionTime, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_retransmission_time) IPv6AcceptRA.UseICMP6RateLimit, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_icmp6_ratelimit) IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_dhcp6_client, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 300fba5dd9..4101296275 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -483,6 +483,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .ipv6_accept_ra_use_onlink_prefix = true, .ipv6_accept_ra_use_mtu = true, .ipv6_accept_ra_use_hop_limit = true, + .ipv6_accept_ra_use_reachable_time = true, .ipv6_accept_ra_use_retransmission_time = true, .ipv6_accept_ra_use_icmp6_ratelimit = true, .ipv6_accept_ra_route_table = RT_TABLE_MAIN, diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 3ab115c3b9..270ffd87a3 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -342,6 +342,7 @@ struct Network { bool ipv6_accept_ra_use_onlink_prefix; bool ipv6_accept_ra_use_mtu; bool ipv6_accept_ra_use_hop_limit; + bool ipv6_accept_ra_use_reachable_time; bool ipv6_accept_ra_use_retransmission_time; bool ipv6_accept_ra_use_icmp6_ratelimit; bool ipv6_accept_ra_quickack;