From 2805536bff6de4001255a3f93b558a1242df0114 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Wed, 25 Sep 2019 05:14:12 +0200 Subject: [PATCH] network: DHCPv6 client add support for prefix delegation hint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for prefix hint lenth and prefix hint address ``` Frame 43: 177 bytes on wire (1416 bits), 177 bytes captured (1416 bits) on interface 0 Ethernet II, Src: f6:c1:08:4d:45:f1 (f6:c1:08:4d:45:f1), Dst: IPv6mcast_01:00:02 (33:33:00:01:00:02) Internet Protocol Version 6, Src: fe80::d250:c82:7f6e:28d6, Dst: ff02::1:2 User Datagram Protocol, Src Port: 546, Dst Port: 547 DHCPv6 Message type: Solicit (1) Transaction ID: 0x5c7902 Rapid Commit Identity Association for Non-temporary Address Fully Qualified Domain Name Identity Association for Prefix Delegation Option: Identity Association for Prefix Delegation (25) Length: 41 Value: 1b97b1690000000000000000001a0019ffffffffffffffff… IAID: 1b97b169 T1: 0 T2: 0 IA Prefix Option: IA Prefix (26) Length: 25 Value: ffffffffffffffff3c000000000000000000000000000000… Preferred lifetime: infinity Valid lifetime: infinity Prefix length: 60 Prefix address: :: Option Request Client Identifier Elapsed time ``` --- man/systemd.network.xml | 8 +++++ src/libsystemd-network/dhcp6-internal.h | 2 +- src/libsystemd-network/dhcp6-option.c | 20 +++++++---- src/libsystemd-network/sd-dhcp6-client.c | 25 +++++++++++-- src/network/networkd-dhcp-common.c | 36 +++++++++++++++++++ src/network/networkd-dhcp-common.h | 1 + src/network/networkd-dhcp6.c | 6 ++++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.h | 2 ++ src/systemd/sd-dhcp6-client.h | 4 +++ .../fuzz-network-parser/directives.network | 1 + 11 files changed, 96 insertions(+), 10 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index e5f9d6f470..ac0f618643 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1632,6 +1632,14 @@ + + PrefixDelegationHint= + + Takes an IPv6 address with prefix length as Addresss= in + the "[Network]" section. Specifies the DHCPv6 client for the requesting router to include + a prefix-hint in the DHCPv6 solicitation. Prefix ranges 1-128. Defaults to unset. + + diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index f28ba68dd1..517e357d3d 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -85,7 +85,7 @@ typedef struct DHCP6IA DHCP6IA; int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, size_t optlen, const void *optval); int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia); -int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd); +int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix); int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn); int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen, uint8_t **optvalue); diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 017402c53b..ca67559e6f 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -168,9 +168,10 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) { return r; } -int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) { +int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) { DHCP6Option *option = (DHCP6Option *)buf; size_t i = sizeof(*option) + sizeof(pd->ia_pd); + DHCP6PDPrefixOption *prefix_opt; DHCP6Address *prefix; assert_return(buf, -EINVAL); @@ -183,10 +184,7 @@ int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) { option->code = htobe16(SD_DHCP6_OPTION_IA_PD); memcpy(&option->data, &pd->ia_pd, sizeof(pd->ia_pd)); - LIST_FOREACH(addresses, prefix, pd->addresses) { - DHCP6PDPrefixOption *prefix_opt; - if (len < i + sizeof(*prefix_opt)) return -ENOBUFS; @@ -194,9 +192,19 @@ int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) { prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX); prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix)); - memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix, - sizeof(struct iapdprefix)); + memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix, sizeof(struct iapdprefix)); + i += sizeof(*prefix_opt); + } + if (hint_pd_prefix && hint_pd_prefix->iapdprefix.prefixlen > 0) { + if (len < i + sizeof(*prefix_opt)) + return -ENOBUFS; + + prefix_opt = (DHCP6PDPrefixOption *)&buf[i]; + prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX); + prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix)); + + memcpy(&prefix_opt->iapdprefix, &hint_pd_prefix->iapdprefix, sizeof(struct iapdprefix)); i += sizeof(*prefix_opt); } diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 9773a067d5..33420fd4c0 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -46,6 +46,7 @@ struct sd_dhcp6_client { sd_event *event; int event_priority; int ifindex; + DHCP6Address hint_pd_prefix; struct in6_addr local_address; uint8_t mac_addr[MAX_MAC_ADDR_LEN]; size_t mac_addr_len; @@ -187,6 +188,22 @@ int sd_dhcp6_client_set_mac( return 0; } +int sd_dhcp6_client_set_prefix_delegation_hint( + sd_dhcp6_client *client, + uint8_t prefixlen, + const struct in6_addr *pd_address) { + + assert_return(client, -EINVAL); + assert_return(pd_address, -EINVAL); + + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->hint_pd_prefix.iapdprefix.address = *pd_address; + client->hint_pd_prefix.iapdprefix.prefixlen = prefixlen; + + return 0; +} + static int client_ensure_duid(sd_dhcp6_client *client) { if (client->duid_len != 0) return 0; @@ -492,7 +509,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { } if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { - r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd); + r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix); if (r < 0) return r; @@ -530,7 +547,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { } if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { - r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd); + r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL); if (r < 0) return r; @@ -556,7 +573,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { } if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { - r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd); + r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL); if (r < 0) return r; @@ -1537,6 +1554,8 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) { .request = DHCP6_REQUEST_IA_NA, .fd = -1, .req_opts_len = ELEMENTSOF(default_req_opts), + .hint_pd_prefix.iapdprefix.lifetime_preferred = (be32_t) -1, + .hint_pd_prefix.iapdprefix.lifetime_valid = (be32_t) -1, .req_opts = TAKE_PTR(req_opts), }; diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 36ae728e24..bbf10affc4 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include "in-addr-util.h" #include "networkd-dhcp-common.h" #include "networkd-network.h" #include "parse-util.h" @@ -227,6 +228,41 @@ int config_parse_iaid(const char *unit, return 0; } +int config_parse_dhcp6_pd_hint( + 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) { + + Network *network = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = in_addr_prefix_from_string(rvalue, AF_INET6, (union in_addr_union *) &network->dhcp6_pd_address, &network->dhcp6_pd_length); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PrefixDelegationHint=%s, ignoring assignment", rvalue); + return 0; + } + + if (network->dhcp6_pd_length < 1 || network->dhcp6_pd_length > 128) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid prefix length='%d', ignoring assignment", network->dhcp6_pd_length); + network->dhcp6_pd_length = 0; + return 0; + } + + return 0; +} + DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting"); diff --git a/src/network/networkd-dhcp-common.h b/src/network/networkd-dhcp-common.h index 3e079b91b9..8f280190b9 100644 --- a/src/network/networkd-dhcp-common.h +++ b/src/network/networkd-dhcp-common.h @@ -34,3 +34,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_ntp); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_sip); CONFIG_PARSER_PROTOTYPE(config_parse_iaid); CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table); +CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index e61eeda7d0..647623ac37 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -686,6 +686,12 @@ int dhcp6_configure(Link *link) { return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix delegation: %m"); } + if (link->network->dhcp6_pd_length > 0) { + r = sd_dhcp6_client_set_prefix_delegation_hint(client, link->network->dhcp6_pd_length, &link->network->dhcp6_pd_address); + if (r < 0) + return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set prefix hint: %m"); + } + link->dhcp6_client = TAKE_PTR(client); return 0; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index ce9fc30162..689b1a123e 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -172,6 +172,7 @@ DHCPv6.UseDNS, config_parse_bool, DHCPv6.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp6_use_ntp) DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit) DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information) +DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0 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.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns) diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index ff97845dd1..35469c05ed 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -109,6 +109,8 @@ struct Network { /* DHCPv6 Client support*/ bool dhcp6_use_dns; bool dhcp6_use_ntp; + uint8_t dhcp6_pd_length; + struct in6_addr dhcp6_pd_address; /* DHCP Server Support */ bool dhcp_server; diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 3aac3f14fe..be34d43e74 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -120,6 +120,10 @@ int sd_dhcp6_client_get_information_request( int sd_dhcp6_client_set_request_option( sd_dhcp6_client *client, uint16_t option); +int sd_dhcp6_client_set_prefix_delegation_hint( + sd_dhcp6_client *client, + uint8_t prefixlen, + const struct in6_addr *pd_address); int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation); int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 78cddcab77..24d94033fc 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -99,6 +99,7 @@ UseNTP= UseDNS= RapidCommit= ForceDHCPv6PDOtherInformation= +PrefixDelegationHint= [Route] Destination= Protocol=