]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-link.c
resolved: make sure DNS configuration pushed in by the user stays around on restarts
[thirdparty/systemd.git] / src / resolve / resolved-link.c
CommitLineData
74b2466e
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2014 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <net/if.h>
21
22#include "sd-network.h"
07630cea 23
b5efdb8a 24#include "alloc-util.h"
943ef07c
LP
25#include "fd-util.h"
26#include "fileio.h"
ec2c5e43 27#include "missing.h"
943ef07c 28#include "mkdir.h"
6bedfcbb 29#include "parse-util.h"
74b2466e 30#include "resolved-link.h"
07630cea
LP
31#include "string-util.h"
32#include "strv.h"
74b2466e
LP
33
34int link_new(Manager *m, Link **ret, int ifindex) {
35 _cleanup_(link_freep) Link *l = NULL;
36 int r;
37
38 assert(m);
39 assert(ifindex > 0);
40
d5099efc 41 r = hashmap_ensure_allocated(&m->links, NULL);
74b2466e
LP
42 if (r < 0)
43 return r;
44
45 l = new0(Link, 1);
46 if (!l)
47 return -ENOMEM;
48
49 l->ifindex = ifindex;
af49ca27 50 l->llmnr_support = RESOLVE_SUPPORT_YES;
ad6c0475
LP
51 l->mdns_support = RESOLVE_SUPPORT_NO;
52 l->dnssec_mode = _DNSSEC_MODE_INVALID;
6955a3ba 53 l->operstate = IF_OPER_UNKNOWN;
74b2466e 54
943ef07c
LP
55 if (asprintf(&l->state_file, "/run/systemd/resolve/netif/%i", ifindex) < 0)
56 return -ENOMEM;
57
74b2466e
LP
58 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
59 if (r < 0)
60 return r;
61
62 l->manager = m;
63
64 if (ret)
65 *ret = l;
66 l = NULL;
67
68 return 0;
69}
70
97e5d693
LP
71void link_flush_settings(Link *l) {
72 assert(l);
73
74 l->llmnr_support = RESOLVE_SUPPORT_YES;
75 l->mdns_support = RESOLVE_SUPPORT_NO;
76 l->dnssec_mode = _DNSSEC_MODE_INVALID;
77
78 dns_server_unlink_all(l->dns_servers);
79 dns_search_domain_unlink_all(l->search_domains);
80
81 l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors);
82}
83
74b2466e 84Link *link_free(Link *l) {
74b2466e
LP
85 if (!l)
86 return NULL;
87
97e5d693 88 link_flush_settings(l);
0eac4623 89
74b2466e 90 while (l->addresses)
97e5d693 91 (void) link_address_free(l->addresses);
74b2466e
LP
92
93 if (l->manager)
94 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
95
96 dns_scope_free(l->unicast_scope);
1716f6dc
LP
97 dns_scope_free(l->llmnr_ipv4_scope);
98 dns_scope_free(l->llmnr_ipv6_scope);
b4f1862d
DM
99 dns_scope_free(l->mdns_ipv4_scope);
100 dns_scope_free(l->mdns_ipv6_scope);
74b2466e 101
943ef07c
LP
102 free(l->state_file);
103
74b2466e
LP
104 free(l);
105 return NULL;
1716f6dc
LP
106}
107
97e5d693 108void link_allocate_scopes(Link *l) {
1716f6dc
LP
109 int r;
110
111 assert(l);
112
dfc1091b
LP
113 if (link_relevant(l, AF_UNSPEC, false) &&
114 l->dns_servers) {
1716f6dc
LP
115 if (!l->unicast_scope) {
116 r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
117 if (r < 0)
da927ba9 118 log_warning_errno(r, "Failed to allocate DNS scope: %m");
1716f6dc
LP
119 }
120 } else
121 l->unicast_scope = dns_scope_free(l->unicast_scope);
122
dfc1091b 123 if (link_relevant(l, AF_INET, true) &&
af49ca27
LP
124 l->llmnr_support != RESOLVE_SUPPORT_NO &&
125 l->manager->llmnr_support != RESOLVE_SUPPORT_NO) {
1716f6dc
LP
126 if (!l->llmnr_ipv4_scope) {
127 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
128 if (r < 0)
da927ba9 129 log_warning_errno(r, "Failed to allocate LLMNR IPv4 scope: %m");
1716f6dc
LP
130 }
131 } else
132 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
133
dfc1091b 134 if (link_relevant(l, AF_INET6, true) &&
af49ca27
LP
135 l->llmnr_support != RESOLVE_SUPPORT_NO &&
136 l->manager->llmnr_support != RESOLVE_SUPPORT_NO &&
db97a66a 137 socket_ipv6_is_supported()) {
1716f6dc
LP
138 if (!l->llmnr_ipv6_scope) {
139 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
140 if (r < 0)
da927ba9 141 log_warning_errno(r, "Failed to allocate LLMNR IPv6 scope: %m");
1716f6dc
LP
142 }
143 } else
144 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
b4f1862d 145
dfc1091b 146 if (link_relevant(l, AF_INET, true) &&
af49ca27
LP
147 l->mdns_support != RESOLVE_SUPPORT_NO &&
148 l->manager->mdns_support != RESOLVE_SUPPORT_NO) {
b4f1862d
DM
149 if (!l->mdns_ipv4_scope) {
150 r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET);
151 if (r < 0)
152 log_warning_errno(r, "Failed to allocate mDNS IPv4 scope: %m");
153 }
154 } else
155 l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope);
156
dfc1091b 157 if (link_relevant(l, AF_INET6, true) &&
af49ca27
LP
158 l->mdns_support != RESOLVE_SUPPORT_NO &&
159 l->manager->mdns_support != RESOLVE_SUPPORT_NO) {
b4f1862d
DM
160 if (!l->mdns_ipv6_scope) {
161 r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6);
162 if (r < 0)
163 log_warning_errno(r, "Failed to allocate mDNS IPv6 scope: %m");
164 }
165 } else
166 l->mdns_ipv6_scope = dns_scope_free(l->mdns_ipv6_scope);
1716f6dc 167}
74b2466e 168
ec2c5e43 169void link_add_rrs(Link *l, bool force_remove) {
623a4c97
LP
170 LinkAddress *a;
171
172 LIST_FOREACH(addresses, a, l->addresses)
ec2c5e43 173 link_address_add_rrs(a, force_remove);
623a4c97
LP
174}
175
943ef07c 176int link_process_rtnl(Link *l, sd_netlink_message *m) {
1716f6dc 177 const char *n = NULL;
74b2466e
LP
178 int r;
179
180 assert(l);
181 assert(m);
182
183 r = sd_rtnl_message_link_get_flags(m, &l->flags);
184 if (r < 0)
185 return r;
186
6955a3ba
LP
187 (void) sd_netlink_message_read_u32(m, IFLA_MTU, &l->mtu);
188 (void) sd_netlink_message_read_u8(m, IFLA_OPERSTATE, &l->operstate);
1716f6dc 189
1c4baffc 190 if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
cc7844e7 191 strncpy(l->name, n, sizeof(l->name)-1);
1716f6dc
LP
192 char_array_0(l->name);
193 }
194
195 link_allocate_scopes(l);
ec2c5e43 196 link_add_rrs(l, false);
623a4c97 197
74b2466e
LP
198 return 0;
199}
200
55e99f20
LP
201static int link_update_dns_server_one(Link *l, const char *name) {
202 union in_addr_union a;
203 DnsServer *s;
204 int family, r;
205
206 assert(l);
207 assert(name);
208
209 r = in_addr_from_string_auto(name, &family, &a);
210 if (r < 0)
211 return r;
212
213 s = dns_server_find(l->dns_servers, family, &a, 0);
214 if (s) {
215 dns_server_move_back_and_unmark(s);
216 return 0;
217 }
218
219 return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0);
220}
221
6073b6f2 222static int link_update_dns_servers(Link *l) {
6f4dedb2
TG
223 _cleanup_strv_free_ char **nameservers = NULL;
224 char **nameserver;
6f4dedb2 225 int r;
74b2466e
LP
226
227 assert(l);
228
d6731e4c 229 r = sd_network_link_get_dns(l->ifindex, &nameservers);
1ade96e9
LP
230 if (r == -ENODATA) {
231 r = 0;
232 goto clear;
233 }
6f4dedb2 234 if (r < 0)
74b2466e 235 goto clear;
74b2466e 236
4b95f179 237 dns_server_mark_all(l->dns_servers);
5cb36f41 238
6f4dedb2 239 STRV_FOREACH(nameserver, nameservers) {
55e99f20 240 r = link_update_dns_server_one(l, *nameserver);
6f4dedb2
TG
241 if (r < 0)
242 goto clear;
74b2466e
LP
243 }
244
4b95f179 245 dns_server_unlink_marked(l->dns_servers);
74b2466e
LP
246 return 0;
247
248clear:
4b95f179 249 dns_server_unlink_all(l->dns_servers);
74b2466e
LP
250 return r;
251}
252
19b50b5b
LP
253static int link_update_llmnr_support(Link *l) {
254 _cleanup_free_ char *b = NULL;
255 int r;
256
257 assert(l);
258
d6731e4c 259 r = sd_network_link_get_llmnr(l->ifindex, &b);
1ade96e9
LP
260 if (r == -ENODATA) {
261 r = 0;
262 goto clear;
263 }
19b50b5b
LP
264 if (r < 0)
265 goto clear;
266
af49ca27
LP
267 l->llmnr_support = resolve_support_from_string(b);
268 if (l->llmnr_support < 0) {
269 r = -EINVAL;
270 goto clear;
271 }
19b50b5b
LP
272
273 return 0;
274
275clear:
af49ca27 276 l->llmnr_support = RESOLVE_SUPPORT_YES;
19b50b5b
LP
277 return r;
278}
279
aaa297d4
LP
280static int link_update_mdns_support(Link *l) {
281 _cleanup_free_ char *b = NULL;
282 int r;
283
284 assert(l);
285
286 r = sd_network_link_get_mdns(l->ifindex, &b);
287 if (r == -ENODATA) {
288 r = 0;
289 goto clear;
290 }
291 if (r < 0)
292 goto clear;
293
294 l->mdns_support = resolve_support_from_string(b);
295 if (l->mdns_support < 0) {
296 r = -EINVAL;
297 goto clear;
298 }
299
300 return 0;
301
302clear:
303 l->mdns_support = RESOLVE_SUPPORT_NO;
304 return r;
305}
306
97e5d693
LP
307void link_set_dnssec_mode(Link *l, DnssecMode mode) {
308
309 assert(l);
310
311 if (l->dnssec_mode == mode)
312 return;
313
314 if ((l->dnssec_mode == _DNSSEC_MODE_INVALID) ||
315 (l->dnssec_mode == DNSSEC_NO && mode != DNSSEC_NO) ||
316 (l->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE && mode == DNSSEC_YES)) {
317
318 /* When switching from non-DNSSEC mode to DNSSEC mode, flush the cache. Also when switching from the
319 * allow-downgrade mode to full DNSSEC mode, flush it too. */
320 if (l->unicast_scope)
321 dns_cache_flush(&l->unicast_scope->cache);
322 }
323
324 l->dnssec_mode = mode;
325}
326
ad6c0475
LP
327static int link_update_dnssec_mode(Link *l) {
328 _cleanup_free_ char *m = NULL;
2e1bab34 329 DnssecMode mode;
ad6c0475
LP
330 int r;
331
332 assert(l);
333
334 r = sd_network_link_get_dnssec(l->ifindex, &m);
335 if (r == -ENODATA) {
336 r = 0;
337 goto clear;
338 }
339 if (r < 0)
340 goto clear;
341
2e1bab34
LP
342 mode = dnssec_mode_from_string(m);
343 if (mode < 0) {
ad6c0475
LP
344 r = -EINVAL;
345 goto clear;
346 }
347
97e5d693 348 link_set_dnssec_mode(l, mode);
2e1bab34 349
ad6c0475
LP
350 return 0;
351
352clear:
353 l->dnssec_mode = _DNSSEC_MODE_INVALID;
354 return r;
355}
356
8a516214
LP
357static int link_update_dnssec_negative_trust_anchors(Link *l) {
358 _cleanup_strv_free_ char **ntas = NULL;
359 _cleanup_set_free_free_ Set *ns = NULL;
8a516214
LP
360 int r;
361
362 assert(l);
363
364 r = sd_network_link_get_dnssec_negative_trust_anchors(l->ifindex, &ntas);
365 if (r == -ENODATA) {
366 r = 0;
367 goto clear;
368 }
369 if (r < 0)
370 goto clear;
371
372 ns = set_new(&dns_name_hash_ops);
373 if (!ns)
374 return -ENOMEM;
375
39f259e0
LP
376 r = set_put_strdupv(ns, ntas);
377 if (r < 0)
378 return r;
8a516214
LP
379
380 set_free_free(l->dnssec_negative_trust_anchors);
381 l->dnssec_negative_trust_anchors = ns;
382 ns = NULL;
383
384 return 0;
385
386clear:
387 l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors);
388 return r;
389}
390
ad44b56b
LP
391static int link_update_search_domain_one(Link *l, const char *name, bool route_only) {
392 DnsSearchDomain *d;
393 int r;
394
39f259e0
LP
395 assert(l);
396 assert(name);
397
ad44b56b
LP
398 r = dns_search_domain_find(l->search_domains, name, &d);
399 if (r < 0)
400 return r;
401 if (r > 0)
402 dns_search_domain_move_back_and_unmark(d);
403 else {
404 r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
405 if (r < 0)
406 return r;
407 }
408
409 d->route_only = route_only;
410 return 0;
411}
412
a51c1048 413static int link_update_search_domains(Link *l) {
ad44b56b 414 _cleanup_strv_free_ char **sdomains = NULL, **rdomains = NULL;
a51c1048 415 char **i;
ad44b56b 416 int r, q;
bda2c408 417
a51c1048 418 assert(l);
bda2c408 419
ad44b56b
LP
420 r = sd_network_link_get_search_domains(l->ifindex, &sdomains);
421 if (r < 0 && r != -ENODATA)
422 goto clear;
423
424 q = sd_network_link_get_route_domains(l->ifindex, &rdomains);
425 if (q < 0 && q != -ENODATA) {
426 r = q;
427 goto clear;
428 }
429
430 if (r == -ENODATA && q == -ENODATA) {
1ade96e9
LP
431 /* networkd knows nothing about this interface, and that's fine. */
432 r = 0;
433 goto clear;
434 }
a51c1048
LP
435
436 dns_search_domain_mark_all(l->search_domains);
437
ad44b56b
LP
438 STRV_FOREACH(i, sdomains) {
439 r = link_update_search_domain_one(l, *i, false);
a51c1048
LP
440 if (r < 0)
441 goto clear;
ad44b56b 442 }
a51c1048 443
ad44b56b
LP
444 STRV_FOREACH(i, rdomains) {
445 r = link_update_search_domain_one(l, *i, true);
446 if (r < 0)
447 goto clear;
a51c1048
LP
448 }
449
450 dns_search_domain_unlink_marked(l->search_domains);
bda2c408 451 return 0;
a51c1048
LP
452
453clear:
454 dns_search_domain_unlink_all(l->search_domains);
455 return r;
bda2c408
TG
456}
457
b6274a0e 458static int link_is_managed(Link *l) {
97e5d693 459 _cleanup_free_ char *state = NULL;
a51c1048
LP
460 int r;
461
74b2466e
LP
462 assert(l);
463
97e5d693
LP
464 r = sd_network_link_get_setup_state(l->ifindex, &state);
465 if (r == -ENODATA)
b6274a0e 466 return 0;
97e5d693
LP
467 if (r < 0)
468 return r;
469
b6274a0e 470 return !STR_IN_SET(state, "pending", "unmanaged");
97e5d693
LP
471}
472
473static void link_read_settings(Link *l) {
474 int r;
475
476 assert(l);
477
478 /* Read settings from networkd, except when networkd is not managing this interface. */
479
b6274a0e 480 r = link_is_managed(l);
97e5d693
LP
481 if (r < 0) {
482 log_warning_errno(r, "Failed to determine whether interface %s is managed: %m", l->name);
483 return;
484 }
b6274a0e 485 if (r == 0) {
97e5d693 486
ccddd104 487 /* If this link used to be managed, but is now unmanaged, flush all our settings — but only once. */
97e5d693
LP
488 if (l->is_managed)
489 link_flush_settings(l);
490
491 l->is_managed = false;
492 return;
493 }
494
495 l->is_managed = true;
496
125ae29d
LP
497 r = link_update_dns_servers(l);
498 if (r < 0)
499 log_warning_errno(r, "Failed to read DNS servers for interface %s, ignoring: %m", l->name);
500
501 r = link_update_llmnr_support(l);
502 if (r < 0)
503 log_warning_errno(r, "Failed to read LLMNR support for interface %s, ignoring: %m", l->name);
504
505 r = link_update_mdns_support(l);
506 if (r < 0)
507 log_warning_errno(r, "Failed to read mDNS support for interface %s, ignoring: %m", l->name);
508
ad6c0475
LP
509 r = link_update_dnssec_mode(l);
510 if (r < 0)
511 log_warning_errno(r, "Failed to read DNSSEC mode for interface %s, ignoring: %m", l->name);
a51c1048 512
8a516214
LP
513 r = link_update_dnssec_negative_trust_anchors(l);
514 if (r < 0)
515 log_warning_errno(r, "Failed to read DNSSEC negative trust anchors for interface %s, ignoring: %m", l->name);
516
a51c1048
LP
517 r = link_update_search_domains(l);
518 if (r < 0)
519 log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name);
97e5d693
LP
520}
521
943ef07c 522int link_update(Link *l) {
97e5d693 523 assert(l);
a51c1048 524
97e5d693 525 link_read_settings(l);
943ef07c 526 link_load_user(l);
ad6c0475 527 link_allocate_scopes(l);
ec2c5e43 528 link_add_rrs(l, false);
74b2466e
LP
529
530 return 0;
531}
532
011696f7 533bool link_relevant(Link *l, int family, bool local_multicast) {
1716f6dc 534 _cleanup_free_ char *state = NULL;
74b2466e
LP
535 LinkAddress *a;
536
537 assert(l);
538
011696f7
LP
539 /* A link is relevant for local multicast traffic if it isn't a loopback or pointopoint device, has a link
540 * beat, can do multicast and has at least one link-local (or better) IP address.
541 *
542 * A link is relevant for non-multicast traffic if it isn't a loopback device, has a link beat, and has at
543 * least one routable address.*/
ec2c5e43 544
dfc1091b 545 if (l->flags & (IFF_LOOPBACK|IFF_DORMANT))
ec2c5e43 546 return false;
74b2466e 547
dfc1091b 548 if ((l->flags & (IFF_UP|IFF_LOWER_UP)) != (IFF_UP|IFF_LOWER_UP))
74b2466e
LP
549 return false;
550
011696f7 551 if (local_multicast) {
dfc1091b
LP
552 if (l->flags & IFF_POINTOPOINT)
553 return false;
554
555 if ((l->flags & IFF_MULTICAST) != IFF_MULTICAST)
556 return false;
557 }
558
6955a3ba
LP
559 /* Check kernel operstate
560 * https://www.kernel.org/doc/Documentation/networking/operstates.txt */
561 if (!IN_SET(l->operstate, IF_OPER_UNKNOWN, IF_OPER_UP))
562 return false;
563
564 (void) sd_network_link_get_operational_state(l->ifindex, &state);
1716f6dc 565 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
74b2466e
LP
566 return false;
567
568 LIST_FOREACH(addresses, a, l->addresses)
011696f7 569 if ((family == AF_UNSPEC || a->family == family) && link_address_relevant(a, local_multicast))
74b2466e
LP
570 return true;
571
572 return false;
573}
574
623a4c97 575LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
74b2466e
LP
576 LinkAddress *a;
577
578 assert(l);
579
1716f6dc
LP
580 LIST_FOREACH(addresses, a, l->addresses)
581 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
74b2466e 582 return a;
74b2466e
LP
583
584 return NULL;
585}
586
2c27fbca 587DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
4e945a6f
LP
588 assert(l);
589
590 if (l->current_dns_server == s)
591 return s;
592
6cb08a89
LP
593 if (s)
594 log_info("Switching to DNS server %s for interface %s.", dns_server_string(s), l->name);
4e945a6f 595
0eac4623
LP
596 dns_server_unref(l->current_dns_server);
597 l->current_dns_server = dns_server_ref(s);
2c27fbca
LP
598
599 if (l->unicast_scope)
600 dns_cache_flush(&l->unicast_scope->cache);
601
4e945a6f
LP
602 return s;
603}
604
74b2466e
LP
605DnsServer *link_get_dns_server(Link *l) {
606 assert(l);
607
608 if (!l->current_dns_server)
4e945a6f 609 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
610
611 return l->current_dns_server;
612}
613
614void link_next_dns_server(Link *l) {
615 assert(l);
616
74b2466e
LP
617 if (!l->current_dns_server)
618 return;
619
0eac4623
LP
620 /* Change to the next one, but make sure to follow the linked
621 * list only if this server is actually still linked. */
622 if (l->current_dns_server->linked && l->current_dns_server->servers_next) {
4e945a6f 623 link_set_dns_server(l, l->current_dns_server->servers_next);
74b2466e
LP
624 return;
625 }
626
4e945a6f 627 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
628}
629
c69fa7e3
LP
630DnssecMode link_get_dnssec_mode(Link *l) {
631 assert(l);
632
633 if (l->dnssec_mode != _DNSSEC_MODE_INVALID)
634 return l->dnssec_mode;
635
636 return manager_get_dnssec_mode(l->manager);
637}
638
639bool link_dnssec_supported(Link *l) {
640 DnsServer *server;
641
642 assert(l);
643
644 if (link_get_dnssec_mode(l) == DNSSEC_NO)
645 return false;
646
647 server = link_get_dns_server(l);
648 if (server)
649 return dns_server_dnssec_supported(server);
650
651 return true;
652}
653
623a4c97 654int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
74b2466e
LP
655 LinkAddress *a;
656
657 assert(l);
658 assert(in_addr);
659
660 a = new0(LinkAddress, 1);
661 if (!a)
662 return -ENOMEM;
663
664 a->family = family;
665 a->in_addr = *in_addr;
666
667 a->link = l;
668 LIST_PREPEND(addresses, l->addresses, a);
669
670 if (ret)
671 *ret = a;
672
673 return 0;
674}
675
676LinkAddress *link_address_free(LinkAddress *a) {
677 if (!a)
678 return NULL;
679
623a4c97 680 if (a->link) {
74b2466e
LP
681 LIST_REMOVE(addresses, a->link->addresses, a);
682
623a4c97 683 if (a->llmnr_address_rr) {
623a4c97
LP
684 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
685 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
686 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
687 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
623a4c97
LP
688 }
689
690 if (a->llmnr_ptr_rr) {
691 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
692 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
693 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
694 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
623a4c97
LP
695 }
696 }
697
ec2c5e43
LP
698 dns_resource_record_unref(a->llmnr_address_rr);
699 dns_resource_record_unref(a->llmnr_ptr_rr);
700
74b2466e
LP
701 free(a);
702 return NULL;
703}
704
ec2c5e43 705void link_address_add_rrs(LinkAddress *a, bool force_remove) {
623a4c97
LP
706 int r;
707
708 assert(a);
709
ec2c5e43 710 if (a->family == AF_INET) {
623a4c97 711
4e945a6f 712 if (!force_remove &&
011696f7 713 link_address_relevant(a, true) &&
4e945a6f 714 a->link->llmnr_ipv4_scope &&
af49ca27
LP
715 a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
716 a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
4e945a6f 717
78c6a153
LP
718 if (!a->link->manager->llmnr_host_ipv4_key) {
719 a->link->manager->llmnr_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->llmnr_hostname);
720 if (!a->link->manager->llmnr_host_ipv4_key) {
ec2c5e43
LP
721 r = -ENOMEM;
722 goto fail;
723 }
623a4c97 724 }
623a4c97 725
623a4c97 726 if (!a->llmnr_address_rr) {
78c6a153 727 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv4_key);
ec2c5e43
LP
728 if (!a->llmnr_address_rr) {
729 r = -ENOMEM;
730 goto fail;
731 }
732
733 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
734 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
735 }
736
ec2c5e43 737 if (!a->llmnr_ptr_rr) {
78c6a153 738 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
ec2c5e43
LP
739 if (r < 0)
740 goto fail;
623a4c97 741
ec2c5e43
LP
742 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
743 }
623a4c97 744
ec2c5e43 745 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
623a4c97 746 if (r < 0)
da927ba9 747 log_warning_errno(r, "Failed to add A record to LLMNR zone: %m");
623a4c97 748
ec2c5e43 749 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
623a4c97 750 if (r < 0)
da927ba9 751 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
623a4c97 752 } else {
ec2c5e43
LP
753 if (a->llmnr_address_rr) {
754 if (a->link->llmnr_ipv4_scope)
755 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
756 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
757 }
758
759 if (a->llmnr_ptr_rr) {
760 if (a->link->llmnr_ipv4_scope)
761 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
762 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
763 }
623a4c97
LP
764 }
765 }
766
ec2c5e43 767 if (a->family == AF_INET6) {
623a4c97 768
4e945a6f 769 if (!force_remove &&
011696f7 770 link_address_relevant(a, true) &&
4e945a6f 771 a->link->llmnr_ipv6_scope &&
af49ca27
LP
772 a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
773 a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
4e945a6f 774
78c6a153
LP
775 if (!a->link->manager->llmnr_host_ipv6_key) {
776 a->link->manager->llmnr_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->llmnr_hostname);
777 if (!a->link->manager->llmnr_host_ipv6_key) {
ec2c5e43
LP
778 r = -ENOMEM;
779 goto fail;
780 }
623a4c97 781 }
623a4c97 782
623a4c97 783 if (!a->llmnr_address_rr) {
78c6a153 784 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv6_key);
ec2c5e43
LP
785 if (!a->llmnr_address_rr) {
786 r = -ENOMEM;
787 goto fail;
788 }
789
790 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
791 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
792 }
793
ec2c5e43 794 if (!a->llmnr_ptr_rr) {
78c6a153 795 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
ec2c5e43
LP
796 if (r < 0)
797 goto fail;
623a4c97 798
ec2c5e43
LP
799 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
800 }
623a4c97 801
ec2c5e43 802 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
623a4c97 803 if (r < 0)
da927ba9 804 log_warning_errno(r, "Failed to add AAAA record to LLMNR zone: %m");
623a4c97 805
ec2c5e43 806 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
623a4c97 807 if (r < 0)
da927ba9 808 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
623a4c97 809 } else {
ec2c5e43
LP
810 if (a->llmnr_address_rr) {
811 if (a->link->llmnr_ipv6_scope)
812 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
813 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
814 }
815
816 if (a->llmnr_ptr_rr) {
817 if (a->link->llmnr_ipv6_scope)
818 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
819 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
820 }
623a4c97
LP
821 }
822 }
823
824 return;
825
826fail:
da927ba9 827 log_debug_errno(r, "Failed to update address RRs: %m");
623a4c97
LP
828}
829
1c4baffc 830int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) {
74b2466e
LP
831 int r;
832 assert(a);
833 assert(m);
834
835 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
836 if (r < 0)
837 return r;
838
1716f6dc 839 sd_rtnl_message_addr_get_scope(m, &a->scope);
74b2466e 840
1716f6dc 841 link_allocate_scopes(a->link);
ec2c5e43 842 link_add_rrs(a->link, false);
623a4c97 843
74b2466e
LP
844 return 0;
845}
846
011696f7 847bool link_address_relevant(LinkAddress *a, bool local_multicast) {
74b2466e
LP
848 assert(a);
849
7b85d72f 850 if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))
74b2466e
LP
851 return false;
852
011696f7 853 if (a->scope >= (local_multicast ? RT_SCOPE_HOST : RT_SCOPE_LINK))
74b2466e
LP
854 return false;
855
856 return true;
857}
943ef07c
LP
858
859static bool link_needs_save(Link *l) {
860 assert(l);
861
862 /* Returns true if any of the settings where set different from the default */
863
864 if (l->is_managed)
865 return false;
866
867 if (l->llmnr_support != RESOLVE_SUPPORT_YES ||
868 l->mdns_support != RESOLVE_SUPPORT_NO ||
869 l->dnssec_mode != _DNSSEC_MODE_INVALID)
870 return true;
871
872 if (l->dns_servers ||
873 l->search_domains)
874 return true;
875
876 if (!set_isempty(l->dnssec_negative_trust_anchors))
877 return true;
878
879 return false;
880}
881
882int link_save_user(Link *l) {
883 _cleanup_free_ char *temp_path = NULL;
884 _cleanup_fclose_ FILE *f = NULL;
885 const char *v;
886 int r;
887
888 assert(l);
889 assert(l->state_file);
890
891 if (!link_needs_save(l)) {
892 (void) unlink(l->state_file);
893 return 0;
894 }
895
896 r = mkdir_parents(l->state_file, 0700);
897 if (r < 0)
898 goto fail;
899
900 r = fopen_temporary(l->state_file, &f, &temp_path);
901 if (r < 0)
902 goto fail;
903
904 fputs("# This is private data. Do not parse.\n", f);
905
906 v = resolve_support_to_string(l->llmnr_support);
907 if (v)
908 fprintf(f, "LLMNR=%s\n", v);
909
910 v = resolve_support_to_string(l->mdns_support);
911 if (v)
912 fprintf(f, "MDNS=%s\n", v);
913
914 v = dnssec_mode_to_string(l->dnssec_mode);
915 if (v)
916 fprintf(f, "DNSSEC=%s\n", v);
917
918 if (l->dns_servers) {
919 DnsServer *server;
920
921 fputs("SERVERS=", f);
922 LIST_FOREACH(servers, server, l->dns_servers) {
923
924 if (server != l->dns_servers)
925 fputc(' ', f);
926
927 v = dns_server_string(server);
928 if (!v) {
929 r = -ENOMEM;
930 goto fail;
931 }
932
933 fputs(v, f);
934 }
935 fputc('\n', f);
936 }
937
938 if (l->search_domains) {
939 DnsSearchDomain *domain;
940
941 fputs("DOMAINS=", f);
942 LIST_FOREACH(domains, domain, l->search_domains) {
943
944 if (domain != l->search_domains)
945 fputc(' ', f);
946
947 if (domain->route_only)
948 fputc('~', f);
949
950 fputs(DNS_SEARCH_DOMAIN_NAME(domain), f);
951 }
952 fputc('\n', f);
953 }
954
955 if (!set_isempty(l->dnssec_negative_trust_anchors)) {
956 bool space = false;
957 Iterator i;
958 char *nta;
959
960 fputs("NTAS=", f);
961 SET_FOREACH(nta, l->dnssec_negative_trust_anchors, i) {
962
963 if (space)
964 fputc(' ', f);
965
966 fputs(nta, f);
967 space = true;
968 }
969 fputc('\n', f);
970 }
971
972 r = fflush_and_check(f);
973 if (r < 0)
974 goto fail;
975
976 if (rename(temp_path, l->state_file) < 0) {
977 r = -errno;
978 goto fail;
979 }
980
981 return 0;
982
983fail:
984 (void) unlink(l->state_file);
985
986 if (temp_path)
987 (void) unlink(temp_path);
988
989 return log_error_errno(r, "Failed to save link data %s: %m", l->state_file);
990}
991
992int link_load_user(Link *l) {
993 _cleanup_free_ char
994 *llmnr = NULL,
995 *mdns = NULL,
996 *dnssec = NULL,
997 *servers = NULL,
998 *domains = NULL,
999 *ntas = NULL;
1000
1001 ResolveSupport s;
1002 int r;
1003
1004 assert(l);
1005 assert(l->state_file);
1006
1007 /* Try to load only a single time */
1008 if (l->loaded)
1009 return 0;
1010 l->loaded = true;
1011
1012 if (l->is_managed)
1013 return 0; /* if the device is managed, then networkd is our configuration source, not the bus API */
1014
1015 r = parse_env_file(l->state_file, NEWLINE,
1016 "LLMNR", &llmnr,
1017 "MDNS", &mdns,
1018 "DNSSEC", &dnssec,
1019 "SERVERS", &servers,
1020 "DOMAINS", &domains,
1021 "NTAS", &ntas,
1022 NULL);
1023 if (r == -ENOENT)
1024 return 0;
1025 if (r < 0)
1026 goto fail;
1027
1028 link_flush_settings(l);
1029
1030 /* If we can't recognize the LLMNR or MDNS setting we don't override the default */
1031 s = resolve_support_from_string(llmnr);
1032 if (s >= 0)
1033 l->llmnr_support = s;
1034
1035 s = resolve_support_from_string(mdns);
1036 if (s >= 0)
1037 l->mdns_support = s;
1038
1039 /* If we can't recognize the DNSSEC setting, then set it to invalid, so that the daemon default is used. */
1040 l->dnssec_mode = dnssec_mode_from_string(dnssec);
1041
1042 if (servers) {
1043 const char *p = servers;
1044
1045 for (;;) {
1046 _cleanup_free_ char *word = NULL;
1047
1048 r = extract_first_word(&p, &word, NULL, 0);
1049 if (r < 0)
1050 goto fail;
1051 if (r == 0)
1052 break;
1053
1054 r = link_update_dns_server_one(l, word);
1055 if (r < 0) {
1056 log_debug_errno(r, "Failed to load DNS server '%s', ignoring: %m", word);
1057 continue;
1058 }
1059 }
1060 }
1061
1062 if (domains) {
1063 const char *p = domains;
1064
1065 for (;;) {
1066 _cleanup_free_ char *word = NULL;
1067 const char *n;
1068 bool is_route;
1069
1070 r = extract_first_word(&p, &word, NULL, 0);
1071 if (r < 0)
1072 goto fail;
1073 if (r == 0)
1074 break;
1075
1076 is_route = word[0] == '~';
1077 n = is_route ? word + 1 : word;
1078
1079 r = link_update_search_domain_one(l, n, is_route);
1080 if (r < 0) {
1081 log_debug_errno(r, "Failed to load search domain '%s', ignoring: %m", word);
1082 continue;
1083 }
1084 }
1085 }
1086
1087 if (ntas) {
1088 _cleanup_set_free_free_ Set *ns = NULL;
1089
1090 ns = set_new(&dns_name_hash_ops);
1091 if (!ns) {
1092 r = -ENOMEM;
1093 goto fail;
1094 }
1095
1096 r = set_put_strsplit(ns, ntas, NULL, 0);
1097 if (r < 0)
1098 goto fail;
1099
1100 l->dnssec_negative_trust_anchors = ns;
1101 ns = NULL;
1102 }
1103
1104 return 0;
1105
1106fail:
1107 return log_error_errno(r, "Failed to load link data %s: %m", l->state_file);
1108}
1109
1110void link_remove_user(Link *l) {
1111 assert(l);
1112 assert(l->state_file);
1113
1114 (void) unlink(l->state_file);
1115}