]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-server.c
resolved: rework OPT RR generation logic
[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_features = _DNS_SERVER_FEATURE_LEVEL_INVALID;
72 s->possible_features = 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);
139 return NULL;
140 }
141
142 void dns_server_unlink(DnsServer *s) {
143 assert(s);
144 assert(s->manager);
145
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. */
149
150 if (!s->linked)
151 return;
152
153 switch (s->type) {
154
155 case DNS_SERVER_LINK:
156 assert(s->link);
157 assert(s->link->n_dns_servers > 0);
158 LIST_REMOVE(servers, s->link->dns_servers, s);
159 break;
160
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--;
165 break;
166
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--;
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);
183 }
184
185 void 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
227 void dns_server_packet_received(DnsServer *s, DnsServerFeatureLevel features, usec_t rtt, size_t size) {
228 assert(s);
229
230 if (features == 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
234 packets. */
235
236 if (s->verified_features < DNS_SERVER_FEATURE_LEVEL_LARGE - 1) {
237 s->verified_features = DNS_SERVER_FEATURE_LEVEL_LARGE - 1;
238 assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0);
239 }
240 } else if (s->verified_features < features) {
241 s->verified_features = features;
242 assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0);
243 }
244
245 if (s->possible_features == features)
246 s->n_failed_attempts = 0;
247
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
254 if (s->max_rtt < rtt) {
255 s->max_rtt = rtt;
256 s->resend_timeout = MIN(MAX(DNS_TIMEOUT_MIN_USEC, s->max_rtt * 2), DNS_TIMEOUT_MAX_USEC);
257 }
258 }
259
260 void dns_server_packet_lost(DnsServer *s, DnsServerFeatureLevel features, usec_t usec) {
261 assert(s);
262 assert(s->manager);
263
264 if (s->possible_features == features)
265 s->n_failed_attempts ++;
266
267 if (s->resend_timeout > usec)
268 return;
269
270 s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC);
271 }
272
273 void dns_server_packet_failed(DnsServer *s, DnsServerFeatureLevel features) {
274 assert(s);
275 assert(s->manager);
276
277 if (s->possible_features != features)
278 return;
279
280 s->n_failed_attempts = (unsigned) -1;
281 }
282
283 void dns_server_packet_rrsig_missing(DnsServer *s) {
284 _cleanup_free_ char *ip = NULL;
285 assert(s);
286 assert(s->manager);
287
288 in_addr_to_string(s->family, &s->address, &ip);
289 log_warning("DNS server %s does not augment replies with RRSIG records, DNSSEC not available.", strna(ip));
290
291 s->rrsig_missing = true;
292 }
293
294 static bool dns_server_grace_period_expired(DnsServer *s) {
295 usec_t ts;
296
297 assert(s);
298 assert(s->manager);
299
300 if (s->verified_usec == 0)
301 return false;
302
303 assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
304
305 if (s->verified_usec + s->features_grace_period_usec > ts)
306 return false;
307
308 s->features_grace_period_usec = MIN(s->features_grace_period_usec * 2, DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC);
309
310 return true;
311 }
312
313 DnsServerFeatureLevel dns_server_possible_features(DnsServer *s) {
314 assert(s);
315
316 if (s->possible_features != DNS_SERVER_FEATURE_LEVEL_BEST &&
317 dns_server_grace_period_expired(s)) {
318 _cleanup_free_ char *ip = NULL;
319
320 s->possible_features = DNS_SERVER_FEATURE_LEVEL_BEST;
321 s->n_failed_attempts = 0;
322 s->verified_usec = 0;
323 s->rrsig_missing = false;
324
325 in_addr_to_string(s->family, &s->address, &ip);
326 log_info("Grace period over, resuming full feature set for DNS server %s", strna(ip));
327 } else if (s->possible_features <= s->verified_features)
328 s->possible_features = s->verified_features;
329 else if (s->n_failed_attempts >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS &&
330 s->possible_features > DNS_SERVER_FEATURE_LEVEL_WORST) {
331 _cleanup_free_ char *ip = NULL;
332
333 s->possible_features --;
334 s->n_failed_attempts = 0;
335 s->verified_usec = 0;
336
337 in_addr_to_string(s->family, &s->address, &ip);
338 log_warning("Using degraded feature set (%s) for DNS server %s",
339 dns_server_feature_level_to_string(s->possible_features), strna(ip));
340 }
341
342 return s->possible_features;
343 }
344
345 int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level) {
346 size_t packet_size;
347 bool edns_do;
348 int r;
349
350 assert(server);
351 assert(packet);
352 assert(packet->protocol == DNS_PROTOCOL_DNS);
353
354 /* Fix the OPT field in the packet to match our current feature level. */
355
356 r = dns_packet_truncate_opt(packet);
357 if (r < 0)
358 return r;
359
360 if (level < DNS_SERVER_FEATURE_LEVEL_EDNS0)
361 return 0;
362
363 edns_do = level >= DNS_SERVER_FEATURE_LEVEL_DO;
364
365 if (level >= DNS_SERVER_FEATURE_LEVEL_LARGE)
366 packet_size = DNS_PACKET_UNICAST_SIZE_LARGE_MAX;
367 else
368 packet_size = server->received_udp_packet_max;
369
370 return dns_packet_append_opt(packet, packet_size, edns_do, NULL);
371 }
372
373 static void dns_server_hash_func(const void *p, struct siphash *state) {
374 const DnsServer *s = p;
375
376 assert(s);
377
378 siphash24_compress(&s->family, sizeof(s->family), state);
379 siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
380 }
381
382 static int dns_server_compare_func(const void *a, const void *b) {
383 const DnsServer *x = a, *y = b;
384
385 if (x->family < y->family)
386 return -1;
387 if (x->family > y->family)
388 return 1;
389
390 return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
391 }
392
393 const struct hash_ops dns_server_hash_ops = {
394 .hash = dns_server_hash_func,
395 .compare = dns_server_compare_func
396 };
397
398 void dns_server_unlink_all(DnsServer *first) {
399 DnsServer *next;
400
401 if (!first)
402 return;
403
404 next = first->servers_next;
405 dns_server_unlink(first);
406
407 dns_server_unlink_all(next);
408 }
409
410 void dns_server_unlink_marked(DnsServer *first) {
411 DnsServer *next;
412
413 if (!first)
414 return;
415
416 next = first->servers_next;
417
418 if (first->marked)
419 dns_server_unlink(first);
420
421 dns_server_unlink_marked(next);
422 }
423
424 void dns_server_mark_all(DnsServer *first) {
425 if (!first)
426 return;
427
428 first->marked = true;
429 dns_server_mark_all(first->servers_next);
430 }
431
432 DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr) {
433 DnsServer *s;
434
435 LIST_FOREACH(servers, s, first)
436 if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
437 return s;
438
439 return NULL;
440 }
441
442 DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t) {
443 assert(m);
444
445 switch (t) {
446
447 case DNS_SERVER_SYSTEM:
448 return m->dns_servers;
449
450 case DNS_SERVER_FALLBACK:
451 return m->fallback_dns_servers;
452
453 default:
454 return NULL;
455 }
456 }
457
458 DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
459 assert(m);
460
461 if (m->current_dns_server == s)
462 return s;
463
464 if (s) {
465 _cleanup_free_ char *ip = NULL;
466
467 in_addr_to_string(s->family, &s->address, &ip);
468 log_info("Switching to system DNS server %s.", strna(ip));
469 }
470
471 dns_server_unref(m->current_dns_server);
472 m->current_dns_server = dns_server_ref(s);
473
474 if (m->unicast_scope)
475 dns_cache_flush(&m->unicast_scope->cache);
476
477 return s;
478 }
479
480 DnsServer *manager_get_dns_server(Manager *m) {
481 Link *l;
482 assert(m);
483
484 /* Try to read updates resolv.conf */
485 manager_read_resolv_conf(m);
486
487 /* If no DNS server was chose so far, pick the first one */
488 if (!m->current_dns_server)
489 manager_set_dns_server(m, m->dns_servers);
490
491 if (!m->current_dns_server) {
492 bool found = false;
493 Iterator i;
494
495 /* No DNS servers configured, let's see if there are
496 * any on any links. If not, we use the fallback
497 * servers */
498
499 HASHMAP_FOREACH(l, m->links, i)
500 if (l->dns_servers) {
501 found = true;
502 break;
503 }
504
505 if (!found)
506 manager_set_dns_server(m, m->fallback_dns_servers);
507 }
508
509 return m->current_dns_server;
510 }
511
512 void manager_next_dns_server(Manager *m) {
513 assert(m);
514
515 /* If there's currently no DNS server set, then the next
516 * manager_get_dns_server() will find one */
517 if (!m->current_dns_server)
518 return;
519
520 /* Change to the next one, but make sure to follow the linked
521 * list only if the server is still linked. */
522 if (m->current_dns_server->linked && m->current_dns_server->servers_next) {
523 manager_set_dns_server(m, m->current_dns_server->servers_next);
524 return;
525 }
526
527 /* If there was no next one, then start from the beginning of
528 * the list */
529 if (m->current_dns_server->type == DNS_SERVER_FALLBACK)
530 manager_set_dns_server(m, m->fallback_dns_servers);
531 else
532 manager_set_dns_server(m, m->dns_servers);
533 }
534
535 static const char* const dns_server_feature_level_table[_DNS_SERVER_FEATURE_LEVEL_MAX] = {
536 [DNS_SERVER_FEATURE_LEVEL_TCP] = "TCP",
537 [DNS_SERVER_FEATURE_LEVEL_UDP] = "UDP",
538 [DNS_SERVER_FEATURE_LEVEL_EDNS0] = "UDP+EDNS0",
539 [DNS_SERVER_FEATURE_LEVEL_DO] = "UDP+EDNS0+DO",
540 [DNS_SERVER_FEATURE_LEVEL_LARGE] = "UDP+EDNS0+DO+LARGE",
541 };
542 DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level, DnsServerFeatureLevel);