]>
Commit | Line | Data |
---|---|---|
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 |
40 | int 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 | 118 | DnsServer* 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 | 128 | DnsServer* 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 |
142 | void 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 |
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 | ||
f4461e56 | 227 | void 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 | 260 | void 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 | 273 | void 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 |
291 | void 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 |
302 | static 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 | 321 | DnsServerFeatureLevel 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 |
363 | int 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 | 391 | static 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 | 400 | static 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 | |
411 | const struct hash_ops dns_server_hash_ops = { | |
412 | .hash = dns_server_hash_func, | |
413 | .compare = dns_server_compare_func | |
414 | }; | |
636e813d | 415 | |
4b95f179 LP |
416 | void 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 |
428 | void 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 |
442 | void 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 |
450 | DnsServer *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 | 460 | DnsServer *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 | ||
476 | DnsServer *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 | ||
498 | DnsServer *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 | ||
530 | void 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 | |
553 | static 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 | }; |
560 | DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level, DnsServerFeatureLevel); |