]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-link.c
resolved: introduce support for per-interface negative trust anchors
[thirdparty/systemd.git] / src / resolve / resolved-link.c
CommitLineData
74b2466e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <net/if.h>
23
24#include "sd-network.h"
07630cea 25
b5efdb8a 26#include "alloc-util.h"
ec2c5e43 27#include "missing.h"
6bedfcbb 28#include "parse-util.h"
74b2466e 29#include "resolved-link.h"
07630cea
LP
30#include "string-util.h"
31#include "strv.h"
74b2466e
LP
32
33int 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
d5099efc 40 r = hashmap_ensure_allocated(&m->links, NULL);
74b2466e
LP
41 if (r < 0)
42 return r;
43
44 l = new0(Link, 1);
45 if (!l)
46 return -ENOMEM;
47
48 l->ifindex = ifindex;
af49ca27 49 l->llmnr_support = RESOLVE_SUPPORT_YES;
ad6c0475
LP
50 l->mdns_support = RESOLVE_SUPPORT_NO;
51 l->dnssec_mode = _DNSSEC_MODE_INVALID;
74b2466e
LP
52
53 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
54 if (r < 0)
55 return r;
56
57 l->manager = m;
58
59 if (ret)
60 *ret = l;
61 l = NULL;
62
63 return 0;
64}
65
66Link *link_free(Link *l) {
74b2466e
LP
67 if (!l)
68 return NULL;
69
00f0a16a 70 dns_server_unlink_all(l->dns_servers);
a51c1048 71 dns_search_domain_unlink_all(l->search_domains);
0eac4623 72
74b2466e
LP
73 while (l->addresses)
74 link_address_free(l->addresses);
75
76 if (l->manager)
77 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
78
79 dns_scope_free(l->unicast_scope);
1716f6dc
LP
80 dns_scope_free(l->llmnr_ipv4_scope);
81 dns_scope_free(l->llmnr_ipv6_scope);
b4f1862d
DM
82 dns_scope_free(l->mdns_ipv4_scope);
83 dns_scope_free(l->mdns_ipv6_scope);
74b2466e 84
8a516214
LP
85 set_free_free(l->dnssec_negative_trust_anchors);
86
74b2466e
LP
87 free(l);
88 return NULL;
1716f6dc
LP
89}
90
91static void link_allocate_scopes(Link *l) {
92 int r;
93
94 assert(l);
95
6073b6f2 96 if (l->dns_servers) {
1716f6dc
LP
97 if (!l->unicast_scope) {
98 r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
99 if (r < 0)
da927ba9 100 log_warning_errno(r, "Failed to allocate DNS scope: %m");
1716f6dc
LP
101 }
102 } else
103 l->unicast_scope = dns_scope_free(l->unicast_scope);
104
90ab5042 105 if (link_relevant(l, AF_INET) &&
af49ca27
LP
106 l->llmnr_support != RESOLVE_SUPPORT_NO &&
107 l->manager->llmnr_support != RESOLVE_SUPPORT_NO) {
1716f6dc
LP
108 if (!l->llmnr_ipv4_scope) {
109 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
110 if (r < 0)
da927ba9 111 log_warning_errno(r, "Failed to allocate LLMNR IPv4 scope: %m");
1716f6dc
LP
112 }
113 } else
114 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
115
90ab5042 116 if (link_relevant(l, AF_INET6) &&
af49ca27
LP
117 l->llmnr_support != RESOLVE_SUPPORT_NO &&
118 l->manager->llmnr_support != RESOLVE_SUPPORT_NO &&
db97a66a 119 socket_ipv6_is_supported()) {
1716f6dc
LP
120 if (!l->llmnr_ipv6_scope) {
121 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
122 if (r < 0)
da927ba9 123 log_warning_errno(r, "Failed to allocate LLMNR IPv6 scope: %m");
1716f6dc
LP
124 }
125 } else
126 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
b4f1862d
DM
127
128 if (link_relevant(l, AF_INET) &&
af49ca27
LP
129 l->mdns_support != RESOLVE_SUPPORT_NO &&
130 l->manager->mdns_support != RESOLVE_SUPPORT_NO) {
b4f1862d
DM
131 if (!l->mdns_ipv4_scope) {
132 r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET);
133 if (r < 0)
134 log_warning_errno(r, "Failed to allocate mDNS IPv4 scope: %m");
135 }
136 } else
137 l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope);
138
139 if (link_relevant(l, AF_INET6) &&
af49ca27
LP
140 l->mdns_support != RESOLVE_SUPPORT_NO &&
141 l->manager->mdns_support != RESOLVE_SUPPORT_NO) {
b4f1862d
DM
142 if (!l->mdns_ipv6_scope) {
143 r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6);
144 if (r < 0)
145 log_warning_errno(r, "Failed to allocate mDNS IPv6 scope: %m");
146 }
147 } else
148 l->mdns_ipv6_scope = dns_scope_free(l->mdns_ipv6_scope);
1716f6dc 149}
74b2466e 150
ec2c5e43 151void link_add_rrs(Link *l, bool force_remove) {
623a4c97
LP
152 LinkAddress *a;
153
154 LIST_FOREACH(addresses, a, l->addresses)
ec2c5e43 155 link_address_add_rrs(a, force_remove);
623a4c97
LP
156}
157
1c4baffc 158int link_update_rtnl(Link *l, sd_netlink_message *m) {
1716f6dc 159 const char *n = NULL;
74b2466e
LP
160 int r;
161
162 assert(l);
163 assert(m);
164
165 r = sd_rtnl_message_link_get_flags(m, &l->flags);
166 if (r < 0)
167 return r;
168
1c4baffc 169 sd_netlink_message_read_u32(m, IFLA_MTU, &l->mtu);
1716f6dc 170
1c4baffc 171 if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
cc7844e7 172 strncpy(l->name, n, sizeof(l->name)-1);
1716f6dc
LP
173 char_array_0(l->name);
174 }
175
176 link_allocate_scopes(l);
ec2c5e43 177 link_add_rrs(l, false);
623a4c97 178
74b2466e
LP
179 return 0;
180}
181
6073b6f2 182static int link_update_dns_servers(Link *l) {
6f4dedb2
TG
183 _cleanup_strv_free_ char **nameservers = NULL;
184 char **nameserver;
6f4dedb2 185 int r;
74b2466e
LP
186
187 assert(l);
188
d6731e4c 189 r = sd_network_link_get_dns(l->ifindex, &nameservers);
1ade96e9
LP
190 if (r == -ENODATA) {
191 r = 0;
192 goto clear;
193 }
6f4dedb2 194 if (r < 0)
74b2466e 195 goto clear;
74b2466e 196
4b95f179 197 dns_server_mark_all(l->dns_servers);
5cb36f41 198
6f4dedb2
TG
199 STRV_FOREACH(nameserver, nameservers) {
200 union in_addr_union a;
0eac4623 201 DnsServer *s;
6f4dedb2 202 int family;
74b2466e 203
6f4dedb2
TG
204 r = in_addr_from_string_auto(*nameserver, &family, &a);
205 if (r < 0)
206 goto clear;
74b2466e 207
4b95f179 208 s = dns_server_find(l->dns_servers, family, &a);
74b2466e 209 if (s)
0b58db65 210 dns_server_move_back_and_unmark(s);
74b2466e 211 else {
4e945a6f 212 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
74b2466e
LP
213 if (r < 0)
214 goto clear;
215 }
216 }
217
4b95f179 218 dns_server_unlink_marked(l->dns_servers);
74b2466e
LP
219 return 0;
220
221clear:
4b95f179 222 dns_server_unlink_all(l->dns_servers);
74b2466e
LP
223 return r;
224}
225
19b50b5b
LP
226static int link_update_llmnr_support(Link *l) {
227 _cleanup_free_ char *b = NULL;
228 int r;
229
230 assert(l);
231
d6731e4c 232 r = sd_network_link_get_llmnr(l->ifindex, &b);
1ade96e9
LP
233 if (r == -ENODATA) {
234 r = 0;
235 goto clear;
236 }
19b50b5b
LP
237 if (r < 0)
238 goto clear;
239
af49ca27
LP
240 l->llmnr_support = resolve_support_from_string(b);
241 if (l->llmnr_support < 0) {
242 r = -EINVAL;
243 goto clear;
244 }
19b50b5b
LP
245
246 return 0;
247
248clear:
af49ca27 249 l->llmnr_support = RESOLVE_SUPPORT_YES;
19b50b5b
LP
250 return r;
251}
252
aaa297d4
LP
253static int link_update_mdns_support(Link *l) {
254 _cleanup_free_ char *b = NULL;
255 int r;
256
257 assert(l);
258
259 r = sd_network_link_get_mdns(l->ifindex, &b);
260 if (r == -ENODATA) {
261 r = 0;
262 goto clear;
263 }
264 if (r < 0)
265 goto clear;
266
267 l->mdns_support = resolve_support_from_string(b);
268 if (l->mdns_support < 0) {
269 r = -EINVAL;
270 goto clear;
271 }
272
273 return 0;
274
275clear:
276 l->mdns_support = RESOLVE_SUPPORT_NO;
277 return r;
278}
279
ad6c0475
LP
280static int link_update_dnssec_mode(Link *l) {
281 _cleanup_free_ char *m = NULL;
282 int r;
283
284 assert(l);
285
286 r = sd_network_link_get_dnssec(l->ifindex, &m);
287 if (r == -ENODATA) {
288 r = 0;
289 goto clear;
290 }
291 if (r < 0)
292 goto clear;
293
294 l->dnssec_mode = dnssec_mode_from_string(m);
295 if (l->dnssec_mode < 0) {
296 r = -EINVAL;
297 goto clear;
298 }
299
300 return 0;
301
302clear:
303 l->dnssec_mode = _DNSSEC_MODE_INVALID;
304 return r;
305}
306
8a516214
LP
307static int link_update_dnssec_negative_trust_anchors(Link *l) {
308 _cleanup_strv_free_ char **ntas = NULL;
309 _cleanup_set_free_free_ Set *ns = NULL;
310 char **i;
311 int r;
312
313 assert(l);
314
315 r = sd_network_link_get_dnssec_negative_trust_anchors(l->ifindex, &ntas);
316 if (r == -ENODATA) {
317 r = 0;
318 goto clear;
319 }
320 if (r < 0)
321 goto clear;
322
323 ns = set_new(&dns_name_hash_ops);
324 if (!ns)
325 return -ENOMEM;
326
327 STRV_FOREACH(i, ntas) {
328 r = set_put_strdup(ns, *i);
329 if (r < 0)
330 return r;
331 }
332
333 set_free_free(l->dnssec_negative_trust_anchors);
334 l->dnssec_negative_trust_anchors = ns;
335 ns = NULL;
336
337 return 0;
338
339clear:
340 l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors);
341 return r;
342}
343
a51c1048
LP
344static int link_update_search_domains(Link *l) {
345 _cleanup_strv_free_ char **domains = NULL;
346 char **i;
bda2c408
TG
347 int r;
348
a51c1048 349 assert(l);
bda2c408 350
a51c1048 351 r = sd_network_link_get_domains(l->ifindex, &domains);
1ade96e9
LP
352 if (r == -ENODATA) {
353 /* networkd knows nothing about this interface, and that's fine. */
354 r = 0;
355 goto clear;
356 }
bda2c408 357 if (r < 0)
a51c1048
LP
358 goto clear;
359
360 dns_search_domain_mark_all(l->search_domains);
361
362 STRV_FOREACH(i, domains) {
363 DnsSearchDomain *d;
bda2c408 364
a51c1048
LP
365 r = dns_search_domain_find(l->search_domains, *i, &d);
366 if (r < 0)
367 goto clear;
368
369 if (r > 0)
370 dns_search_domain_move_back_and_unmark(d);
371 else {
372 r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
373 if (r < 0)
374 goto clear;
375 }
376 }
377
378 dns_search_domain_unlink_marked(l->search_domains);
bda2c408 379 return 0;
a51c1048
LP
380
381clear:
382 dns_search_domain_unlink_all(l->search_domains);
383 return r;
bda2c408
TG
384}
385
74b2466e 386int link_update_monitor(Link *l) {
a51c1048
LP
387 int r;
388
74b2466e
LP
389 assert(l);
390
125ae29d
LP
391 r = link_update_dns_servers(l);
392 if (r < 0)
393 log_warning_errno(r, "Failed to read DNS servers for interface %s, ignoring: %m", l->name);
394
395 r = link_update_llmnr_support(l);
396 if (r < 0)
397 log_warning_errno(r, "Failed to read LLMNR support for interface %s, ignoring: %m", l->name);
398
399 r = link_update_mdns_support(l);
400 if (r < 0)
401 log_warning_errno(r, "Failed to read mDNS support for interface %s, ignoring: %m", l->name);
402
ad6c0475
LP
403 r = link_update_dnssec_mode(l);
404 if (r < 0)
405 log_warning_errno(r, "Failed to read DNSSEC mode for interface %s, ignoring: %m", l->name);
a51c1048 406
8a516214
LP
407 r = link_update_dnssec_negative_trust_anchors(l);
408 if (r < 0)
409 log_warning_errno(r, "Failed to read DNSSEC negative trust anchors for interface %s, ignoring: %m", l->name);
410
a51c1048
LP
411 r = link_update_search_domains(l);
412 if (r < 0)
413 log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name);
414
ad6c0475 415 link_allocate_scopes(l);
ec2c5e43 416 link_add_rrs(l, false);
74b2466e
LP
417
418 return 0;
419}
420
0dd25fb9 421bool link_relevant(Link *l, int family) {
1716f6dc 422 _cleanup_free_ char *state = NULL;
74b2466e
LP
423 LinkAddress *a;
424
425 assert(l);
426
ec2c5e43
LP
427 /* A link is relevant if it isn't a loopback or pointopoint
428 * device, has a link beat, can do multicast and has at least
429 * one relevant IP address */
430
431 if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT))
432 return false;
74b2466e 433
ec2c5e43 434 if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST))
74b2466e
LP
435 return false;
436
d6731e4c 437 sd_network_link_get_operational_state(l->ifindex, &state);
1716f6dc 438 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
74b2466e
LP
439 return false;
440
441 LIST_FOREACH(addresses, a, l->addresses)
1716f6dc 442 if (a->family == family && link_address_relevant(a))
74b2466e
LP
443 return true;
444
445 return false;
446}
447
623a4c97 448LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
74b2466e
LP
449 LinkAddress *a;
450
451 assert(l);
452
1716f6dc
LP
453 LIST_FOREACH(addresses, a, l->addresses)
454 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
74b2466e 455 return a;
74b2466e
LP
456
457 return NULL;
458}
459
2c27fbca 460DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
4e945a6f
LP
461 assert(l);
462
463 if (l->current_dns_server == s)
464 return s;
465
466 if (s) {
467 _cleanup_free_ char *ip = NULL;
468
469 in_addr_to_string(s->family, &s->address, &ip);
470 log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name);
2c27fbca 471 }
4e945a6f 472
0eac4623
LP
473 dns_server_unref(l->current_dns_server);
474 l->current_dns_server = dns_server_ref(s);
2c27fbca
LP
475
476 if (l->unicast_scope)
477 dns_cache_flush(&l->unicast_scope->cache);
478
4e945a6f
LP
479 return s;
480}
481
74b2466e
LP
482DnsServer *link_get_dns_server(Link *l) {
483 assert(l);
484
485 if (!l->current_dns_server)
4e945a6f 486 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
487
488 return l->current_dns_server;
489}
490
491void link_next_dns_server(Link *l) {
492 assert(l);
493
74b2466e
LP
494 if (!l->current_dns_server)
495 return;
496
0eac4623
LP
497 /* Change to the next one, but make sure to follow the linked
498 * list only if this server is actually still linked. */
499 if (l->current_dns_server->linked && l->current_dns_server->servers_next) {
4e945a6f 500 link_set_dns_server(l, l->current_dns_server->servers_next);
74b2466e
LP
501 return;
502 }
503
4e945a6f 504 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
505}
506
623a4c97 507int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
74b2466e
LP
508 LinkAddress *a;
509
510 assert(l);
511 assert(in_addr);
512
513 a = new0(LinkAddress, 1);
514 if (!a)
515 return -ENOMEM;
516
517 a->family = family;
518 a->in_addr = *in_addr;
519
520 a->link = l;
521 LIST_PREPEND(addresses, l->addresses, a);
522
523 if (ret)
524 *ret = a;
525
526 return 0;
527}
528
529LinkAddress *link_address_free(LinkAddress *a) {
530 if (!a)
531 return NULL;
532
623a4c97 533 if (a->link) {
74b2466e
LP
534 LIST_REMOVE(addresses, a->link->addresses, a);
535
623a4c97 536 if (a->llmnr_address_rr) {
623a4c97
LP
537 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
538 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
539 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
540 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
623a4c97
LP
541 }
542
543 if (a->llmnr_ptr_rr) {
544 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
545 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
546 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
547 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
623a4c97
LP
548 }
549 }
550
ec2c5e43
LP
551 dns_resource_record_unref(a->llmnr_address_rr);
552 dns_resource_record_unref(a->llmnr_ptr_rr);
553
74b2466e
LP
554 free(a);
555 return NULL;
556}
557
ec2c5e43 558void link_address_add_rrs(LinkAddress *a, bool force_remove) {
623a4c97
LP
559 int r;
560
561 assert(a);
562
ec2c5e43 563 if (a->family == AF_INET) {
623a4c97 564
4e945a6f
LP
565 if (!force_remove &&
566 link_address_relevant(a) &&
567 a->link->llmnr_ipv4_scope &&
af49ca27
LP
568 a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
569 a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
4e945a6f 570
78c6a153
LP
571 if (!a->link->manager->llmnr_host_ipv4_key) {
572 a->link->manager->llmnr_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->llmnr_hostname);
573 if (!a->link->manager->llmnr_host_ipv4_key) {
ec2c5e43
LP
574 r = -ENOMEM;
575 goto fail;
576 }
623a4c97 577 }
623a4c97 578
623a4c97 579 if (!a->llmnr_address_rr) {
78c6a153 580 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv4_key);
ec2c5e43
LP
581 if (!a->llmnr_address_rr) {
582 r = -ENOMEM;
583 goto fail;
584 }
585
586 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
587 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
588 }
589
ec2c5e43 590 if (!a->llmnr_ptr_rr) {
78c6a153 591 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
ec2c5e43
LP
592 if (r < 0)
593 goto fail;
623a4c97 594
ec2c5e43
LP
595 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
596 }
623a4c97 597
ec2c5e43 598 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
623a4c97 599 if (r < 0)
da927ba9 600 log_warning_errno(r, "Failed to add A record to LLMNR zone: %m");
623a4c97 601
ec2c5e43 602 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
623a4c97 603 if (r < 0)
da927ba9 604 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
623a4c97 605 } else {
ec2c5e43
LP
606 if (a->llmnr_address_rr) {
607 if (a->link->llmnr_ipv4_scope)
608 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
609 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
610 }
611
612 if (a->llmnr_ptr_rr) {
613 if (a->link->llmnr_ipv4_scope)
614 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
615 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
616 }
623a4c97
LP
617 }
618 }
619
ec2c5e43 620 if (a->family == AF_INET6) {
623a4c97 621
4e945a6f
LP
622 if (!force_remove &&
623 link_address_relevant(a) &&
624 a->link->llmnr_ipv6_scope &&
af49ca27
LP
625 a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
626 a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
4e945a6f 627
78c6a153
LP
628 if (!a->link->manager->llmnr_host_ipv6_key) {
629 a->link->manager->llmnr_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->llmnr_hostname);
630 if (!a->link->manager->llmnr_host_ipv6_key) {
ec2c5e43
LP
631 r = -ENOMEM;
632 goto fail;
633 }
623a4c97 634 }
623a4c97 635
623a4c97 636 if (!a->llmnr_address_rr) {
78c6a153 637 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv6_key);
ec2c5e43
LP
638 if (!a->llmnr_address_rr) {
639 r = -ENOMEM;
640 goto fail;
641 }
642
643 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
644 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
645 }
646
ec2c5e43 647 if (!a->llmnr_ptr_rr) {
78c6a153 648 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
ec2c5e43
LP
649 if (r < 0)
650 goto fail;
623a4c97 651
ec2c5e43
LP
652 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
653 }
623a4c97 654
ec2c5e43 655 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
623a4c97 656 if (r < 0)
da927ba9 657 log_warning_errno(r, "Failed to add AAAA record to LLMNR zone: %m");
623a4c97 658
ec2c5e43 659 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
623a4c97 660 if (r < 0)
da927ba9 661 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
623a4c97 662 } else {
ec2c5e43
LP
663 if (a->llmnr_address_rr) {
664 if (a->link->llmnr_ipv6_scope)
665 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
666 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
667 }
668
669 if (a->llmnr_ptr_rr) {
670 if (a->link->llmnr_ipv6_scope)
671 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
672 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
673 }
623a4c97
LP
674 }
675 }
676
677 return;
678
679fail:
da927ba9 680 log_debug_errno(r, "Failed to update address RRs: %m");
623a4c97
LP
681}
682
1c4baffc 683int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) {
74b2466e
LP
684 int r;
685 assert(a);
686 assert(m);
687
688 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
689 if (r < 0)
690 return r;
691
1716f6dc 692 sd_rtnl_message_addr_get_scope(m, &a->scope);
74b2466e 693
1716f6dc 694 link_allocate_scopes(a->link);
ec2c5e43 695 link_add_rrs(a->link, false);
623a4c97 696
74b2466e
LP
697 return 0;
698}
699
700bool link_address_relevant(LinkAddress *a) {
701 assert(a);
702
7b85d72f 703 if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))
74b2466e
LP
704 return false;
705
706 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
707 return false;
708
709 return true;
710}