diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 585041095d..e5f9d6f470 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1309,7 +1309,14 @@ 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. - + + + IPServiceType= + + 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. + + diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index e0269b5456..c231773bdd 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -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); diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c index 94c10ed14c..8e7f8a65ab 100644 --- a/src/libsystemd-network/dhcp-network.c +++ b/src/libsystemd-network/dhcp-network.c @@ -146,7 +146,7 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, bcast_addr, ð_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; diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c index ad5f8e267a..fe7d51703b 100644 --- a/src/libsystemd-network/dhcp-packet.c +++ b/src/libsystemd-network/dhcp-packet.c @@ -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; diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index cadacc24d4..2d511f7feb 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -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) { diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 13f104f9ef..bba82c21dd 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -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; diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index 5f31d24d20..4e9b388a45 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -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); diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 1ef5beb203..eef7788c49 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -4,6 +4,7 @@ ***/ #include +#include #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; +} diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h index 88a2c64031..a615998f92 100644 --- a/src/network/networkd-conf.h +++ b/src/network/networkd-conf.h @@ -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); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 06e87199c6..78cd241140 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -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( diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 11e541e093..ce9fc30162 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -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) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index a2cd7f4c60..23a21d8c9e 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -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, diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 837206a29c..ff97845dd1 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -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; diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index d2d74b2b4c..98e3281397 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -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); diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 3be643075a..78cddcab77 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -93,6 +93,7 @@ BlackList= RequestOptions= SendRelease= MaxAttempts= +IPServiceType= [DHCPv6] UseNTP= UseDNS=