]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-link.c
resolved: cache stringified transaction key once per transaction
[thirdparty/systemd.git] / src / resolve / resolved-link.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 <net/if.h>
23
24 #include "sd-network.h"
25
26 #include "alloc-util.h"
27 #include "missing.h"
28 #include "parse-util.h"
29 #include "resolved-link.h"
30 #include "string-util.h"
31 #include "strv.h"
32
33 int link_new(Manager *m, Link **ret, int ifindex) {
34 _cleanup_(link_freep) Link *l = NULL;
35 int r;
36
37 assert(m);
38 assert(ifindex > 0);
39
40 r = hashmap_ensure_allocated(&m->links, NULL);
41 if (r < 0)
42 return r;
43
44 l = new0(Link, 1);
45 if (!l)
46 return -ENOMEM;
47
48 l->ifindex = ifindex;
49 l->llmnr_support = SUPPORT_YES;
50
51 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
52 if (r < 0)
53 return r;
54
55 l->manager = m;
56
57 if (ret)
58 *ret = l;
59 l = NULL;
60
61 return 0;
62 }
63
64 Link *link_free(Link *l) {
65 if (!l)
66 return NULL;
67
68 dns_server_unlink_marked(l->dns_servers);
69 dns_search_domain_unlink_all(l->search_domains);
70
71 while (l->addresses)
72 link_address_free(l->addresses);
73
74 if (l->manager)
75 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
76
77 dns_scope_free(l->unicast_scope);
78 dns_scope_free(l->llmnr_ipv4_scope);
79 dns_scope_free(l->llmnr_ipv6_scope);
80 dns_scope_free(l->mdns_ipv4_scope);
81 dns_scope_free(l->mdns_ipv6_scope);
82
83 free(l);
84 return NULL;
85 }
86
87 static void link_allocate_scopes(Link *l) {
88 int r;
89
90 assert(l);
91
92 if (l->dns_servers) {
93 if (!l->unicast_scope) {
94 r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
95 if (r < 0)
96 log_warning_errno(r, "Failed to allocate DNS scope: %m");
97 }
98 } else
99 l->unicast_scope = dns_scope_free(l->unicast_scope);
100
101 if (link_relevant(l, AF_INET) &&
102 l->llmnr_support != SUPPORT_NO &&
103 l->manager->llmnr_support != SUPPORT_NO) {
104 if (!l->llmnr_ipv4_scope) {
105 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
106 if (r < 0)
107 log_warning_errno(r, "Failed to allocate LLMNR IPv4 scope: %m");
108 }
109 } else
110 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
111
112 if (link_relevant(l, AF_INET6) &&
113 l->llmnr_support != SUPPORT_NO &&
114 l->manager->llmnr_support != SUPPORT_NO &&
115 socket_ipv6_is_supported()) {
116 if (!l->llmnr_ipv6_scope) {
117 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
118 if (r < 0)
119 log_warning_errno(r, "Failed to allocate LLMNR IPv6 scope: %m");
120 }
121 } else
122 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
123
124 if (link_relevant(l, AF_INET) &&
125 l->mdns_support != SUPPORT_NO &&
126 l->manager->mdns_support != SUPPORT_NO) {
127 if (!l->mdns_ipv4_scope) {
128 r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET);
129 if (r < 0)
130 log_warning_errno(r, "Failed to allocate mDNS IPv4 scope: %m");
131 }
132 } else
133 l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope);
134
135 if (link_relevant(l, AF_INET6) &&
136 l->mdns_support != SUPPORT_NO &&
137 l->manager->mdns_support != SUPPORT_NO) {
138 if (!l->mdns_ipv6_scope) {
139 r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6);
140 if (r < 0)
141 log_warning_errno(r, "Failed to allocate mDNS IPv6 scope: %m");
142 }
143 } else
144 l->mdns_ipv6_scope = dns_scope_free(l->mdns_ipv6_scope);
145 }
146
147 void link_add_rrs(Link *l, bool force_remove) {
148 LinkAddress *a;
149
150 LIST_FOREACH(addresses, a, l->addresses)
151 link_address_add_rrs(a, force_remove);
152 }
153
154 int link_update_rtnl(Link *l, sd_netlink_message *m) {
155 const char *n = NULL;
156 int r;
157
158 assert(l);
159 assert(m);
160
161 r = sd_rtnl_message_link_get_flags(m, &l->flags);
162 if (r < 0)
163 return r;
164
165 sd_netlink_message_read_u32(m, IFLA_MTU, &l->mtu);
166
167 if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
168 strncpy(l->name, n, sizeof(l->name)-1);
169 char_array_0(l->name);
170 }
171
172 link_allocate_scopes(l);
173 link_add_rrs(l, false);
174
175 return 0;
176 }
177
178 static int link_update_dns_servers(Link *l) {
179 _cleanup_strv_free_ char **nameservers = NULL;
180 char **nameserver;
181 int r;
182
183 assert(l);
184
185 r = sd_network_link_get_dns(l->ifindex, &nameservers);
186 if (r == -ENODATA) {
187 r = 0;
188 goto clear;
189 }
190 if (r < 0)
191 goto clear;
192
193 dns_server_mark_all(l->dns_servers);
194
195 STRV_FOREACH(nameserver, nameservers) {
196 union in_addr_union a;
197 DnsServer *s;
198 int family;
199
200 r = in_addr_from_string_auto(*nameserver, &family, &a);
201 if (r < 0)
202 goto clear;
203
204 s = dns_server_find(l->dns_servers, family, &a);
205 if (s)
206 dns_server_move_back_and_unmark(s);
207 else {
208 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
209 if (r < 0)
210 goto clear;
211 }
212 }
213
214 dns_server_unlink_marked(l->dns_servers);
215 return 0;
216
217 clear:
218 dns_server_unlink_all(l->dns_servers);
219 return r;
220 }
221
222 static int link_update_llmnr_support(Link *l) {
223 _cleanup_free_ char *b = NULL;
224 int r;
225
226 assert(l);
227
228 r = sd_network_link_get_llmnr(l->ifindex, &b);
229 if (r == -ENODATA) {
230 r = 0;
231 goto clear;
232 }
233 if (r < 0)
234 goto clear;
235
236 r = parse_boolean(b);
237 if (r < 0) {
238 if (streq(b, "resolve"))
239 l->llmnr_support = SUPPORT_RESOLVE;
240 else
241 goto clear;
242
243 } else if (r > 0)
244 l->llmnr_support = SUPPORT_YES;
245 else
246 l->llmnr_support = SUPPORT_NO;
247
248 return 0;
249
250 clear:
251 l->llmnr_support = SUPPORT_YES;
252 return r;
253 }
254
255 static int link_update_search_domains(Link *l) {
256 _cleanup_strv_free_ char **domains = NULL;
257 char **i;
258 int r;
259
260 assert(l);
261
262 r = sd_network_link_get_domains(l->ifindex, &domains);
263 if (r == -ENODATA) {
264 /* networkd knows nothing about this interface, and that's fine. */
265 r = 0;
266 goto clear;
267 }
268 if (r < 0)
269 goto clear;
270
271 dns_search_domain_mark_all(l->search_domains);
272
273 STRV_FOREACH(i, domains) {
274 DnsSearchDomain *d;
275
276 r = dns_search_domain_find(l->search_domains, *i, &d);
277 if (r < 0)
278 goto clear;
279
280 if (r > 0)
281 dns_search_domain_move_back_and_unmark(d);
282 else {
283 r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
284 if (r < 0)
285 goto clear;
286 }
287 }
288
289 dns_search_domain_unlink_marked(l->search_domains);
290 return 0;
291
292 clear:
293 dns_search_domain_unlink_all(l->search_domains);
294 return r;
295 }
296
297 int link_update_monitor(Link *l) {
298 int r;
299
300 assert(l);
301
302 link_update_dns_servers(l);
303 link_update_llmnr_support(l);
304 link_allocate_scopes(l);
305
306 r = link_update_search_domains(l);
307 if (r < 0)
308 log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name);
309
310 link_add_rrs(l, false);
311
312 return 0;
313 }
314
315 bool link_relevant(Link *l, int family) {
316 _cleanup_free_ char *state = NULL;
317 LinkAddress *a;
318
319 assert(l);
320
321 /* A link is relevant if it isn't a loopback or pointopoint
322 * device, has a link beat, can do multicast and has at least
323 * one relevant IP address */
324
325 if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT))
326 return false;
327
328 if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST))
329 return false;
330
331 sd_network_link_get_operational_state(l->ifindex, &state);
332 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
333 return false;
334
335 LIST_FOREACH(addresses, a, l->addresses)
336 if (a->family == family && link_address_relevant(a))
337 return true;
338
339 return false;
340 }
341
342 LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
343 LinkAddress *a;
344
345 assert(l);
346
347 LIST_FOREACH(addresses, a, l->addresses)
348 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
349 return a;
350
351 return NULL;
352 }
353
354 DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
355 assert(l);
356
357 if (l->current_dns_server == s)
358 return s;
359
360 if (s) {
361 _cleanup_free_ char *ip = NULL;
362
363 in_addr_to_string(s->family, &s->address, &ip);
364 log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name);
365 }
366
367 dns_server_unref(l->current_dns_server);
368 l->current_dns_server = dns_server_ref(s);
369
370 if (l->unicast_scope)
371 dns_cache_flush(&l->unicast_scope->cache);
372
373 return s;
374 }
375
376 DnsServer *link_get_dns_server(Link *l) {
377 assert(l);
378
379 if (!l->current_dns_server)
380 link_set_dns_server(l, l->dns_servers);
381
382 return l->current_dns_server;
383 }
384
385 void link_next_dns_server(Link *l) {
386 assert(l);
387
388 if (!l->current_dns_server)
389 return;
390
391 /* Change to the next one, but make sure to follow the linked
392 * list only if this server is actually still linked. */
393 if (l->current_dns_server->linked && l->current_dns_server->servers_next) {
394 link_set_dns_server(l, l->current_dns_server->servers_next);
395 return;
396 }
397
398 link_set_dns_server(l, l->dns_servers);
399 }
400
401 int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
402 LinkAddress *a;
403
404 assert(l);
405 assert(in_addr);
406
407 a = new0(LinkAddress, 1);
408 if (!a)
409 return -ENOMEM;
410
411 a->family = family;
412 a->in_addr = *in_addr;
413
414 a->link = l;
415 LIST_PREPEND(addresses, l->addresses, a);
416
417 if (ret)
418 *ret = a;
419
420 return 0;
421 }
422
423 LinkAddress *link_address_free(LinkAddress *a) {
424 if (!a)
425 return NULL;
426
427 if (a->link) {
428 LIST_REMOVE(addresses, a->link->addresses, a);
429
430 if (a->llmnr_address_rr) {
431 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
432 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
433 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
434 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
435 }
436
437 if (a->llmnr_ptr_rr) {
438 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
439 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
440 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
441 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
442 }
443 }
444
445 dns_resource_record_unref(a->llmnr_address_rr);
446 dns_resource_record_unref(a->llmnr_ptr_rr);
447
448 free(a);
449 return NULL;
450 }
451
452 void link_address_add_rrs(LinkAddress *a, bool force_remove) {
453 int r;
454
455 assert(a);
456
457 if (a->family == AF_INET) {
458
459 if (!force_remove &&
460 link_address_relevant(a) &&
461 a->link->llmnr_ipv4_scope &&
462 a->link->llmnr_support == SUPPORT_YES &&
463 a->link->manager->llmnr_support == SUPPORT_YES) {
464
465 if (!a->link->manager->llmnr_host_ipv4_key) {
466 a->link->manager->llmnr_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->llmnr_hostname);
467 if (!a->link->manager->llmnr_host_ipv4_key) {
468 r = -ENOMEM;
469 goto fail;
470 }
471 }
472
473 if (!a->llmnr_address_rr) {
474 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv4_key);
475 if (!a->llmnr_address_rr) {
476 r = -ENOMEM;
477 goto fail;
478 }
479
480 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
481 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
482 }
483
484 if (!a->llmnr_ptr_rr) {
485 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
486 if (r < 0)
487 goto fail;
488
489 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
490 }
491
492 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
493 if (r < 0)
494 log_warning_errno(r, "Failed to add A record to LLMNR zone: %m");
495
496 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
497 if (r < 0)
498 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
499 } else {
500 if (a->llmnr_address_rr) {
501 if (a->link->llmnr_ipv4_scope)
502 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
503 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
504 }
505
506 if (a->llmnr_ptr_rr) {
507 if (a->link->llmnr_ipv4_scope)
508 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
509 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
510 }
511 }
512 }
513
514 if (a->family == AF_INET6) {
515
516 if (!force_remove &&
517 link_address_relevant(a) &&
518 a->link->llmnr_ipv6_scope &&
519 a->link->llmnr_support == SUPPORT_YES &&
520 a->link->manager->llmnr_support == SUPPORT_YES) {
521
522 if (!a->link->manager->llmnr_host_ipv6_key) {
523 a->link->manager->llmnr_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->llmnr_hostname);
524 if (!a->link->manager->llmnr_host_ipv6_key) {
525 r = -ENOMEM;
526 goto fail;
527 }
528 }
529
530 if (!a->llmnr_address_rr) {
531 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv6_key);
532 if (!a->llmnr_address_rr) {
533 r = -ENOMEM;
534 goto fail;
535 }
536
537 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
538 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
539 }
540
541 if (!a->llmnr_ptr_rr) {
542 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
543 if (r < 0)
544 goto fail;
545
546 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
547 }
548
549 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
550 if (r < 0)
551 log_warning_errno(r, "Failed to add AAAA record to LLMNR zone: %m");
552
553 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
554 if (r < 0)
555 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
556 } else {
557 if (a->llmnr_address_rr) {
558 if (a->link->llmnr_ipv6_scope)
559 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
560 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
561 }
562
563 if (a->llmnr_ptr_rr) {
564 if (a->link->llmnr_ipv6_scope)
565 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
566 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
567 }
568 }
569 }
570
571 return;
572
573 fail:
574 log_debug_errno(r, "Failed to update address RRs: %m");
575 }
576
577 int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) {
578 int r;
579 assert(a);
580 assert(m);
581
582 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
583 if (r < 0)
584 return r;
585
586 sd_rtnl_message_addr_get_scope(m, &a->scope);
587
588 link_allocate_scopes(a->link);
589 link_add_rrs(a->link, false);
590
591 return 0;
592 }
593
594 bool link_address_relevant(LinkAddress *a) {
595 assert(a);
596
597 if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))
598 return false;
599
600 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
601 return false;
602
603 return true;
604 }