summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/meson.build2
-rw-r--r--src/network/networkd-address-generation.c11
-rw-r--r--src/network/networkd-dhcp-common.c2
-rw-r--r--src/network/networkd-dhcp4-bus.c78
-rw-r--r--src/network/networkd-dhcp4-bus.h10
-rw-r--r--src/network/networkd-dhcp4.c5
-rw-r--r--src/network/networkd-dhcp6-bus.c76
-rw-r--r--src/network/networkd-dhcp6-bus.h10
-rw-r--r--src/network/networkd-dhcp6.c6
-rw-r--r--src/network/networkd-json.c32
-rw-r--r--src/network/networkd-link-bus.c6
-rw-r--r--src/network/networkd-link.h1
-rw-r--r--src/network/networkd-manager-bus.c5
-rw-r--r--src/network/networkd-ndisc.c168
-rw-r--r--src/network/networkd-ndisc.h9
-rw-r--r--src/network/networkd-network-gperf.gperf4
-rw-r--r--src/network/networkd-network.h5
-rw-r--r--src/network/networkd-radv.c56
-rw-r--r--src/network/networkd-radv.h1
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, &timestamp_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);