network dhcp4: Add support send request options in a generic manner
authorSusant Sahani <ssahani@vmware.com>
Tue, 17 Sep 2019 12:49:22 +0000 (14:49 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 20 Sep 2019 12:05:48 +0000 (21:05 +0900)
man/systemd.network.xml
src/network/networkd-dhcp4.c
src/network/networkd-dhcp4.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
test/fuzz/fuzz-network-parser/directives.network

index 8ecc39c..0fbc4df 100644 (file)
         </varlistentry>
 
         <varlistentry>
-          <term><varname>BlackList=</varname></term>
+        <term><varname>BlackList=</varname></term>
+        <listitem>
+          <para>A whitespace-separated list of IPv4 addresses. DHCP offers from servers in the list are rejected.</para>
+        </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>RequestOptions=</varname></term>
           <listitem>
-            <para>A whitespace-separated list of IPv4 addresses. DHCP offers from servers in the list are rejected.</para>
+            <para>A whitespace-separated list of integers in the range 1–254.</para>
           </listitem>
         </varlistentry>
 
index d9951ab..01fe769 100644 (file)
@@ -1078,6 +1078,8 @@ int dhcp4_set_client_identifier(Link *link) {
 }
 
 int dhcp4_configure(Link *link) {
+        void *request_options;
+        Iterator i;
         int r;
 
         assert(link);
@@ -1163,6 +1165,19 @@ int dhcp4_configure(Link *link) {
                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m");
         }
 
+        SET_FOREACH(request_options, link->network->dhcp_request_options, i) {
+                uint32_t option = PTR_TO_UINT32(request_options);
+
+                r = sd_dhcp_client_set_request_option(link->dhcp_client, option);
+                if (r == -EEXIST) {
+                        log_link_debug(link, "DHCP4 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
+                        continue;
+                }
+
+                if (r < 0)
+                        return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for '%u': %m", option);
+        }
+
         r = dhcp4_set_hostname(link);
         if (r < 0)
                 return r;
@@ -1357,6 +1372,72 @@ int config_parse_dhcp_user_class(
         return 0;
 }
 
+int config_parse_dhcp_request_options(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Network *network = data;
+        const char *p;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (isempty(rvalue)) {
+                network->dhcp_request_options = set_free(network->dhcp_request_options);
+                return 0;
+        }
+
+        for (p = rvalue;;) {
+                _cleanup_free_ char *n = NULL;
+                uint32_t i;
+
+                r = extract_first_word(&p, &n, NULL, 0);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to parse DHCP request option, ignoring assignment: %s",
+                                   rvalue);
+                        return 0;
+                }
+                if (r == 0)
+                        return 0;
+
+                r = safe_atou32(n, &i);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "DHCP request option is invalid, ignoring assignment: %s", n);
+                        continue;
+                }
+
+                if (i < 1 || i >= 255) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n);
+                        continue;
+                }
+
+                r = set_ensure_allocated(&network->dhcp_request_options, NULL);
+                if (r < 0)
+                        return log_oom();
+
+                r = set_put(network->dhcp_request_options, UINT32_TO_PTR(i));
+                if (r < 0)
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to store DHCP request option '%s', ignoring assignment: %m", n);
+        }
+
+        return 0;
+}
+
 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
         [DHCP_CLIENT_ID_MAC] = "mac",
         [DHCP_CLIENT_ID_DUID] = "duid",
index 117b711..fce11ef 100644 (file)
@@ -26,3 +26,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_black_listed_ip_address);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options);
index 43163a3..8772b0e 100644 (file)
@@ -149,6 +149,7 @@ DHCPv4.UseMTU,                          config_parse_bool,
 DHCPv4.UseHostname,                     config_parse_bool,                               0,                             offsetof(Network, dhcp_use_hostname)
 DHCPv4.UseDomains,                      config_parse_dhcp_use_domains,                   0,                             offsetof(Network, dhcp_use_domains)
 DHCPv4.UseRoutes,                       config_parse_bool,                               0,                             offsetof(Network, dhcp_use_routes)
+DHCPv4.RequestOptions,                  config_parse_dhcp_request_options,               0,                             0
 DHCPv4.Anonymize,                       config_parse_bool,                               0,                             offsetof(Network, dhcp_anonymize)
 DHCPv4.SendHostname,                    config_parse_bool,                               0,                             offsetof(Network, dhcp_send_hostname)
 DHCPv4.Hostname,                        config_parse_hostname,                           0,                             offsetof(Network, dhcp_hostname)
index 0608219..2fe4c2d 100644 (file)
@@ -541,6 +541,7 @@ static Network *network_free(Network *network) {
         strv_free(network->dhcp_user_class);
         free(network->dhcp_hostname);
         set_free(network->dhcp_black_listed_ip);
+        set_free(network->dhcp_request_options);
         free(network->mac);
 
         strv_free(network->ntp);
index 486b8c3..3bb21ef 100644 (file)
@@ -102,6 +102,7 @@ struct Network {
         bool dhcp_send_release;
         DHCPUseDomains dhcp_use_domains;
         Set *dhcp_black_listed_ip;
+        Set *dhcp_request_options;
 
         /* DHCPv6 Client support*/
         bool dhcp6_use_dns;
index b688d37..0381d8d 100644 (file)
@@ -89,6 +89,7 @@ ListenPort=
 UseTimezone=
 RouteTable=
 BlackList=
+RequestOptions=
 SendRelease=
 MaxAttempts=
 [DHCPv6]