]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-link.c
resolved: rework what ResolveHostname() with family == AF_UNSPEC means
[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;
6955a3ba 52 l->operstate = IF_OPER_UNKNOWN;
74b2466e
LP
53
54 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
55 if (r < 0)
56 return r;
57
58 l->manager = m;
59
60 if (ret)
61 *ret = l;
62 l = NULL;
63
64 return 0;
65}
66
97e5d693
LP
67void link_flush_settings(Link *l) {
68 assert(l);
69
70 l->llmnr_support = RESOLVE_SUPPORT_YES;
71 l->mdns_support = RESOLVE_SUPPORT_NO;
72 l->dnssec_mode = _DNSSEC_MODE_INVALID;
73
74 dns_server_unlink_all(l->dns_servers);
75 dns_search_domain_unlink_all(l->search_domains);
76
77 l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors);
78}
79
74b2466e 80Link *link_free(Link *l) {
74b2466e
LP
81 if (!l)
82 return NULL;
83
97e5d693 84 link_flush_settings(l);
0eac4623 85
74b2466e 86 while (l->addresses)
97e5d693 87 (void) link_address_free(l->addresses);
74b2466e
LP
88
89 if (l->manager)
90 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
91
92 dns_scope_free(l->unicast_scope);
1716f6dc
LP
93 dns_scope_free(l->llmnr_ipv4_scope);
94 dns_scope_free(l->llmnr_ipv6_scope);
b4f1862d
DM
95 dns_scope_free(l->mdns_ipv4_scope);
96 dns_scope_free(l->mdns_ipv6_scope);
74b2466e 97
74b2466e
LP
98 free(l);
99 return NULL;
1716f6dc
LP
100}
101
97e5d693 102void link_allocate_scopes(Link *l) {
1716f6dc
LP
103 int r;
104
105 assert(l);
106
dfc1091b
LP
107 if (link_relevant(l, AF_UNSPEC, false) &&
108 l->dns_servers) {
1716f6dc
LP
109 if (!l->unicast_scope) {
110 r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
111 if (r < 0)
da927ba9 112 log_warning_errno(r, "Failed to allocate DNS scope: %m");
1716f6dc
LP
113 }
114 } else
115 l->unicast_scope = dns_scope_free(l->unicast_scope);
116
dfc1091b 117 if (link_relevant(l, AF_INET, true) &&
af49ca27
LP
118 l->llmnr_support != RESOLVE_SUPPORT_NO &&
119 l->manager->llmnr_support != RESOLVE_SUPPORT_NO) {
1716f6dc
LP
120 if (!l->llmnr_ipv4_scope) {
121 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
122 if (r < 0)
da927ba9 123 log_warning_errno(r, "Failed to allocate LLMNR IPv4 scope: %m");
1716f6dc
LP
124 }
125 } else
126 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
127
dfc1091b 128 if (link_relevant(l, AF_INET6, true) &&
af49ca27
LP
129 l->llmnr_support != RESOLVE_SUPPORT_NO &&
130 l->manager->llmnr_support != RESOLVE_SUPPORT_NO &&
db97a66a 131 socket_ipv6_is_supported()) {
1716f6dc
LP
132 if (!l->llmnr_ipv6_scope) {
133 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
134 if (r < 0)
da927ba9 135 log_warning_errno(r, "Failed to allocate LLMNR IPv6 scope: %m");
1716f6dc
LP
136 }
137 } else
138 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
b4f1862d 139
dfc1091b 140 if (link_relevant(l, AF_INET, true) &&
af49ca27
LP
141 l->mdns_support != RESOLVE_SUPPORT_NO &&
142 l->manager->mdns_support != RESOLVE_SUPPORT_NO) {
b4f1862d
DM
143 if (!l->mdns_ipv4_scope) {
144 r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET);
145 if (r < 0)
146 log_warning_errno(r, "Failed to allocate mDNS IPv4 scope: %m");
147 }
148 } else
149 l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope);
150
dfc1091b 151 if (link_relevant(l, AF_INET6, true) &&
af49ca27
LP
152 l->mdns_support != RESOLVE_SUPPORT_NO &&
153 l->manager->mdns_support != RESOLVE_SUPPORT_NO) {
b4f1862d
DM
154 if (!l->mdns_ipv6_scope) {
155 r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6);
156 if (r < 0)
157 log_warning_errno(r, "Failed to allocate mDNS IPv6 scope: %m");
158 }
159 } else
160 l->mdns_ipv6_scope = dns_scope_free(l->mdns_ipv6_scope);
1716f6dc 161}
74b2466e 162
ec2c5e43 163void link_add_rrs(Link *l, bool force_remove) {
623a4c97
LP
164 LinkAddress *a;
165
166 LIST_FOREACH(addresses, a, l->addresses)
ec2c5e43 167 link_address_add_rrs(a, force_remove);
623a4c97
LP
168}
169
1c4baffc 170int link_update_rtnl(Link *l, sd_netlink_message *m) {
1716f6dc 171 const char *n = NULL;
74b2466e
LP
172 int r;
173
174 assert(l);
175 assert(m);
176
177 r = sd_rtnl_message_link_get_flags(m, &l->flags);
178 if (r < 0)
179 return r;
180
6955a3ba
LP
181 (void) sd_netlink_message_read_u32(m, IFLA_MTU, &l->mtu);
182 (void) sd_netlink_message_read_u8(m, IFLA_OPERSTATE, &l->operstate);
1716f6dc 183
1c4baffc 184 if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
cc7844e7 185 strncpy(l->name, n, sizeof(l->name)-1);
1716f6dc
LP
186 char_array_0(l->name);
187 }
188
189 link_allocate_scopes(l);
ec2c5e43 190 link_add_rrs(l, false);
623a4c97 191
74b2466e
LP
192 return 0;
193}
194
6073b6f2 195static int link_update_dns_servers(Link *l) {
6f4dedb2
TG
196 _cleanup_strv_free_ char **nameservers = NULL;
197 char **nameserver;
6f4dedb2 198 int r;
74b2466e
LP
199
200 assert(l);
201
d6731e4c 202 r = sd_network_link_get_dns(l->ifindex, &nameservers);
1ade96e9
LP
203 if (r == -ENODATA) {
204 r = 0;
205 goto clear;
206 }
6f4dedb2 207 if (r < 0)
74b2466e 208 goto clear;
74b2466e 209
4b95f179 210 dns_server_mark_all(l->dns_servers);
5cb36f41 211
6f4dedb2
TG
212 STRV_FOREACH(nameserver, nameservers) {
213 union in_addr_union a;
0eac4623 214 DnsServer *s;
6f4dedb2 215 int family;
74b2466e 216
6f4dedb2
TG
217 r = in_addr_from_string_auto(*nameserver, &family, &a);
218 if (r < 0)
219 goto clear;
74b2466e 220
4b95f179 221 s = dns_server_find(l->dns_servers, family, &a);
74b2466e 222 if (s)
0b58db65 223 dns_server_move_back_and_unmark(s);
74b2466e 224 else {
4e945a6f 225 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
74b2466e
LP
226 if (r < 0)
227 goto clear;
228 }
229 }
230
4b95f179 231 dns_server_unlink_marked(l->dns_servers);
74b2466e
LP
232 return 0;
233
234clear:
4b95f179 235 dns_server_unlink_all(l->dns_servers);
74b2466e
LP
236 return r;
237}
238
19b50b5b
LP
239static int link_update_llmnr_support(Link *l) {
240 _cleanup_free_ char *b = NULL;
241 int r;
242
243 assert(l);
244
d6731e4c 245 r = sd_network_link_get_llmnr(l->ifindex, &b);
1ade96e9
LP
246 if (r == -ENODATA) {
247 r = 0;
248 goto clear;
249 }
19b50b5b
LP
250 if (r < 0)
251 goto clear;
252
af49ca27
LP
253 l->llmnr_support = resolve_support_from_string(b);
254 if (l->llmnr_support < 0) {
255 r = -EINVAL;
256 goto clear;
257 }
19b50b5b
LP
258
259 return 0;
260
261clear:
af49ca27 262 l->llmnr_support = RESOLVE_SUPPORT_YES;
19b50b5b
LP
263 return r;
264}
265
aaa297d4
LP
266static int link_update_mdns_support(Link *l) {
267 _cleanup_free_ char *b = NULL;
268 int r;
269
270 assert(l);
271
272 r = sd_network_link_get_mdns(l->ifindex, &b);
273 if (r == -ENODATA) {
274 r = 0;
275 goto clear;
276 }
277 if (r < 0)
278 goto clear;
279
280 l->mdns_support = resolve_support_from_string(b);
281 if (l->mdns_support < 0) {
282 r = -EINVAL;
283 goto clear;
284 }
285
286 return 0;
287
288clear:
289 l->mdns_support = RESOLVE_SUPPORT_NO;
290 return r;
291}
292
97e5d693
LP
293void link_set_dnssec_mode(Link *l, DnssecMode mode) {
294
295 assert(l);
296
297 if (l->dnssec_mode == mode)
298 return;
299
300 if ((l->dnssec_mode == _DNSSEC_MODE_INVALID) ||
301 (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}
312
ad6c0475
LP
313static int link_update_dnssec_mode(Link *l) {
314 _cleanup_free_ char *m = NULL;
2e1bab34 315 DnssecMode mode;
ad6c0475
LP
316 int r;
317
318 assert(l);
319
320 r = sd_network_link_get_dnssec(l->ifindex, &m);
321 if (r == -ENODATA) {
322 r = 0;
323 goto clear;
324 }
325 if (r < 0)
326 goto clear;
327
2e1bab34
LP
328 mode = dnssec_mode_from_string(m);
329 if (mode < 0) {
ad6c0475
LP
330 r = -EINVAL;
331 goto clear;
332 }
333
97e5d693 334 link_set_dnssec_mode(l, mode);
2e1bab34 335
ad6c0475
LP
336 return 0;
337
338clear:
339 l->dnssec_mode = _DNSSEC_MODE_INVALID;
340 return r;
341}
342
8a516214
LP
343static int link_update_dnssec_negative_trust_anchors(Link *l) {
344 _cleanup_strv_free_ char **ntas = NULL;
345 _cleanup_set_free_free_ Set *ns = NULL;
346 char **i;
347 int r;
348
349 assert(l);
350
351 r = sd_network_link_get_dnssec_negative_trust_anchors(l->ifindex, &ntas);
352 if (r == -ENODATA) {
353 r = 0;
354 goto clear;
355 }
356 if (r < 0)
357 goto clear;
358
359 ns = set_new(&dns_name_hash_ops);
360 if (!ns)
361 return -ENOMEM;
362
363 STRV_FOREACH(i, ntas) {
364 r = set_put_strdup(ns, *i);
365 if (r < 0)
366 return r;
367 }
368
369 set_free_free(l->dnssec_negative_trust_anchors);
370 l->dnssec_negative_trust_anchors = ns;
371 ns = NULL;
372
373 return 0;
374
375clear:
376 l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors);
377 return r;
378}
379
ad44b56b
LP
380static int link_update_search_domain_one(Link *l, const char *name, bool route_only) {
381 DnsSearchDomain *d;
382 int r;
383
384 r = dns_search_domain_find(l->search_domains, name, &d);
385 if (r < 0)
386 return r;
387 if (r > 0)
388 dns_search_domain_move_back_and_unmark(d);
389 else {
390 r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
391 if (r < 0)
392 return r;
393 }
394
395 d->route_only = route_only;
396 return 0;
397}
398
a51c1048 399static int link_update_search_domains(Link *l) {
ad44b56b 400 _cleanup_strv_free_ char **sdomains = NULL, **rdomains = NULL;
a51c1048 401 char **i;
ad44b56b 402 int r, q;
bda2c408 403
a51c1048 404 assert(l);
bda2c408 405
ad44b56b
LP
406 r = sd_network_link_get_search_domains(l->ifindex, &sdomains);
407 if (r < 0 && r != -ENODATA)
408 goto clear;
409
410 q = sd_network_link_get_route_domains(l->ifindex, &rdomains);
411 if (q < 0 && q != -ENODATA) {
412 r = q;
413 goto clear;
414 }
415
416 if (r == -ENODATA && q == -ENODATA) {
1ade96e9
LP
417 /* networkd knows nothing about this interface, and that's fine. */
418 r = 0;
419 goto clear;
420 }
a51c1048
LP
421
422 dns_search_domain_mark_all(l->search_domains);
423
ad44b56b
LP
424 STRV_FOREACH(i, sdomains) {
425 r = link_update_search_domain_one(l, *i, false);
a51c1048
LP
426 if (r < 0)
427 goto clear;
ad44b56b 428 }
a51c1048 429
ad44b56b
LP
430 STRV_FOREACH(i, rdomains) {
431 r = link_update_search_domain_one(l, *i, true);
432 if (r < 0)
433 goto clear;
a51c1048
LP
434 }
435
436 dns_search_domain_unlink_marked(l->search_domains);
bda2c408 437 return 0;
a51c1048
LP
438
439clear:
440 dns_search_domain_unlink_all(l->search_domains);
441 return r;
bda2c408
TG
442}
443
97e5d693
LP
444static int link_is_unmanaged(Link *l) {
445 _cleanup_free_ char *state = NULL;
a51c1048
LP
446 int r;
447
74b2466e
LP
448 assert(l);
449
97e5d693
LP
450 r = sd_network_link_get_setup_state(l->ifindex, &state);
451 if (r == -ENODATA)
452 return 1;
453 if (r < 0)
454 return r;
455
456 return STR_IN_SET(state, "pending", "unmanaged");
457}
458
459static void link_read_settings(Link *l) {
460 int r;
461
462 assert(l);
463
464 /* Read settings from networkd, except when networkd is not managing this interface. */
465
466 r = link_is_unmanaged(l);
467 if (r < 0) {
468 log_warning_errno(r, "Failed to determine whether interface %s is managed: %m", l->name);
469 return;
470 }
471 if (r > 0) {
472
473 /* If this link used to be managed, but is now unmanaged, flush all our settings -- but only once. */
474 if (l->is_managed)
475 link_flush_settings(l);
476
477 l->is_managed = false;
478 return;
479 }
480
481 l->is_managed = true;
482
125ae29d
LP
483 r = link_update_dns_servers(l);
484 if (r < 0)
485 log_warning_errno(r, "Failed to read DNS servers for interface %s, ignoring: %m", l->name);
486
487 r = link_update_llmnr_support(l);
488 if (r < 0)
489 log_warning_errno(r, "Failed to read LLMNR support for interface %s, ignoring: %m", l->name);
490
491 r = link_update_mdns_support(l);
492 if (r < 0)
493 log_warning_errno(r, "Failed to read mDNS support for interface %s, ignoring: %m", l->name);
494
ad6c0475
LP
495 r = link_update_dnssec_mode(l);
496 if (r < 0)
497 log_warning_errno(r, "Failed to read DNSSEC mode for interface %s, ignoring: %m", l->name);
a51c1048 498
8a516214
LP
499 r = link_update_dnssec_negative_trust_anchors(l);
500 if (r < 0)
501 log_warning_errno(r, "Failed to read DNSSEC negative trust anchors for interface %s, ignoring: %m", l->name);
502
a51c1048
LP
503 r = link_update_search_domains(l);
504 if (r < 0)
505 log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name);
97e5d693
LP
506}
507
508int link_update_monitor(Link *l) {
509 assert(l);
a51c1048 510
97e5d693 511 link_read_settings(l);
ad6c0475 512 link_allocate_scopes(l);
ec2c5e43 513 link_add_rrs(l, false);
74b2466e
LP
514
515 return 0;
516}
517
011696f7 518bool link_relevant(Link *l, int family, bool local_multicast) {
1716f6dc 519 _cleanup_free_ char *state = NULL;
74b2466e
LP
520 LinkAddress *a;
521
522 assert(l);
523
011696f7
LP
524 /* A link is relevant for local multicast traffic if it isn't a loopback or pointopoint device, has a link
525 * beat, can do multicast and has at least one link-local (or better) IP address.
526 *
527 * A link is relevant for non-multicast traffic if it isn't a loopback device, has a link beat, and has at
528 * least one routable address.*/
ec2c5e43 529
dfc1091b 530 if (l->flags & (IFF_LOOPBACK|IFF_DORMANT))
ec2c5e43 531 return false;
74b2466e 532
dfc1091b 533 if ((l->flags & (IFF_UP|IFF_LOWER_UP)) != (IFF_UP|IFF_LOWER_UP))
74b2466e
LP
534 return false;
535
011696f7 536 if (local_multicast) {
dfc1091b
LP
537 if (l->flags & IFF_POINTOPOINT)
538 return false;
539
540 if ((l->flags & IFF_MULTICAST) != IFF_MULTICAST)
541 return false;
542 }
543
6955a3ba
LP
544 /* Check kernel operstate
545 * https://www.kernel.org/doc/Documentation/networking/operstates.txt */
546 if (!IN_SET(l->operstate, IF_OPER_UNKNOWN, IF_OPER_UP))
547 return false;
548
549 (void) sd_network_link_get_operational_state(l->ifindex, &state);
1716f6dc 550 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
74b2466e
LP
551 return false;
552
553 LIST_FOREACH(addresses, a, l->addresses)
011696f7 554 if ((family == AF_UNSPEC || a->family == family) && link_address_relevant(a, local_multicast))
74b2466e
LP
555 return true;
556
557 return false;
558}
559
623a4c97 560LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
74b2466e
LP
561 LinkAddress *a;
562
563 assert(l);
564
1716f6dc
LP
565 LIST_FOREACH(addresses, a, l->addresses)
566 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
74b2466e 567 return a;
74b2466e
LP
568
569 return NULL;
570}
571
2c27fbca 572DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
4e945a6f
LP
573 assert(l);
574
575 if (l->current_dns_server == s)
576 return s;
577
6cb08a89
LP
578 if (s)
579 log_info("Switching to DNS server %s for interface %s.", dns_server_string(s), l->name);
4e945a6f 580
0eac4623
LP
581 dns_server_unref(l->current_dns_server);
582 l->current_dns_server = dns_server_ref(s);
2c27fbca
LP
583
584 if (l->unicast_scope)
585 dns_cache_flush(&l->unicast_scope->cache);
586
4e945a6f
LP
587 return s;
588}
589
74b2466e
LP
590DnsServer *link_get_dns_server(Link *l) {
591 assert(l);
592
593 if (!l->current_dns_server)
4e945a6f 594 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
595
596 return l->current_dns_server;
597}
598
599void link_next_dns_server(Link *l) {
600 assert(l);
601
74b2466e
LP
602 if (!l->current_dns_server)
603 return;
604
0eac4623
LP
605 /* Change to the next one, but make sure to follow the linked
606 * list only if this server is actually still linked. */
607 if (l->current_dns_server->linked && l->current_dns_server->servers_next) {
4e945a6f 608 link_set_dns_server(l, l->current_dns_server->servers_next);
74b2466e
LP
609 return;
610 }
611
4e945a6f 612 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
613}
614
c69fa7e3
LP
615DnssecMode link_get_dnssec_mode(Link *l) {
616 assert(l);
617
618 if (l->dnssec_mode != _DNSSEC_MODE_INVALID)
619 return l->dnssec_mode;
620
621 return manager_get_dnssec_mode(l->manager);
622}
623
624bool link_dnssec_supported(Link *l) {
625 DnsServer *server;
626
627 assert(l);
628
629 if (link_get_dnssec_mode(l) == DNSSEC_NO)
630 return false;
631
632 server = link_get_dns_server(l);
633 if (server)
634 return dns_server_dnssec_supported(server);
635
636 return true;
637}
638
623a4c97 639int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
74b2466e
LP
640 LinkAddress *a;
641
642 assert(l);
643 assert(in_addr);
644
645 a = new0(LinkAddress, 1);
646 if (!a)
647 return -ENOMEM;
648
649 a->family = family;
650 a->in_addr = *in_addr;
651
652 a->link = l;
653 LIST_PREPEND(addresses, l->addresses, a);
654
655 if (ret)
656 *ret = a;
657
658 return 0;
659}
660
661LinkAddress *link_address_free(LinkAddress *a) {
662 if (!a)
663 return NULL;
664
623a4c97 665 if (a->link) {
74b2466e
LP
666 LIST_REMOVE(addresses, a->link->addresses, a);
667
623a4c97 668 if (a->llmnr_address_rr) {
623a4c97
LP
669 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
670 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
671 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
672 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
623a4c97
LP
673 }
674
675 if (a->llmnr_ptr_rr) {
676 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
677 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
678 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
679 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
623a4c97
LP
680 }
681 }
682
ec2c5e43
LP
683 dns_resource_record_unref(a->llmnr_address_rr);
684 dns_resource_record_unref(a->llmnr_ptr_rr);
685
74b2466e
LP
686 free(a);
687 return NULL;
688}
689
ec2c5e43 690void link_address_add_rrs(LinkAddress *a, bool force_remove) {
623a4c97
LP
691 int r;
692
693 assert(a);
694
ec2c5e43 695 if (a->family == AF_INET) {
623a4c97 696
4e945a6f 697 if (!force_remove &&
011696f7 698 link_address_relevant(a, true) &&
4e945a6f 699 a->link->llmnr_ipv4_scope &&
af49ca27
LP
700 a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
701 a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
4e945a6f 702
78c6a153
LP
703 if (!a->link->manager->llmnr_host_ipv4_key) {
704 a->link->manager->llmnr_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->llmnr_hostname);
705 if (!a->link->manager->llmnr_host_ipv4_key) {
ec2c5e43
LP
706 r = -ENOMEM;
707 goto fail;
708 }
623a4c97 709 }
623a4c97 710
623a4c97 711 if (!a->llmnr_address_rr) {
78c6a153 712 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv4_key);
ec2c5e43
LP
713 if (!a->llmnr_address_rr) {
714 r = -ENOMEM;
715 goto fail;
716 }
717
718 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
719 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
720 }
721
ec2c5e43 722 if (!a->llmnr_ptr_rr) {
78c6a153 723 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
ec2c5e43
LP
724 if (r < 0)
725 goto fail;
623a4c97 726
ec2c5e43
LP
727 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
728 }
623a4c97 729
ec2c5e43 730 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
623a4c97 731 if (r < 0)
da927ba9 732 log_warning_errno(r, "Failed to add A record to LLMNR zone: %m");
623a4c97 733
ec2c5e43 734 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
623a4c97 735 if (r < 0)
da927ba9 736 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
623a4c97 737 } else {
ec2c5e43
LP
738 if (a->llmnr_address_rr) {
739 if (a->link->llmnr_ipv4_scope)
740 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
741 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
742 }
743
744 if (a->llmnr_ptr_rr) {
745 if (a->link->llmnr_ipv4_scope)
746 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
747 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
748 }
623a4c97
LP
749 }
750 }
751
ec2c5e43 752 if (a->family == AF_INET6) {
623a4c97 753
4e945a6f 754 if (!force_remove &&
011696f7 755 link_address_relevant(a, true) &&
4e945a6f 756 a->link->llmnr_ipv6_scope &&
af49ca27
LP
757 a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
758 a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
4e945a6f 759
78c6a153
LP
760 if (!a->link->manager->llmnr_host_ipv6_key) {
761 a->link->manager->llmnr_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->llmnr_hostname);
762 if (!a->link->manager->llmnr_host_ipv6_key) {
ec2c5e43
LP
763 r = -ENOMEM;
764 goto fail;
765 }
623a4c97 766 }
623a4c97 767
623a4c97 768 if (!a->llmnr_address_rr) {
78c6a153 769 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv6_key);
ec2c5e43
LP
770 if (!a->llmnr_address_rr) {
771 r = -ENOMEM;
772 goto fail;
773 }
774
775 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
776 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
777 }
778
ec2c5e43 779 if (!a->llmnr_ptr_rr) {
78c6a153 780 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
ec2c5e43
LP
781 if (r < 0)
782 goto fail;
623a4c97 783
ec2c5e43
LP
784 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
785 }
623a4c97 786
ec2c5e43 787 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
623a4c97 788 if (r < 0)
da927ba9 789 log_warning_errno(r, "Failed to add AAAA record to LLMNR zone: %m");
623a4c97 790
ec2c5e43 791 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
623a4c97 792 if (r < 0)
da927ba9 793 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
623a4c97 794 } else {
ec2c5e43
LP
795 if (a->llmnr_address_rr) {
796 if (a->link->llmnr_ipv6_scope)
797 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
798 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
799 }
800
801 if (a->llmnr_ptr_rr) {
802 if (a->link->llmnr_ipv6_scope)
803 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
804 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
805 }
623a4c97
LP
806 }
807 }
808
809 return;
810
811fail:
da927ba9 812 log_debug_errno(r, "Failed to update address RRs: %m");
623a4c97
LP
813}
814
1c4baffc 815int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) {
74b2466e
LP
816 int r;
817 assert(a);
818 assert(m);
819
820 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
821 if (r < 0)
822 return r;
823
1716f6dc 824 sd_rtnl_message_addr_get_scope(m, &a->scope);
74b2466e 825
1716f6dc 826 link_allocate_scopes(a->link);
ec2c5e43 827 link_add_rrs(a->link, false);
623a4c97 828
74b2466e
LP
829 return 0;
830}
831
011696f7 832bool link_address_relevant(LinkAddress *a, bool local_multicast) {
74b2466e
LP
833 assert(a);
834
7b85d72f 835 if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))
74b2466e
LP
836 return false;
837
011696f7 838 if (a->scope >= (local_multicast ? RT_SCOPE_HOST : RT_SCOPE_LINK))
74b2466e
LP
839 return false;
840
841 return true;
842}