]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-link.c
resolve-host: support --interface= as long form for -i
[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;
2e1bab34 282 DnssecMode mode;
ad6c0475
LP
283 int r;
284
285 assert(l);
286
287 r = sd_network_link_get_dnssec(l->ifindex, &m);
288 if (r == -ENODATA) {
289 r = 0;
290 goto clear;
291 }
292 if (r < 0)
293 goto clear;
294
2e1bab34
LP
295 mode = dnssec_mode_from_string(m);
296 if (mode < 0) {
ad6c0475
LP
297 r = -EINVAL;
298 goto clear;
299 }
300
2e1bab34
LP
301 if ((l->dnssec_mode == DNSSEC_NO && mode != DNSSEC_NO) ||
302 (l->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE && mode == DNSSEC_YES)) {
303
304 /* When switching from non-DNSSEC mode to DNSSEC mode, flush the cache. Also when switching from the
305 * allow-downgrade mode to full DNSSEC mode, flush it too. */
306 if (l->unicast_scope)
307 dns_cache_flush(&l->unicast_scope->cache);
308 }
309
310 l->dnssec_mode = mode;
311
ad6c0475
LP
312 return 0;
313
314clear:
315 l->dnssec_mode = _DNSSEC_MODE_INVALID;
316 return r;
317}
318
8a516214
LP
319static int link_update_dnssec_negative_trust_anchors(Link *l) {
320 _cleanup_strv_free_ char **ntas = NULL;
321 _cleanup_set_free_free_ Set *ns = NULL;
322 char **i;
323 int r;
324
325 assert(l);
326
327 r = sd_network_link_get_dnssec_negative_trust_anchors(l->ifindex, &ntas);
328 if (r == -ENODATA) {
329 r = 0;
330 goto clear;
331 }
332 if (r < 0)
333 goto clear;
334
335 ns = set_new(&dns_name_hash_ops);
336 if (!ns)
337 return -ENOMEM;
338
339 STRV_FOREACH(i, ntas) {
340 r = set_put_strdup(ns, *i);
341 if (r < 0)
342 return r;
343 }
344
345 set_free_free(l->dnssec_negative_trust_anchors);
346 l->dnssec_negative_trust_anchors = ns;
347 ns = NULL;
348
349 return 0;
350
351clear:
352 l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors);
353 return r;
354}
355
a51c1048
LP
356static int link_update_search_domains(Link *l) {
357 _cleanup_strv_free_ char **domains = NULL;
358 char **i;
bda2c408
TG
359 int r;
360
a51c1048 361 assert(l);
bda2c408 362
a51c1048 363 r = sd_network_link_get_domains(l->ifindex, &domains);
1ade96e9
LP
364 if (r == -ENODATA) {
365 /* networkd knows nothing about this interface, and that's fine. */
366 r = 0;
367 goto clear;
368 }
bda2c408 369 if (r < 0)
a51c1048
LP
370 goto clear;
371
372 dns_search_domain_mark_all(l->search_domains);
373
374 STRV_FOREACH(i, domains) {
375 DnsSearchDomain *d;
bda2c408 376
a51c1048
LP
377 r = dns_search_domain_find(l->search_domains, *i, &d);
378 if (r < 0)
379 goto clear;
380
381 if (r > 0)
382 dns_search_domain_move_back_and_unmark(d);
383 else {
384 r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
385 if (r < 0)
386 goto clear;
387 }
388 }
389
390 dns_search_domain_unlink_marked(l->search_domains);
bda2c408 391 return 0;
a51c1048
LP
392
393clear:
394 dns_search_domain_unlink_all(l->search_domains);
395 return r;
bda2c408
TG
396}
397
74b2466e 398int link_update_monitor(Link *l) {
a51c1048
LP
399 int r;
400
74b2466e
LP
401 assert(l);
402
125ae29d
LP
403 r = link_update_dns_servers(l);
404 if (r < 0)
405 log_warning_errno(r, "Failed to read DNS servers for interface %s, ignoring: %m", l->name);
406
407 r = link_update_llmnr_support(l);
408 if (r < 0)
409 log_warning_errno(r, "Failed to read LLMNR support for interface %s, ignoring: %m", l->name);
410
411 r = link_update_mdns_support(l);
412 if (r < 0)
413 log_warning_errno(r, "Failed to read mDNS support for interface %s, ignoring: %m", l->name);
414
ad6c0475
LP
415 r = link_update_dnssec_mode(l);
416 if (r < 0)
417 log_warning_errno(r, "Failed to read DNSSEC mode for interface %s, ignoring: %m", l->name);
a51c1048 418
8a516214
LP
419 r = link_update_dnssec_negative_trust_anchors(l);
420 if (r < 0)
421 log_warning_errno(r, "Failed to read DNSSEC negative trust anchors for interface %s, ignoring: %m", l->name);
422
a51c1048
LP
423 r = link_update_search_domains(l);
424 if (r < 0)
425 log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name);
426
ad6c0475 427 link_allocate_scopes(l);
ec2c5e43 428 link_add_rrs(l, false);
74b2466e
LP
429
430 return 0;
431}
432
0dd25fb9 433bool link_relevant(Link *l, int family) {
1716f6dc 434 _cleanup_free_ char *state = NULL;
74b2466e
LP
435 LinkAddress *a;
436
437 assert(l);
438
ec2c5e43
LP
439 /* A link is relevant if it isn't a loopback or pointopoint
440 * device, has a link beat, can do multicast and has at least
441 * one relevant IP address */
442
443 if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT))
444 return false;
74b2466e 445
ec2c5e43 446 if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST))
74b2466e
LP
447 return false;
448
d6731e4c 449 sd_network_link_get_operational_state(l->ifindex, &state);
1716f6dc 450 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
74b2466e
LP
451 return false;
452
453 LIST_FOREACH(addresses, a, l->addresses)
1716f6dc 454 if (a->family == family && link_address_relevant(a))
74b2466e
LP
455 return true;
456
457 return false;
458}
459
623a4c97 460LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
74b2466e
LP
461 LinkAddress *a;
462
463 assert(l);
464
1716f6dc
LP
465 LIST_FOREACH(addresses, a, l->addresses)
466 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
74b2466e 467 return a;
74b2466e
LP
468
469 return NULL;
470}
471
2c27fbca 472DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
4e945a6f
LP
473 assert(l);
474
475 if (l->current_dns_server == s)
476 return s;
477
6cb08a89
LP
478 if (s)
479 log_info("Switching to DNS server %s for interface %s.", dns_server_string(s), l->name);
4e945a6f 480
0eac4623
LP
481 dns_server_unref(l->current_dns_server);
482 l->current_dns_server = dns_server_ref(s);
2c27fbca
LP
483
484 if (l->unicast_scope)
485 dns_cache_flush(&l->unicast_scope->cache);
486
4e945a6f
LP
487 return s;
488}
489
74b2466e
LP
490DnsServer *link_get_dns_server(Link *l) {
491 assert(l);
492
493 if (!l->current_dns_server)
4e945a6f 494 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
495
496 return l->current_dns_server;
497}
498
499void link_next_dns_server(Link *l) {
500 assert(l);
501
74b2466e
LP
502 if (!l->current_dns_server)
503 return;
504
0eac4623
LP
505 /* Change to the next one, but make sure to follow the linked
506 * list only if this server is actually still linked. */
507 if (l->current_dns_server->linked && l->current_dns_server->servers_next) {
4e945a6f 508 link_set_dns_server(l, l->current_dns_server->servers_next);
74b2466e
LP
509 return;
510 }
511
4e945a6f 512 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
513}
514
623a4c97 515int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
74b2466e
LP
516 LinkAddress *a;
517
518 assert(l);
519 assert(in_addr);
520
521 a = new0(LinkAddress, 1);
522 if (!a)
523 return -ENOMEM;
524
525 a->family = family;
526 a->in_addr = *in_addr;
527
528 a->link = l;
529 LIST_PREPEND(addresses, l->addresses, a);
530
531 if (ret)
532 *ret = a;
533
534 return 0;
535}
536
537LinkAddress *link_address_free(LinkAddress *a) {
538 if (!a)
539 return NULL;
540
623a4c97 541 if (a->link) {
74b2466e
LP
542 LIST_REMOVE(addresses, a->link->addresses, a);
543
623a4c97 544 if (a->llmnr_address_rr) {
623a4c97
LP
545 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
546 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
547 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
548 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
623a4c97
LP
549 }
550
551 if (a->llmnr_ptr_rr) {
552 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
553 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
554 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
555 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
623a4c97
LP
556 }
557 }
558
ec2c5e43
LP
559 dns_resource_record_unref(a->llmnr_address_rr);
560 dns_resource_record_unref(a->llmnr_ptr_rr);
561
74b2466e
LP
562 free(a);
563 return NULL;
564}
565
ec2c5e43 566void link_address_add_rrs(LinkAddress *a, bool force_remove) {
623a4c97
LP
567 int r;
568
569 assert(a);
570
ec2c5e43 571 if (a->family == AF_INET) {
623a4c97 572
4e945a6f
LP
573 if (!force_remove &&
574 link_address_relevant(a) &&
575 a->link->llmnr_ipv4_scope &&
af49ca27
LP
576 a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
577 a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
4e945a6f 578
78c6a153
LP
579 if (!a->link->manager->llmnr_host_ipv4_key) {
580 a->link->manager->llmnr_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->llmnr_hostname);
581 if (!a->link->manager->llmnr_host_ipv4_key) {
ec2c5e43
LP
582 r = -ENOMEM;
583 goto fail;
584 }
623a4c97 585 }
623a4c97 586
623a4c97 587 if (!a->llmnr_address_rr) {
78c6a153 588 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv4_key);
ec2c5e43
LP
589 if (!a->llmnr_address_rr) {
590 r = -ENOMEM;
591 goto fail;
592 }
593
594 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
595 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
596 }
597
ec2c5e43 598 if (!a->llmnr_ptr_rr) {
78c6a153 599 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
ec2c5e43
LP
600 if (r < 0)
601 goto fail;
623a4c97 602
ec2c5e43
LP
603 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
604 }
623a4c97 605
ec2c5e43 606 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
623a4c97 607 if (r < 0)
da927ba9 608 log_warning_errno(r, "Failed to add A record to LLMNR zone: %m");
623a4c97 609
ec2c5e43 610 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
623a4c97 611 if (r < 0)
da927ba9 612 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
623a4c97 613 } else {
ec2c5e43
LP
614 if (a->llmnr_address_rr) {
615 if (a->link->llmnr_ipv4_scope)
616 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
617 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
618 }
619
620 if (a->llmnr_ptr_rr) {
621 if (a->link->llmnr_ipv4_scope)
622 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
623 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
624 }
623a4c97
LP
625 }
626 }
627
ec2c5e43 628 if (a->family == AF_INET6) {
623a4c97 629
4e945a6f
LP
630 if (!force_remove &&
631 link_address_relevant(a) &&
632 a->link->llmnr_ipv6_scope &&
af49ca27
LP
633 a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
634 a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
4e945a6f 635
78c6a153
LP
636 if (!a->link->manager->llmnr_host_ipv6_key) {
637 a->link->manager->llmnr_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->llmnr_hostname);
638 if (!a->link->manager->llmnr_host_ipv6_key) {
ec2c5e43
LP
639 r = -ENOMEM;
640 goto fail;
641 }
623a4c97 642 }
623a4c97 643
623a4c97 644 if (!a->llmnr_address_rr) {
78c6a153 645 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv6_key);
ec2c5e43
LP
646 if (!a->llmnr_address_rr) {
647 r = -ENOMEM;
648 goto fail;
649 }
650
651 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
652 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
653 }
654
ec2c5e43 655 if (!a->llmnr_ptr_rr) {
78c6a153 656 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
ec2c5e43
LP
657 if (r < 0)
658 goto fail;
623a4c97 659
ec2c5e43
LP
660 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
661 }
623a4c97 662
ec2c5e43 663 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
623a4c97 664 if (r < 0)
da927ba9 665 log_warning_errno(r, "Failed to add AAAA record to LLMNR zone: %m");
623a4c97 666
ec2c5e43 667 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
623a4c97 668 if (r < 0)
da927ba9 669 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
623a4c97 670 } else {
ec2c5e43
LP
671 if (a->llmnr_address_rr) {
672 if (a->link->llmnr_ipv6_scope)
673 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
674 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
675 }
676
677 if (a->llmnr_ptr_rr) {
678 if (a->link->llmnr_ipv6_scope)
679 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
680 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
681 }
623a4c97
LP
682 }
683 }
684
685 return;
686
687fail:
da927ba9 688 log_debug_errno(r, "Failed to update address RRs: %m");
623a4c97
LP
689}
690
1c4baffc 691int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) {
74b2466e
LP
692 int r;
693 assert(a);
694 assert(m);
695
696 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
697 if (r < 0)
698 return r;
699
1716f6dc 700 sd_rtnl_message_addr_get_scope(m, &a->scope);
74b2466e 701
1716f6dc 702 link_allocate_scopes(a->link);
ec2c5e43 703 link_add_rrs(a->link, false);
623a4c97 704
74b2466e
LP
705 return 0;
706}
707
708bool link_address_relevant(LinkAddress *a) {
709 assert(a);
710
7b85d72f 711 if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))
74b2466e
LP
712 return false;
713
714 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
715 return false;
716
717 return true;
718}