]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dhcp4: make IPServiceType configurable
authorSiddharth Chandrasekara <csiddharth@vmware.com>
Mon, 23 Sep 2019 11:25:21 +0000 (04:25 -0700)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 26 Sep 2019 02:39:46 +0000 (11:39 +0900)
IPServiceType set to CS6 (network control) causes problems on some old
network setups that continue to interpret the field as IP TOS.

Make DHCP work on such networks by allowing this field to be set to
CS4 (Realtime) instead, as this maps to IPTOS_LOWDELAY.

Signed-off-by: Siddharth Chandrasekaran <csiddharth@vmware.com>
15 files changed:
man/systemd.network.xml
src/libsystemd-network/dhcp-internal.h
src/libsystemd-network/dhcp-network.c
src/libsystemd-network/dhcp-packet.c
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/sd-dhcp-server.c
src/libsystemd-network/test-dhcp-client.c
src/network/networkd-conf.c
src/network/networkd-conf.h
src/network/networkd-dhcp4.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/systemd/sd-dhcp-client.h
test/fuzz/fuzz-network-parser/directives.network

index 585041095d738a706a9f8f28fb8a7aed7f8c552d..e5f9d6f470652dcd2e82cc0eca03ca62ddfa7c34 100644 (file)
           <para>Note that if IPv6 is enabled on the interface, and the MTU is chosen
           below 1280 (the minimum MTU for IPv6) it will automatically be increased to this value.</para>
         </listitem>
-      </varlistentry>
+        </varlistentry>
+        <varlistentry>
+          <term><varname>IPServiceType=</varname></term>
+          <listitem>
+            <para>Takes string; "CS6" or "CS4". Used to set IP service type to CS6 (network control)
+            or CS4 (Realtime). IPServiceType defaults to CS6 if nothing is specified.</para>
+          </listitem>
+        </varlistentry>
       </variablelist>
   </refsect1>
 
index e0269b54564f15837f4e98fc5473d2bfbf89998c..c231773bddb324f0c332037d6e18e91aeefe6d10 100644 (file)
@@ -19,7 +19,7 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
                                  uint32_t xid, const uint8_t *mac_addr,
                                  size_t mac_addr_len, uint16_t arp_type,
                                  uint16_t port);
-int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port);
+int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type);
 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
                                  const void *packet, size_t len);
 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
@@ -41,7 +41,7 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
 
 void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
                                    uint16_t source, be32_t destination_addr,
-                                   uint16_t destination, uint16_t len);
+                                   uint16_t destination, uint16_t len, int ip_service_type);
 
 int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port);
 
index 94c10ed14c01ac37175a4eab0e2b371d8f376197..8e7f8a65ab64014064456fa08bfa8635f2da795b 100644 (file)
@@ -146,7 +146,7 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
                                 bcast_addr, &eth_mac, arp_type, dhcp_hlen, port);
 }
 
-int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
+int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
         union sockaddr_union src = {
                 .in.sin_family = AF_INET,
                 .in.sin_port = htobe16(port),
@@ -159,7 +159,11 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
         if (s < 0)
                 return -errno;
 
-        r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
+        if (ip_service_type >= 0)
+                r = setsockopt_int(s, IPPROTO_IP, IP_TOS, ip_service_type);
+        else
+                r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
+
         if (r < 0)
                 return r;
 
index ad5f8e267abd20a1461cc46ef34e4d79fe3b4210..fe7d51703badb3669c65637a1176dafe7abf442a 100644 (file)
@@ -75,12 +75,15 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) {
 
 void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
                                    uint16_t source_port, be32_t destination_addr,
-                                   uint16_t destination_port, uint16_t len) {
+                                   uint16_t destination_port, uint16_t len, int ip_service_type) {
         packet->ip.version = IPVERSION;
         packet->ip.ihl = DHCP_IP_SIZE / 4;
         packet->ip.tot_len = htobe16(len);
 
-        packet->ip.tos = IPTOS_CLASS_CS6;
+        if (ip_service_type >= 0)
+                packet->ip.tos = ip_service_type;
+        else
+                packet->ip.tos = IPTOS_CLASS_CS6;
 
         packet->ip.protocol = IPPROTO_UDP;
         packet->ip.saddr = source_addr;
index cadacc24d46925b2bc390f41000dcbd1e26d9b4a..2d511f7feb4578ec352874ac1daa6f22804f5156 100644 (file)
@@ -98,6 +98,7 @@ struct sd_dhcp_client {
         void *userdata;
         sd_dhcp_lease *lease;
         usec_t start_delay;
+        int ip_service_type;
 };
 
 static const uint8_t default_req_opts[] = {
@@ -541,6 +542,14 @@ int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
         return 0;
 }
 
+int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
+        assert_return(client, -EINVAL);
+
+        client->ip_service_type = type;
+
+        return 0;
+}
+
 static int client_notify(sd_dhcp_client *client, int event) {
         assert(client);
 
@@ -773,7 +782,7 @@ static int dhcp_client_send_raw(
                 size_t len) {
 
         dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
-                                      INADDR_BROADCAST, DHCP_PORT_SERVER, len);
+                                      INADDR_BROADCAST, DHCP_PORT_SERVER, len, client->ip_service_type);
 
         return dhcp_network_send_raw_socket(client->fd, &client->link,
                                             packet, len);
@@ -1661,7 +1670,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
                                 goto error;
                         }
 
-                        r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port);
+                        r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port, client->ip_service_type);
                         if (r < 0) {
                                 log_dhcp_client(client, "could not bind UDP socket");
                                 goto error;
@@ -2013,6 +2022,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
                 .port = DHCP_PORT_CLIENT,
                 .anonymize = !!anonymize,
                 .max_attempts = (uint64_t) -1,
+                .ip_service_type = -1,
         };
         /* NOTE: this could be moved to a function. */
         if (anonymize) {
index 13f104f9ef556519b89bc8aeec6f0b5cba6402a6..bba82c21dd7f70a503a8777fc45ac2346f541019 100644 (file)
@@ -244,7 +244,7 @@ static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
 
         dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
                                       packet->dhcp.yiaddr,
-                                      DHCP_PORT_CLIENT, len);
+                                      DHCP_PORT_CLIENT, len, -1);
 
         return dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
 }
@@ -994,7 +994,7 @@ int sd_dhcp_server_start(sd_dhcp_server *server) {
         }
         server->fd_raw = r;
 
-        r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER);
+        r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER, -1);
         if (r < 0) {
                 sd_dhcp_server_stop(server);
                 return r;
index 5f31d24d20bd4d3e750d5bd88d02a9c835909746..4e9b388a451aa0be06c3838d9aa34773b8e45717 100644 (file)
@@ -269,7 +269,7 @@ int dhcp_network_bind_raw_socket(
         return test_fd[0];
 }
 
-int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
+int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
         int fd;
 
         fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
index 1ef5beb2032d48c4b29d0bd9028aa19a4c8f881f..eef7788c49efbd88509a9f90df576929e8ce12da 100644 (file)
@@ -4,6 +4,7 @@
  ***/
 
 #include <ctype.h>
+#include <netinet/ip.h>
 
 #include "conf-parser.h"
 #include "def.h"
@@ -14,6 +15,7 @@
 #include "networkd-manager.h"
 #include "networkd-network.h"
 #include "networkd-speed-meter.h"
+#include "networkd-dhcp4.h"
 #include "string-table.h"
 
 int manager_parse_config_file(Manager *m) {
@@ -180,3 +182,30 @@ int config_parse_duid_rawdata(
         ret->raw_data_len = count;
         return 0;
 }
+
+int config_parse_ip_service_type(
+                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) {
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        if (streq(rvalue, "CS4"))
+                *((int *)data) = IPTOS_CLASS_CS4;
+        else if (streq(rvalue, "CS6"))
+                *((int *)data) = IPTOS_CLASS_CS6;
+        else
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "Failed to parse IPServiceType type '%s', ignoring.", rvalue);
+
+        return 0;
+}
index 88a2c64031c22fcc5a497c3e380d2699695a4074..a615998f92d922946fe2f2ed075643bacba8a678 100644 (file)
@@ -15,3 +15,4 @@ const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, GPERF_LEN_TY
 
 CONFIG_PARSER_PROTOTYPE(config_parse_duid_type);
 CONFIG_PARSER_PROTOTYPE(config_parse_duid_rawdata);
+CONFIG_PARSER_PROTOTYPE(config_parse_ip_service_type);
index 06e87199c69debc162e2ebb85e50349cba2e12a6..78cd24114021d350781bce40c2338224587d6370 100644 (file)
@@ -1213,7 +1213,12 @@ int dhcp4_configure(Link *link) {
                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
         }
 
-        return dhcp4_set_client_identifier(link);
+        if (link->network->ip_service_type > 0) {
+                r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->ip_service_type);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ip service type: %m");
+        }
+       return dhcp4_set_client_identifier(link);
 }
 
 int config_parse_dhcp_max_attempts(
index 11e541e0932fef56acdfa4988d57cb29a7b8c7b6..ce9fc30162655581b6ac92c69f8cdb97ceef536c 100644 (file)
@@ -167,6 +167,7 @@ DHCPv4.IAID,                            config_parse_iaid,
 DHCPv4.ListenPort,                      config_parse_uint16,                             0,                             offsetof(Network, dhcp_client_port)
 DHCPv4.SendRelease,                     config_parse_bool,                               0,                             offsetof(Network, dhcp_send_release)
 DHCPv4.BlackList,                       config_parse_dhcp_black_listed_ip_address,       0,                             0
+DHCPv4.IPServiceType,                   config_parse_ip_service_type,                    0,                             offsetof(Network, ip_service_type)
 DHCPv6.UseDNS,                          config_parse_bool,                               0,                             offsetof(Network, dhcp6_use_dns)
 DHCPv6.UseNTP,                          config_parse_bool,                               0,                             offsetof(Network, dhcp6_use_ntp)
 DHCPv6.RapidCommit,                     config_parse_bool,                               0,                             offsetof(Network, rapid_commit)
index a2cd7f4c602f1d2295bc4cd057fda07a78353feb..23a21d8c9e82ebe490037b69971d02545c6705a4 100644 (file)
@@ -442,6 +442,7 @@ int network_load_one(Manager *manager, const char *filename) {
                 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
 
                 .can_triple_sampling = -1,
+                .ip_service_type = -1,
         };
 
         r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
index 837206a29cabc4371adbd056080904fe9f7e92f8..ff97845dd1df9880d28fe50f0c722e8ca79faf02 100644 (file)
@@ -104,6 +104,7 @@ struct Network {
         DHCPUseDomains dhcp_use_domains;
         Set *dhcp_black_listed_ip;
         Set *dhcp_request_options;
+        int ip_service_type;
 
         /* DHCPv6 Client support*/
         bool dhcp6_use_dns;
index d2d74b2b4cf876e51b77d4023668b0e35443c927..98e328139784150c457bc04f97672d73cdd3f018 100644 (file)
@@ -174,6 +174,9 @@ int sd_dhcp_client_set_user_class(
 int sd_dhcp_client_get_lease(
                 sd_dhcp_client *client,
                 sd_dhcp_lease **ret);
+int sd_dhcp_client_set_service_type(
+                sd_dhcp_client *client,
+                int type);
 
 int sd_dhcp_client_stop(sd_dhcp_client *client);
 int sd_dhcp_client_start(sd_dhcp_client *client);
index 3be643075a89d450affe3e9760465181d8d41e39..78cddcab77464d6f9b9021a8bd508df23d1fb7c2 100644 (file)
@@ -93,6 +93,7 @@ BlackList=
 RequestOptions=
 SendRelease=
 MaxAttempts=
+IPServiceType=
 [DHCPv6]
 UseNTP=
 UseDNS=