[systemd-devel] [PATCH] sd-dhcp6-client: support custom DUIDs

Dan Williams dcbw at redhat.com
Wed Aug 6 09:17:16 PDT 2014


The caller may have an existing DUID that it wants to use, and may
want to use some other DUID generation scheme than systemd's
default DUID-EN.
---
 src/libsystemd-network/sd-dhcp6-client.c   | 52 +++++++++++++++++++-----------
 src/libsystemd-network/test-dhcp6-client.c |  4 +--
 src/network/networkd-link.c                |  2 +-
 src/systemd/sd-dhcp6-client.h              |  2 +-
 4 files changed, 38 insertions(+), 22 deletions(-)

diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index c6c82eb..8123dc8 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -35,14 +35,16 @@
 #include "dhcp6-protocol.h"
 #include "dhcp6-internal.h"
 #include "dhcp6-lease-internal.h"
 
 #define SYSTEMD_PEN 43793
 #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
 
+#define MAX_DUID_LEN 32
+
 struct sd_dhcp6_client {
         RefCount n_ref;
 
         enum DHCP6State state;
         sd_event *event;
         int event_priority;
         int index;
@@ -57,20 +59,16 @@ struct sd_dhcp6_client {
         sd_event_source *receive_message;
         usec_t retransmit_time;
         uint8_t retransmit_count;
         sd_event_source *timeout_resend;
         sd_event_source *timeout_resend_expire;
         sd_dhcp6_client_cb_t cb;
         void *userdata;
-
-        struct duid_en {
-                uint16_t type; /* DHCP6_DUID_EN */
-                uint32_t pen;
-                uint8_t id[8];
-        } _packed_ duid;
+        uint8_t duid[MAX_DUID_LEN];
+        size_t duid_len;
 };
 
 static const uint16_t default_req_opts[] = {
         DHCP6_OPTION_DNS_SERVERS,
         DHCP6_OPTION_DOMAIN_LIST,
         DHCP6_OPTION_NTP_SERVER,
 };
@@ -300,15 +298,15 @@ static int client_send_message(sd_dhcp6_client *client) {
         r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ORO,
                                 client->req_opts_len * sizeof(be16_t),
                                 client->req_opts);
         if (r < 0)
                 return r;
 
         r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID,
-                                sizeof(client->duid), &client->duid);
+                                client->duid_len, &client->duid);
         if (r < 0)
                 return r;
 
         r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
                                           len - optlen);
         if (r < 0)
                 return r;
@@ -585,15 +583,15 @@ static int client_parse_message(sd_dhcp6_client *client,
                 case DHCP6_OPTION_CLIENTID:
                         if (clientid) {
                                 log_dhcp6_client(client, "%s contains multiple clientids",
                                                  dhcp6_message_type_to_string(message->type));
                                 return -EINVAL;
                         }
 
-                        if (optlen != sizeof(client->duid) ||
+                        if (optlen != client->duid_len ||
                             memcmp(&client->duid, optval, optlen) != 0) {
                                 log_dhcp6_client(client, "%s DUID does not match",
                                                  dhcp6_message_type_to_string(message->type));
 
                                 return -EINVAL;
                         }
                         clientid = true;
@@ -1059,47 +1057,65 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
 
                 return NULL;
         }
 
         return client;
 }
 
-int sd_dhcp6_client_new(sd_dhcp6_client **ret)
+struct duid_en {
+        uint16_t type; /* DHCP6_DUID_EN */
+        uint32_t pen;
+        uint8_t id[8];
+} _packed_;
+
+int sd_dhcp6_client_new(sd_dhcp6_client **ret, uint8_t *duid, size_t duid_len)
 {
         _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL;
         sd_id128_t machine_id;
         int r;
         size_t t;
 
         assert_return(ret, -EINVAL);
+        if (duid)
+                assert_return(duid_len > 0 && duid_len < MAX_DUID_LEN, -EINVAL);
+        else
+                assert_return(duid_len == 0, -EINVAL);
 
         client = new0(sd_dhcp6_client, 1);
         if (!client)
                 return -ENOMEM;
 
         client->n_ref = REFCNT_INIT;
 
         client->ia_na.type = DHCP6_OPTION_IA_NA;
 
         client->index = -1;
 
         client->fd = -1;
 
         /* initialize DUID */
-        client->duid.type = htobe16(DHCP6_DUID_EN);
-        client->duid.pen = htobe32(SYSTEMD_PEN);
+        if (duid) {
+                memcpy(&client->duid, duid, duid_len);
+                client->duid_len = duid_len;
+        } else {
+                struct duid_en *en = (struct duid_en *) &client->duid;
 
-        r = sd_id128_get_machine(&machine_id);
-        if (r < 0)
-                return r;
+                en->type = htobe16(DHCP6_DUID_EN);
+                en->pen = htobe32(SYSTEMD_PEN);
 
-        /* a bit of snake-oil perhaps, but no need to expose the machine-id
-           directly */
-        siphash24(client->duid.id, &machine_id, sizeof(machine_id),
-                  HASH_KEY.bytes);
+                r = sd_id128_get_machine(&machine_id);
+                if (r < 0)
+                        return r;
+
+                /* a bit of snake-oil perhaps, but no need to expose the
+                   machine-id directly */
+                siphash24(en->id, &machine_id, sizeof(machine_id),
+                          HASH_KEY.bytes);
+                client->duid_len = sizeof (*en);
+        }
 
         client->req_opts_len = ELEMENTSOF(default_req_opts);
 
         client->req_opts = new0(be16_t, client->req_opts_len);
         if (!client->req_opts)
                 return -ENOMEM;
 
diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c
index 96c68e1..3545935 100644
--- a/src/libsystemd-network/test-dhcp6-client.c
+++ b/src/libsystemd-network/test-dhcp6-client.c
@@ -52,15 +52,15 @@ static uint8_t test_duid[14] = { };
 
 static int test_client_basic(sd_event *e) {
         sd_dhcp6_client *client;
 
         if (verbose)
                 printf("* %s\n", __FUNCTION__);
 
-        assert_se(sd_dhcp6_client_new(&client) >= 0);
+        assert_se(sd_dhcp6_client_new(&client, NULL, 0) >= 0);
         assert_se(client);
 
         assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
 
         assert_se(sd_dhcp6_client_set_index(client, 15) == 0);
         assert_se(sd_dhcp6_client_set_index(client, -42) == -EINVAL);
         assert_se(sd_dhcp6_client_set_index(client, -1) == 0);
@@ -538,15 +538,15 @@ static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
 static int test_client_solicit(sd_event *e) {
         sd_dhcp6_client *client;
         usec_t time_now = now(clock_boottime_or_monotonic());
 
         if (verbose)
                 printf("* %s\n", __FUNCTION__);
 
-        assert_se(sd_dhcp6_client_new(&client) >= 0);
+        assert_se(sd_dhcp6_client_new(&client, NULL, 0) >= 0);
         assert_se(client);
 
         assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
 
         assert_se(sd_dhcp6_client_set_index(client, test_index) == 0);
         assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0);
 
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index accb42b..eff14ca 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -1367,15 +1367,15 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
 
                 return;
         }
 
         if (link->dhcp6_client)
                 return;
 
-        r = sd_dhcp6_client_new(&link->dhcp6_client);
+        r = sd_dhcp6_client_new(&link->dhcp6_client, NULL, 0);
         if (r < 0)
                 return;
 
         r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
         if (r < 0) {
                 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
                 return;
diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h
index 93edcc4..b3ec82f 100644
--- a/src/systemd/sd-dhcp6-client.h
+++ b/src/systemd/sd-dhcp6-client.h
@@ -54,10 +54,10 @@ int sd_dhcp6_client_stop(sd_dhcp6_client *client);
 int sd_dhcp6_client_start(sd_dhcp6_client *client);
 int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
                                  int priority);
 int sd_dhcp6_client_detach_event(sd_dhcp6_client *client);
 sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client);
 sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client);
 sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client);
-int sd_dhcp6_client_new(sd_dhcp6_client **ret);
+int sd_dhcp6_client_new(sd_dhcp6_client **ret, uint8_t *duid, size_t duid_len);
 
 #endif
-- 
1.9.3




More information about the systemd-devel mailing list