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