From: Dan Streetman Date: Fri, 20 Aug 2021 18:44:35 +0000 (-0400) Subject: resolve: remove server 'large' level X-Git-Tag: v250-rc1~38 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=526fce97afe130f71dba3bd4646196bbb1188b82;p=thirdparty%2Fsystemd.git resolve: remove server 'large' level This removes the DNS_SERVER_FEATURE_LEVEL_LARGE, and sets the EDNS0 advertised max packet size as if always in 'large' mode. Without this, we always send out EDNS0 opts that limit response sizes to 512 bytes, thus the remote server will never send anything larger and will always truncate responses larger than 512 bytes, forcing us to drop from EDNS0 down to TCP, even though one of the primary benefits of EDNS0 is larger packet sizes. Fixes: #20993 --- diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 9bb716e2c13..7d180378b61 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -282,11 +282,6 @@ void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLeve if (s->packet_bad_opt && level >= DNS_SERVER_FEATURE_LEVEL_EDNS0) level = DNS_SERVER_FEATURE_LEVEL_EDNS0 - 1; - /* Even if we successfully receive a reply to a request announcing support for large packets, that - * does not mean we can necessarily receive large packets. */ - if (level == DNS_SERVER_FEATURE_LEVEL_LARGE) - level = DNS_SERVER_FEATURE_LEVEL_LARGE - 1; - dns_server_verified(s, level); /* Remember the size of the largest UDP packet fragment we received from a server, we know that we @@ -429,7 +424,7 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) { * better than EDNS0, hence don't even try. */ if (dns_server_get_dnssec_mode(s) != DNSSEC_NO) best = dns_server_get_dns_over_tls_mode(s) == DNS_OVER_TLS_NO ? - DNS_SERVER_FEATURE_LEVEL_LARGE : + DNS_SERVER_FEATURE_LEVEL_DO : DNS_SERVER_FEATURE_LEVEL_TLS_DO; else best = dns_server_get_dns_over_tls_mode(s) == DNS_OVER_TLS_NO ? @@ -597,7 +592,7 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) { } int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level) { - size_t packet_size; + size_t packet_size, udp_size; bool edns_do; int r; @@ -616,40 +611,29 @@ int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeature edns_do = level >= DNS_SERVER_FEATURE_LEVEL_DO; - if (level == DNS_SERVER_FEATURE_LEVEL_LARGE) { - size_t udp_size; - - /* In large mode, advertise the local MTU, in order to avoid fragmentation (for security - * reasons) – except if we are talking to localhost (where the security considerations don't - * matter). If we see fragmentation, lower the reported size to the largest fragment, to - * avoid it. */ - - udp_size = udp_header_size(server->family); - - if (in_addr_is_localhost(server->family, &server->address) > 0) - packet_size = 65536 - udp_size; /* force linux loopback MTU if localhost address */ - else { - /* Use the MTU pointing to the server, subtract the IP/UDP header size */ - packet_size = LESS_BY(dns_server_get_mtu(server), udp_size); + udp_size = udp_header_size(server->family); - /* On the Internet we want to avoid fragmentation for security reasons. If we saw - * fragmented packets, the above was too large, let's clamp it to the largest - * fragment we saw */ - if (server->packet_fragmented) - packet_size = MIN(server->received_udp_fragment_max, packet_size); - - /* Let's not pick ridiculously large sizes, i.e. not more than 4K. No one appears - * to ever use such large sized on the Internet IRL, hence let's not either. */ - packet_size = MIN(packet_size, 4096U); - } + if (in_addr_is_localhost(server->family, &server->address) > 0) + packet_size = 65536 - udp_size; /* force linux loopback MTU if localhost address */ + else { + /* Use the MTU pointing to the server, subtract the IP/UDP header size */ + packet_size = LESS_BY(dns_server_get_mtu(server), udp_size); + + /* On the Internet we want to avoid fragmentation for security reasons. If we saw + * fragmented packets, the above was too large, let's clamp it to the largest + * fragment we saw */ + if (server->packet_fragmented) + packet_size = MIN(server->received_udp_fragment_max, packet_size); + + /* Let's not pick ridiculously large sizes, i.e. not more than 4K. No one appears + * to ever use such large sized on the Internet IRL, hence let's not either. */ + packet_size = MIN(packet_size, 4096U); + } - /* Strictly speaking we quite possibly can receive larger datagrams than the MTU (since the - * MTU is for egress, not for ingress), but more often than not the value is symmetric, and - * we want something that does the right thing in the majority of cases, and not just in the - * theoretical edge case. */ - } else - /* In non-large mode, let's advertise the size of the largest fragment we ever managed to accept. */ - packet_size = server->received_udp_fragment_max; + /* Strictly speaking we quite possibly can receive larger datagrams than the MTU (since the + * MTU is for egress, not for ingress), but more often than not the value is symmetric, and + * we want something that does the right thing in the majority of cases, and not just in the + * theoretical edge case. */ /* Safety clamp, never advertise less than 512 or more than 65535 */ packet_size = CLAMP(packet_size, @@ -1097,7 +1081,6 @@ static const char* const dns_server_feature_level_table[_DNS_SERVER_FEATURE_LEVE [DNS_SERVER_FEATURE_LEVEL_EDNS0] = "UDP+EDNS0", [DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN] = "TLS+EDNS0", [DNS_SERVER_FEATURE_LEVEL_DO] = "UDP+EDNS0+DO", - [DNS_SERVER_FEATURE_LEVEL_LARGE] = "UDP+EDNS0+DO+LARGE", [DNS_SERVER_FEATURE_LEVEL_TLS_DO] = "TLS+EDNS0+D0", }; DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level, DnsServerFeatureLevel); diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index fe0eaee49ca..be9efb0a79a 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -32,7 +32,6 @@ typedef enum DnsServerFeatureLevel { DNS_SERVER_FEATURE_LEVEL_EDNS0, DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN, DNS_SERVER_FEATURE_LEVEL_DO, - DNS_SERVER_FEATURE_LEVEL_LARGE, DNS_SERVER_FEATURE_LEVEL_TLS_DO, _DNS_SERVER_FEATURE_LEVEL_MAX, _DNS_SERVER_FEATURE_LEVEL_INVALID = -EINVAL, @@ -43,7 +42,7 @@ typedef enum DnsServerFeatureLevel { #define DNS_SERVER_FEATURE_LEVEL_IS_EDNS0(x) ((x) >= DNS_SERVER_FEATURE_LEVEL_EDNS0) #define DNS_SERVER_FEATURE_LEVEL_IS_TLS(x) IN_SET(x, DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN, DNS_SERVER_FEATURE_LEVEL_TLS_DO) #define DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(x) ((x) >= DNS_SERVER_FEATURE_LEVEL_DO) -#define DNS_SERVER_FEATURE_LEVEL_IS_UDP(x) IN_SET(x, DNS_SERVER_FEATURE_LEVEL_UDP, DNS_SERVER_FEATURE_LEVEL_EDNS0, DNS_SERVER_FEATURE_LEVEL_DO, DNS_SERVER_FEATURE_LEVEL_LARGE) +#define DNS_SERVER_FEATURE_LEVEL_IS_UDP(x) IN_SET(x, DNS_SERVER_FEATURE_LEVEL_UDP, DNS_SERVER_FEATURE_LEVEL_EDNS0, DNS_SERVER_FEATURE_LEVEL_DO) const char* dns_server_feature_level_to_string(int i) _const_; int dns_server_feature_level_from_string(const char *s) _pure_;