From 7860677e03b0cd316ac545a0394e2744f7cdff92 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 16 Sep 2024 04:12:02 +0900 Subject: [PATCH 1/7] sd-dhcp6-lease: use free_and_replace_full() --- src/libsystemd-network/sd-dhcp6-lease.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index c2eb0db87de..30c0e514f86 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -763,8 +763,7 @@ static int dhcp6_lease_parse_message( continue; } - dhcp6_ia_free(lease->ia_na); - lease->ia_na = TAKE_PTR(ia); + free_and_replace_full(lease->ia_na, ia, dhcp6_ia_free); break; } case SD_DHCP6_OPTION_IA_PD: { @@ -788,8 +787,7 @@ static int dhcp6_lease_parse_message( continue; } - dhcp6_ia_free(lease->ia_pd); - lease->ia_pd = TAKE_PTR(ia); + free_and_replace_full(lease->ia_pd, ia, dhcp6_ia_free); break; } case SD_DHCP6_OPTION_RAPID_COMMIT: From 8fead9c9e46e5f71ae6f6b038ff7f72c5a13b663 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 16 Sep 2024 04:45:13 +0900 Subject: [PATCH 2/7] network/dhcp6: set hostname even if UseAddress=no Follow-up for f963f8953daeab03b892616ce0c65f7572932187 and 1536b7b2d00819615bf8eba194de7ccd20c3689f. --- src/network/networkd-dhcp6.c | 48 +++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 3f773cbb993..39471d6628d 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -264,25 +264,35 @@ static int dhcp6_address_acquired(Link *link) { return r; } - if (link->network->dhcp6_use_hostname) { - const char *dhcpname = NULL; - _cleanup_free_ char *hostname = NULL; + return 0; +} - (void) sd_dhcp6_lease_get_fqdn(link->dhcp6_lease, &dhcpname); +static int dhcp6_request_hostname(Link *link) { + _cleanup_free_ char *hostname = NULL; + const char *dhcpname = NULL; + int r; - if (dhcpname) { - r = shorten_overlong(dhcpname, &hostname); - if (r < 0) - log_link_warning_errno(link, r, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname); - if (r == 1) - log_link_notice(link, "Overlong DHCP hostname received, shortened from '%s' to '%s'", dhcpname, hostname); - } - if (hostname) { - r = manager_set_hostname(link->manager, hostname); - if (r < 0) - log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname); - } - } + assert(link); + assert(link->network); + + if (!link->network->dhcp6_use_hostname) + return 0; + + r = sd_dhcp6_lease_get_fqdn(link->dhcp6_lease, &dhcpname); + if (r == -ENODATA) + return 0; + if (r < 0) + return r; + + r = shorten_overlong(dhcpname, &hostname); + if (r < 0) + return log_link_warning_errno(link, r, "Unable to shorten overlong DHCP hostname '%s': %m", dhcpname); + if (r == 1) + log_link_notice(link, "Overlong DHCP hostname received, shortened from '%s' to '%s'", dhcpname, hostname); + + r = manager_set_hostname(link->manager, hostname); + if (r < 0) + log_link_warning_errno(link, r, "Failed to set transient hostname to '%s', ignoring: %m", hostname); return 0; } @@ -302,6 +312,10 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) { lease_old = TAKE_PTR(link->dhcp6_lease); link->dhcp6_lease = sd_dhcp6_lease_ref(lease); + r = dhcp6_request_hostname(link); + if (r < 0) + return r; + r = dhcp6_address_acquired(link); if (r < 0) return r; From 180cc5421d9712fb95a6bbc725dc8ba459360c8b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 16 Sep 2024 05:00:57 +0900 Subject: [PATCH 3/7] sd-dhcp6-client: allow to request IA_PD on information requesting mode To support RFC 7084, WPD-4. --- src/libsystemd-network/sd-dhcp6-client.c | 8 ++++++++ src/libsystemd-network/sd-dhcp6-lease.c | 5 ----- src/libsystemd-network/test-dhcp6-client.c | 5 +++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 3e992d7cadc..5661beeb657 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -767,6 +767,14 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) { switch (client->state) { case DHCP6_STATE_INFORMATION_REQUEST: + /* RFC 7084 section 4.2 (https://datatracker.ietf.org/doc/html/rfc7084#section-4.2) + * WPD-4: By default, the IPv6 CE router MUST initiate DHCPv6 prefix delegation when either + * the M or O flags are set to 1 in a received Router Advertisement (RA) message. */ + if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD)) { + r = dhcp6_option_append_ia(&buf, &offset, (client->lease ? client->lease->ia_pd : NULL) ?: &client->ia_pd); + if (r < 0) + return r; + } break; case DHCP6_STATE_SOLICITATION: diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index 30c0e514f86..3f8183c2c6f 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -769,11 +769,6 @@ static int dhcp6_lease_parse_message( case SD_DHCP6_OPTION_IA_PD: { _cleanup_(dhcp6_ia_freep) DHCP6IA *ia = NULL; - if (client->state == DHCP6_STATE_INFORMATION_REQUEST) { - log_dhcp6_client(client, "Ignoring IA PD option in information requesting mode."); - break; - } - r = dhcp6_option_parse_ia(client, client->ia_pd.header.id, optcode, optlen, optval, &ia); if (r == -ENOMEM) return log_oom_debug(); diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 7afd464dc0f..29cbdc95b4a 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -493,6 +493,11 @@ static const uint8_t msg_information_request[] = { DHCP6_MESSAGE_INFORMATION_REQUEST, /* Transaction ID */ 0x0f, 0xb4, 0xe5, + /* IA_PD */ + 0x00, SD_DHCP6_OPTION_IA_PD, 0x00, 0x0c, + IA_ID_BYTES, + 0x00, 0x00, 0x00, 0x00, /* lifetime T1 */ + 0x00, 0x00, 0x00, 0x00, /* lifetime T2 */ /* MUD URL */ /* ORO */ 0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x0c, From cf7a403e470368049165ecff7ac7686928778d7c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 16 Sep 2024 05:02:06 +0900 Subject: [PATCH 4/7] sd-dhcp6-lease: adjust information refresh time with lifetime of IA_PD For the case when IRT is too large but lifetime of IA_PD is too short. --- src/libsystemd-network/sd-dhcp6-lease.c | 35 ++++++++++++++++++++----- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index 3f8183c2c6f..261ab83c648 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -71,6 +71,32 @@ static void dhcp6_lease_set_lifetime(sd_dhcp6_lease *lease) { lease->lifetime_t2 = t2; } +static void dhcp6_client_set_information_refresh_time(sd_dhcp6_client *client, sd_dhcp6_lease *lease, usec_t irt) { + usec_t t1 = USEC_INFINITY, t2 = USEC_INFINITY, min_valid_lt = USEC_INFINITY; + + if (lease->ia_pd) { + t1 = be32_sec_to_usec(lease->ia_pd->header.lifetime_t1, /* max_as_infinity = */ true); + t2 = be32_sec_to_usec(lease->ia_pd->header.lifetime_t2, /* max_as_infinity = */ true); + + LIST_FOREACH(addresses, a, lease->ia_pd->addresses) + min_valid_lt = MIN(min_valid_lt, be32_sec_to_usec(a->iapdprefix.lifetime_valid, /* max_as_infinity = */ true)); + + if (t2 == 0 || t2 > min_valid_lt) { + /* If T2 is zero or longer than the minimum valid lifetime of the prefixes, + * then adjust lifetime with it. */ + t1 = min_valid_lt / 2; + t2 = min_valid_lt / 10 * 8; + } + + /* Adjust the received information refresh time with T1. */ + irt = MIN(irt, t1); + } + + client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM); + log_dhcp6_client(client, "New information request will be refused in %s.", + FORMAT_TIMESPAN(client->information_refresh_time_usec, USEC_PER_SEC)); +} + #define DEFINE_GET_TIME_FUNCTIONS(name, val) \ int sd_dhcp6_lease_get_##name( \ sd_dhcp6_lease *lease, \ @@ -865,12 +891,9 @@ static int dhcp6_lease_parse_message( "The client ID in %s message does not match. Ignoring.", dhcp6_message_type_to_string(message->type)); - if (client->state == DHCP6_STATE_INFORMATION_REQUEST) { - client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM); - log_dhcp6_client(client, "New information request will be refused in %s.", - FORMAT_TIMESPAN(client->information_refresh_time_usec, USEC_PER_SEC)); - - } else { + if (client->state == DHCP6_STATE_INFORMATION_REQUEST) + dhcp6_client_set_information_refresh_time(client, lease, irt); + else { r = dhcp6_lease_get_serverid(lease, NULL, NULL); if (r < 0) return log_dhcp6_client_errno(client, r, "%s has no server id", From 1918eda30d12e1ba3ee55921c18ec53267463e24 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 16 Sep 2024 05:03:57 +0900 Subject: [PATCH 5/7] network/dhcp6: process hostname and IA_PD on information requesting mode Fixes #34299. --- src/network/networkd-dhcp6.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 39471d6628d..f1ecf642051 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -297,7 +297,7 @@ static int dhcp6_request_hostname(Link *link) { return 0; } -static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) { +static int dhcp6_lease_acquired(sd_dhcp6_client *client, Link *link) { _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease_old = NULL; sd_dhcp6_lease *lease; int r; @@ -341,22 +341,6 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) { link_set_state(link, LINK_STATE_CONFIGURING); link_check_ready(link); - return 0; -} - -static int dhcp6_lease_information_acquired(sd_dhcp6_client *client, Link *link) { - sd_dhcp6_lease *lease; - int r; - - assert(client); - assert(link); - - r = sd_dhcp6_client_get_lease(client, &lease); - if (r < 0) - return log_link_error_errno(link, r, "Failed to get DHCPv6 lease: %m"); - - unref_and_replace_full(link->dhcp6_lease, lease, sd_dhcp6_lease_ref, sd_dhcp6_lease_unref); - link_dirty(link); return 0; } @@ -401,11 +385,8 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { break; case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE: - r = dhcp6_lease_ip_acquired(client, link); - break; - case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST: - r = dhcp6_lease_information_acquired(client, link); + r = dhcp6_lease_acquired(client, link); break; default: From daf9f42f9183c206c0f8308efece019797e95e89 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 16 Sep 2024 05:12:50 +0900 Subject: [PATCH 6/7] man/network: update example for router upstream interface This comments out all optional settings. --- man/systemd.network.xml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index e743e6d2a02..d2a6773883d 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -6243,22 +6243,22 @@ Name=enp1s0 [Network] DHCP=ipv6 -# The below setting is optional, to also assign an address in the delegated prefix -# to the upstream interface. If not necessary, then comment out the line below and -# the [DHCPPrefixDelegation] section. -DHCPPrefixDelegation=yes +# The lines below are optional, to also assign an address in the delegated prefix +# to the upstream interface. Uncomment the lines below if necessary. +#[Network] +#DHCPPrefixDelegation=yes +#[DHCPPrefixDelegation] +#UplinkInterface=:self +#SubnetId=0 +#Announce=no -# If the upstream network provides Router Advertisement with Managed bit set, -# then comment out the line below and WithoutRA= setting in the [DHCPv6] section. -IPv6AcceptRA=no - -[DHCPv6] -WithoutRA=solicit - -[DHCPPrefixDelegation] -UplinkInterface=:self -SubnetId=0 -Announce=no +# If the upstream network does not provides any Router Advertisement (RA) messages +# or provides an RA with both Managed and Other-information bits unset, then +# uncomment the lines below. +#[Network] +#IPv6AcceptRA=no +#[DHCPv6] +#WithoutRA=solicit # /etc/systemd/network/55-dhcpv6-pd-downstream.network [Match] From e71b0e2ec507771a6266dc0d54710c7781572515 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 16 Sep 2024 11:37:35 +0900 Subject: [PATCH 7/7] network/radv: update comment DHCPv6PrefixDelegation= is replaced with DHCPPrefixDelegation=. --- src/network/networkd-radv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index 8486151b111..8cff0237a96 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -1372,7 +1372,7 @@ int config_parse_router_prefix_delegation( } /* When IPv6SendRA= is enabled, only static prefixes are sent by default, and users - * need to explicitly enable DHCPv6PrefixDelegation=. */ + * need to explicitly enable DHCPPrefixDelegation=. */ *ra = r ? RADV_PREFIX_DELEGATION_STATIC : RADV_PREFIX_DELEGATION_NONE; return 0; }