]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-server.c
dcfef66d4c2b729dd1a2ead9ea23385a3e4e3c07
[thirdparty/systemd.git] / src / resolve / resolved-dns-server.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
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"
28
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)
32
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)
36
37 /* The number of times we will attempt a certain feature set before degrading */
38 #define DNS_SERVER_FEATURE_RETRY_ATTEMPTS 3
39
40 int dns_server_new(
41 Manager *m,
42 DnsServer **ret,
43 DnsServerType type,
44 Link *l,
45 int family,
46 const union in_addr_union *in_addr) {
47
48 DnsServer *s;
49
50 assert(m);
51 assert((type == DNS_SERVER_LINK) == !!l);
52 assert(in_addr);
53
54 if (!IN_SET(family, AF_INET, AF_INET6))
55 return -EAFNOSUPPORT;
56
57 if (l) {
58 if (l->n_dns_servers >= LINK_DNS_SERVERS_MAX)
59 return -E2BIG;
60 } else {
61 if (m->n_dns_servers >= MANAGER_DNS_SERVERS_MAX)
62 return -E2BIG;
63 }
64
65 s = new0(DnsServer, 1);
66 if (!s)
67 return -ENOMEM;
68
69 s->n_ref = 1;
70 s->manager = m;
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;
75 s->type = type;
76 s->family = family;
77 s->address = *in_addr;
78 s->resend_timeout = DNS_TIMEOUT_MIN_USEC;
79
80 switch (type) {
81
82 case DNS_SERVER_LINK:
83 s->link = l;
84 LIST_APPEND(servers, l->dns_servers, s);
85 l->n_dns_servers++;
86 break;
87
88 case DNS_SERVER_SYSTEM:
89 LIST_APPEND(servers, m->dns_servers, s);
90 m->n_dns_servers++;
91 break;
92
93 case DNS_SERVER_FALLBACK:
94 LIST_APPEND(servers, m->fallback_dns_servers, s);
95 m->n_dns_servers++;
96 break;
97
98 default:
99 assert_not_reached("Unknown server type");
100 }
101
102 s->linked = true;
103
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
106 * the new one */
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);
111
112 if (ret)
113 *ret = s;
114
115 return 0;
116 }
117
118 DnsServer* dns_server_ref(DnsServer *s) {
119 if (!s)
120 return NULL;
121
122 assert(s->n_ref > 0);
123 s->n_ref ++;
124
125 return s;
126 }
127
128 DnsServer* dns_server_unref(DnsServer *s) {
129 if (!s)
130 return NULL;
131
132 assert(s->n_ref > 0);
133 s->n_ref --;
134
135 if (s->n_ref > 0)
136 return NULL;
137
138 free(s->server_string);
139 free(s);
140 return NULL;
141 }
142
143 void dns_server_unlink(DnsServer *s) {
144 assert(s);
145 assert(s->manager);
146
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. */
150
151 if (!s->linked)
152 return;
153
154 switch (s->type) {
155
156 case DNS_SERVER_LINK:
157 assert(s->link);
158 assert(s->link->n_dns_servers > 0);
159 LIST_REMOVE(servers, s->link->dns_servers, s);
160 break;
161
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--;
166 break;
167
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--;
172 break;
173 }
174
175 s->linked = false;
176
177 if (s->link && s->link->current_dns_server == s)
178 link_set_dns_server(s->link, NULL);
179
180 if (s->manager->current_dns_server == s)
181 manager_set_dns_server(s->manager, NULL);
182
183 dns_server_unref(s);
184 }
185
186 void dns_server_move_back_and_unmark(DnsServer *s) {
187 DnsServer *tail;
188
189 assert(s);
190
191 if (!s->marked)
192 return;
193
194 s->marked = false;
195
196 if (!s->linked || !s->servers_next)
197 return;
198
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. */
201
202 switch (s->type) {
203
204 case DNS_SERVER_LINK:
205 assert(s->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);
209 break;
210
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);
215 break;
216
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);
221 break;
222
223 default:
224 assert_not_reached("Unknown server type");
225 }
226 }
227
228 static void dns_server_verified(DnsServer *s, DnsServerFeatureLevel level) {
229 assert(s);
230
231 if (s->verified_feature_level > level)
232 return;
233
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;
237 }
238
239 assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0);
240 }
241
242 void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLevel level, usec_t rtt, size_t size) {
243 assert(s);
244
245 if (protocol == IPPROTO_UDP) {
246 if (s->possible_feature_level == level)
247 s->n_failed_udp = 0;
248
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);
253 else
254 /* A successful UDP reply, verifies UDP, ENDS0 and DO levels */
255 dns_server_verified(s, level);
256
257 } else if (protocol == IPPROTO_TCP) {
258
259 if (s->possible_feature_level == level)
260 s->n_failed_tcp = 0;
261
262 /* Successful TCP connections are only useful to verify the TCP feature level. */
263 dns_server_verified(s, DNS_SERVER_FEATURE_LEVEL_TCP);
264 }
265
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
268 this size. */
269 if (protocol == IPPROTO_UDP && s->received_udp_packet_max < size)
270 s->received_udp_packet_max = size;
271
272 if (s->max_rtt < rtt) {
273 s->max_rtt = rtt;
274 s->resend_timeout = CLAMP(s->max_rtt * 2, DNS_TIMEOUT_MIN_USEC, DNS_TIMEOUT_MAX_USEC);
275 }
276 }
277
278 void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel level, usec_t usec) {
279 assert(s);
280 assert(s->manager);
281
282 if (s->possible_feature_level == level) {
283 if (protocol == IPPROTO_UDP)
284 s->n_failed_udp ++;
285 else if (protocol == IPPROTO_TCP)
286 s->n_failed_tcp ++;
287 }
288
289 if (s->resend_timeout > usec)
290 return;
291
292 s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC);
293 }
294
295 void dns_server_packet_failed(DnsServer *s, DnsServerFeatureLevel level) {
296 assert(s);
297 assert(s->manager);
298
299 /* Invoked whenever we get a FORMERR, SERVFAIL or NOTIMP rcode from a server. */
300
301 if (s->possible_feature_level != level)
302 return;
303
304 s->packet_failed = true;
305 }
306
307 void dns_server_packet_truncated(DnsServer *s, DnsServerFeatureLevel level) {
308 assert(s);
309 assert(s->manager);
310
311 /* Invoked whenever we get a packet with TC bit set. */
312
313 if (s->possible_feature_level != level)
314 return;
315
316 s->packet_truncated = true;
317 }
318
319 void dns_server_packet_rrsig_missing(DnsServer *s) {
320 assert(s);
321 assert(s->manager);
322
323 log_warning("DNS server %s does not augment replies with RRSIG records, DNSSEC not available.", dns_server_string(s));
324
325 s->rrsig_missing = true;
326 }
327
328 static bool dns_server_grace_period_expired(DnsServer *s) {
329 usec_t ts;
330
331 assert(s);
332 assert(s->manager);
333
334 if (s->verified_usec == 0)
335 return false;
336
337 assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
338
339 if (s->verified_usec + s->features_grace_period_usec > ts)
340 return false;
341
342 s->features_grace_period_usec = MIN(s->features_grace_period_usec * 2, DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC);
343
344 return true;
345 }
346
347 DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
348 assert(s);
349
350 if (s->possible_feature_level != DNS_SERVER_FEATURE_LEVEL_BEST &&
351 dns_server_grace_period_expired(s)) {
352
353 s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST;
354 s->n_failed_udp = 0;
355 s->n_failed_tcp = 0;
356 s->packet_failed = false;
357 s->packet_truncated = false;
358 s->verified_usec = 0;
359 s->rrsig_missing = false;
360
361 log_info("Grace period over, resuming full feature set (%s) for DNS server %s",
362 dns_server_feature_level_to_string(s->possible_feature_level),
363 dns_server_string(s));
364
365 } else if (s->possible_feature_level <= s->verified_feature_level)
366 s->possible_feature_level = s->verified_feature_level;
367 else {
368 DnsServerFeatureLevel p = s->possible_feature_level;
369
370 if (s->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS &&
371 s->possible_feature_level == DNS_SERVER_FEATURE_LEVEL_TCP)
372
373 /* We are at the TCP (lowest) level, and we tried a couple of TCP connections, and it didn't
374 * work. Upgrade back to UDP again. */
375 s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_UDP;
376
377 else if ((s->n_failed_udp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS &&
378 s->possible_feature_level >= DNS_SERVER_FEATURE_LEVEL_UDP) ||
379 (s->packet_failed &&
380 s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP) ||
381 (s->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS &&
382 s->packet_truncated &&
383 s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP))
384
385 /* Downgrade the feature one level, maybe things will work better then. We do this under any of
386 * three conditions:
387 *
388 * 1. We lost too many UDP packets in a row, and are on a feature level of UDP or higher. If
389 * the packets are lost, maybe the server cannot parse them, hence downgrading sounds like a
390 * good idea. We might downgrade all the way down to TCP this way.
391 *
392 * 2. We got a failure packet, and are at a feature level above UDP. Note that in this case we
393 * downgrade no further than UDP, under the assumption that a failure packet indicates an
394 * incompatible packet contents, but not a problem with the transport.
395 *
396 * 3. We got too many TCP connection failures in a row, we had at least one truncated packet,
397 * and are on a feature level above UDP. By downgrading things and getting rid of DNSSEC or
398 * EDNS0 data we hope to make the packet smaller, so that it still works via UDP given that
399 * TCP appears not to be a fallback. Note that if we are already at the lowest UDP level, we
400 * don't go further down, since that's TCP, and TCP failed too often after all.
401 */
402
403 s->possible_feature_level--;
404
405 if (p != s->possible_feature_level) {
406
407 /* We changed the feature level, reset the counting */
408 s->n_failed_udp = 0;
409 s->n_failed_tcp = 0;
410 s->packet_failed = false;
411 s->packet_truncated = false;
412 s->verified_usec = 0;
413
414 log_warning("Using degraded feature set (%s) for DNS server %s",
415 dns_server_feature_level_to_string(s->possible_feature_level),
416 dns_server_string(s));
417 }
418 }
419
420 return s->possible_feature_level;
421 }
422
423 int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level) {
424 size_t packet_size;
425 bool edns_do;
426 int r;
427
428 assert(server);
429 assert(packet);
430 assert(packet->protocol == DNS_PROTOCOL_DNS);
431
432 /* Fix the OPT field in the packet to match our current feature level. */
433
434 r = dns_packet_truncate_opt(packet);
435 if (r < 0)
436 return r;
437
438 if (level < DNS_SERVER_FEATURE_LEVEL_EDNS0)
439 return 0;
440
441 edns_do = level >= DNS_SERVER_FEATURE_LEVEL_DO;
442
443 if (level >= DNS_SERVER_FEATURE_LEVEL_LARGE)
444 packet_size = DNS_PACKET_UNICAST_SIZE_LARGE_MAX;
445 else
446 packet_size = server->received_udp_packet_max;
447
448 return dns_packet_append_opt(packet, packet_size, edns_do, NULL);
449 }
450
451 const char *dns_server_string(DnsServer *server) {
452 assert(server);
453
454 if (!server->server_string)
455 (void) in_addr_to_string(server->family, &server->address, &server->server_string);
456
457 return strna(server->server_string);
458 }
459
460 static void dns_server_hash_func(const void *p, struct siphash *state) {
461 const DnsServer *s = p;
462
463 assert(s);
464
465 siphash24_compress(&s->family, sizeof(s->family), state);
466 siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
467 }
468
469 static int dns_server_compare_func(const void *a, const void *b) {
470 const DnsServer *x = a, *y = b;
471
472 if (x->family < y->family)
473 return -1;
474 if (x->family > y->family)
475 return 1;
476
477 return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
478 }
479
480 const struct hash_ops dns_server_hash_ops = {
481 .hash = dns_server_hash_func,
482 .compare = dns_server_compare_func
483 };
484
485 void dns_server_unlink_all(DnsServer *first) {
486 DnsServer *next;
487
488 if (!first)
489 return;
490
491 next = first->servers_next;
492 dns_server_unlink(first);
493
494 dns_server_unlink_all(next);
495 }
496
497 void dns_server_unlink_marked(DnsServer *first) {
498 DnsServer *next;
499
500 if (!first)
501 return;
502
503 next = first->servers_next;
504
505 if (first->marked)
506 dns_server_unlink(first);
507
508 dns_server_unlink_marked(next);
509 }
510
511 void dns_server_mark_all(DnsServer *first) {
512 if (!first)
513 return;
514
515 first->marked = true;
516 dns_server_mark_all(first->servers_next);
517 }
518
519 DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr) {
520 DnsServer *s;
521
522 LIST_FOREACH(servers, s, first)
523 if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
524 return s;
525
526 return NULL;
527 }
528
529 DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t) {
530 assert(m);
531
532 switch (t) {
533
534 case DNS_SERVER_SYSTEM:
535 return m->dns_servers;
536
537 case DNS_SERVER_FALLBACK:
538 return m->fallback_dns_servers;
539
540 default:
541 return NULL;
542 }
543 }
544
545 DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
546 assert(m);
547
548 if (m->current_dns_server == s)
549 return s;
550
551 if (s)
552 log_info("Switching to system DNS server %s.", dns_server_string(s));
553
554 dns_server_unref(m->current_dns_server);
555 m->current_dns_server = dns_server_ref(s);
556
557 if (m->unicast_scope)
558 dns_cache_flush(&m->unicast_scope->cache);
559
560 return s;
561 }
562
563 DnsServer *manager_get_dns_server(Manager *m) {
564 Link *l;
565 assert(m);
566
567 /* Try to read updates resolv.conf */
568 manager_read_resolv_conf(m);
569
570 /* If no DNS server was chose so far, pick the first one */
571 if (!m->current_dns_server)
572 manager_set_dns_server(m, m->dns_servers);
573
574 if (!m->current_dns_server) {
575 bool found = false;
576 Iterator i;
577
578 /* No DNS servers configured, let's see if there are
579 * any on any links. If not, we use the fallback
580 * servers */
581
582 HASHMAP_FOREACH(l, m->links, i)
583 if (l->dns_servers) {
584 found = true;
585 break;
586 }
587
588 if (!found)
589 manager_set_dns_server(m, m->fallback_dns_servers);
590 }
591
592 return m->current_dns_server;
593 }
594
595 void manager_next_dns_server(Manager *m) {
596 assert(m);
597
598 /* If there's currently no DNS server set, then the next
599 * manager_get_dns_server() will find one */
600 if (!m->current_dns_server)
601 return;
602
603 /* Change to the next one, but make sure to follow the linked
604 * list only if the server is still linked. */
605 if (m->current_dns_server->linked && m->current_dns_server->servers_next) {
606 manager_set_dns_server(m, m->current_dns_server->servers_next);
607 return;
608 }
609
610 /* If there was no next one, then start from the beginning of
611 * the list */
612 if (m->current_dns_server->type == DNS_SERVER_FALLBACK)
613 manager_set_dns_server(m, m->fallback_dns_servers);
614 else
615 manager_set_dns_server(m, m->dns_servers);
616 }
617
618 static const char* const dns_server_feature_level_table[_DNS_SERVER_FEATURE_LEVEL_MAX] = {
619 [DNS_SERVER_FEATURE_LEVEL_TCP] = "TCP",
620 [DNS_SERVER_FEATURE_LEVEL_UDP] = "UDP",
621 [DNS_SERVER_FEATURE_LEVEL_EDNS0] = "UDP+EDNS0",
622 [DNS_SERVER_FEATURE_LEVEL_DO] = "UDP+EDNS0+DO",
623 [DNS_SERVER_FEATURE_LEVEL_LARGE] = "UDP+EDNS0+DO+LARGE",
624 };
625 DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level, DnsServerFeatureLevel);