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