153 lines
8.3 KiB
Diff
153 lines
8.3 KiB
Diff
From 0bc9811acfd2535bf8a7a16a3903a2c22df206c9 Mon Sep 17 00:00:00 2001
|
||
From: Dan Streetman <ddstreet@canonical.com>
|
||
Date: Fri, 20 Aug 2021 14:44:35 -0400
|
||
Subject: [PATCH] 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
|
||
(cherry picked from commit 526fce97afe130f71dba3bd4646196bbb1188b82)
|
||
|
||
Conflict:NA
|
||
Reference:https://github.com/systemd/systemd/commit/0bc9811acfd2535bf8a7a16a3903a2c22df206c9
|
||
---
|
||
src/resolve/resolved-dns-server.c | 63 +++++++++++--------------------
|
||
src/resolve/resolved-dns-server.h | 3 +-
|
||
2 files changed, 24 insertions(+), 42 deletions(-)
|
||
|
||
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
|
||
index 58a1376708..a21148d288 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 fe0eaee49c..be9efb0a79 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_;
|
||
--
|
||
2.33.0
|
||
|