1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include "alloc-util.h"
23 #include "resolved-dns-server.h"
24 #include "resolved-resolv-conf.h"
25 #include "siphash24.h"
26 #include "string-table.h"
27 #include "string-util.h"
29 /* After how much time to repeat classic DNS requests */
30 #define DNS_TIMEOUT_MIN_USEC (500 * USEC_PER_MSEC)
31 #define DNS_TIMEOUT_MAX_USEC (5 * USEC_PER_SEC)
33 /* The amount of time to wait before retrying with a full feature set */
34 #define DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC (6 * USEC_PER_HOUR)
35 #define DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC (5 * USEC_PER_MINUTE)
37 /* The number of times we will attempt a certain feature set before degrading */
38 #define DNS_SERVER_FEATURE_RETRY_ATTEMPTS 3
46 const union in_addr_union
*in_addr
) {
51 assert((type
== DNS_SERVER_LINK
) == !!l
);
54 if (!IN_SET(family
, AF_INET
, AF_INET6
))
58 if (l
->n_dns_servers
>= LINK_DNS_SERVERS_MAX
)
61 if (m
->n_dns_servers
>= MANAGER_DNS_SERVERS_MAX
)
65 s
= new0(DnsServer
, 1);
71 s
->verified_feature_level
= _DNS_SERVER_FEATURE_LEVEL_INVALID
;
72 s
->possible_feature_level
= DNS_SERVER_FEATURE_LEVEL_BEST
;
73 s
->features_grace_period_usec
= DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC
;
74 s
->received_udp_packet_max
= DNS_PACKET_UNICAST_SIZE_MAX
;
77 s
->address
= *in_addr
;
78 s
->resend_timeout
= DNS_TIMEOUT_MIN_USEC
;
84 LIST_APPEND(servers
, l
->dns_servers
, s
);
88 case DNS_SERVER_SYSTEM
:
89 LIST_APPEND(servers
, m
->dns_servers
, s
);
93 case DNS_SERVER_FALLBACK
:
94 LIST_APPEND(servers
, m
->fallback_dns_servers
, s
);
99 assert_not_reached("Unknown server type");
104 /* A new DNS server that isn't fallback is added and the one
105 * we used so far was a fallback one? Then let's try to pick
107 if (type
!= DNS_SERVER_FALLBACK
&&
108 m
->current_dns_server
&&
109 m
->current_dns_server
->type
== DNS_SERVER_FALLBACK
)
110 manager_set_dns_server(m
, NULL
);
118 DnsServer
* dns_server_ref(DnsServer
*s
) {
122 assert(s
->n_ref
> 0);
128 DnsServer
* dns_server_unref(DnsServer
*s
) {
132 assert(s
->n_ref
> 0);
138 free(s
->server_string
);
143 void dns_server_unlink(DnsServer
*s
) {
147 /* This removes the specified server from the linked list of
148 * servers, but any server might still stay around if it has
149 * refs, for example from an ongoing transaction. */
156 case DNS_SERVER_LINK
:
158 assert(s
->link
->n_dns_servers
> 0);
159 LIST_REMOVE(servers
, s
->link
->dns_servers
, s
);
162 case DNS_SERVER_SYSTEM
:
163 assert(s
->manager
->n_dns_servers
> 0);
164 LIST_REMOVE(servers
, s
->manager
->dns_servers
, s
);
165 s
->manager
->n_dns_servers
--;
168 case DNS_SERVER_FALLBACK
:
169 assert(s
->manager
->n_dns_servers
> 0);
170 LIST_REMOVE(servers
, s
->manager
->fallback_dns_servers
, s
);
171 s
->manager
->n_dns_servers
--;
177 if (s
->link
&& s
->link
->current_dns_server
== s
)
178 link_set_dns_server(s
->link
, NULL
);
180 if (s
->manager
->current_dns_server
== s
)
181 manager_set_dns_server(s
->manager
, NULL
);
186 void dns_server_move_back_and_unmark(DnsServer
*s
) {
196 if (!s
->linked
|| !s
->servers_next
)
199 /* Move us to the end of the list, so that the order is
200 * strictly kept, if we are not at the end anyway. */
204 case DNS_SERVER_LINK
:
206 LIST_FIND_TAIL(servers
, s
, tail
);
207 LIST_REMOVE(servers
, s
->link
->dns_servers
, s
);
208 LIST_INSERT_AFTER(servers
, s
->link
->dns_servers
, tail
, s
);
211 case DNS_SERVER_SYSTEM
:
212 LIST_FIND_TAIL(servers
, s
, tail
);
213 LIST_REMOVE(servers
, s
->manager
->dns_servers
, s
);
214 LIST_INSERT_AFTER(servers
, s
->manager
->dns_servers
, tail
, s
);
217 case DNS_SERVER_FALLBACK
:
218 LIST_FIND_TAIL(servers
, s
, tail
);
219 LIST_REMOVE(servers
, s
->manager
->fallback_dns_servers
, s
);
220 LIST_INSERT_AFTER(servers
, s
->manager
->fallback_dns_servers
, tail
, s
);
224 assert_not_reached("Unknown server type");
228 static void dns_server_verified(DnsServer
*s
, DnsServerFeatureLevel level
) {
231 if (s
->verified_feature_level
> level
)
234 if (s
->verified_feature_level
!= level
) {
235 log_debug("Verified we get a response at feature level %s from DNS server %s.",
236 dns_server_feature_level_to_string(level
),
237 dns_server_string(s
));
238 s
->verified_feature_level
= level
;
241 assert_se(sd_event_now(s
->manager
->event
, clock_boottime_or_monotonic(), &s
->verified_usec
) >= 0);
244 void dns_server_packet_received(DnsServer
*s
, int protocol
, DnsServerFeatureLevel level
, usec_t rtt
, size_t size
) {
247 if (protocol
== IPPROTO_UDP
) {
248 if (s
->possible_feature_level
== level
)
251 /* If the RRSIG data is missing, then we can only validate EDNS0 at max */
252 if (s
->packet_rrsig_missing
&& level
>= DNS_SERVER_FEATURE_LEVEL_DO
)
253 level
= DNS_SERVER_FEATURE_LEVEL_DO
- 1;
255 /* If the OPT RR got lost, then we can only validate UDP at max */
256 if (s
->packet_bad_opt
&& level
>= DNS_SERVER_FEATURE_LEVEL_EDNS0
)
257 level
= DNS_SERVER_FEATURE_LEVEL_EDNS0
- 1;
259 /* Even if we successfully receive a reply to a request announcing support for large packets,
260 that does not mean we can necessarily receive large packets. */
261 if (level
== DNS_SERVER_FEATURE_LEVEL_LARGE
)
262 level
= DNS_SERVER_FEATURE_LEVEL_LARGE
- 1;
264 } else if (protocol
== IPPROTO_TCP
) {
266 if (s
->possible_feature_level
== level
)
269 /* Successful TCP connections are only useful to verify the TCP feature level. */
270 level
= DNS_SERVER_FEATURE_LEVEL_TCP
;
273 dns_server_verified(s
, level
);
275 /* Remember the size of the largest UDP packet we received from a server,
276 we know that we can always announce support for packets with at least
278 if (protocol
== IPPROTO_UDP
&& s
->received_udp_packet_max
< size
)
279 s
->received_udp_packet_max
= size
;
281 if (s
->max_rtt
< rtt
) {
283 s
->resend_timeout
= CLAMP(s
->max_rtt
* 2, DNS_TIMEOUT_MIN_USEC
, DNS_TIMEOUT_MAX_USEC
);
287 void dns_server_packet_lost(DnsServer
*s
, int protocol
, DnsServerFeatureLevel level
, usec_t usec
) {
291 if (s
->possible_feature_level
== level
) {
292 if (protocol
== IPPROTO_UDP
)
294 else if (protocol
== IPPROTO_TCP
)
298 if (s
->resend_timeout
> usec
)
301 s
->resend_timeout
= MIN(s
->resend_timeout
* 2, DNS_TIMEOUT_MAX_USEC
);
304 void dns_server_packet_failed(DnsServer
*s
, DnsServerFeatureLevel level
) {
307 /* Invoked whenever we get a FORMERR, SERVFAIL or NOTIMP rcode from a server. */
309 if (s
->possible_feature_level
!= level
)
312 s
->packet_failed
= true;
315 void dns_server_packet_truncated(DnsServer
*s
, DnsServerFeatureLevel level
) {
318 /* Invoked whenever we get a packet with TC bit set. */
320 if (s
->possible_feature_level
!= level
)
323 s
->packet_truncated
= true;
326 void dns_server_packet_rrsig_missing(DnsServer
*s
, DnsServerFeatureLevel level
) {
329 if (level
< DNS_SERVER_FEATURE_LEVEL_DO
)
332 /* If the RRSIG RRs are missing, we have to downgrade what we previously verified */
333 if (s
->verified_feature_level
>= DNS_SERVER_FEATURE_LEVEL_DO
)
334 s
->verified_feature_level
= DNS_SERVER_FEATURE_LEVEL_DO
-1;
336 s
->packet_rrsig_missing
= true;
339 void dns_server_packet_bad_opt(DnsServer
*s
, DnsServerFeatureLevel level
) {
342 if (level
< DNS_SERVER_FEATURE_LEVEL_EDNS0
)
345 /* If the OPT RR got lost, we have to downgrade what we previously verified */
346 if (s
->verified_feature_level
>= DNS_SERVER_FEATURE_LEVEL_EDNS0
)
347 s
->verified_feature_level
= DNS_SERVER_FEATURE_LEVEL_EDNS0
-1;
349 s
->packet_bad_opt
= true;
352 static bool dns_server_grace_period_expired(DnsServer
*s
) {
358 if (s
->verified_usec
== 0)
361 assert_se(sd_event_now(s
->manager
->event
, clock_boottime_or_monotonic(), &ts
) >= 0);
363 if (s
->verified_usec
+ s
->features_grace_period_usec
> ts
)
366 s
->features_grace_period_usec
= MIN(s
->features_grace_period_usec
* 2, DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC
);
371 static void dns_server_reset_counters(DnsServer
*s
) {
376 s
->packet_failed
= false;
377 s
->packet_truncated
= false;
378 s
->packet_bad_opt
= false;
379 s
->packet_rrsig_missing
= false;
380 s
->verified_usec
= 0;
383 DnsServerFeatureLevel
dns_server_possible_feature_level(DnsServer
*s
) {
386 if (s
->possible_feature_level
!= DNS_SERVER_FEATURE_LEVEL_BEST
&&
387 dns_server_grace_period_expired(s
)) {
389 s
->possible_feature_level
= DNS_SERVER_FEATURE_LEVEL_BEST
;
390 dns_server_reset_counters(s
);
392 log_info("Grace period over, resuming full feature set (%s) for DNS server %s.",
393 dns_server_feature_level_to_string(s
->possible_feature_level
),
394 dns_server_string(s
));
396 } else if (s
->possible_feature_level
<= s
->verified_feature_level
)
397 s
->possible_feature_level
= s
->verified_feature_level
;
399 DnsServerFeatureLevel p
= s
->possible_feature_level
;
401 if (s
->n_failed_tcp
>= DNS_SERVER_FEATURE_RETRY_ATTEMPTS
&&
402 s
->possible_feature_level
== DNS_SERVER_FEATURE_LEVEL_TCP
) {
404 /* We are at the TCP (lowest) level, and we tried a couple of TCP connections, and it didn't
405 * work. Upgrade back to UDP again. */
406 log_debug("Reached maximum number of failed TCP connection attempts, trying UDP again...");
407 s
->possible_feature_level
= DNS_SERVER_FEATURE_LEVEL_UDP
;
409 } else if (s
->packet_bad_opt
&&
410 s
->possible_feature_level
>= DNS_SERVER_FEATURE_LEVEL_EDNS0
) {
412 /* A reply to one of our EDNS0 queries didn't carry a valid OPT RR, then downgrade to below
413 * EDNS0 levels. After all, some records generate different responses with and without OPT RR
414 * in the request. Example:
415 * https://open.nlnetlabs.nl/pipermail/dnssec-trigger/2014-November/000376.html */
417 log_debug("Server doesn't support EDNS(0) properly, downgrading feature level...");
418 s
->possible_feature_level
= DNS_SERVER_FEATURE_LEVEL_UDP
;
420 } else if (s
->packet_rrsig_missing
&&
421 s
->possible_feature_level
>= DNS_SERVER_FEATURE_LEVEL_DO
) {
423 /* RRSIG data was missing on a EDNS0 packet with DO bit set. This means the server doesn't
424 * augment responses with DNSSEC RRs. If so, let's better not ask the server for it anymore,
425 * after all some servers generate different replies depending if an OPT RR is in the query or
428 log_debug("Detected server responses lack RRSIG records, downgrading feature level...");
429 s
->possible_feature_level
= DNS_SERVER_FEATURE_LEVEL_EDNS0
;
431 } else if (s
->n_failed_udp
>= DNS_SERVER_FEATURE_RETRY_ATTEMPTS
&&
432 s
->possible_feature_level
>= DNS_SERVER_FEATURE_LEVEL_UDP
) {
434 /* We lost too many UDP packets in a row, and are on a feature level of UDP or higher. If the
435 * packets are lost, maybe the server cannot parse them, hence downgrading sounds like a good
436 * idea. We might downgrade all the way down to TCP this way. */
438 log_debug("Lost too many UDP packets, downgrading feature level...");
439 s
->possible_feature_level
--;
441 } else if (s
->packet_failed
&&
442 s
->possible_feature_level
> DNS_SERVER_FEATURE_LEVEL_UDP
) {
444 /* We got a failure packet, and are at a feature level above UDP. Note that in this case we
445 * downgrade no further than UDP, under the assumption that a failure packet indicates an
446 * incompatible packet contents, but not a problem with the transport. */
448 log_debug("Got server failure, downgrading feature level...");
449 s
->possible_feature_level
--;
451 } else if (s
->n_failed_tcp
>= DNS_SERVER_FEATURE_RETRY_ATTEMPTS
&&
452 s
->packet_truncated
&&
453 s
->possible_feature_level
> DNS_SERVER_FEATURE_LEVEL_UDP
) {
455 /* We got too many TCP connection failures in a row, we had at least one truncated packet, and
456 * are on a feature level above UDP. By downgrading things and getting rid of DNSSEC or EDNS0
457 * data we hope to make the packet smaller, so that it still works via UDP given that TCP
458 * appears not to be a fallback. Note that if we are already at the lowest UDP level, we don't
459 * go further down, since that's TCP, and TCP failed too often after all. */
461 log_debug("Got too many failed TCP connection failures and truncated UDP packets, downgrading feature level...");
462 s
->possible_feature_level
--;
465 if (p
!= s
->possible_feature_level
) {
467 /* We changed the feature level, reset the counting */
468 dns_server_reset_counters(s
);
470 log_warning("Using degraded feature set (%s) for DNS server %s.",
471 dns_server_feature_level_to_string(s
->possible_feature_level
),
472 dns_server_string(s
));
476 return s
->possible_feature_level
;
479 int dns_server_adjust_opt(DnsServer
*server
, DnsPacket
*packet
, DnsServerFeatureLevel level
) {
486 assert(packet
->protocol
== DNS_PROTOCOL_DNS
);
488 /* Fix the OPT field in the packet to match our current feature level. */
490 r
= dns_packet_truncate_opt(packet
);
494 if (level
< DNS_SERVER_FEATURE_LEVEL_EDNS0
)
497 edns_do
= level
>= DNS_SERVER_FEATURE_LEVEL_DO
;
499 if (level
>= DNS_SERVER_FEATURE_LEVEL_LARGE
)
500 packet_size
= DNS_PACKET_UNICAST_SIZE_LARGE_MAX
;
502 packet_size
= server
->received_udp_packet_max
;
504 return dns_packet_append_opt(packet
, packet_size
, edns_do
, NULL
);
507 const char *dns_server_string(DnsServer
*server
) {
510 if (!server
->server_string
)
511 (void) in_addr_to_string(server
->family
, &server
->address
, &server
->server_string
);
513 return strna(server
->server_string
);
516 bool dns_server_dnssec_supported(DnsServer
*server
) {
519 /* Returns whether the server supports DNSSEC according to what we know about it */
521 if (server
->possible_feature_level
< DNS_SERVER_FEATURE_LEVEL_DO
)
524 if (server
->packet_bad_opt
)
527 if (server
->packet_rrsig_missing
)
530 /* DNSSEC servers need to support TCP properly (see RFC5966), if they don't, we assume DNSSEC is borked too */
531 if (server
->n_failed_tcp
>= DNS_SERVER_FEATURE_RETRY_ATTEMPTS
)
537 static void dns_server_hash_func(const void *p
, struct siphash
*state
) {
538 const DnsServer
*s
= p
;
542 siphash24_compress(&s
->family
, sizeof(s
->family
), state
);
543 siphash24_compress(&s
->address
, FAMILY_ADDRESS_SIZE(s
->family
), state
);
546 static int dns_server_compare_func(const void *a
, const void *b
) {
547 const DnsServer
*x
= a
, *y
= b
;
549 if (x
->family
< y
->family
)
551 if (x
->family
> y
->family
)
554 return memcmp(&x
->address
, &y
->address
, FAMILY_ADDRESS_SIZE(x
->family
));
557 const struct hash_ops dns_server_hash_ops
= {
558 .hash
= dns_server_hash_func
,
559 .compare
= dns_server_compare_func
562 void dns_server_unlink_all(DnsServer
*first
) {
568 next
= first
->servers_next
;
569 dns_server_unlink(first
);
571 dns_server_unlink_all(next
);
574 void dns_server_unlink_marked(DnsServer
*first
) {
580 next
= first
->servers_next
;
583 dns_server_unlink(first
);
585 dns_server_unlink_marked(next
);
588 void dns_server_mark_all(DnsServer
*first
) {
592 first
->marked
= true;
593 dns_server_mark_all(first
->servers_next
);
596 DnsServer
*dns_server_find(DnsServer
*first
, int family
, const union in_addr_union
*in_addr
) {
599 LIST_FOREACH(servers
, s
, first
)
600 if (s
->family
== family
&& in_addr_equal(family
, &s
->address
, in_addr
) > 0)
606 DnsServer
*manager_get_first_dns_server(Manager
*m
, DnsServerType t
) {
611 case DNS_SERVER_SYSTEM
:
612 return m
->dns_servers
;
614 case DNS_SERVER_FALLBACK
:
615 return m
->fallback_dns_servers
;
622 DnsServer
*manager_set_dns_server(Manager
*m
, DnsServer
*s
) {
625 if (m
->current_dns_server
== s
)
629 log_info("Switching to system DNS server %s.", dns_server_string(s
));
631 dns_server_unref(m
->current_dns_server
);
632 m
->current_dns_server
= dns_server_ref(s
);
634 if (m
->unicast_scope
)
635 dns_cache_flush(&m
->unicast_scope
->cache
);
640 DnsServer
*manager_get_dns_server(Manager
*m
) {
644 /* Try to read updates resolv.conf */
645 manager_read_resolv_conf(m
);
647 /* If no DNS server was chose so far, pick the first one */
648 if (!m
->current_dns_server
)
649 manager_set_dns_server(m
, m
->dns_servers
);
651 if (!m
->current_dns_server
) {
655 /* No DNS servers configured, let's see if there are
656 * any on any links. If not, we use the fallback
659 HASHMAP_FOREACH(l
, m
->links
, i
)
660 if (l
->dns_servers
) {
666 manager_set_dns_server(m
, m
->fallback_dns_servers
);
669 return m
->current_dns_server
;
672 void manager_next_dns_server(Manager
*m
) {
675 /* If there's currently no DNS server set, then the next
676 * manager_get_dns_server() will find one */
677 if (!m
->current_dns_server
)
680 /* Change to the next one, but make sure to follow the linked
681 * list only if the server is still linked. */
682 if (m
->current_dns_server
->linked
&& m
->current_dns_server
->servers_next
) {
683 manager_set_dns_server(m
, m
->current_dns_server
->servers_next
);
687 /* If there was no next one, then start from the beginning of
689 if (m
->current_dns_server
->type
== DNS_SERVER_FALLBACK
)
690 manager_set_dns_server(m
, m
->fallback_dns_servers
);
692 manager_set_dns_server(m
, m
->dns_servers
);
695 static const char* const dns_server_feature_level_table
[_DNS_SERVER_FEATURE_LEVEL_MAX
] = {
696 [DNS_SERVER_FEATURE_LEVEL_TCP
] = "TCP",
697 [DNS_SERVER_FEATURE_LEVEL_UDP
] = "UDP",
698 [DNS_SERVER_FEATURE_LEVEL_EDNS0
] = "UDP+EDNS0",
699 [DNS_SERVER_FEATURE_LEVEL_DO
] = "UDP+EDNS0+DO",
700 [DNS_SERVER_FEATURE_LEVEL_LARGE
] = "UDP+EDNS0+DO+LARGE",
702 DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level
, DnsServerFeatureLevel
);