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);
142 void dns_server_unlink(DnsServer
*s
) {
146 /* This removes the specified server from the linked list of
147 * servers, but any server might still stay around if it has
148 * refs, for example from an ongoing transaction. */
155 case DNS_SERVER_LINK
:
157 assert(s
->link
->n_dns_servers
> 0);
158 LIST_REMOVE(servers
, s
->link
->dns_servers
, s
);
161 case DNS_SERVER_SYSTEM
:
162 assert(s
->manager
->n_dns_servers
> 0);
163 LIST_REMOVE(servers
, s
->manager
->dns_servers
, s
);
164 s
->manager
->n_dns_servers
--;
167 case DNS_SERVER_FALLBACK
:
168 assert(s
->manager
->n_dns_servers
> 0);
169 LIST_REMOVE(servers
, s
->manager
->fallback_dns_servers
, s
);
170 s
->manager
->n_dns_servers
--;
176 if (s
->link
&& s
->link
->current_dns_server
== s
)
177 link_set_dns_server(s
->link
, NULL
);
179 if (s
->manager
->current_dns_server
== s
)
180 manager_set_dns_server(s
->manager
, NULL
);
185 void dns_server_move_back_and_unmark(DnsServer
*s
) {
195 if (!s
->linked
|| !s
->servers_next
)
198 /* Move us to the end of the list, so that the order is
199 * strictly kept, if we are not at the end anyway. */
203 case DNS_SERVER_LINK
:
205 LIST_FIND_TAIL(servers
, s
, tail
);
206 LIST_REMOVE(servers
, s
->link
->dns_servers
, s
);
207 LIST_INSERT_AFTER(servers
, s
->link
->dns_servers
, tail
, s
);
210 case DNS_SERVER_SYSTEM
:
211 LIST_FIND_TAIL(servers
, s
, tail
);
212 LIST_REMOVE(servers
, s
->manager
->dns_servers
, s
);
213 LIST_INSERT_AFTER(servers
, s
->manager
->dns_servers
, tail
, s
);
216 case DNS_SERVER_FALLBACK
:
217 LIST_FIND_TAIL(servers
, s
, tail
);
218 LIST_REMOVE(servers
, s
->manager
->fallback_dns_servers
, s
);
219 LIST_INSERT_AFTER(servers
, s
->manager
->fallback_dns_servers
, tail
, s
);
223 assert_not_reached("Unknown server type");
227 void dns_server_packet_received(DnsServer
*s
, DnsServerFeatureLevel level
, usec_t rtt
, size_t size
) {
230 if (level
== DNS_SERVER_FEATURE_LEVEL_LARGE
) {
231 /* Even if we successfully receive a reply to a
232 request announcing support for large packets, that
233 does not mean we can necessarily receive large
236 if (s
->verified_feature_level
< DNS_SERVER_FEATURE_LEVEL_LARGE
- 1) {
237 s
->verified_feature_level
= DNS_SERVER_FEATURE_LEVEL_LARGE
- 1;
238 assert_se(sd_event_now(s
->manager
->event
, clock_boottime_or_monotonic(), &s
->verified_usec
) >= 0);
240 } else if (s
->verified_feature_level
< level
) {
241 s
->verified_feature_level
= level
;
242 assert_se(sd_event_now(s
->manager
->event
, clock_boottime_or_monotonic(), &s
->verified_usec
) >= 0);
245 if (s
->possible_feature_level
== level
)
246 s
->n_failed_attempts
= 0;
248 /* Remember the size of the largest UDP packet we received from a server,
249 we know that we can always announce support for packets with at least
251 if (s
->received_udp_packet_max
< size
)
252 s
->received_udp_packet_max
= size
;
254 if (s
->max_rtt
< rtt
) {
256 s
->resend_timeout
= CLAMP(s
->max_rtt
* 2, DNS_TIMEOUT_MIN_USEC
, DNS_TIMEOUT_MAX_USEC
);
260 void dns_server_packet_lost(DnsServer
*s
, DnsServerFeatureLevel level
, usec_t usec
) {
264 if (s
->possible_feature_level
== level
)
265 s
->n_failed_attempts
++;
267 if (s
->resend_timeout
> usec
)
270 s
->resend_timeout
= MIN(s
->resend_timeout
* 2, DNS_TIMEOUT_MAX_USEC
);
273 void dns_server_packet_failed(DnsServer
*s
, DnsServerFeatureLevel level
) {
277 if (s
->possible_feature_level
!= level
)
280 /* Invoked whenever we get a FORMERR, SERVFAIL or NOTIMP rcode from a server. This is an immediate trigger for
281 * us to go one feature level down. Except when we are already at TCP or UDP level, in which case there's no
282 * point in changing, under the assumption that packet failures are caused by packet contents, not by used
285 if (s
->possible_feature_level
<= DNS_SERVER_FEATURE_LEVEL_UDP
)
288 s
->n_failed_attempts
= (unsigned) -1;
291 void dns_server_packet_rrsig_missing(DnsServer
*s
) {
292 _cleanup_free_
char *ip
= NULL
;
296 in_addr_to_string(s
->family
, &s
->address
, &ip
);
297 log_warning("DNS server %s does not augment replies with RRSIG records, DNSSEC not available.", strna(ip
));
299 s
->rrsig_missing
= true;
302 static bool dns_server_grace_period_expired(DnsServer
*s
) {
308 if (s
->verified_usec
== 0)
311 assert_se(sd_event_now(s
->manager
->event
, clock_boottime_or_monotonic(), &ts
) >= 0);
313 if (s
->verified_usec
+ s
->features_grace_period_usec
> ts
)
316 s
->features_grace_period_usec
= MIN(s
->features_grace_period_usec
* 2, DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC
);
321 DnsServerFeatureLevel
dns_server_possible_feature_level(DnsServer
*s
) {
324 if (s
->possible_feature_level
!= DNS_SERVER_FEATURE_LEVEL_BEST
&&
325 dns_server_grace_period_expired(s
)) {
326 _cleanup_free_
char *ip
= NULL
;
328 s
->possible_feature_level
= DNS_SERVER_FEATURE_LEVEL_BEST
;
329 s
->n_failed_attempts
= 0;
330 s
->verified_usec
= 0;
331 s
->rrsig_missing
= false;
333 in_addr_to_string(s
->family
, &s
->address
, &ip
);
334 log_info("Grace period over, resuming full feature set for DNS server %s", strna(ip
));
335 } else if (s
->possible_feature_level
<= s
->verified_feature_level
)
336 s
->possible_feature_level
= s
->verified_feature_level
;
337 else if (s
->n_failed_attempts
>= DNS_SERVER_FEATURE_RETRY_ATTEMPTS
) {
338 _cleanup_free_
char *ip
= NULL
;
340 /* Switch one feature level down. Except when we are at TCP already, in which case we try UDP
341 * again. Thus, if a DNS server is not responding we'll keep toggling between UDP and TCP until it
342 * responds on one of them. Note that we generally prefer UDP over TCP (which is why it is at a higher
343 * feature level), but many DNS servers support lack TCP support. */
345 if (s
->possible_feature_level
== DNS_SERVER_FEATURE_LEVEL_TCP
)
346 s
->possible_feature_level
= DNS_SERVER_FEATURE_LEVEL_UDP
;
348 assert(s
->possible_feature_level
> DNS_SERVER_FEATURE_LEVEL_WORST
);
349 s
->possible_feature_level
--;
352 s
->n_failed_attempts
= 0;
353 s
->verified_usec
= 0;
355 in_addr_to_string(s
->family
, &s
->address
, &ip
);
356 log_warning("Using degraded feature set (%s) for DNS server %s",
357 dns_server_feature_level_to_string(s
->possible_feature_level
), strna(ip
));
360 return s
->possible_feature_level
;
363 int dns_server_adjust_opt(DnsServer
*server
, DnsPacket
*packet
, DnsServerFeatureLevel level
) {
370 assert(packet
->protocol
== DNS_PROTOCOL_DNS
);
372 /* Fix the OPT field in the packet to match our current feature level. */
374 r
= dns_packet_truncate_opt(packet
);
378 if (level
< DNS_SERVER_FEATURE_LEVEL_EDNS0
)
381 edns_do
= level
>= DNS_SERVER_FEATURE_LEVEL_DO
;
383 if (level
>= DNS_SERVER_FEATURE_LEVEL_LARGE
)
384 packet_size
= DNS_PACKET_UNICAST_SIZE_LARGE_MAX
;
386 packet_size
= server
->received_udp_packet_max
;
388 return dns_packet_append_opt(packet
, packet_size
, edns_do
, NULL
);
391 static void dns_server_hash_func(const void *p
, struct siphash
*state
) {
392 const DnsServer
*s
= p
;
396 siphash24_compress(&s
->family
, sizeof(s
->family
), state
);
397 siphash24_compress(&s
->address
, FAMILY_ADDRESS_SIZE(s
->family
), state
);
400 static int dns_server_compare_func(const void *a
, const void *b
) {
401 const DnsServer
*x
= a
, *y
= b
;
403 if (x
->family
< y
->family
)
405 if (x
->family
> y
->family
)
408 return memcmp(&x
->address
, &y
->address
, FAMILY_ADDRESS_SIZE(x
->family
));
411 const struct hash_ops dns_server_hash_ops
= {
412 .hash
= dns_server_hash_func
,
413 .compare
= dns_server_compare_func
416 void dns_server_unlink_all(DnsServer
*first
) {
422 next
= first
->servers_next
;
423 dns_server_unlink(first
);
425 dns_server_unlink_all(next
);
428 void dns_server_unlink_marked(DnsServer
*first
) {
434 next
= first
->servers_next
;
437 dns_server_unlink(first
);
439 dns_server_unlink_marked(next
);
442 void dns_server_mark_all(DnsServer
*first
) {
446 first
->marked
= true;
447 dns_server_mark_all(first
->servers_next
);
450 DnsServer
*dns_server_find(DnsServer
*first
, int family
, const union in_addr_union
*in_addr
) {
453 LIST_FOREACH(servers
, s
, first
)
454 if (s
->family
== family
&& in_addr_equal(family
, &s
->address
, in_addr
) > 0)
460 DnsServer
*manager_get_first_dns_server(Manager
*m
, DnsServerType t
) {
465 case DNS_SERVER_SYSTEM
:
466 return m
->dns_servers
;
468 case DNS_SERVER_FALLBACK
:
469 return m
->fallback_dns_servers
;
476 DnsServer
*manager_set_dns_server(Manager
*m
, DnsServer
*s
) {
479 if (m
->current_dns_server
== s
)
483 _cleanup_free_
char *ip
= NULL
;
485 in_addr_to_string(s
->family
, &s
->address
, &ip
);
486 log_info("Switching to system DNS server %s.", strna(ip
));
489 dns_server_unref(m
->current_dns_server
);
490 m
->current_dns_server
= dns_server_ref(s
);
492 if (m
->unicast_scope
)
493 dns_cache_flush(&m
->unicast_scope
->cache
);
498 DnsServer
*manager_get_dns_server(Manager
*m
) {
502 /* Try to read updates resolv.conf */
503 manager_read_resolv_conf(m
);
505 /* If no DNS server was chose so far, pick the first one */
506 if (!m
->current_dns_server
)
507 manager_set_dns_server(m
, m
->dns_servers
);
509 if (!m
->current_dns_server
) {
513 /* No DNS servers configured, let's see if there are
514 * any on any links. If not, we use the fallback
517 HASHMAP_FOREACH(l
, m
->links
, i
)
518 if (l
->dns_servers
) {
524 manager_set_dns_server(m
, m
->fallback_dns_servers
);
527 return m
->current_dns_server
;
530 void manager_next_dns_server(Manager
*m
) {
533 /* If there's currently no DNS server set, then the next
534 * manager_get_dns_server() will find one */
535 if (!m
->current_dns_server
)
538 /* Change to the next one, but make sure to follow the linked
539 * list only if the server is still linked. */
540 if (m
->current_dns_server
->linked
&& m
->current_dns_server
->servers_next
) {
541 manager_set_dns_server(m
, m
->current_dns_server
->servers_next
);
545 /* If there was no next one, then start from the beginning of
547 if (m
->current_dns_server
->type
== DNS_SERVER_FALLBACK
)
548 manager_set_dns_server(m
, m
->fallback_dns_servers
);
550 manager_set_dns_server(m
, m
->dns_servers
);
553 static const char* const dns_server_feature_level_table
[_DNS_SERVER_FEATURE_LEVEL_MAX
] = {
554 [DNS_SERVER_FEATURE_LEVEL_TCP
] = "TCP",
555 [DNS_SERVER_FEATURE_LEVEL_UDP
] = "UDP",
556 [DNS_SERVER_FEATURE_LEVEL_EDNS0
] = "UDP+EDNS0",
557 [DNS_SERVER_FEATURE_LEVEL_DO
] = "UDP+EDNS0+DO",
558 [DNS_SERVER_FEATURE_LEVEL_LARGE
] = "UDP+EDNS0+DO+LARGE",
560 DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level
, DnsServerFeatureLevel
);