]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-server.c
Merge pull request #2131 from evverx/regenerate-m4-on-reconfigure
[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 static void dns_server_reset_counters(DnsServer *s) {
348 assert(s);
349
350 s->n_failed_udp = 0;
351 s->n_failed_tcp = 0;
352 s->packet_failed = false;
353 s->packet_truncated = false;
354 s->verified_usec = 0;
355 }
356
357 DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
358 assert(s);
359
360 if (s->possible_feature_level != DNS_SERVER_FEATURE_LEVEL_BEST &&
361 dns_server_grace_period_expired(s)) {
362
363 s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST;
364 s->rrsig_missing = false;
365
366 dns_server_reset_counters(s);
367
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));
371
372 } else if (s->possible_feature_level <= s->verified_feature_level)
373 s->possible_feature_level = s->verified_feature_level;
374 else {
375 DnsServerFeatureLevel p = s->possible_feature_level;
376
377 if (s->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS &&
378 s->possible_feature_level == DNS_SERVER_FEATURE_LEVEL_TCP)
379
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;
383
384 else if ((s->n_failed_udp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS &&
385 s->possible_feature_level >= DNS_SERVER_FEATURE_LEVEL_UDP) ||
386 (s->packet_failed &&
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))
391
392 /* Downgrade the feature one level, maybe things will work better then. We do this under any of
393 * three conditions:
394 *
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.
398 *
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.
402 *
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.
408 */
409
410 s->possible_feature_level--;
411
412 if (p != s->possible_feature_level) {
413
414 /* We changed the feature level, reset the counting */
415 dns_server_reset_counters(s);
416
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));
420 }
421 }
422
423 return s->possible_feature_level;
424 }
425
426 int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level) {
427 size_t packet_size;
428 bool edns_do;
429 int r;
430
431 assert(server);
432 assert(packet);
433 assert(packet->protocol == DNS_PROTOCOL_DNS);
434
435 /* Fix the OPT field in the packet to match our current feature level. */
436
437 r = dns_packet_truncate_opt(packet);
438 if (r < 0)
439 return r;
440
441 if (level < DNS_SERVER_FEATURE_LEVEL_EDNS0)
442 return 0;
443
444 edns_do = level >= DNS_SERVER_FEATURE_LEVEL_DO;
445
446 if (level >= DNS_SERVER_FEATURE_LEVEL_LARGE)
447 packet_size = DNS_PACKET_UNICAST_SIZE_LARGE_MAX;
448 else
449 packet_size = server->received_udp_packet_max;
450
451 return dns_packet_append_opt(packet, packet_size, edns_do, NULL);
452 }
453
454 const char *dns_server_string(DnsServer *server) {
455 assert(server);
456
457 if (!server->server_string)
458 (void) in_addr_to_string(server->family, &server->address, &server->server_string);
459
460 return strna(server->server_string);
461 }
462
463 bool dns_server_dnssec_supported(DnsServer *server) {
464 assert(server);
465
466 /* Returns whether the server supports DNSSEC according to what we know about it */
467
468 if (server->possible_feature_level < DNS_SERVER_FEATURE_LEVEL_DO)
469 return false;
470
471 if (server->rrsig_missing)
472 return false;
473
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)
476 return false;
477
478 return true;
479 }
480
481 static void dns_server_hash_func(const void *p, struct siphash *state) {
482 const DnsServer *s = p;
483
484 assert(s);
485
486 siphash24_compress(&s->family, sizeof(s->family), state);
487 siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
488 }
489
490 static int dns_server_compare_func(const void *a, const void *b) {
491 const DnsServer *x = a, *y = b;
492
493 if (x->family < y->family)
494 return -1;
495 if (x->family > y->family)
496 return 1;
497
498 return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
499 }
500
501 const struct hash_ops dns_server_hash_ops = {
502 .hash = dns_server_hash_func,
503 .compare = dns_server_compare_func
504 };
505
506 void dns_server_unlink_all(DnsServer *first) {
507 DnsServer *next;
508
509 if (!first)
510 return;
511
512 next = first->servers_next;
513 dns_server_unlink(first);
514
515 dns_server_unlink_all(next);
516 }
517
518 void dns_server_unlink_marked(DnsServer *first) {
519 DnsServer *next;
520
521 if (!first)
522 return;
523
524 next = first->servers_next;
525
526 if (first->marked)
527 dns_server_unlink(first);
528
529 dns_server_unlink_marked(next);
530 }
531
532 void dns_server_mark_all(DnsServer *first) {
533 if (!first)
534 return;
535
536 first->marked = true;
537 dns_server_mark_all(first->servers_next);
538 }
539
540 DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr) {
541 DnsServer *s;
542
543 LIST_FOREACH(servers, s, first)
544 if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
545 return s;
546
547 return NULL;
548 }
549
550 DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t) {
551 assert(m);
552
553 switch (t) {
554
555 case DNS_SERVER_SYSTEM:
556 return m->dns_servers;
557
558 case DNS_SERVER_FALLBACK:
559 return m->fallback_dns_servers;
560
561 default:
562 return NULL;
563 }
564 }
565
566 DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
567 assert(m);
568
569 if (m->current_dns_server == s)
570 return s;
571
572 if (s)
573 log_info("Switching to system DNS server %s.", dns_server_string(s));
574
575 dns_server_unref(m->current_dns_server);
576 m->current_dns_server = dns_server_ref(s);
577
578 if (m->unicast_scope)
579 dns_cache_flush(&m->unicast_scope->cache);
580
581 return s;
582 }
583
584 DnsServer *manager_get_dns_server(Manager *m) {
585 Link *l;
586 assert(m);
587
588 /* Try to read updates resolv.conf */
589 manager_read_resolv_conf(m);
590
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);
594
595 if (!m->current_dns_server) {
596 bool found = false;
597 Iterator i;
598
599 /* No DNS servers configured, let's see if there are
600 * any on any links. If not, we use the fallback
601 * servers */
602
603 HASHMAP_FOREACH(l, m->links, i)
604 if (l->dns_servers) {
605 found = true;
606 break;
607 }
608
609 if (!found)
610 manager_set_dns_server(m, m->fallback_dns_servers);
611 }
612
613 return m->current_dns_server;
614 }
615
616 void manager_next_dns_server(Manager *m) {
617 assert(m);
618
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)
622 return;
623
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);
628 return;
629 }
630
631 /* If there was no next one, then start from the beginning of
632 * the list */
633 if (m->current_dns_server->type == DNS_SERVER_FALLBACK)
634 manager_set_dns_server(m, m->fallback_dns_servers);
635 else
636 manager_set_dns_server(m, m->dns_servers);
637 }
638
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",
645 };
646 DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level, DnsServerFeatureLevel);