]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-server.c
resolved: add missing case to switch statement
[thirdparty/systemd.git] / src / resolve / resolved-dns-server.c
CommitLineData
74b2466e
LP
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
b5efdb8a 22#include "alloc-util.h"
74b2466e 23#include "resolved-dns-server.h"
f2f1dbe5 24#include "resolved-resolv-conf.h"
b5efdb8a 25#include "siphash24.h"
be808ea0 26#include "string-table.h"
f2f1dbe5 27#include "string-util.h"
74b2466e 28
9df3ba6c
TG
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
be808ea0
TG
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
74b2466e
LP
40int dns_server_new(
41 Manager *m,
42 DnsServer **ret,
4e945a6f 43 DnsServerType type,
74b2466e 44 Link *l,
0dd25fb9 45 int family,
3c0cf502 46 const union in_addr_union *in_addr) {
74b2466e 47
eed857b7 48 DnsServer *s;
74b2466e
LP
49
50 assert(m);
4e945a6f 51 assert((type == DNS_SERVER_LINK) == !!l);
74b2466e 52 assert(in_addr);
74b2466e 53
eed857b7
LP
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
74b2466e
LP
65 s = new0(DnsServer, 1);
66 if (!s)
67 return -ENOMEM;
68
91b14d6f 69 s->n_ref = 1;
0b58db65 70 s->manager = m;
f4461e56
LP
71 s->verified_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID;
72 s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST;
be808ea0 73 s->features_grace_period_usec = DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC;
d74fb368 74 s->received_udp_packet_max = DNS_PACKET_UNICAST_SIZE_MAX;
4e945a6f 75 s->type = type;
74b2466e
LP
76 s->family = family;
77 s->address = *in_addr;
9df3ba6c 78 s->resend_timeout = DNS_TIMEOUT_MIN_USEC;
74b2466e 79
0b58db65
LP
80 switch (type) {
81
82 case DNS_SERVER_LINK:
83 s->link = l;
eed857b7
LP
84 LIST_APPEND(servers, l->dns_servers, s);
85 l->n_dns_servers++;
0b58db65
LP
86 break;
87
88 case DNS_SERVER_SYSTEM:
eed857b7
LP
89 LIST_APPEND(servers, m->dns_servers, s);
90 m->n_dns_servers++;
0b58db65
LP
91 break;
92
93 case DNS_SERVER_FALLBACK:
eed857b7
LP
94 LIST_APPEND(servers, m->fallback_dns_servers, s);
95 m->n_dns_servers++;
0b58db65
LP
96 break;
97
98 default:
4e945a6f 99 assert_not_reached("Unknown server type");
0b58db65 100 }
74b2466e 101
0eac4623 102 s->linked = true;
74b2466e 103
4e945a6f
LP
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 &&
3e684349
LP
108 m->current_dns_server &&
109 m->current_dns_server->type == DNS_SERVER_FALLBACK)
110 manager_set_dns_server(m, NULL);
4e945a6f 111
74b2466e
LP
112 if (ret)
113 *ret = s;
114
115 return 0;
116}
117
91b14d6f 118DnsServer* dns_server_ref(DnsServer *s) {
74b2466e
LP
119 if (!s)
120 return NULL;
121
91b14d6f 122 assert(s->n_ref > 0);
91b14d6f 123 s->n_ref ++;
cab5b059 124
91b14d6f
TG
125 return s;
126}
127
0eac4623 128DnsServer* dns_server_unref(DnsServer *s) {
91b14d6f
TG
129 if (!s)
130 return NULL;
3e684349 131
0eac4623
LP
132 assert(s->n_ref > 0);
133 s->n_ref --;
91b14d6f 134
0eac4623
LP
135 if (s->n_ref > 0)
136 return NULL;
74b2466e 137
74b2466e 138 free(s);
74b2466e
LP
139 return NULL;
140}
87f5a193 141
0eac4623
LP
142void dns_server_unlink(DnsServer *s) {
143 assert(s);
144 assert(s->manager);
91b14d6f 145
0eac4623
LP
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. */
91b14d6f 149
0eac4623
LP
150 if (!s->linked)
151 return;
91b14d6f 152
0eac4623
LP
153 switch (s->type) {
154
155 case DNS_SERVER_LINK:
156 assert(s->link);
eed857b7 157 assert(s->link->n_dns_servers > 0);
0eac4623
LP
158 LIST_REMOVE(servers, s->link->dns_servers, s);
159 break;
160
161 case DNS_SERVER_SYSTEM:
eed857b7 162 assert(s->manager->n_dns_servers > 0);
0eac4623 163 LIST_REMOVE(servers, s->manager->dns_servers, s);
eed857b7 164 s->manager->n_dns_servers--;
0eac4623
LP
165 break;
166
167 case DNS_SERVER_FALLBACK:
eed857b7 168 assert(s->manager->n_dns_servers > 0);
0eac4623 169 LIST_REMOVE(servers, s->manager->fallback_dns_servers, s);
eed857b7 170 s->manager->n_dns_servers--;
0eac4623
LP
171 break;
172 }
173
174 s->linked = false;
175
176 if (s->link && s->link->current_dns_server == s)
177 link_set_dns_server(s->link, NULL);
178
179 if (s->manager->current_dns_server == s)
180 manager_set_dns_server(s->manager, NULL);
181
182 dns_server_unref(s);
91b14d6f
TG
183}
184
0b58db65
LP
185void dns_server_move_back_and_unmark(DnsServer *s) {
186 DnsServer *tail;
187
188 assert(s);
189
190 if (!s->marked)
191 return;
192
193 s->marked = false;
194
195 if (!s->linked || !s->servers_next)
196 return;
197
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. */
200
201 switch (s->type) {
202
203 case DNS_SERVER_LINK:
204 assert(s->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);
208 break;
209
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);
214 break;
215
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);
220 break;
221
222 default:
223 assert_not_reached("Unknown server type");
224 }
225}
226
f4461e56 227void dns_server_packet_received(DnsServer *s, DnsServerFeatureLevel level, usec_t rtt, size_t size) {
9df3ba6c
TG
228 assert(s);
229
f4461e56 230 if (level == DNS_SERVER_FEATURE_LEVEL_LARGE) {
b652d4a2
LP
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
234 packets. */
235
f4461e56
LP
236 if (s->verified_feature_level < DNS_SERVER_FEATURE_LEVEL_LARGE - 1) {
237 s->verified_feature_level = DNS_SERVER_FEATURE_LEVEL_LARGE - 1;
d74fb368
TG
238 assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0);
239 }
f4461e56
LP
240 } else if (s->verified_feature_level < level) {
241 s->verified_feature_level = level;
be808ea0
TG
242 assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0);
243 }
244
f4461e56 245 if (s->possible_feature_level == level)
be808ea0 246 s->n_failed_attempts = 0;
84129d46 247
d74fb368
TG
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
250 this size. */
251 if (s->received_udp_packet_max < size)
252 s->received_udp_packet_max = size;
253
be808ea0
TG
254 if (s->max_rtt < rtt) {
255 s->max_rtt = rtt;
efd46a69 256 s->resend_timeout = CLAMP(s->max_rtt * 2, DNS_TIMEOUT_MIN_USEC, DNS_TIMEOUT_MAX_USEC);
be808ea0 257 }
9df3ba6c
TG
258}
259
f4461e56 260void dns_server_packet_lost(DnsServer *s, DnsServerFeatureLevel level, usec_t usec) {
9df3ba6c 261 assert(s);
be808ea0
TG
262 assert(s->manager);
263
f4461e56 264 if (s->possible_feature_level == level)
be808ea0 265 s->n_failed_attempts ++;
9df3ba6c 266
84129d46
LP
267 if (s->resend_timeout > usec)
268 return;
269
270 s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC);
9df3ba6c
TG
271}
272
f4461e56 273void dns_server_packet_failed(DnsServer *s, DnsServerFeatureLevel level) {
4e0b8b17
TG
274 assert(s);
275 assert(s->manager);
276
f4461e56 277 if (s->possible_feature_level != level)
4e0b8b17
TG
278 return;
279
571370c1
LP
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
283 * transport. */
284
285 if (s->possible_feature_level <= DNS_SERVER_FEATURE_LEVEL_UDP)
286 return;
287
4e0b8b17
TG
288 s->n_failed_attempts = (unsigned) -1;
289}
290
b652d4a2
LP
291void dns_server_packet_rrsig_missing(DnsServer *s) {
292 _cleanup_free_ char *ip = NULL;
293 assert(s);
294 assert(s->manager);
295
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));
298
299 s->rrsig_missing = true;
300}
301
be808ea0
TG
302static bool dns_server_grace_period_expired(DnsServer *s) {
303 usec_t ts;
304
305 assert(s);
306 assert(s->manager);
307
308 if (s->verified_usec == 0)
309 return false;
310
311 assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
312
313 if (s->verified_usec + s->features_grace_period_usec > ts)
314 return false;
315
316 s->features_grace_period_usec = MIN(s->features_grace_period_usec * 2, DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC);
317
318 return true;
319}
320
f4461e56 321DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
be808ea0
TG
322 assert(s);
323
f4461e56 324 if (s->possible_feature_level != DNS_SERVER_FEATURE_LEVEL_BEST &&
be808ea0
TG
325 dns_server_grace_period_expired(s)) {
326 _cleanup_free_ char *ip = NULL;
327
f4461e56 328 s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST;
be808ea0
TG
329 s->n_failed_attempts = 0;
330 s->verified_usec = 0;
b652d4a2 331 s->rrsig_missing = false;
be808ea0
TG
332
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));
f4461e56
LP
335 } else if (s->possible_feature_level <= s->verified_feature_level)
336 s->possible_feature_level = s->verified_feature_level;
6a1a5eec 337 else if (s->n_failed_attempts >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS) {
be808ea0
TG
338 _cleanup_free_ char *ip = NULL;
339
6a1a5eec
LP
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. */
344
345 if (s->possible_feature_level == DNS_SERVER_FEATURE_LEVEL_TCP)
346 s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_UDP;
347 else {
348 assert(s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_WORST);
349 s->possible_feature_level --;
350 }
351
be808ea0
TG
352 s->n_failed_attempts = 0;
353 s->verified_usec = 0;
354
355 in_addr_to_string(s->family, &s->address, &ip);
356 log_warning("Using degraded feature set (%s) for DNS server %s",
f4461e56 357 dns_server_feature_level_to_string(s->possible_feature_level), strna(ip));
be808ea0
TG
358 }
359
f4461e56 360 return s->possible_feature_level;
be808ea0
TG
361}
362
519ef046
LP
363int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level) {
364 size_t packet_size;
365 bool edns_do;
366 int r;
367
368 assert(server);
369 assert(packet);
370 assert(packet->protocol == DNS_PROTOCOL_DNS);
371
372 /* Fix the OPT field in the packet to match our current feature level. */
373
374 r = dns_packet_truncate_opt(packet);
375 if (r < 0)
376 return r;
377
378 if (level < DNS_SERVER_FEATURE_LEVEL_EDNS0)
379 return 0;
380
381 edns_do = level >= DNS_SERVER_FEATURE_LEVEL_DO;
382
383 if (level >= DNS_SERVER_FEATURE_LEVEL_LARGE)
384 packet_size = DNS_PACKET_UNICAST_SIZE_LARGE_MAX;
385 else
386 packet_size = server->received_udp_packet_max;
387
388 return dns_packet_append_opt(packet, packet_size, edns_do, NULL);
389}
390
b826ab58 391static void dns_server_hash_func(const void *p, struct siphash *state) {
87f5a193 392 const DnsServer *s = p;
87f5a193 393
b826ab58 394 assert(s);
87f5a193 395
b826ab58
TG
396 siphash24_compress(&s->family, sizeof(s->family), state);
397 siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
87f5a193
LP
398}
399
d5099efc 400static int dns_server_compare_func(const void *a, const void *b) {
87f5a193
LP
401 const DnsServer *x = a, *y = b;
402
403 if (x->family < y->family)
404 return -1;
405 if (x->family > y->family)
406 return 1;
407
408 return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
409}
d5099efc
MS
410
411const struct hash_ops dns_server_hash_ops = {
412 .hash = dns_server_hash_func,
413 .compare = dns_server_compare_func
414};
636e813d 415
4b95f179
LP
416void dns_server_unlink_all(DnsServer *first) {
417 DnsServer *next;
0eac4623 418
4b95f179
LP
419 if (!first)
420 return;
0eac4623 421
4b95f179
LP
422 next = first->servers_next;
423 dns_server_unlink(first);
636e813d 424
4b95f179 425 dns_server_unlink_all(next);
0eac4623
LP
426}
427
4b95f179
LP
428void dns_server_unlink_marked(DnsServer *first) {
429 DnsServer *next;
636e813d 430
4b95f179
LP
431 if (!first)
432 return;
636e813d 433
4b95f179 434 next = first->servers_next;
636e813d 435
4b95f179 436 if (first->marked)
0eac4623 437 dns_server_unlink(first);
636e813d 438
4b95f179
LP
439 dns_server_unlink_marked(next);
440}
636e813d 441
4b95f179
LP
442void dns_server_mark_all(DnsServer *first) {
443 if (!first)
444 return;
636e813d 445
4b95f179
LP
446 first->marked = true;
447 dns_server_mark_all(first->servers_next);
636e813d
LP
448}
449
4b95f179
LP
450DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr) {
451 DnsServer *s;
636e813d 452
636e813d 453 LIST_FOREACH(servers, s, first)
4b95f179
LP
454 if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
455 return s;
f2f1dbe5 456
4b95f179
LP
457 return NULL;
458}
f2f1dbe5 459
4b95f179 460DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t) {
f2f1dbe5 461 assert(m);
f2f1dbe5 462
4b95f179 463 switch (t) {
f2f1dbe5 464
4b95f179
LP
465 case DNS_SERVER_SYSTEM:
466 return m->dns_servers;
f2f1dbe5 467
4b95f179
LP
468 case DNS_SERVER_FALLBACK:
469 return m->fallback_dns_servers;
470
471 default:
472 return NULL;
473 }
f2f1dbe5
LP
474}
475
476DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
477 assert(m);
478
479 if (m->current_dns_server == s)
480 return s;
481
482 if (s) {
483 _cleanup_free_ char *ip = NULL;
484
485 in_addr_to_string(s->family, &s->address, &ip);
486 log_info("Switching to system DNS server %s.", strna(ip));
487 }
488
0eac4623
LP
489 dns_server_unref(m->current_dns_server);
490 m->current_dns_server = dns_server_ref(s);
f2f1dbe5
LP
491
492 if (m->unicast_scope)
493 dns_cache_flush(&m->unicast_scope->cache);
494
495 return s;
496}
497
498DnsServer *manager_get_dns_server(Manager *m) {
499 Link *l;
500 assert(m);
501
502 /* Try to read updates resolv.conf */
503 manager_read_resolv_conf(m);
504
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);
508
509 if (!m->current_dns_server) {
510 bool found = false;
511 Iterator i;
512
513 /* No DNS servers configured, let's see if there are
514 * any on any links. If not, we use the fallback
515 * servers */
516
517 HASHMAP_FOREACH(l, m->links, i)
518 if (l->dns_servers) {
519 found = true;
520 break;
521 }
522
523 if (!found)
524 manager_set_dns_server(m, m->fallback_dns_servers);
525 }
526
527 return m->current_dns_server;
528}
529
530void manager_next_dns_server(Manager *m) {
531 assert(m);
532
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)
536 return;
537
0eac4623
LP
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) {
f2f1dbe5
LP
541 manager_set_dns_server(m, m->current_dns_server->servers_next);
542 return;
543 }
544
545 /* If there was no next one, then start from the beginning of
546 * the list */
547 if (m->current_dns_server->type == DNS_SERVER_FALLBACK)
548 manager_set_dns_server(m, m->fallback_dns_servers);
549 else
550 manager_set_dns_server(m, m->dns_servers);
551}
be808ea0
TG
552
553static 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",
9c5e12a4 556 [DNS_SERVER_FEATURE_LEVEL_EDNS0] = "UDP+EDNS0",
7586f4d1 557 [DNS_SERVER_FEATURE_LEVEL_DO] = "UDP+EDNS0+DO",
d74fb368 558 [DNS_SERVER_FEATURE_LEVEL_LARGE] = "UDP+EDNS0+DO+LARGE",
be808ea0
TG
559};
560DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level, DnsServerFeatureLevel);