diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/meson.build | 2 | ||||
-rw-r--r-- | src/network/networkd-address-generation.c | 11 | ||||
-rw-r--r-- | src/network/networkd-dhcp-common.c | 2 | ||||
-rw-r--r-- | src/network/networkd-dhcp4-bus.c | 78 | ||||
-rw-r--r-- | src/network/networkd-dhcp4-bus.h | 10 | ||||
-rw-r--r-- | src/network/networkd-dhcp4.c | 5 | ||||
-rw-r--r-- | src/network/networkd-dhcp6-bus.c | 76 | ||||
-rw-r--r-- | src/network/networkd-dhcp6-bus.h | 10 | ||||
-rw-r--r-- | src/network/networkd-dhcp6.c | 6 | ||||
-rw-r--r-- | src/network/networkd-json.c | 32 | ||||
-rw-r--r-- | src/network/networkd-link-bus.c | 6 | ||||
-rw-r--r-- | src/network/networkd-link.h | 1 | ||||
-rw-r--r-- | src/network/networkd-manager-bus.c | 5 | ||||
-rw-r--r-- | src/network/networkd-ndisc.c | 168 | ||||
-rw-r--r-- | src/network/networkd-ndisc.h | 9 | ||||
-rw-r--r-- | src/network/networkd-network-gperf.gperf | 4 | ||||
-rw-r--r-- | src/network/networkd-network.h | 5 | ||||
-rw-r--r-- | src/network/networkd-radv.c | 56 | ||||
-rw-r--r-- | src/network/networkd-radv.h | 1 |
19 files changed, 440 insertions, 47 deletions
diff --git a/src/network/meson.build b/src/network/meson.build index 7d0e5d6345..2ca9eac714 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -43,7 +43,9 @@ sources = files( 'networkd-dhcp-server-bus.c', 'networkd-dhcp-server-static-lease.c', 'networkd-dhcp-server.c', + 'networkd-dhcp4-bus.c', 'networkd-dhcp4.c', + 'networkd-dhcp6-bus.c', 'networkd-dhcp6.c', 'networkd-ipv4acd.c', 'networkd-ipv4ll.c', diff --git a/src/network/networkd-address-generation.c b/src/network/networkd-address-generation.c index 769cccf748..79fde024a3 100644 --- a/src/network/networkd-address-generation.c +++ b/src/network/networkd-address-generation.c @@ -370,16 +370,11 @@ int config_parse_address_generation_type( } if (comma) { - r = sd_id128_from_string(comma + 1, &secret_key); + r = id128_from_string_nonzero(comma + 1, &secret_key); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to parse secret key in %s=, ignoring assignment: %s", - lvalue, rvalue); - return 0; - } - if (sd_id128_is_null(secret_key)) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "Secret key in %s= cannot be null, ignoring assignment: %s", + r == -ENXIO ? "Secret key in %s= cannot be null, ignoring assignment: %s" + : "Failed to parse secret key in %s=, ignoring assignment: %s", lvalue, rvalue); return 0; } diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 5b5b251e61..ff0ee717c5 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -6,7 +6,7 @@ #include "bus-error.h" #include "bus-locator.h" #include "dhcp-identifier.h" -#include "dhcp-internal.h" +#include "dhcp-client-internal.h" #include "dhcp6-internal.h" #include "escape.h" #include "hexdecoct.h" diff --git a/src/network/networkd-dhcp4-bus.c b/src/network/networkd-dhcp4-bus.c new file mode 100644 index 0000000000..cb88627d20 --- /dev/null +++ b/src/network/networkd-dhcp4-bus.c @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "sd-dhcp-client.h" + +#include "alloc-util.h" +#include "bus-common-errors.h" +#include "bus-util.h" +#include "dhcp-client-internal.h" +#include "dhcp-protocol.h" +#include "networkd-dhcp4-bus.h" +#include "networkd-link-bus.h" +#include "networkd-manager.h" +#include "string-table.h" +#include "strv.h" + +static int property_get_dhcp_client_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Link *l = ASSERT_PTR(userdata); + sd_dhcp_client *c; + + assert(reply); + + c = l->dhcp_client; + if (!c) + return sd_bus_message_append(reply, "s", "disabled"); + + return sd_bus_message_append(reply, "s", dhcp_state_to_string(dhcp_client_get_state(c))); +} + +static int dhcp_client_emit_changed(Link *link, const char *property, ...) { + _cleanup_free_ char *path = NULL; + char **l; + + assert(link); + + if (sd_bus_is_ready(link->manager->bus) <= 0) + return 0; + + path = link_bus_path(link); + if (!path) + return log_oom(); + + l = strv_from_stdarg_alloca(property); + + return sd_bus_emit_properties_changed_strv( + link->manager->bus, + path, + "org.freedesktop.network1.DHCPv4Client", + l); +} + +int dhcp_client_callback_bus(sd_dhcp_client *c, int event, void *userdata) { + Link *l = ASSERT_PTR(userdata); + + return dhcp_client_emit_changed(l, "State", NULL); +} + +static const sd_bus_vtable dhcp_client_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("State", "s", property_get_dhcp_client_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + + SD_BUS_VTABLE_END +}; + +const BusObjectImplementation dhcp_client_object = { + "/org/freedesktop/network1/link", + "org.freedesktop.network1.DHCPv4Client", + .fallback_vtables = BUS_FALLBACK_VTABLES({dhcp_client_vtable, link_object_find}), + .node_enumerator = link_node_enumerator, +}; diff --git a/src/network/networkd-dhcp4-bus.h b/src/network/networkd-dhcp4-bus.h new file mode 100644 index 0000000000..482e824c0a --- /dev/null +++ b/src/network/networkd-dhcp4-bus.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "sd-dhcp-client.h" + +#include "networkd-link-bus.h" + +extern const BusObjectImplementation dhcp_client_object; + +int dhcp_client_callback_bus(sd_dhcp_client *client, int event, void *userdata); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 9dcd37e11c..f952d6dfbc 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -13,6 +13,7 @@ #include "network-internal.h" #include "networkd-address.h" #include "networkd-dhcp-prefix-delegation.h" +#include "networkd-dhcp4-bus.h" #include "networkd-dhcp4.h" #include "networkd-ipv4acd.h" #include "networkd-link.h" @@ -1482,6 +1483,10 @@ static int dhcp4_configure(Link *link) { if (r < 0) return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for broadcast: %m"); + r = dhcp_client_set_state_callback(link->dhcp_client, dhcp_client_callback_bus, link); + if (r < 0) + return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set state change callback: %m"); + if (link->mtu > 0) { r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu); if (r < 0) diff --git a/src/network/networkd-dhcp6-bus.c b/src/network/networkd-dhcp6-bus.c new file mode 100644 index 0000000000..a225877373 --- /dev/null +++ b/src/network/networkd-dhcp6-bus.c @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "bus-common-errors.h" +#include "bus-util.h" +#include "dhcp6-client-internal.h" +#include "dhcp6-protocol.h" +#include "networkd-dhcp6-bus.h" +#include "networkd-link-bus.h" +#include "networkd-manager.h" +#include "string-table.h" +#include "strv.h" + +static int property_get_dhcp6_client_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Link *l = ASSERT_PTR(userdata); + sd_dhcp6_client *c; + + assert(reply); + + c = l->dhcp6_client; + if (!c) + return sd_bus_message_append(reply, "s", "disabled"); + + return sd_bus_message_append(reply, "s", dhcp6_state_to_string(dhcp6_client_get_state(c))); +} + +static int dhcp6_client_emit_changed(Link *link, const char *property, ...) { + _cleanup_free_ char *path = NULL; + char **l; + + assert(link); + + if (sd_bus_is_ready(link->manager->bus) <= 0) + return 0; + + path = link_bus_path(link); + if (!path) + return log_oom(); + + l = strv_from_stdarg_alloca(property); + + return sd_bus_emit_properties_changed_strv( + link->manager->bus, + path, + "org.freedesktop.network1.DHCPv6Client", + l); +} + +void dhcp6_client_callback_bus(sd_dhcp6_client *c, int event, void *userdata) { + Link *l = ASSERT_PTR(userdata); + + dhcp6_client_emit_changed(l, "State", NULL); +} + +static const sd_bus_vtable dhcp6_client_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("State", "s", property_get_dhcp6_client_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + + SD_BUS_VTABLE_END +}; + +const BusObjectImplementation dhcp6_client_object = { + "/org/freedesktop/network1/link", + "org.freedesktop.network1.DHCPv6Client", + .fallback_vtables = BUS_FALLBACK_VTABLES({dhcp6_client_vtable, link_object_find}), + .node_enumerator = link_node_enumerator, +}; diff --git a/src/network/networkd-dhcp6-bus.h b/src/network/networkd-dhcp6-bus.h new file mode 100644 index 0000000000..76a6b727aa --- /dev/null +++ b/src/network/networkd-dhcp6-bus.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "sd-dhcp6-client.h" + +#include "networkd-link-bus.h" + +extern const BusObjectImplementation dhcp6_client_object; + +void dhcp6_client_callback_bus(sd_dhcp6_client *client, int event, void *userdata); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 95b13ca93c..57e1087211 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -5,11 +5,13 @@ #include "sd-dhcp6-client.h" +#include "dhcp6-client-internal.h" #include "hashmap.h" #include "hostname-setup.h" #include "hostname-util.h" #include "networkd-address.h" #include "networkd-dhcp-prefix-delegation.h" +#include "networkd-dhcp6-bus.h" #include "networkd-dhcp6.h" #include "networkd-link.h" #include "networkd-manager.h" @@ -699,6 +701,10 @@ static int dhcp6_configure(Link *link) { if (r < 0) return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set callback: %m"); + r = dhcp6_client_set_state_callback(client, dhcp6_client_callback_bus, link); + if (r < 0) + return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set state change callback: %m"); + r = sd_dhcp6_client_set_prefix_delegation(client, link->network->dhcp6_use_pd_prefix); if (r < 0) return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to %s requesting prefixes to be delegated: %m", diff --git a/src/network/networkd-json.c b/src/network/networkd-json.c index 86488c9816..7c3639d245 100644 --- a/src/network/networkd-json.c +++ b/src/network/networkd-json.c @@ -922,6 +922,34 @@ static int captive_portal_append_json(Link *link, JsonVariant **v) { return json_variant_merge_objectb(v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_STRING("CaptivePortal", captive_portal))); } +static int pref64_append_json(Link *link, JsonVariant **v) { + _cleanup_(json_variant_unrefp) JsonVariant *array = NULL, *w = NULL; + NDiscPREF64 *i; + int r; + + assert(link); + assert(v); + + if (!link->network || !link->network->ipv6_accept_ra_use_pref64) + return 0; + + SET_FOREACH(i, link->ndisc_pref64) { + r = json_build(&array, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("Prefix", &i->prefix), + JSON_BUILD_PAIR_UNSIGNED("PrefixLength", i->prefix_len), + JSON_BUILD_PAIR_FINITE_USEC("LifetimeUSec", i->lifetime_usec), + JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("ConfigProvider", &i->router))); + if (r < 0) + return r; + } + + r = json_append_one(&w, "PREF64", array); + if (r < 0) + return r; + + return json_append_one(v, "NDisc", w); +} + static int dhcp_server_offered_leases_append_json(Link *link, JsonVariant **v) { _cleanup_(json_variant_unrefp) JsonVariant *array = NULL; DHCPLease *lease; @@ -1288,6 +1316,10 @@ int link_build_json(Link *link, JsonVariant **ret) { if (r < 0) return r; + r = pref64_append_json(link, &v); + if (r < 0) + return r; + r = addresses_append_json(link->addresses, &v); if (r < 0) return r; diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index e9c18f0fd0..0674930783 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -862,6 +862,12 @@ int link_object_find(sd_bus *bus, const char *path, const char *interface, void (!link->dhcp_server || sd_dhcp_server_is_in_relay_mode(link->dhcp_server))) return 0; + if (streq(interface, "org.freedesktop.network1.DHCPv4Client") && !link->dhcp_client) + return 0; + + if (streq(interface, "org.freedesktop.network1.DHCPv6Client") && !link->dhcp6_client) + return 0; + *found = link; return 1; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index e46e5f0c61..8ced02f3c1 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -157,6 +157,7 @@ typedef struct Link { Set *ndisc_rdnss; Set *ndisc_dnssl; Set *ndisc_captive_portals; + Set *ndisc_pref64; unsigned ndisc_messages; bool ndisc_configured:1; diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index 67f951df69..7813a3173a 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -9,6 +9,8 @@ #include "bus-message-util.h" #include "bus-polkit.h" #include "networkd-dhcp-server-bus.h" +#include "networkd-dhcp4-bus.h" +#include "networkd-dhcp6-bus.h" #include "networkd-json.h" #include "networkd-link-bus.h" #include "networkd-link.h" @@ -413,5 +415,6 @@ const BusObjectImplementation manager_object = { "/org/freedesktop/network1", "org.freedesktop.network1.Manager", .vtables = BUS_VTABLES(manager_vtable), - .children = BUS_IMPLEMENTATIONS(&dhcp_server_object, &link_object, &network_object), + .children = BUS_IMPLEMENTATIONS(&dhcp_server_object, &dhcp_client_object, + &dhcp6_client_object, &link_object, &network_object), }; diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index ae267ce5ca..e860650691 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -885,6 +885,9 @@ static int ndisc_router_process_captive_portal(Link *link, sd_ndisc_router *rt) if (r < 0) return log_link_warning_errno(link, r, "Failed to get router address from RA: %m"); + /* RFC 4861 section 4.2. states that the lifetime in the message header should be used only for the + * default gateway, but the captive portal option does not have a lifetime field, hence, we use the + * main lifetime for the portal. */ r = sd_ndisc_router_get_lifetime(rt, &lifetime_sec); if (r < 0) return log_link_warning_errno(link, r, "Failed to get lifetime of RA message: %m"); @@ -909,7 +912,19 @@ static int ndisc_router_process_captive_portal(Link *link, sd_ndisc_router *rt) if (!in_charset(captive_portal, URI_VALID)) return log_link_warning_errno(link, SYNTHETIC_ERRNO(EBADMSG), "Received invalid captive portal, ignoring."); - exist = set_get(link->ndisc_captive_portals, &(NDiscCaptivePortal) { .captive_portal = captive_portal }); + if (lifetime_usec == 0) { + /* Drop the portal with zero lifetime. */ + ndisc_captive_portal_free(set_remove(link->ndisc_captive_portals, + &(NDiscCaptivePortal) { + .captive_portal = captive_portal, + })); + return 0; + } + + exist = set_get(link->ndisc_captive_portals, + &(NDiscCaptivePortal) { + .captive_portal = captive_portal, + }); if (exist) { /* update existing entry */ exist->router = router; @@ -950,6 +965,113 @@ static int ndisc_router_process_captive_portal(Link *link, sd_ndisc_router *rt) return 1; } +static void ndisc_pref64_hash_func(const NDiscPREF64 *x, struct siphash *state) { + assert(x); + + siphash24_compress(&x->prefix_len, sizeof(x->prefix_len), state); + siphash24_compress(&x->prefix, sizeof(x->prefix), state); +} + +static int ndisc_pref64_compare_func(const NDiscPREF64 *a, const NDiscPREF64 *b) { + int r; + + assert(a); + assert(b); + + r = CMP(a->prefix_len, b->prefix_len); + if (r != 0) + return r; + + return memcmp(&a->prefix, &b->prefix, sizeof(a->prefix)); +} + +DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( + ndisc_pref64_hash_ops, + NDiscPREF64, + ndisc_pref64_hash_func, + ndisc_pref64_compare_func, + mfree); + +static int ndisc_router_process_pref64(Link *link, sd_ndisc_router *rt) { + _cleanup_free_ NDiscPREF64 *new_entry = NULL; + usec_t lifetime_usec, timestamp_usec; + struct in6_addr a, router; + uint16_t lifetime_sec; + unsigned prefix_len; + NDiscPREF64 *exist; + int r; + + assert(link); + assert(link->network); + assert(rt); + + if (!link->network->ipv6_accept_ra_use_pref64) + return 0; + + r = sd_ndisc_router_get_address(rt, &router); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to get router address from RA: %m"); + + r = sd_ndisc_router_prefix64_get_prefix(rt, &a); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to get pref64 prefix: %m"); + + r = sd_ndisc_router_prefix64_get_prefixlen(rt, &prefix_len); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to get pref64 prefix length: %m"); + + r = sd_ndisc_router_prefix64_get_lifetime_sec(rt, &lifetime_sec); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to get pref64 prefix lifetime: %m"); + + r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, ×tamp_usec); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); + + lifetime_usec = sec16_to_usec(lifetime_sec, timestamp_usec); + + if (lifetime_usec == 0) { + free(set_remove(link->ndisc_pref64, + &(NDiscPREF64) { + .prefix = a, + .prefix_len = prefix_len + })); + return 0; + } + + exist = set_get(link->ndisc_pref64, + &(NDiscPREF64) { + .prefix = a, + .prefix_len = prefix_len + }); + if (exist) { + /* update existing entry */ + exist->router = router; + exist->lifetime_usec = lifetime_usec; + return 0; + } + + new_entry = new(NDiscPREF64, 1); + if (!new_entry) + return log_oom(); + + *new_entry = (NDiscPREF64) { + .router = router, + .lifetime_usec = lifetime_usec, + .prefix = a, + .prefix_len = prefix_len, + }; + + r = set_ensure_put(&link->ndisc_pref64, &ndisc_pref64_hash_ops, new_entry); + if (r < 0) + return log_oom(); + + assert(r > 0); + TAKE_PTR(new_entry); + + return 0; +} + static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) { size_t n_captive_portal = 0; int r; @@ -998,13 +1120,16 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) { if (r > 0) n_captive_portal++; break; + case SD_NDISC_OPTION_PREF64: + r = ndisc_router_process_pref64(link, rt); + break; } if (r < 0 && r != -EBADMSG) return r; } } -static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec, const struct in6_addr *router) { +static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) { bool updated = false; NDiscDNSSL *dnssl; NDiscRDNSS *rdnss; @@ -1028,9 +1153,6 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec, const struct i if (route->lifetime_usec >= timestamp_usec) continue; /* the route is still valid */ - if (router && !in6_addr_equal(&route->provider.in6, router)) - continue; - k = route_remove_and_drop(route); if (k < 0) r = log_link_warning_errno(link, k, "Failed to remove outdated SLAAC route, ignoring: %m"); @@ -1043,9 +1165,6 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec, const struct i if (address->lifetime_valid_usec >= timestamp_usec) continue; /* the address is still valid */ - if (router && !in6_addr_equal(&address->provider.in6, router)) - continue; - k = address_remove_and_drop(address); if (k < 0) r = log_link_warning_errno(link, k, "Failed to remove outdated SLAAC address, ignoring: %m"); @@ -1055,9 +1174,6 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec, const struct i 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; } @@ -1066,9 +1182,6 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec, const struct i 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; } @@ -1077,9 +1190,6 @@ static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec, const struct i 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; } @@ -1100,7 +1210,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, NULL); + (void) ndisc_drop_outdated(link, now_usec); (void) ndisc_setup_expire(link); return 0; } @@ -1201,7 +1311,6 @@ static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) { } static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) { - uint16_t router_lifetime_sec; struct in6_addr router; usec_t timestamp_usec; int r; @@ -1234,28 +1343,12 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) { log_link_debug(link, "Received RA without timestamp, ignoring."); return 0; } - - r = ndisc_drop_outdated(link, timestamp_usec, NULL); if (r < 0) return r; - r = sd_ndisc_router_get_lifetime(rt, &router_lifetime_sec); + r = ndisc_drop_outdated(link, timestamp_usec); if (r < 0) - return log_link_warning_errno(link, r, "Failed to get lifetime of RA message: %m"); - - /* https://datatracker.ietf.org/doc/html/rfc4861 - * Router Lifetime: A Lifetime of 0 indicates that the router is not a default router - * and SHOULD NOT appear on the default router list. - */ - if (router_lifetime_sec == 0) { - log_link_debug(link, "Received RA with lifetime = 0, dropping configurations."); - - r = ndisc_drop_outdated(link, USEC_INFINITY, &router); - if (r < 0) - log_link_warning_errno(link, r, "Failed to process RA with zero lifetime, ignoring: %m"); - - return 0; - } + return r; r = ndisc_start_dhcp6_client(link, rt); if (r < 0) @@ -1430,6 +1523,7 @@ void ndisc_flush(Link *link) { link->ndisc_rdnss = set_free(link->ndisc_rdnss); link->ndisc_dnssl = set_free(link->ndisc_dnssl); link->ndisc_captive_portals = set_free(link->ndisc_captive_portals); + link->ndisc_pref64 = set_free(link->ndisc_pref64); } static const char* const ipv6_accept_ra_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = { diff --git a/src/network/networkd-ndisc.h b/src/network/networkd-ndisc.h index 267f7d4a02..a463f42b52 100644 --- a/src/network/networkd-ndisc.h +++ b/src/network/networkd-ndisc.h @@ -39,6 +39,15 @@ typedef struct NDiscCaptivePortal { char *captive_portal; } NDiscCaptivePortal; +typedef struct NDiscPREF64 { + struct in6_addr router; + /* This is an absolute point in time, and NOT a timespan/duration. + * Must be specified with CLOCK_BOOTTIME. */ + usec_t lifetime_usec; + uint8_t prefix_len; + struct in6_addr prefix; +} NDiscPREF64; + static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) { return ((char*) n) + ALIGN(sizeof(NDiscDNSSL)); } diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 6309baa056..bbb87e00bd 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -285,6 +285,7 @@ IPv6AcceptRA.UseGateway, config_parse_bool, IPv6AcceptRA.UseRoutePrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_route_prefix) IPv6AcceptRA.UseAutonomousPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_autonomous_prefix) IPv6AcceptRA.UseOnLinkPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_onlink_prefix) +IPv6AcceptRA.UsePREF64, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_pref64) IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns) 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) @@ -384,6 +385,9 @@ IPv6SendRA.EmitDomains, config_parse_bool, IPv6SendRA.Domains, config_parse_radv_search_domains, 0, 0 IPv6SendRA.DNSLifetimeSec, config_parse_sec, 0, offsetof(Network, router_dns_lifetime_usec) IPv6SendRA.UplinkInterface, config_parse_uplink, 0, 0 +IPv6SendRA.HomeAgent, config_parse_bool, 0, offsetof(Network, router_home_agent_information) +IPv6SendRA.HomeAgentLifetimeSec, config_parse_router_home_agent_lifetime, 0, offsetof(Network, home_agent_lifetime_usec) +IPv6SendRA.HomeAgentPreference, config_parse_uint16, 0, offsetof(Network, router_home_agent_preference) IPv6Prefix.Prefix, config_parse_prefix, 0, 0 IPv6Prefix.OnLink, config_parse_prefix_boolean, 0, 0 IPv6Prefix.AddressAutoconfiguration, config_parse_prefix_boolean, 0, 0 diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 19e4657f3c..3e1110e6d7 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -242,6 +242,10 @@ struct Network { OrderedSet *router_search_domains; int router_uplink_index; char *router_uplink_name; + /* Mobile IPv6 Home Agent */ + bool router_home_agent_information; + uint16_t router_home_agent_preference; + usec_t home_agent_lifetime_usec; /* DHCP Prefix Delegation support */ int dhcp_pd; @@ -329,6 +333,7 @@ struct Network { bool ipv6_accept_ra_use_icmp6_ratelimit; bool ipv6_accept_ra_quickack; bool ipv6_accept_ra_use_captive_portal; + bool ipv6_accept_ra_use_pref64; bool active_slave; bool primary_slave; DHCPUseDomains ipv6_accept_ra_use_domains; diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index 57fd68f5a0..b5ee1c322d 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -600,6 +600,18 @@ static int radv_configure(Link *link) { if (r < 0) return log_link_debug_errno(link, r, "Could not set RA Domains: %m"); + r = sd_radv_set_home_agent_information(link->radv, link->network->router_home_agent_information); + if (r < 0) + return r; + + r = sd_radv_set_home_agent_preference(link->radv, link->network->router_home_agent_preference); + if (r < 0) + return r; + + r = sd_radv_set_home_agent_lifetime(link->radv, DIV_ROUND_UP(link->network->home_agent_lifetime_usec, USEC_PER_SEC)); + if (r < 0) + return r; + return 0; } @@ -1575,3 +1587,47 @@ int config_parse_router_preference( return 0; } + +int config_parse_router_home_agent_lifetime( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + usec_t usec, *home_agent_lifetime_usec = ASSERT_PTR(data); + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + *home_agent_lifetime_usec = 0; + return 0; + } + + r = parse_sec(rvalue, &usec); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + if (usec == USEC_INFINITY || usec == 0 || + DIV_ROUND_UP(usec, USEC_PER_SEC) > RADV_MAX_HOME_AGENT_LIFETIME_USEC) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid %s= must be in the range 1...%lu seconds, ignoring: %s", lvalue, + RADV_MAX_HOME_AGENT_LIFETIME_USEC / USEC_PER_SEC, rvalue); + return 0; + } + + *home_agent_lifetime_usec = usec; + return 0; +} diff --git a/src/network/networkd-radv.h b/src/network/networkd-radv.h index 8ea1a85b26..48677b50de 100644 --- a/src/network/networkd-radv.h +++ b/src/network/networkd-radv.h @@ -98,3 +98,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_route_prefix); CONFIG_PARSER_PROTOTYPE(config_parse_route_prefix_lifetime); CONFIG_PARSER_PROTOTYPE(config_parse_pref64_prefix); CONFIG_PARSER_PROTOTYPE(config_parse_pref64_prefix_lifetime); +CONFIG_PARSER_PROTOTYPE(config_parse_router_home_agent_lifetime); |