dhcp4: introduce new option 'duid-only' for ClientIdentifier= (#8350)
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 12 Mar 2018 16:18:07 +0000 (01:18 +0900)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 12 Mar 2018 16:18:07 +0000 (17:18 +0100)
This makes users can configure DHCPv4 client with ClientIdentifier=duid-only.
If set so, then DHCP client sends only DUID as the client identifier.
This may not be RFC compliant, but some setups require this.

Closes #7828.

man/systemd.network.xml
src/libsystemd-network/sd-dhcp-client.c
src/network/networkd-dhcp4.c
src/network/networkd-link.c
src/network/networkd-network.c
src/network/networkd-network.h
src/systemd/sd-dhcp-client.h

index 80d2802..e4e7bad 100644 (file)
         <varlistentry>
           <term><varname>ClientIdentifier=</varname></term>
           <listitem>
-            <para>The DHCPv4 client identifier to use. Either <literal>mac</literal> to use the MAC address of the link
-            or <literal>duid</literal> (the default, see below) to use an RFC4361-compliant Client ID.</para>
+            <para>The DHCPv4 client identifier to use. Takes one of <literal>mac</literal>, <literal>duid</literal> or <literal>duid-only</literal>.
+            If set to <literal>mac</literal>, the MAC address of the link is used.
+            If set to <literal>duid</literal>, an RFC4361-compliant Client ID, which is the combination of IAID and DUID (see below), is used.
+            If set to <literal>duid-only</literal>, only DUID is used, this may not be RFC compliant, but some setups may require to use this.
+            Defaults to <literal>duid</literal>.</para>
           </listitem>
         </varlistentry>
 
index 33f3469..9cf4974 100644 (file)
@@ -354,9 +354,10 @@ int sd_dhcp_client_set_client_id(
  * without further modification. Otherwise, if duid_type is supported, DUID
  * is set based on that type. Otherwise, an error is returned.
  */
-int sd_dhcp_client_set_iaid_duid(
+static int dhcp_client_set_iaid_duid(
                 sd_dhcp_client *client,
                 uint32_t iaid,
+                bool append_iaid,
                 uint16_t duid_type,
                 const void *duid,
                 size_t duid_len) {
@@ -377,15 +378,17 @@ int sd_dhcp_client_set_iaid_duid(
         zero(client->client_id);
         client->client_id.type = 255;
 
-        /* If IAID is not configured, generate it. */
-        if (iaid == 0) {
-                r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
-                                             client->mac_addr_len,
-                                             &client->client_id.ns.iaid);
-                if (r < 0)
-                        return r;
-        } else
-                client->client_id.ns.iaid = htobe32(iaid);
+        if (append_iaid) {
+                /* If IAID is not configured, generate it. */
+                if (iaid == 0) {
+                        r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
+                                                     client->mac_addr_len,
+                                                     &client->client_id.ns.iaid);
+                        if (r < 0)
+                                return r;
+                } else
+                        client->client_id.ns.iaid = htobe32(iaid);
+        }
 
         if (duid != NULL) {
                 client->client_id.ns.duid.type = htobe16(duid_type);
@@ -399,7 +402,7 @@ int sd_dhcp_client_set_iaid_duid(
                 return -EOPNOTSUPP;
 
         client->client_id_len = sizeof(client->client_id.type) + len +
-                                sizeof(client->client_id.ns.iaid);
+                                (append_iaid ? sizeof(client->client_id.ns.iaid) : 0);
 
         if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
                 log_dhcp_client(client, "Configured IAID+DUID, restarting.");
@@ -410,6 +413,23 @@ int sd_dhcp_client_set_iaid_duid(
         return 0;
 }
 
+int sd_dhcp_client_set_iaid_duid(
+                sd_dhcp_client *client,
+                uint32_t iaid,
+                uint16_t duid_type,
+                const void *duid,
+                size_t duid_len) {
+        return dhcp_client_set_iaid_duid(client, iaid, true, duid_type, duid, duid_len);
+}
+
+int sd_dhcp_client_set_duid(
+                sd_dhcp_client *client,
+                uint16_t duid_type,
+                const void *duid,
+                size_t duid_len) {
+        return dhcp_client_set_iaid_duid(client, 0, false, duid_type, duid, duid_len);
+}
+
 int sd_dhcp_client_set_hostname(
                 sd_dhcp_client *client,
                 const char *hostname) {
index ecb96cd..9176236 100644 (file)
@@ -776,6 +776,18 @@ int dhcp4_configure(Link *link) {
                         return r;
                 break;
         }
+        case DHCP_CLIENT_ID_DUID_ONLY: {
+                /* If configured, apply user specified DUID */
+                const DUID *duid = link_duid(link);
+
+                r = sd_dhcp_client_set_duid(link->dhcp_client,
+                                            duid->type,
+                                            duid->raw_data_len > 0 ? duid->raw_data : NULL,
+                                            duid->raw_data_len);
+                if (r < 0)
+                        return r;
+                break;
+        }
         case DHCP_CLIENT_ID_MAC:
                 r = sd_dhcp_client_set_client_id(link->dhcp_client,
                                                  ARPHRD_ETHER,
index 64c4508..ad2d90b 100644 (file)
@@ -3282,6 +3282,17 @@ int link_update(Link *link, sd_netlink_message *m) {
                                                 return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m");
                                         break;
                                 }
+                                case DHCP_CLIENT_ID_DUID_ONLY: {
+                                        const DUID *duid = link_duid(link);
+
+                                        r = sd_dhcp_client_set_duid(link->dhcp_client,
+                                                                    duid->type,
+                                                                    duid->raw_data_len > 0 ? duid->raw_data : NULL,
+                                                                    duid->raw_data_len);
+                                        if (r < 0)
+                                                return log_link_warning_errno(link, r, "Could not update DUID in DHCP client: %m");
+                                        break;
+                                }
                                 case DHCP_CLIENT_ID_MAC:
                                         r = sd_dhcp_client_set_client_id(link->dhcp_client,
                                                                          ARPHRD_ETHER,
index 709ae2a..fc9fbed 100644 (file)
@@ -859,7 +859,8 @@ int config_parse_dhcp(
 
 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
         [DHCP_CLIENT_ID_MAC] = "mac",
-        [DHCP_CLIENT_ID_DUID] = "duid"
+        [DHCP_CLIENT_ID_DUID] = "duid",
+        [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
 };
 
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
index 7b40ba5..8163d9e 100644 (file)
 typedef enum DHCPClientIdentifier {
         DHCP_CLIENT_ID_MAC,
         DHCP_CLIENT_ID_DUID,
+        /* The following option may not be good for RFC regarding DHCP (3315 and 4361).
+         * But some setups require this. E.g., Sky Broadband, the second largest provider in the UK
+         * requires the client id to be set to a custom string, reported at
+         * https://github.com/systemd/systemd/issues/7828 */
+        DHCP_CLIENT_ID_DUID_ONLY,
         _DHCP_CLIENT_ID_MAX,
         _DHCP_CLIENT_ID_INVALID = -1,
 } DHCPClientIdentifier;
index 6eb9eb6..789cc50 100644 (file)
@@ -132,6 +132,11 @@ int sd_dhcp_client_set_iaid_duid(
                 uint16_t duid_type,
                 const void *duid,
                 size_t duid_len);
+int sd_dhcp_client_set_duid(
+                sd_dhcp_client *client,
+                uint16_t duid_type,
+                const void *duid,
+                size_t duid_len);
 int sd_dhcp_client_get_client_id(
                 sd_dhcp_client *client,
                 uint8_t *type,