summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libsystemd-network/dhcp-duid-internal.h (renamed from src/libsystemd-network/dhcp-identifier.h)58
-rw-r--r--src/libsystemd-network/dhcp-identifier.c209
-rw-r--r--src/libsystemd-network/dhcp6-internal.h5
-rw-r--r--src/libsystemd-network/meson.build2
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c88
-rw-r--r--src/libsystemd-network/sd-dhcp-duid.c241
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c28
-rw-r--r--src/libsystemd-network/sd-dhcp6-lease.c2
-rw-r--r--src/libsystemd-network/test-dhcp-client.c11
-rw-r--r--src/libsystemd-network/test-dhcp6-client.c2
-rw-r--r--src/network/networkd-dhcp-common.c1
-rw-r--r--src/network/networkd-dhcp-common.h2
-rw-r--r--src/network/networkd-link.c1
-rw-r--r--src/network/networkd-manager.h2
-rw-r--r--src/systemd/meson.build1
-rw-r--r--src/systemd/sd-dhcp-duid.h69
16 files changed, 404 insertions, 318 deletions
diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-duid-internal.h
index cc1a2008a0..ae888f789a 100644
--- a/src/libsystemd-network/dhcp-identifier.h
+++ b/src/libsystemd-network/dhcp-duid-internal.h
@@ -2,30 +2,31 @@
#pragma once
#include "sd-device.h"
+#include "sd-dhcp-duid.h"
#include "sd-id128.h"
#include "ether-addr-util.h"
#include "macro.h"
#include "sparse-endian.h"
-#include "time-util.h"
#define SYSTEMD_PEN 43793
typedef enum DUIDType {
- DUID_TYPE_LLT = 1,
- DUID_TYPE_EN = 2,
- DUID_TYPE_LL = 3,
- DUID_TYPE_UUID = 4,
+ DUID_TYPE_LLT = SD_DUID_TYPE_LLT,
+ DUID_TYPE_EN = SD_DUID_TYPE_EN,
+ DUID_TYPE_LL = SD_DUID_TYPE_LL,
+ DUID_TYPE_UUID = SD_DUID_TYPE_UUID,
_DUID_TYPE_MAX,
- _DUID_TYPE_INVALID = -EINVAL,
- _DUID_TYPE_FORCE_U16 = UINT16_MAX,
+ _DUID_TYPE_INVALID = -EINVAL,
} DUIDType;
/* RFC 8415 section 11.1:
* A DUID consists of a 2-octet type code represented in network byte order, followed by a variable number of
* octets that make up the actual identifier. The length of the DUID (not including the type code) is at
* least 1 octet and at most 128 octets. */
+#define MIN_DUID_DATA_LEN 1
#define MAX_DUID_DATA_LEN 128
+#define MIN_DUID_LEN (sizeof(be16_t) + MIN_DUID_DATA_LEN)
#define MAX_DUID_LEN (sizeof(be16_t) + MAX_DUID_DATA_LEN)
/* https://tools.ietf.org/html/rfc3315#section-9.1 */
@@ -52,35 +53,30 @@ struct duid {
/* DUID_TYPE_UUID */
sd_id128_t uuid;
} _packed_ uuid;
- struct {
- uint8_t data[MAX_DUID_DATA_LEN];
- } _packed_ raw;
+ uint8_t data[MAX_DUID_DATA_LEN];
};
} _packed_;
-int dhcp_identifier_set_duid_llt(
- const struct hw_addr_data *hw_addr,
- uint16_t arp_type,
- usec_t t,
- struct duid *ret_duid,
- size_t *ret_len);
-int dhcp_identifier_set_duid_ll(
- const struct hw_addr_data *hw_addr,
- uint16_t arp_type,
- struct duid *ret_duid,
- size_t *ret_len);
-int dhcp_identifier_set_duid_en(struct duid *ret_duid, size_t *ret_len);
-int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len);
-int dhcp_identifier_set_duid_raw(
- DUIDType duid_type,
- const uint8_t *buf,
- size_t buf_len,
- struct duid *ret_duid,
- size_t *ret_len);
+typedef struct sd_dhcp_duid {
+ size_t size;
+ union {
+ struct duid duid;
+ uint8_t raw[MAX_DUID_LEN];
+ };
+} sd_dhcp_duid;
+
+static inline bool duid_size_is_valid(size_t size) {
+ return size >= MIN_DUID_LEN && size <= MAX_DUID_LEN;
+}
+
+static inline bool duid_data_size_is_valid(size_t size) {
+ return size >= MIN_DUID_DATA_LEN && size <= MAX_DUID_DATA_LEN;
+}
+
+const char *duid_type_to_string(DUIDType t) _const_;
+
int dhcp_identifier_set_iaid(
sd_device *dev,
const struct hw_addr_data *hw_addr,
bool legacy_unstable_byteorder,
void *ret);
-
-const char *duid_type_to_string(DUIDType t) _const_;
diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c
deleted file mode 100644
index 09bab592dc..0000000000
--- a/src/libsystemd-network/dhcp-identifier.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include <linux/if_infiniband.h>
-#include <net/ethernet.h>
-#include <net/if_arp.h>
-
-#include "dhcp-identifier.h"
-#include "netif-util.h"
-#include "network-common.h"
-#include "siphash24.h"
-#include "string-table.h"
-#include "unaligned.h"
-
-#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
-#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03)
-#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",
-};
-
-DEFINE_STRING_TABLE_LOOKUP_TO_STRING(duid_type, DUIDType);
-
-int dhcp_identifier_set_duid_llt(
- const struct hw_addr_data *hw_addr,
- uint16_t arp_type,
- usec_t t,
- struct duid *ret_duid,
- size_t *ret_len) {
-
- uint16_t time_from_2000y;
-
- assert(hw_addr);
- assert(ret_duid);
- assert(ret_len);
-
- if (hw_addr->length == 0)
- return -EOPNOTSUPP;
-
- if (arp_type == ARPHRD_ETHER)
- assert_return(hw_addr->length == ETH_ALEN, -EINVAL);
- else if (arp_type == ARPHRD_INFINIBAND)
- assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL);
- else
- return -EOPNOTSUPP;
-
- if (t < USEC_2000)
- time_from_2000y = 0;
- else
- time_from_2000y = (uint16_t) (((t - USEC_2000) / USEC_PER_SEC) & 0xffffffff);
-
- unaligned_write_be16(&ret_duid->type, DUID_TYPE_LLT);
- unaligned_write_be16(&ret_duid->llt.htype, arp_type);
- unaligned_write_be32(&ret_duid->llt.time, time_from_2000y);
- memcpy(ret_duid->llt.haddr, hw_addr->bytes, hw_addr->length);
-
- *ret_len = offsetof(struct duid, llt.haddr) + hw_addr->length;
-
- return 0;
-}
-
-int dhcp_identifier_set_duid_ll(
- const struct hw_addr_data *hw_addr,
- uint16_t arp_type,
- struct duid *ret_duid,
- size_t *ret_len) {
-
- assert(hw_addr);
- assert(ret_duid);
- assert(ret_len);
-
- if (hw_addr->length == 0)
- return -EOPNOTSUPP;
-
- if (arp_type == ARPHRD_ETHER)
- assert_return(hw_addr->length == ETH_ALEN, -EINVAL);
- else if (arp_type == ARPHRD_INFINIBAND)
- assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL);
- else
- return -EOPNOTSUPP;
-
- unaligned_write_be16(&ret_duid->type, DUID_TYPE_LL);
- unaligned_write_be16(&ret_duid->ll.htype, arp_type);
- memcpy(ret_duid->ll.haddr, hw_addr->bytes, hw_addr->length);
-
- *ret_len = offsetof(struct duid, ll.haddr) + hw_addr->length;
-
- return 0;
-}
-
-int dhcp_identifier_set_duid_en(struct duid *ret_duid, size_t *ret_len) {
- sd_id128_t machine_id;
- bool test_mode;
- uint64_t hash;
- int r;
-
- assert(ret_duid);
- assert(ret_len);
-
- test_mode = network_test_mode_enabled();
-
- if (!test_mode) {
- r = sd_id128_get_machine(&machine_id);
- if (r < 0)
- return r;
- } else
- /* For tests, especially for fuzzers, reproducibility is important.
- * Hence, use a static and constant machine ID.
- * See 9216fddc5a8ac2742e6cfa7660f95c20ca4f2193. */
- machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10);
-
- unaligned_write_be16(&ret_duid->type, DUID_TYPE_EN);
- unaligned_write_be32(&ret_duid->en.pen, SYSTEMD_PEN);
-
- /* a bit of snake-oil perhaps, but no need to expose the machine-id
- * directly; duid->en.id might not be aligned, so we need to copy */
- hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes));
- memcpy(ret_duid->en.id, &hash, sizeof(hash));
-
- *ret_len = offsetof(struct duid, en.id) + sizeof(hash);
-
- if (test_mode)
- assert_se(memcmp(ret_duid, (const uint8_t[]) { 0x00, 0x02, 0x00, 0x00, 0xab, 0x11, 0x61, 0x77, 0x40, 0xde, 0x13, 0x42, 0xc3, 0xa2 }, *ret_len) == 0);
-
- return 0;
-}
-
-int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len) {
- sd_id128_t machine_id;
- int r;
-
- assert(ret_duid);
- assert(ret_len);
-
- r = sd_id128_get_machine_app_specific(APPLICATION_ID, &machine_id);
- if (r < 0)
- return r;
-
- unaligned_write_be16(&ret_duid->type, DUID_TYPE_UUID);
- memcpy(&ret_duid->uuid.uuid, &machine_id, sizeof(machine_id));
-
- *ret_len = offsetof(struct duid, uuid.uuid) + sizeof(machine_id);
-
- return 0;
-}
-
-int dhcp_identifier_set_duid_raw(
- DUIDType duid_type,
- const uint8_t *buf,
- size_t buf_len,
- struct duid *ret_duid,
- size_t *ret_len) {
-
- assert(buf || buf_len == 0);
- assert(ret_duid);
- assert(ret_len);
-
- if (duid_type < 0 || duid_type > UINT16_MAX)
- return -EINVAL;
-
- if (buf_len > MAX_DUID_DATA_LEN)
- return -EINVAL;
-
- unaligned_write_be16(&ret_duid->type, duid_type);
- memcpy_safe(ret_duid->raw.data, buf, buf_len);
-
- *ret_len = offsetof(struct duid, raw.data) + buf_len;
- return 0;
-}
-
-int dhcp_identifier_set_iaid(
- sd_device *dev,
- const struct hw_addr_data *hw_addr,
- bool legacy_unstable_byteorder,
- void *ret) {
-
- const char *name = NULL;
- uint32_t id32;
- uint64_t id;
-
- assert(hw_addr);
- assert(ret);
-
- if (dev)
- name = net_get_persistent_name(dev);
- if (name)
- id = siphash24(name, strlen(name), HASH_KEY.bytes);
- else
- /* fall back to MAC address if no predictable name available */
- id = siphash24(hw_addr->bytes, hw_addr->length, HASH_KEY.bytes);
-
- id32 = (id & 0xffffffff) ^ (id >> 32);
-
- if (legacy_unstable_byteorder)
- /* for historical reasons (a bug), the bits were swapped and thus
- * the result was endianness dependent. Preserve that behavior. */
- id32 = bswap_32(id32);
- else
- /* the fixed behavior returns a stable byte order. Since LE is expected
- * to be more common, swap the bytes on LE to give the same as legacy
- * behavior. */
- id32 = be32toh(id32);
-
- unaligned_write_ne32(ret, id32);
- return 0;
-}
diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h
index e5b3b1302c..3fbfc028e9 100644
--- a/src/libsystemd-network/dhcp6-internal.h
+++ b/src/libsystemd-network/dhcp6-internal.h
@@ -11,7 +11,7 @@
#include "sd-event.h"
#include "sd-dhcp6-client.h"
-#include "dhcp-identifier.h"
+#include "dhcp-duid-internal.h"
#include "dhcp6-client-internal.h"
#include "dhcp6-option.h"
#include "dhcp6-protocol.h"
@@ -64,8 +64,7 @@ struct sd_dhcp6_client {
DHCP6IA ia_na;
DHCP6IA ia_pd;
DHCP6RequestIA request_ia;
- struct duid duid;
- size_t duid_len;
+ sd_dhcp_duid duid;
be16_t *req_opts;
size_t n_req_opts;
char *fqdn;
diff --git a/src/libsystemd-network/meson.build b/src/libsystemd-network/meson.build
index 93186e23a1..510b0ed99e 100644
--- a/src/libsystemd-network/meson.build
+++ b/src/libsystemd-network/meson.build
@@ -2,7 +2,6 @@
sources = files(
'arp-util.c',
- 'dhcp-identifier.c',
'dhcp-network.c',
'dhcp-option.c',
'dhcp-packet.c',
@@ -17,6 +16,7 @@ sources = files(
'network-common.c',
'network-internal.c',
'sd-dhcp-client.c',
+ 'sd-dhcp-duid.c',
'sd-dhcp-lease.c',
'sd-dhcp-server.c',
'sd-dhcp6-client.c',
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 67911a2b93..8e370f1d7e 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -16,7 +16,7 @@
#include "alloc-util.h"
#include "device-util.h"
#include "dhcp-client-internal.h"
-#include "dhcp-identifier.h"
+#include "dhcp-duid-internal.h"
#include "dhcp-lease-internal.h"
#include "dhcp-network.h"
#include "dhcp-option.h"
@@ -451,29 +451,45 @@ static int dhcp_client_set_iaid(
return 0;
}
-int sd_dhcp_client_set_iaid_duid_llt(
+static int dhcp_client_set_iaid_duid(
sd_dhcp_client *client,
bool iaid_set,
uint32_t iaid,
- usec_t llt_time) {
+ sd_dhcp_duid *duid) {
- size_t len;
int r;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
+ assert_return(duid, -EINVAL);
+ assert_return(sd_dhcp_duid_is_set(duid), -ESTALE);
r = dhcp_client_set_iaid(client, iaid_set, iaid);
if (r < 0)
return r;
- r = dhcp_identifier_set_duid_llt(&client->hw_addr, client->arp_type, llt_time, &client->client_id.ns.duid, &len);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set DUID-LLT: %m");
+ memcpy(&client->client_id.ns.duid, &duid->duid, duid->size);
+ client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid->size;
+ return 0;
+}
+
+int sd_dhcp_client_set_iaid_duid_llt(
+ sd_dhcp_client *client,
+ bool iaid_set,
+ uint32_t iaid,
+ usec_t llt_time) {
- client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
+ sd_dhcp_duid duid;
+ int r;
- return 0;
+ assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
+
+ r = sd_dhcp_duid_set_llt(&duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type, llt_time);
+ if (r < 0)
+ return r;
+
+ return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
}
int sd_dhcp_client_set_iaid_duid_ll(
@@ -481,23 +497,17 @@ int sd_dhcp_client_set_iaid_duid_ll(
bool iaid_set,
uint32_t iaid) {
- size_t len;
+ sd_dhcp_duid duid;
int r;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
- r = dhcp_client_set_iaid(client, iaid_set, iaid);
+ r = sd_dhcp_duid_set_ll(&duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type);
if (r < 0)
return r;
- r = dhcp_identifier_set_duid_ll(&client->hw_addr, client->arp_type, &client->client_id.ns.duid, &len);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set DUID-LL: %m");
-
- client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
-
- return 0;
+ return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
}
int sd_dhcp_client_set_iaid_duid_en(
@@ -505,23 +515,17 @@ int sd_dhcp_client_set_iaid_duid_en(
bool iaid_set,
uint32_t iaid) {
- size_t len;
+ sd_dhcp_duid duid;
int r;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
- r = dhcp_client_set_iaid(client, iaid_set, iaid);
+ r = sd_dhcp_duid_set_en(&duid);
if (r < 0)
return r;
- r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set DUID-EN: %m");
-
- client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
-
- return 0;
+ return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
}
int sd_dhcp_client_set_iaid_duid_uuid(
@@ -529,23 +533,17 @@ int sd_dhcp_client_set_iaid_duid_uuid(
bool iaid_set,
uint32_t iaid) {
- size_t len;
+ sd_dhcp_duid duid;
int r;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
- r = dhcp_client_set_iaid(client, iaid_set, iaid);
+ r = sd_dhcp_duid_set_uuid(&duid);
if (r < 0)
return r;
- r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set DUID-UUID: %m");
-
- client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
-
- return 0;
+ return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
}
int sd_dhcp_client_set_iaid_duid_raw(
@@ -553,27 +551,21 @@ int sd_dhcp_client_set_iaid_duid_raw(
bool iaid_set,
uint32_t iaid,
uint16_t duid_type,
- const uint8_t *duid,
- size_t duid_len) {
+ const uint8_t *duid_data,
+ size_t duid_data_len) {
- size_t len;
+ sd_dhcp_duid duid;
int r;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
- assert_return(duid || duid_len == 0, -EINVAL);
+ assert_return(duid_data || duid_data_len == 0, -EINVAL);
- r = dhcp_client_set_iaid(client, iaid_set, iaid);
+ r = sd_dhcp_duid_set(&duid, duid_type, duid_data, duid_data_len);
if (r < 0)
return r;
- r = dhcp_identifier_set_duid_raw(duid_type, duid, duid_len, &client->client_id.ns.duid, &len);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set DUID: %m");
-
- client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len;
-
- return 0;
+ return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
}
int sd_dhcp_client_set_rapid_commit(sd_dhcp_client *client, bool rapid_commit) {
diff --git a/src/libsystemd-network/sd-dhcp-duid.c b/src/libsystemd-network/sd-dhcp-duid.c
new file mode 100644
index 0000000000..303e332320
--- /dev/null
+++ b/src/libsystemd-network/sd-dhcp-duid.c
@@ -0,0 +1,241 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <linux/if_infiniband.h>
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+
+#include "dhcp-duid-internal.h"
+#include "netif-util.h"
+#include "network-common.h"
+#include "siphash24.h"
+#include "string-table.h"
+#include "unaligned.h"
+
+#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
+#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03)
+#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",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_TO_STRING(duid_type, DUIDType);
+
+int sd_dhcp_duid_clear(sd_dhcp_duid *duid) {
+ assert_return(duid, -EINVAL);
+
+ *duid = (sd_dhcp_duid) {};
+ return 0;
+}
+
+int sd_dhcp_duid_is_set(const sd_dhcp_duid *duid) {
+ if (!duid)
+ return false;
+
+ return duid_size_is_valid(duid->size);
+}
+
+int sd_dhcp_duid_get(const sd_dhcp_duid *duid, uint16_t *ret_type, const void **ret_data, size_t *ret_size) {
+ assert_return(sd_dhcp_duid_is_set(duid), -EINVAL);
+ assert_return(ret_type, -EINVAL);
+ assert_return(ret_data, -EINVAL);
+ assert_return(ret_size, -EINVAL);
+
+ *ret_type = be16toh(duid->duid.type);
+ *ret_data = duid->duid.data;
+ *ret_size = duid->size - offsetof(struct duid, data);
+ return 0;
+}
+
+int sd_dhcp_duid_get_raw(const sd_dhcp_duid *duid, const void **ret_data, size_t *ret_size) {
+ assert_return(sd_dhcp_duid_is_set(duid), -EINVAL);
+ assert_return(ret_data, -EINVAL);
+ assert_return(ret_size, -EINVAL);
+
+ /* Unlike sd_dhcp_duid_get(), this returns whole DUID including its type. */
+
+ *ret_data = duid->raw;
+ *ret_size = duid->size;
+ return 0;
+}
+
+int sd_dhcp_duid_set(
+ sd_dhcp_duid *duid,
+ uint16_t duid_type,
+ const void *data,
+ size_t data_size) {
+
+ assert_return(duid, -EINVAL);
+ assert_return(data, -EINVAL);
+ assert_return(duid_data_size_is_valid(data_size), -EINVAL);
+
+ unaligned_write_be16(&duid->duid.type, duid_type);
+ memcpy(duid->duid.data, data, data_size);
+
+ duid->size = offsetof(struct duid, data) + data_size;
+ return 0;
+}
+
+int sd_dhcp_duid_set_raw(
+ sd_dhcp_duid *duid,
+ const void *data,
+ size_t data_size) {
+
+ assert_return(duid, -EINVAL);
+ assert_return(data, -EINVAL);
+ assert_return(duid_size_is_valid(data_size), -EINVAL);
+
+ /* Unlike sd_dhcp_duid_set(), this takes whole DUID including its type. */
+
+ memcpy(duid->raw, data, data_size);
+
+ duid->size = data_size;
+ return 0;
+}
+
+int sd_dhcp_duid_set_llt(
+ sd_dhcp_duid *duid,
+ const void *hw_addr,
+ size_t hw_addr_size,
+ uint16_t arp_type,
+ uint64_t usec) {
+
+ uint16_t time_from_2000y;
+
+ assert_return(duid, -EINVAL);
+ assert_return(hw_addr, -EINVAL);
+
+ if (arp_type == ARPHRD_ETHER)
+ assert_return(hw_addr_size == ETH_ALEN, -EINVAL);
+ else if (arp_type == ARPHRD_INFINIBAND)
+ assert_return(hw_addr_size == INFINIBAND_ALEN, -EINVAL);
+ else
+ return -EOPNOTSUPP;
+
+ time_from_2000y = (uint16_t) ((usec_sub_unsigned(usec, USEC_2000) / USEC_PER_SEC) & 0xffffffff);
+
+ unaligned_write_be16(&duid->duid.type, SD_DUID_TYPE_LLT);
+ unaligned_write_be16(&duid->duid.llt.htype, arp_type);
+ unaligned_write_be32(&duid->duid.llt.time, time_from_2000y);
+ memcpy(duid->duid.llt.haddr, hw_addr, hw_addr_size);
+
+ duid->size = offsetof(struct duid, llt.haddr) + hw_addr_size;
+ return 0;
+}
+
+int sd_dhcp_duid_set_ll(
+ sd_dhcp_duid *duid,
+ const void *hw_addr,
+ size_t hw_addr_size,
+ uint16_t arp_type) {
+
+ assert_return(duid, -EINVAL);
+ assert_return(hw_addr, -EINVAL);
+
+ if (arp_type == ARPHRD_ETHER)
+ assert_return(hw_addr_size == ETH_ALEN, -EINVAL);
+ else if (arp_type == ARPHRD_INFINIBAND)
+ assert_return(hw_addr_size == INFINIBAND_ALEN, -EINVAL);
+ else
+ return -EOPNOTSUPP;
+
+ unaligned_write_be16(&duid->duid.type, SD_DUID_TYPE_LL);
+ unaligned_write_be16(&duid->duid.ll.htype, arp_type);
+ memcpy(duid->duid.ll.haddr, hw_addr, hw_addr_size);
+
+ duid->size = offsetof(struct duid, ll.haddr) + hw_addr_size;
+ return 0;
+}
+
+int sd_dhcp_duid_set_en(sd_dhcp_duid *duid) {
+ sd_id128_t machine_id;
+ bool test_mode;
+ uint64_t hash;
+ int r;
+
+ assert_return(duid, -EINVAL);
+
+ test_mode = network_test_mode_enabled();
+
+ if (!test_mode) {
+ r = sd_id128_get_machine(&machine_id);
+ if (r < 0)
+ return r;
+ } else
+ /* For tests, especially for fuzzers, reproducibility is important.
+ * Hence, use a static and constant machine ID.
+ * See 9216fddc5a8ac2742e6cfa7660f95c20ca4f2193. */
+ machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10);
+
+ unaligned_write_be16(&duid->duid.type, SD_DUID_TYPE_EN);
+ unaligned_write_be32(&duid->duid.en.pen, SYSTEMD_PEN);
+
+ /* a bit of snake-oil perhaps, but no need to expose the machine-id
+ * directly; duid->en.id might not be aligned, so we need to copy */
+ hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes));
+ memcpy(duid->duid.en.id, &hash, sizeof(hash));
+
+ duid->size = offsetof(struct duid, en.id) + sizeof(hash);
+
+ if (test_mode)
+ assert_se(memcmp(&duid->duid, (const uint8_t[]) { 0x00, 0x02, 0x00, 0x00, 0xab, 0x11, 0x61, 0x77, 0x40, 0xde, 0x13, 0x42, 0xc3, 0xa2 }, duid->size) == 0);
+
+ return 0;
+}
+
+int sd_dhcp_duid_set_uuid(sd_dhcp_duid *duid) {
+ sd_id128_t machine_id;
+ int r;
+
+ assert_return(duid, -EINVAL);
+
+ r = sd_id128_get_machine_app_specific(APPLICATION_ID, &machine_id);
+ if (r < 0)
+ return r;
+
+ unaligned_write_be16(&duid->duid.type, SD_DUID_TYPE_UUID);
+ memcpy(&duid->duid.uuid.uuid, &machine_id, sizeof(machine_id));
+
+ duid->size = offsetof(struct duid, uuid.uuid) + sizeof(machine_id);
+ return 0;
+}
+
+int dhcp_identifier_set_iaid(
+ sd_device *dev,
+ const struct hw_addr_data *hw_addr,
+ bool legacy_unstable_byteorder,
+ void *ret) {
+
+ const char *name = NULL;
+ uint32_t id32;
+ uint64_t id;
+
+ assert(hw_addr);
+ assert(ret);
+
+ if (dev)
+ name = net_get_persistent_name(dev);
+ if (name)
+ id = siphash24(name, strlen(name), HASH_KEY.bytes);
+ else
+ /* fall back to MAC address if no predictable name available */
+ id = siphash24(hw_addr->bytes, hw_addr->length, HASH_KEY.bytes);
+
+ id32 = (id & 0xffffffff) ^ (id >> 32);
+
+ if (legacy_unstable_byteorder)
+ /* for historical reasons (a bug), the bits were swapped and thus
+ * the result was endianness dependent. Preserve that behavior. */
+ id32 = bswap_32(id32);
+ else
+ /* the fixed behavior returns a stable byte order. Since LE is expected
+ * to be more common, swap the bytes on LE to give the same as legacy
+ * behavior. */
+ id32 = be32toh(id32);
+
+ unaligned_write_ne32(ret, id32);
+ return 0;
+}
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index c20367dfc9..ed173b1e09 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -12,7 +12,7 @@
#include "alloc-util.h"
#include "device-util.h"
-#include "dhcp-identifier.h"
+#include "dhcp-duid-internal.h"
#include "dhcp6-internal.h"
#include "dhcp6-lease-internal.h"
#include "dns-domain.h"
@@ -191,10 +191,10 @@ int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client, sd_dhcp6_option *
static int client_ensure_duid(sd_dhcp6_client *client) {
assert(client);
- if (client->duid_len != 0)
+ if (sd_dhcp_duid_is_set(&client->duid))
return 0;
- return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
+ return sd_dhcp6_client_set_duid_en(client);
}
/**
@@ -208,7 +208,7 @@ int sd_dhcp6_client_set_duid_llt(sd_dhcp6_client *client, uint64_t llt_time) {
assert_return(client, -EINVAL);
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
- r = dhcp_identifier_set_duid_llt(&client->hw_addr, client->arp_type, llt_time, &client->duid, &client->duid_len);
+ r = sd_dhcp_duid_set_llt(&client->duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type, llt_time);
if (r < 0)
return log_dhcp6_client_errno(client, r, "Failed to set DUID-LLT: %m");
@@ -221,7 +221,7 @@ int sd_dhcp6_client_set_duid_ll(sd_dhcp6_client *client) {
assert_return(client, -EINVAL);
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
- r = dhcp_identifier_set_duid_ll(&client->hw_addr, client->arp_type, &client->duid, &client->duid_len);
+ r = sd_dhcp_duid_set_ll(&client->duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type);
if (r < 0)
return log_dhcp6_client_errno(client, r, "Failed to set DUID-LL: %m");
@@ -234,7 +234,7 @@ int sd_dhcp6_client_set_duid_en(sd_dhcp6_client *client) {
assert_return(client, -EINVAL);
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
- r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
+ r = sd_dhcp_duid_set_en(&client->duid);
if (r < 0)
return log_dhcp6_client_errno(client, r, "Failed to set DUID-EN: %m");
@@ -247,7 +247,7 @@ int sd_dhcp6_client_set_duid_uuid(sd_dhcp6_client *client) {
assert_return(client, -EINVAL);
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
- r = dhcp_identifier_set_duid_uuid(&client->duid, &client->duid_len);
+ r = sd_dhcp_duid_set_uuid(&client->duid);
if (r < 0)
return log_dhcp6_client_errno(client, r, "Failed to set DUID-UUID: %m");
@@ -261,7 +261,7 @@ int sd_dhcp6_client_set_duid_raw(sd_dhcp6_client *client, uint16_t duid_type, co
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
assert_return(duid || duid_len == 0, -EINVAL);
- r = dhcp_identifier_set_duid_raw(duid_type, duid, duid_len, &client->duid, &client->duid_len);
+ r = sd_dhcp_duid_set(&client->duid, duid_type, duid, duid_len);
if (r < 0)
return log_dhcp6_client_errno(client, r, "Failed to set DUID: %m");
@@ -276,21 +276,21 @@ int sd_dhcp6_client_duid_as_string(
int r;
assert_return(client, -EINVAL);
- assert_return(client->duid_len > offsetof(struct duid, raw.data), -ENODATA);
+ assert_return(sd_dhcp_duid_is_set(&client->duid), -ENODATA);
assert_return(duid, -EINVAL);
- v = duid_type_to_string(be16toh(client->duid.type));
+ v = duid_type_to_string(be16toh(client->duid.duid.type));
if (v) {
s = strdup(v);
if (!s)
return -ENOMEM;
} else {
- r = asprintf(&s, "%0x", client->duid.type);
+ r = asprintf(&s, "%0x", client->duid.duid.type);
if (r < 0)
return -ENOMEM;
}
- t = hexmem(client->duid.raw.data, client->duid_len - offsetof(struct duid, raw.data));
+ t = hexmem(client->duid.duid.data, client->duid.size - offsetof(struct duid, data));
if (!t)
return -ENOMEM;
@@ -825,9 +825,9 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
if (r < 0)
return r;
- assert(client->duid_len > 0);
+ assert(sd_dhcp_duid_is_set(&client->duid));
r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_CLIENTID,
- client->duid_len, &client->duid);
+ client->duid.size, &client->duid.duid);
if (r < 0)
return r;
diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c
index a7180ea585..e5d6547588 100644
--- a/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/libsystemd-network/sd-dhcp6-lease.c
@@ -867,7 +867,7 @@ static int dhcp6_lease_parse_message(
"%s message does not contain client ID. Ignoring.",
dhcp6_message_type_to_string(message->type));
- if (memcmp_nn(clientid, clientid_len, &client->duid, client->duid_len) != 0)
+ if (memcmp_nn(clientid, clientid_len, &client->duid.duid, client->duid.size) != 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"The client ID in %s message does not match. Ignoring.",
dhcp6_message_type_to_string(message->type));
diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c
index e3f148daf5..ff3ff2fc4b 100644
--- a/src/libsystemd-network/test-dhcp-client.c
+++ b/src/libsystemd-network/test-dhcp-client.c
@@ -17,7 +17,7 @@
#include "sd-event.h"
#include "alloc-util.h"
-#include "dhcp-identifier.h"
+#include "dhcp-duid-internal.h"
#include "dhcp-network.h"
#include "dhcp-option.h"
#include "dhcp-packet.h"
@@ -165,19 +165,18 @@ static int check_options(uint8_t code, uint8_t len, const void *option, void *us
switch (code) {
case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
{
+ sd_dhcp_duid duid;
uint32_t iaid;
- struct duid duid;
- size_t duid_len;
- assert_se(dhcp_identifier_set_duid_en(&duid, &duid_len) >= 0);
+ assert_se(sd_dhcp_duid_set_en(&duid) >= 0);
assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy = */ true, &iaid) >= 0);
- assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len);
+ assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid.size);
assert_se(len == 19);
assert_se(((uint8_t*) option)[0] == 0xff);
assert_se(memcmp((uint8_t*) option + 1, &iaid, sizeof(iaid)) == 0);
- assert_se(memcmp((uint8_t*) option + 5, &duid, duid_len) == 0);
+ assert_se(memcmp((uint8_t*) option + 5, &duid.duid, duid.size) == 0);
break;
}
diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c
index c9539050b9..ecf3f095c3 100644
--- a/src/libsystemd-network/test-dhcp6-client.c
+++ b/src/libsystemd-network/test-dhcp6-client.c
@@ -13,7 +13,7 @@
#include "sd-dhcp6-client.h"
#include "sd-event.h"
-#include "dhcp-identifier.h"
+#include "dhcp-duid-internal.h"
#include "dhcp6-internal.h"
#include "dhcp6-lease-internal.h"
#include "dhcp6-protocol.h"
diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c
index 080b15387c..ac8baeb94c 100644
--- a/src/network/networkd-dhcp-common.c
+++ b/src/network/networkd-dhcp-common.c
@@ -5,7 +5,6 @@
#include "bus-error.h"
#include "bus-locator.h"
-#include "dhcp-identifier.h"
#include "dhcp-option.h"
#include "dhcp6-internal.h"
#include "escape.h"
diff --git a/src/network/networkd-dhcp-common.h b/src/network/networkd-dhcp-common.h
index 6e3f3b2a1e..f888e03b96 100644
--- a/src/network/networkd-dhcp-common.h
+++ b/src/network/networkd-dhcp-common.h
@@ -4,7 +4,7 @@
#include <netinet/in.h>
#include "conf-parser.h"
-#include "dhcp-identifier.h"
+#include "dhcp-duid-internal.h"
#include "in-addr-util.h"
#include "set.h"
#include "time-util.h"
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 47433ef1ab..ac8841681d 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -17,7 +17,6 @@
#include "bus-util.h"
#include "device-private.h"
#include "device-util.h"
-#include "dhcp-identifier.h"
#include "dhcp-lease-internal.h"
#include "env-file.h"
#include "ethtool-util.h"
diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h
index 2554e0e031..3f3569f44d 100644
--- a/src/network/networkd-manager.h
+++ b/src/network/networkd-manager.h
@@ -8,7 +8,7 @@
#include "sd-netlink.h"
#include "sd-resolve.h"
-#include "dhcp-identifier.h"
+#include "dhcp-duid-internal.h"
#include "firewall-util.h"
#include "hashmap.h"
#include "networkd-link.h"
diff --git a/src/systemd/meson.build b/src/systemd/meson.build
index a9cdcd24a0..76531dd12a 100644
--- a/src/systemd/meson.build
+++ b/src/systemd/meson.build
@@ -21,6 +21,7 @@ systemd_headers = files(_systemd_headers)
_not_installed_headers = [
'sd-dhcp-client.h',
+ 'sd-dhcp-duid.h',
'sd-dhcp-lease.h',
'sd-dhcp-option.h',
'sd-dhcp-protocol.h',
diff --git a/src/systemd/sd-dhcp-duid.h b/src/systemd/sd-dhcp-duid.h
new file mode 100644
index 0000000000..06e3f8af17
--- /dev/null
+++ b/src/systemd/sd-dhcp-duid.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#ifndef foosddhcpduidhfoo
+#define foosddhcpduidhfoo
+
+/***
+ Copyright © 2013 Intel Corporation. All rights reserved.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <https://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
+enum {
+ SD_DUID_TYPE_LLT = 1,
+ SD_DUID_TYPE_EN = 2,
+ SD_DUID_TYPE_LL = 3,
+ SD_DUID_TYPE_UUID = 4
+};
+
+typedef struct sd_dhcp_duid sd_dhcp_duid;
+
+int sd_dhcp_duid_clear(sd_dhcp_duid *duid);
+
+int sd_dhcp_duid_is_set(const sd_dhcp_duid *duid);
+
+int sd_dhcp_duid_get(const sd_dhcp_duid *duid, uint16_t *ret_type, const void **ret_data, size_t *ret_size);
+int sd_dhcp_duid_get_raw(const sd_dhcp_duid *duid, const void **ret_data, size_t *ret_size);
+
+int sd_dhcp_duid_set(
+ sd_dhcp_duid *duid,
+ uint16_t duid_type,
+ const void *data,
+ size_t data_size);
+int sd_dhcp_duid_set_raw(
+ sd_dhcp_duid *duid,
+ const void *data,
+ size_t data_size);
+int sd_dhcp_duid_set_llt(
+ sd_dhcp_duid *duid,
+ const void *hw_addr,
+ size_t hw_addr_size,
+ uint16_t arp_type,
+ uint64_t usec);
+int sd_dhcp_duid_set_ll(
+ sd_dhcp_duid *duid,
+ const void *hw_addr,
+ size_t hw_addr_size,
+ uint16_t arp_type);
+int sd_dhcp_duid_set_en(sd_dhcp_duid *duid);
+int sd_dhcp_duid_set_uuid(sd_dhcp_duid *duid);
+
+_SD_END_DECLARATIONS;
+
+#endif