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 feature level %s.", dns_server_feature_level_to_string(level
));
236 s
->verified_feature_level
= level
;
239 assert_se(sd_event_now(s
->manager
->event
, clock_boottime_or_monotonic(), &s
->verified_usec
) >= 0);
242 void dns_server_packet_received(DnsServer
*s
, int protocol
, DnsServerFeatureLevel level
, usec_t rtt
, size_t size
) {
245 if (protocol
== IPPROTO_UDP
) {
246 if (s
->possible_feature_level
== level
)
249 if (level
== DNS_SERVER_FEATURE_LEVEL_LARGE
)
250 /* Even if we successfully receive a reply to a request announcing support for large packets,
251 that does not mean we can necessarily receive large packets. */
252 dns_server_verified(s
, DNS_SERVER_FEATURE_LEVEL_LARGE
- 1);
254 /* A successful UDP reply, verifies UDP, ENDS0 and DO levels */
255 dns_server_verified(s
, level
);
257 } else if (protocol
== IPPROTO_TCP
) {
259 if (s
->possible_feature_level
== level
)
262 /* Successful TCP connections are only useful to verify the TCP feature level. */
263 dns_server_verified(s
, DNS_SERVER_FEATURE_LEVEL_TCP
);
266 /* Remember the size of the largest UDP packet we received from a server,
267 we know that we can always announce support for packets with at least
269 if (protocol
== IPPROTO_UDP
&& s
->received_udp_packet_max
< size
)
270 s
->received_udp_packet_max
= size
;
272 if (s
->max_rtt
< rtt
) {
274 s
->resend_timeout
= CLAMP(s
->max_rtt
* 2, DNS_TIMEOUT_MIN_USEC
, DNS_TIMEOUT_MAX_USEC
);
278 void dns_server_packet_lost(DnsServer
*s
, int protocol
, DnsServerFeatureLevel level
, usec_t usec
) {
282 if (s
->possible_feature_level
== level
) {
283 if (protocol
== IPPROTO_UDP
)
285 else if (protocol
== IPPROTO_TCP
)
289 if (s
->resend_timeout
> usec
)
292 s
->resend_timeout
= MIN(s
->resend_timeout
* 2, DNS_TIMEOUT_MAX_USEC
);
295 void dns_server_packet_failed(DnsServer
*s
, DnsServerFeatureLevel level
) {
299 /* Invoked whenever we get a FORMERR, SERVFAIL or NOTIMP rcode from a server. */
301 if (s
->possible_feature_level
!= level
)
304 s
->packet_failed
= true;
307 void dns_server_packet_truncated(DnsServer
*s
, DnsServerFeatureLevel level
) {
311 /* Invoked whenever we get a packet with TC bit set. */
313 if (s
->possible_feature_level
!= level
)
316 s
->packet_truncated
= true;
319 void dns_server_packet_rrsig_missing(DnsServer
*s
) {
323 log_warning("DNS server %s does not augment replies with RRSIG records, DNSSEC not available.", dns_server_string(s
));
325 s
->rrsig_missing
= true;
328 static bool dns_server_grace_period_expired(DnsServer
*s
) {
334 if (s
->verified_usec
== 0)
337 assert_se(sd_event_now(s
->manager
->event
, clock_boottime_or_monotonic(), &ts
) >= 0);
339 if (s
->verified_usec
+ s
->features_grace_period_usec
> ts
)
342 s
->features_grace_period_usec
= MIN(s
->features_grace_period_usec
* 2, DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC
);
347 static void dns_server_reset_counters(DnsServer
*s
) {
352 s
->packet_failed
= false;
353 s
->packet_truncated
= false;
354 s
->verified_usec
= 0;
357 DnsServerFeatureLevel
dns_server_possible_feature_level(DnsServer
*s
) {
360 if (s
->possible_feature_level
!= DNS_SERVER_FEATURE_LEVEL_BEST
&&
361 dns_server_grace_period_expired(s
)) {
363 s
->possible_feature_level
= DNS_SERVER_FEATURE_LEVEL_BEST
;
364 s
->rrsig_missing
= false;
366 dns_server_reset_counters(s
);
368 log_info("Grace period over, resuming full feature set (%s) for DNS server %s",
369 dns_server_feature_level_to_string(s
->possible_feature_level
),
370 dns_server_string(s
));
372 } else if (s
->possible_feature_level
<= s
->verified_feature_level
)
373 s
->possible_feature_level
= s
->verified_feature_level
;
375 DnsServerFeatureLevel p
= s
->possible_feature_level
;
377 if (s
->n_failed_tcp
>= DNS_SERVER_FEATURE_RETRY_ATTEMPTS
&&
378 s
->possible_feature_level
== DNS_SERVER_FEATURE_LEVEL_TCP
)
380 /* We are at the TCP (lowest) level, and we tried a couple of TCP connections, and it didn't
381 * work. Upgrade back to UDP again. */
382 s
->possible_feature_level
= DNS_SERVER_FEATURE_LEVEL_UDP
;
384 else if ((s
->n_failed_udp
>= DNS_SERVER_FEATURE_RETRY_ATTEMPTS
&&
385 s
->possible_feature_level
>= DNS_SERVER_FEATURE_LEVEL_UDP
) ||
387 s
->possible_feature_level
> DNS_SERVER_FEATURE_LEVEL_UDP
) ||
388 (s
->n_failed_tcp
>= DNS_SERVER_FEATURE_RETRY_ATTEMPTS
&&
389 s
->packet_truncated
&&
390 s
->possible_feature_level
> DNS_SERVER_FEATURE_LEVEL_UDP
))
392 /* Downgrade the feature one level, maybe things will work better then. We do this under any of
395 * 1. We lost too many UDP packets in a row, and are on a feature level of UDP or higher. If
396 * the packets are lost, maybe the server cannot parse them, hence downgrading sounds like a
397 * good idea. We might downgrade all the way down to TCP this way.
399 * 2. We got a failure packet, and are at a feature level above UDP. Note that in this case we
400 * downgrade no further than UDP, under the assumption that a failure packet indicates an
401 * incompatible packet contents, but not a problem with the transport.
403 * 3. We got too many TCP connection failures in a row, we had at least one truncated packet,
404 * and are on a feature level above UDP. By downgrading things and getting rid of DNSSEC or
405 * EDNS0 data we hope to make the packet smaller, so that it still works via UDP given that
406 * TCP appears not to be a fallback. Note that if we are already at the lowest UDP level, we
407 * don't go further down, since that's TCP, and TCP failed too often after all.
410 s
->possible_feature_level
--;
412 if (p
!= s
->possible_feature_level
) {
414 /* We changed the feature level, reset the counting */
415 dns_server_reset_counters(s
);
417 log_warning("Using degraded feature set (%s) for DNS server %s",
418 dns_server_feature_level_to_string(s
->possible_feature_level
),
419 dns_server_string(s
));
423 return s
->possible_feature_level
;
426 int dns_server_adjust_opt(DnsServer
*server
, DnsPacket
*packet
, DnsServerFeatureLevel level
) {
433 assert(packet
->protocol
== DNS_PROTOCOL_DNS
);
435 /* Fix the OPT field in the packet to match our current feature level. */
437 r
= dns_packet_truncate_opt(packet
);
441 if (level
< DNS_SERVER_FEATURE_LEVEL_EDNS0
)
444 edns_do
= level
>= DNS_SERVER_FEATURE_LEVEL_DO
;
446 if (level
>= DNS_SERVER_FEATURE_LEVEL_LARGE
)
447 packet_size
= DNS_PACKET_UNICAST_SIZE_LARGE_MAX
;
449 packet_size
= server
->received_udp_packet_max
;
451 return dns_packet_append_opt(packet
, packet_size
, edns_do
, NULL
);
454 const char *dns_server_string(DnsServer
*server
) {
457 if (!server
->server_string
)
458 (void) in_addr_to_string(server
->family
, &server
->address
, &server
->server_string
);
460 return strna(server
->server_string
);
463 bool dns_server_dnssec_supported(DnsServer
*server
) {
466 /* Returns whether the server supports DNSSEC according to what we know about it */
468 if (server
->possible_feature_level
< DNS_SERVER_FEATURE_LEVEL_DO
)
471 if (server
->rrsig_missing
)
474 /* DNSSEC servers need to support TCP properly (see RFC5966), if they don't, we assume DNSSEC is borked too */
475 if (server
->n_failed_tcp
>= DNS_SERVER_FEATURE_RETRY_ATTEMPTS
)
481 static void dns_server_hash_func(const void *p
, struct siphash
*state
) {
482 const DnsServer
*s
= p
;
486 siphash24_compress(&s
->family
, sizeof(s
->family
), state
);
487 siphash24_compress(&s
->address
, FAMILY_ADDRESS_SIZE(s
->family
), state
);
490 static int dns_server_compare_func(const void *a
, const void *b
) {
491 const DnsServer
*x
= a
, *y
= b
;
493 if (x
->family
< y
->family
)
495 if (x
->family
> y
->family
)
498 return memcmp(&x
->address
, &y
->address
, FAMILY_ADDRESS_SIZE(x
->family
));
501 const struct hash_ops dns_server_hash_ops
= {
502 .hash
= dns_server_hash_func
,
503 .compare
= dns_server_compare_func
506 void dns_server_unlink_all(DnsServer
*first
) {
512 next
= first
->servers_next
;
513 dns_server_unlink(first
);
515 dns_server_unlink_all(next
);
518 void dns_server_unlink_marked(DnsServer
*first
) {
524 next
= first
->servers_next
;
527 dns_server_unlink(first
);
529 dns_server_unlink_marked(next
);
532 void dns_server_mark_all(DnsServer
*first
) {
536 first
->marked
= true;
537 dns_server_mark_all(first
->servers_next
);
540 DnsServer
*dns_server_find(DnsServer
*first
, int family
, const union in_addr_union
*in_addr
) {
543 LIST_FOREACH(servers
, s
, first
)
544 if (s
->family
== family
&& in_addr_equal(family
, &s
->address
, in_addr
) > 0)
550 DnsServer
*manager_get_first_dns_server(Manager
*m
, DnsServerType t
) {
555 case DNS_SERVER_SYSTEM
:
556 return m
->dns_servers
;
558 case DNS_SERVER_FALLBACK
:
559 return m
->fallback_dns_servers
;
566 DnsServer
*manager_set_dns_server(Manager
*m
, DnsServer
*s
) {
569 if (m
->current_dns_server
== s
)
573 log_info("Switching to system DNS server %s.", dns_server_string(s
));
575 dns_server_unref(m
->current_dns_server
);
576 m
->current_dns_server
= dns_server_ref(s
);
578 if (m
->unicast_scope
)
579 dns_cache_flush(&m
->unicast_scope
->cache
);
584 DnsServer
*manager_get_dns_server(Manager
*m
) {
588 /* Try to read updates resolv.conf */
589 manager_read_resolv_conf(m
);
591 /* If no DNS server was chose so far, pick the first one */
592 if (!m
->current_dns_server
)
593 manager_set_dns_server(m
, m
->dns_servers
);
595 if (!m
->current_dns_server
) {
599 /* No DNS servers configured, let's see if there are
600 * any on any links. If not, we use the fallback
603 HASHMAP_FOREACH(l
, m
->links
, i
)
604 if (l
->dns_servers
) {
610 manager_set_dns_server(m
, m
->fallback_dns_servers
);
613 return m
->current_dns_server
;
616 void manager_next_dns_server(Manager
*m
) {
619 /* If there's currently no DNS server set, then the next
620 * manager_get_dns_server() will find one */
621 if (!m
->current_dns_server
)
624 /* Change to the next one, but make sure to follow the linked
625 * list only if the server is still linked. */
626 if (m
->current_dns_server
->linked
&& m
->current_dns_server
->servers_next
) {
627 manager_set_dns_server(m
, m
->current_dns_server
->servers_next
);
631 /* If there was no next one, then start from the beginning of
633 if (m
->current_dns_server
->type
== DNS_SERVER_FALLBACK
)
634 manager_set_dns_server(m
, m
->fallback_dns_servers
);
636 manager_set_dns_server(m
, m
->dns_servers
);
639 static const char* const dns_server_feature_level_table
[_DNS_SERVER_FEATURE_LEVEL_MAX
] = {
640 [DNS_SERVER_FEATURE_LEVEL_TCP
] = "TCP",
641 [DNS_SERVER_FEATURE_LEVEL_UDP
] = "UDP",
642 [DNS_SERVER_FEATURE_LEVEL_EDNS0
] = "UDP+EDNS0",
643 [DNS_SERVER_FEATURE_LEVEL_DO
] = "UDP+EDNS0+DO",
644 [DNS_SERVER_FEATURE_LEVEL_LARGE
] = "UDP+EDNS0+DO+LARGE",
646 DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level
, DnsServerFeatureLevel
);