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

Dan Williams dcbw at redhat.com
Tue Aug 12 07:39:14 PDT 2014


On Tue, 2014-08-12 at 01:12 +0200, Tom Gundersen wrote:
> On Wed, Aug 6, 2014 at 6:17 PM, Dan Williams <dcbw at redhat.com> wrote:
> > 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.
> 
> I have no objections a priori to this patch. But what is the use case?
> Is there some DUID scheme that is preferable to DUID-EN that we could
> simply use unconditionally, or do you really depend on the possibility
> of customizing it?

The DUID is like the v4 Client ID; it's the way to identify a specific
client so that you hand out specific options.  There may also be
installations that have existing configuration where the DUID is already
specified, and when changing the DHCP client suddenly everything would
get renumbered.  If you replace a machine with another machine, perhaps
you don't want to use whatever new DUID systemd would generate with
DUID-EN, but you want to use the old DUID.  I'm reluctant to just
mandate a specific DUID scheme mostly for the configuration reasons
above, but also because there are at least 4 DUID RFCs and it's not
clear to me which one is really "better".

Dan

> > ---
> >  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
> >
> >
> > _______________________________________________
> > systemd-devel mailing list
> > systemd-devel at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/systemd-devel




More information about the systemd-devel mailing list