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
|
|||
|
|
|