From 89e73ce86fb115c2e319bf9f28b63efad2975495 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Tue, 15 Aug 2023 18:56:19 +0530 Subject: [PATCH 1/2] network: DHCP6 client- Allow to send manual DUID ``` [DHCPv6] DUIDType=custom DUIDRawData=00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 ``` ``` Client Identifier Option: Client Identifier (1) Length: 12 DUID: 0000ab11f92ac27729f95c00 DUID Type: Unknown (0) ``` --- man/networkd.conf.xml | 7 +++++++ src/libsystemd-network/dhcp-identifier.c | 9 +++++---- src/libsystemd-network/dhcp-identifier.h | 1 + src/libsystemd-network/sd-dhcp6-client.c | 12 ++++++++---- src/network/networkd-dhcp-common.c | 9 +++++---- src/network/networkd-dhcp6.c | 5 +++++ 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml index bf597cac2ec..9fa925e85c8 100644 --- a/man/networkd.conf.xml +++ b/man/networkd.conf.xml @@ -138,6 +138,13 @@ + + + If DUIDType=custom, then the DUIDRawData= value will + used be as custom identifier. If DUIDType=custom is specified then the + DUIDRawData= key is mandatory. Note it applies only on DHCPv6 clients. + + If DUIDType=uuid, and DUIDRawData= is not set, diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index a27d67a315d..83fb6ce3408 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -15,10 +15,11 @@ #define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */ static const char * const duid_type_table[_DUID_TYPE_MAX] = { - [DUID_TYPE_LLT] = "DUID-LLT", - [DUID_TYPE_EN] = "DUID-EN/Vendor", - [DUID_TYPE_LL] = "DUID-LL", - [DUID_TYPE_UUID] = "UUID", + [DUID_TYPE_LLT] = "DUID-LLT", + [DUID_TYPE_EN] = "DUID-EN/Vendor", + [DUID_TYPE_LL] = "DUID-LL", + [DUID_TYPE_UUID] = "UUID", + [DUID_TYPE_CUSTOM] = "Custom", }; DEFINE_STRING_TABLE_LOOKUP_TO_STRING(duid_type, DUIDType); diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 523dfc4a71b..1ac34761573 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -17,6 +17,7 @@ typedef enum DUIDType { DUID_TYPE_EN = 2, DUID_TYPE_LL = 3, DUID_TYPE_UUID = 4, + DUID_TYPE_CUSTOM = 5, _DUID_TYPE_MAX, _DUID_TYPE_INVALID = -EINVAL, } DUIDType; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 2f4053caad0..e8d99718b30 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -212,10 +212,14 @@ static int dhcp6_client_set_duid_internal( log_dhcp6_client(client, "Using DUID of type %i of incorrect length, proceeding.", duid_type); } - client->duid.type = htobe16(duid_type); - memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = sizeof(client->duid.type) + duid_len; - + if (duid_type == DUID_TYPE_CUSTOM) { + memcpy(&client->duid, duid, duid_len); + client->duid_len = duid_len; + } else { + client->duid.type = htobe16(duid_type); + memcpy(&client->duid.raw.data, duid, duid_len); + client->duid_len = sizeof(client->duid.type) + duid_len; + } } else { r = dhcp_identifier_set_duid(duid_type, &client->hw_addr, client->arp_type, llt_time, client->test_mode, &client->duid, &client->duid_len); diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 5f9ef80e3e5..baf80cb6442 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -1106,10 +1106,11 @@ static const char * const dhcp_option_data_type_table[_DHCP_OPTION_DATA_MAX] = { DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type, DHCPOptionDataType); static const char* const duid_type_table[_DUID_TYPE_MAX] = { - [DUID_TYPE_LLT] = "link-layer-time", - [DUID_TYPE_EN] = "vendor", - [DUID_TYPE_LL] = "link-layer", - [DUID_TYPE_UUID] = "uuid", + [DUID_TYPE_LLT] = "link-layer-time", + [DUID_TYPE_EN] = "vendor", + [DUID_TYPE_LL] = "link-layer", + [DUID_TYPE_UUID] = "uuid", + [DUID_TYPE_CUSTOM] = "custom", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 00c767e1fb8..e0f08508988 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -555,6 +555,11 @@ static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) { } duid = link_get_dhcp6_duid(link); + + if (duid->type == DUID_TYPE_CUSTOM && duid->raw_data_len == 0) + return log_link_debug_errno(link, SYNTHETIC_ERRNO(EINVAL), + "DHCPv6 CLIENT: Missing DUID Raw Data as duid type set to 'custom': %m"); + if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0) r = sd_dhcp6_client_set_duid_llt(client, duid->llt_time); else From 543d2a4d45ba199a62c87b3bf69dfd4ff55abf0c Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Thu, 17 Aug 2023 19:20:02 +0530 Subject: [PATCH 2/2] CI: network dhcp6 - Add test for custom client identifier --- ...ipv6-only-custom-client-identifier.network | 15 ++++++++ test/test-network/systemd-networkd-tests.py | 35 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 test/test-network/conf/25-dhcp-client-ipv6-only-custom-client-identifier.network diff --git a/test/test-network/conf/25-dhcp-client-ipv6-only-custom-client-identifier.network b/test/test-network/conf/25-dhcp-client-ipv6-only-custom-client-identifier.network new file mode 100644 index 00000000000..edd5b7f5017 --- /dev/null +++ b/test/test-network/conf/25-dhcp-client-ipv6-only-custom-client-identifier.network @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Name=veth99 + +[Network] +DHCP=ipv6 +IPv6Token=::1a:2b:3c:4d + +[Route] +Gateway=_ipv6ra +Destination=2001:1234:5:9fff:ff:ff:ff:ff/128 + +[DHCPv6] +DUIDType=custom +DUIDRawData=00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 07afe354f79..799d3bf784d 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -5018,6 +5018,41 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): self.assertIn('DHCPREPLY(veth-peer)', output) self.assertNotIn('rapid-commit', output) + def test_dhcp_client_ipv6_only_with_custom_client_identifier(self): + copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv6-only-custom-client-identifier.network') + + start_networkd() + self.wait_online(['veth-peer:carrier']) + start_dnsmasq() + self.wait_online(['veth99:routable', 'veth-peer:routable']) + + # checking address + output = check_output('ip address show dev veth99 scope global') + print(output) + self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute') + self.assertNotIn('192.168.5', output) + + # checking semi-static route + output = check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff') + print(output) + self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd') + + # Confirm that ipv6 token is not set in the kernel + output = check_output('ip token show dev veth99') + print(output) + self.assertRegex(output, 'token :: dev veth99') + + print('## dnsmasq log') + output = read_dnsmasq_log_file() + print(output) + self.assertIn('DHCPSOLICIT(veth-peer) 00:00:ab:11:f9:2a:c2:77:29:f9:5c:00', output) + self.assertNotIn('DHCPADVERTISE(veth-peer)', output) + self.assertNotIn('DHCPREQUEST(veth-peer)', output) + self.assertIn('DHCPREPLY(veth-peer)', output) + self.assertIn('sent size: 0 option: 14 rapid-commit', output) + + stop_dnsmasq() + def test_dhcp_client_ipv4_only(self): copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client-ipv4-only.network')