diff options
author | Tom Gundersen <teg@jklm.no> | 2015-07-06 16:48:24 +0200 |
---|---|---|
committer | Tom Gundersen <teg@jklm.no> | 2015-11-27 01:35:47 +0100 |
commit | d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01 (patch) | |
tree | d7f2e66d4b67420d6c9bd0dfd399492254b4fd14 /src/resolve/resolved-dns-server.c | |
parent | 7586f4d172dd9c3ccc3126fc47dca9e49adec132 (diff) |
resolved: announce support for large UDP packets
This is often needed for proper DNSSEC support, and even to handle AAAA records
without falling back to TCP.
If the path between the client and server is fully compliant, this should always
work, however, that is not the case, and overlarge packets will get mysteriously
lost in some cases.
For that reason, we use a similar fallback mechanism as we do for palin EDNS0,
EDNS0+DO, etc.:
The large UDP size feature is different from the other supported feature, as we
cannot simply verify that it works based on receiving a reply (as the server
will usually send us much smaller packets than what we claim to support, so
simply receiving a reply does not mean much).
For that reason, we keep track of the largest UDP packet we ever received, as this
is the smallest known good size (defaulting to the standard 512 bytes). If
announcing the default large size of 4096 fails (in the same way as the other
features), we fall back to the known good size. The same logic of retrying after a
grace-period applies.
Diffstat (limited to 'src/resolve/resolved-dns-server.c')
-rw-r--r-- | src/resolve/resolved-dns-server.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 916f5dadb8..d565f99c09 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -71,6 +71,7 @@ int dns_server_new( s->verified_features = _DNS_SERVER_FEATURE_LEVEL_INVALID; s->possible_features = DNS_SERVER_FEATURE_LEVEL_BEST; s->features_grace_period_usec = DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC; + s->received_udp_packet_max = DNS_PACKET_UNICAST_SIZE_MAX; s->type = type; s->family = family; s->address = *in_addr; @@ -223,10 +224,18 @@ void dns_server_move_back_and_unmark(DnsServer *s) { } } -void dns_server_packet_received(DnsServer *s, DnsServerFeatureLevel features, usec_t rtt) { +void dns_server_packet_received(DnsServer *s, DnsServerFeatureLevel features, usec_t rtt, size_t size) { assert(s); - if (s->verified_features < features) { + if (features == DNS_SERVER_FEATURE_LEVEL_LARGE) { + /* 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 (s->verified_features < DNS_SERVER_FEATURE_LEVEL_LARGE - 1) { + s->verified_features = DNS_SERVER_FEATURE_LEVEL_LARGE - 1; + assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0); + } + } else if (s->verified_features < features) { s->verified_features = features; assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0); } @@ -234,6 +243,12 @@ void dns_server_packet_received(DnsServer *s, DnsServerFeatureLevel features, us if (s->possible_features == features) s->n_failed_attempts = 0; + /* Remember the size of the largest UDP packet we received from a server, + we know that we can always announce support for packets with at least + this size. */ + if (s->received_udp_packet_max < size) + s->received_udp_packet_max = size; + if (s->max_rtt < rtt) { s->max_rtt = rtt; s->resend_timeout = MIN(MAX(DNS_TIMEOUT_MIN_USEC, s->max_rtt * 2), DNS_TIMEOUT_MAX_USEC); @@ -480,5 +495,6 @@ static const char* const dns_server_feature_level_table[_DNS_SERVER_FEATURE_LEVE [DNS_SERVER_FEATURE_LEVEL_UDP] = "UDP", [DNS_SERVER_FEATURE_LEVEL_EDNS0] = "UDP+EDNS0", [DNS_SERVER_FEATURE_LEVEL_DO] = "UDP+EDNS0+DO", + [DNS_SERVER_FEATURE_LEVEL_LARGE] = "UDP+EDNS0+DO+LARGE", }; DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level, DnsServerFeatureLevel); |