]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-server.c
resolved: cache stringified transaction key once per transaction
[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;
be808ea0
TG
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;
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
d74fb368 227void dns_server_packet_received(DnsServer *s, DnsServerFeatureLevel features, usec_t rtt, size_t size) {
9df3ba6c
TG
228 assert(s);
229
d74fb368
TG
230 if (features == DNS_SERVER_FEATURE_LEVEL_LARGE) {
231 /* even if we successfully receive a reply to a request announcing
232 support for large packets, that does not mean we can necessarily
233 receive large packets. */
234 if (s->verified_features < DNS_SERVER_FEATURE_LEVEL_LARGE - 1) {
235 s->verified_features = DNS_SERVER_FEATURE_LEVEL_LARGE - 1;
236 assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0);
237 }
238 } else if (s->verified_features < features) {
be808ea0
TG
239 s->verified_features = features;
240 assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0);
241 }
242
243 if (s->possible_features == features)
244 s->n_failed_attempts = 0;
84129d46 245
d74fb368
TG
246 /* Remember the size of the largest UDP packet we received from a server,
247 we know that we can always announce support for packets with at least
248 this size. */
249 if (s->received_udp_packet_max < size)
250 s->received_udp_packet_max = size;
251
be808ea0
TG
252 if (s->max_rtt < rtt) {
253 s->max_rtt = rtt;
254 s->resend_timeout = MIN(MAX(DNS_TIMEOUT_MIN_USEC, s->max_rtt * 2), DNS_TIMEOUT_MAX_USEC);
255 }
9df3ba6c
TG
256}
257
be808ea0 258void dns_server_packet_lost(DnsServer *s, DnsServerFeatureLevel features, usec_t usec) {
9df3ba6c 259 assert(s);
be808ea0
TG
260 assert(s->manager);
261
262 if (s->possible_features == features)
263 s->n_failed_attempts ++;
9df3ba6c 264
84129d46
LP
265 if (s->resend_timeout > usec)
266 return;
267
268 s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC);
9df3ba6c
TG
269}
270
4e0b8b17
TG
271void dns_server_packet_failed(DnsServer *s, DnsServerFeatureLevel features) {
272 assert(s);
273 assert(s->manager);
274
275 if (s->possible_features != features)
276 return;
277
278 s->n_failed_attempts = (unsigned) -1;
279}
280
be808ea0
TG
281static bool dns_server_grace_period_expired(DnsServer *s) {
282 usec_t ts;
283
284 assert(s);
285 assert(s->manager);
286
287 if (s->verified_usec == 0)
288 return false;
289
290 assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
291
292 if (s->verified_usec + s->features_grace_period_usec > ts)
293 return false;
294
295 s->features_grace_period_usec = MIN(s->features_grace_period_usec * 2, DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC);
296
297 return true;
298}
299
300DnsServerFeatureLevel dns_server_possible_features(DnsServer *s) {
301 assert(s);
302
303 if (s->possible_features != DNS_SERVER_FEATURE_LEVEL_BEST &&
304 dns_server_grace_period_expired(s)) {
305 _cleanup_free_ char *ip = NULL;
306
307 s->possible_features = DNS_SERVER_FEATURE_LEVEL_BEST;
308 s->n_failed_attempts = 0;
309 s->verified_usec = 0;
310
311 in_addr_to_string(s->family, &s->address, &ip);
312 log_info("Grace period over, resuming full feature set for DNS server %s", strna(ip));
313 } else if (s->possible_features <= s->verified_features)
314 s->possible_features = s->verified_features;
315 else if (s->n_failed_attempts >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS &&
316 s->possible_features > DNS_SERVER_FEATURE_LEVEL_WORST) {
317 _cleanup_free_ char *ip = NULL;
318
319 s->possible_features --;
320 s->n_failed_attempts = 0;
321 s->verified_usec = 0;
322
323 in_addr_to_string(s->family, &s->address, &ip);
324 log_warning("Using degraded feature set (%s) for DNS server %s",
325 dns_server_feature_level_to_string(s->possible_features), strna(ip));
326 }
327
328 return s->possible_features;
329}
330
b826ab58 331static void dns_server_hash_func(const void *p, struct siphash *state) {
87f5a193 332 const DnsServer *s = p;
87f5a193 333
b826ab58 334 assert(s);
87f5a193 335
b826ab58
TG
336 siphash24_compress(&s->family, sizeof(s->family), state);
337 siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
87f5a193
LP
338}
339
d5099efc 340static int dns_server_compare_func(const void *a, const void *b) {
87f5a193
LP
341 const DnsServer *x = a, *y = b;
342
343 if (x->family < y->family)
344 return -1;
345 if (x->family > y->family)
346 return 1;
347
348 return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
349}
d5099efc
MS
350
351const struct hash_ops dns_server_hash_ops = {
352 .hash = dns_server_hash_func,
353 .compare = dns_server_compare_func
354};
636e813d 355
4b95f179
LP
356void dns_server_unlink_all(DnsServer *first) {
357 DnsServer *next;
0eac4623 358
4b95f179
LP
359 if (!first)
360 return;
0eac4623 361
4b95f179
LP
362 next = first->servers_next;
363 dns_server_unlink(first);
636e813d 364
4b95f179 365 dns_server_unlink_all(next);
0eac4623
LP
366}
367
4b95f179
LP
368void dns_server_unlink_marked(DnsServer *first) {
369 DnsServer *next;
636e813d 370
4b95f179
LP
371 if (!first)
372 return;
636e813d 373
4b95f179 374 next = first->servers_next;
636e813d 375
4b95f179 376 if (first->marked)
0eac4623 377 dns_server_unlink(first);
636e813d 378
4b95f179
LP
379 dns_server_unlink_marked(next);
380}
636e813d 381
4b95f179
LP
382void dns_server_mark_all(DnsServer *first) {
383 if (!first)
384 return;
636e813d 385
4b95f179
LP
386 first->marked = true;
387 dns_server_mark_all(first->servers_next);
636e813d
LP
388}
389
4b95f179
LP
390DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr) {
391 DnsServer *s;
636e813d 392
636e813d 393 LIST_FOREACH(servers, s, first)
4b95f179
LP
394 if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
395 return s;
f2f1dbe5 396
4b95f179
LP
397 return NULL;
398}
f2f1dbe5 399
4b95f179 400DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t) {
f2f1dbe5 401 assert(m);
f2f1dbe5 402
4b95f179 403 switch (t) {
f2f1dbe5 404
4b95f179
LP
405 case DNS_SERVER_SYSTEM:
406 return m->dns_servers;
f2f1dbe5 407
4b95f179
LP
408 case DNS_SERVER_FALLBACK:
409 return m->fallback_dns_servers;
410
411 default:
412 return NULL;
413 }
f2f1dbe5
LP
414}
415
416DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
417 assert(m);
418
419 if (m->current_dns_server == s)
420 return s;
421
422 if (s) {
423 _cleanup_free_ char *ip = NULL;
424
425 in_addr_to_string(s->family, &s->address, &ip);
426 log_info("Switching to system DNS server %s.", strna(ip));
427 }
428
0eac4623
LP
429 dns_server_unref(m->current_dns_server);
430 m->current_dns_server = dns_server_ref(s);
f2f1dbe5
LP
431
432 if (m->unicast_scope)
433 dns_cache_flush(&m->unicast_scope->cache);
434
435 return s;
436}
437
438DnsServer *manager_get_dns_server(Manager *m) {
439 Link *l;
440 assert(m);
441
442 /* Try to read updates resolv.conf */
443 manager_read_resolv_conf(m);
444
445 /* If no DNS server was chose so far, pick the first one */
446 if (!m->current_dns_server)
447 manager_set_dns_server(m, m->dns_servers);
448
449 if (!m->current_dns_server) {
450 bool found = false;
451 Iterator i;
452
453 /* No DNS servers configured, let's see if there are
454 * any on any links. If not, we use the fallback
455 * servers */
456
457 HASHMAP_FOREACH(l, m->links, i)
458 if (l->dns_servers) {
459 found = true;
460 break;
461 }
462
463 if (!found)
464 manager_set_dns_server(m, m->fallback_dns_servers);
465 }
466
467 return m->current_dns_server;
468}
469
470void manager_next_dns_server(Manager *m) {
471 assert(m);
472
473 /* If there's currently no DNS server set, then the next
474 * manager_get_dns_server() will find one */
475 if (!m->current_dns_server)
476 return;
477
0eac4623
LP
478 /* Change to the next one, but make sure to follow the linked
479 * list only if the server is still linked. */
480 if (m->current_dns_server->linked && m->current_dns_server->servers_next) {
f2f1dbe5
LP
481 manager_set_dns_server(m, m->current_dns_server->servers_next);
482 return;
483 }
484
485 /* If there was no next one, then start from the beginning of
486 * the list */
487 if (m->current_dns_server->type == DNS_SERVER_FALLBACK)
488 manager_set_dns_server(m, m->fallback_dns_servers);
489 else
490 manager_set_dns_server(m, m->dns_servers);
491}
be808ea0
TG
492
493static const char* const dns_server_feature_level_table[_DNS_SERVER_FEATURE_LEVEL_MAX] = {
494 [DNS_SERVER_FEATURE_LEVEL_TCP] = "TCP",
495 [DNS_SERVER_FEATURE_LEVEL_UDP] = "UDP",
9c5e12a4 496 [DNS_SERVER_FEATURE_LEVEL_EDNS0] = "UDP+EDNS0",
7586f4d1 497 [DNS_SERVER_FEATURE_LEVEL_DO] = "UDP+EDNS0+DO",
d74fb368 498 [DNS_SERVER_FEATURE_LEVEL_LARGE] = "UDP+EDNS0+DO+LARGE",
be808ea0
TG
499};
500DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level, DnsServerFeatureLevel);