]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-link.c
resolved: when checking whether a link is relevant, check kernel operstate
[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
a51c1048
LP
380static int link_update_search_domains(Link *l) {
381 _cleanup_strv_free_ char **domains = NULL;
382 char **i;
bda2c408
TG
383 int r;
384
a51c1048 385 assert(l);
bda2c408 386
a51c1048 387 r = sd_network_link_get_domains(l->ifindex, &domains);
1ade96e9
LP
388 if (r == -ENODATA) {
389 /* networkd knows nothing about this interface, and that's fine. */
390 r = 0;
391 goto clear;
392 }
bda2c408 393 if (r < 0)
a51c1048
LP
394 goto clear;
395
396 dns_search_domain_mark_all(l->search_domains);
397
398 STRV_FOREACH(i, domains) {
399 DnsSearchDomain *d;
bda2c408 400
a51c1048
LP
401 r = dns_search_domain_find(l->search_domains, *i, &d);
402 if (r < 0)
403 goto clear;
404
405 if (r > 0)
406 dns_search_domain_move_back_and_unmark(d);
407 else {
408 r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
409 if (r < 0)
410 goto clear;
411 }
412 }
413
414 dns_search_domain_unlink_marked(l->search_domains);
bda2c408 415 return 0;
a51c1048
LP
416
417clear:
418 dns_search_domain_unlink_all(l->search_domains);
419 return r;
bda2c408
TG
420}
421
97e5d693
LP
422static int link_is_unmanaged(Link *l) {
423 _cleanup_free_ char *state = NULL;
a51c1048
LP
424 int r;
425
74b2466e
LP
426 assert(l);
427
97e5d693
LP
428 r = sd_network_link_get_setup_state(l->ifindex, &state);
429 if (r == -ENODATA)
430 return 1;
431 if (r < 0)
432 return r;
433
434 return STR_IN_SET(state, "pending", "unmanaged");
435}
436
437static void link_read_settings(Link *l) {
438 int r;
439
440 assert(l);
441
442 /* Read settings from networkd, except when networkd is not managing this interface. */
443
444 r = link_is_unmanaged(l);
445 if (r < 0) {
446 log_warning_errno(r, "Failed to determine whether interface %s is managed: %m", l->name);
447 return;
448 }
449 if (r > 0) {
450
451 /* If this link used to be managed, but is now unmanaged, flush all our settings -- but only once. */
452 if (l->is_managed)
453 link_flush_settings(l);
454
455 l->is_managed = false;
456 return;
457 }
458
459 l->is_managed = true;
460
125ae29d
LP
461 r = link_update_dns_servers(l);
462 if (r < 0)
463 log_warning_errno(r, "Failed to read DNS servers for interface %s, ignoring: %m", l->name);
464
465 r = link_update_llmnr_support(l);
466 if (r < 0)
467 log_warning_errno(r, "Failed to read LLMNR support for interface %s, ignoring: %m", l->name);
468
469 r = link_update_mdns_support(l);
470 if (r < 0)
471 log_warning_errno(r, "Failed to read mDNS support for interface %s, ignoring: %m", l->name);
472
ad6c0475
LP
473 r = link_update_dnssec_mode(l);
474 if (r < 0)
475 log_warning_errno(r, "Failed to read DNSSEC mode for interface %s, ignoring: %m", l->name);
a51c1048 476
8a516214
LP
477 r = link_update_dnssec_negative_trust_anchors(l);
478 if (r < 0)
479 log_warning_errno(r, "Failed to read DNSSEC negative trust anchors for interface %s, ignoring: %m", l->name);
480
a51c1048
LP
481 r = link_update_search_domains(l);
482 if (r < 0)
483 log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name);
97e5d693
LP
484}
485
486int link_update_monitor(Link *l) {
487 assert(l);
a51c1048 488
97e5d693 489 link_read_settings(l);
ad6c0475 490 link_allocate_scopes(l);
ec2c5e43 491 link_add_rrs(l, false);
74b2466e
LP
492
493 return 0;
494}
495
dfc1091b 496bool link_relevant(Link *l, int family, bool multicast) {
1716f6dc 497 _cleanup_free_ char *state = NULL;
74b2466e
LP
498 LinkAddress *a;
499
500 assert(l);
501
dfc1091b
LP
502 /* A link is relevant for multicast traffic if it isn't a loopback or pointopoint device, has a link beat, can
503 * do multicast and has at least one relevant IP address */
ec2c5e43 504
dfc1091b 505 if (l->flags & (IFF_LOOPBACK|IFF_DORMANT))
ec2c5e43 506 return false;
74b2466e 507
dfc1091b 508 if ((l->flags & (IFF_UP|IFF_LOWER_UP)) != (IFF_UP|IFF_LOWER_UP))
74b2466e
LP
509 return false;
510
dfc1091b
LP
511 if (multicast) {
512 if (l->flags & IFF_POINTOPOINT)
513 return false;
514
515 if ((l->flags & IFF_MULTICAST) != IFF_MULTICAST)
516 return false;
517 }
518
6955a3ba
LP
519 /* Check kernel operstate
520 * https://www.kernel.org/doc/Documentation/networking/operstates.txt */
521 if (!IN_SET(l->operstate, IF_OPER_UNKNOWN, IF_OPER_UP))
522 return false;
523
524 (void) sd_network_link_get_operational_state(l->ifindex, &state);
1716f6dc 525 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
74b2466e
LP
526 return false;
527
528 LIST_FOREACH(addresses, a, l->addresses)
dfc1091b 529 if ((family == AF_UNSPEC || a->family == family) && link_address_relevant(a))
74b2466e
LP
530 return true;
531
532 return false;
533}
534
623a4c97 535LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
74b2466e
LP
536 LinkAddress *a;
537
538 assert(l);
539
1716f6dc
LP
540 LIST_FOREACH(addresses, a, l->addresses)
541 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
74b2466e 542 return a;
74b2466e
LP
543
544 return NULL;
545}
546
2c27fbca 547DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
4e945a6f
LP
548 assert(l);
549
550 if (l->current_dns_server == s)
551 return s;
552
6cb08a89
LP
553 if (s)
554 log_info("Switching to DNS server %s for interface %s.", dns_server_string(s), l->name);
4e945a6f 555
0eac4623
LP
556 dns_server_unref(l->current_dns_server);
557 l->current_dns_server = dns_server_ref(s);
2c27fbca
LP
558
559 if (l->unicast_scope)
560 dns_cache_flush(&l->unicast_scope->cache);
561
4e945a6f
LP
562 return s;
563}
564
74b2466e
LP
565DnsServer *link_get_dns_server(Link *l) {
566 assert(l);
567
568 if (!l->current_dns_server)
4e945a6f 569 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
570
571 return l->current_dns_server;
572}
573
574void link_next_dns_server(Link *l) {
575 assert(l);
576
74b2466e
LP
577 if (!l->current_dns_server)
578 return;
579
0eac4623
LP
580 /* Change to the next one, but make sure to follow the linked
581 * list only if this server is actually still linked. */
582 if (l->current_dns_server->linked && l->current_dns_server->servers_next) {
4e945a6f 583 link_set_dns_server(l, l->current_dns_server->servers_next);
74b2466e
LP
584 return;
585 }
586
4e945a6f 587 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
588}
589
c69fa7e3
LP
590DnssecMode link_get_dnssec_mode(Link *l) {
591 assert(l);
592
593 if (l->dnssec_mode != _DNSSEC_MODE_INVALID)
594 return l->dnssec_mode;
595
596 return manager_get_dnssec_mode(l->manager);
597}
598
599bool link_dnssec_supported(Link *l) {
600 DnsServer *server;
601
602 assert(l);
603
604 if (link_get_dnssec_mode(l) == DNSSEC_NO)
605 return false;
606
607 server = link_get_dns_server(l);
608 if (server)
609 return dns_server_dnssec_supported(server);
610
611 return true;
612}
613
623a4c97 614int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
74b2466e
LP
615 LinkAddress *a;
616
617 assert(l);
618 assert(in_addr);
619
620 a = new0(LinkAddress, 1);
621 if (!a)
622 return -ENOMEM;
623
624 a->family = family;
625 a->in_addr = *in_addr;
626
627 a->link = l;
628 LIST_PREPEND(addresses, l->addresses, a);
629
630 if (ret)
631 *ret = a;
632
633 return 0;
634}
635
636LinkAddress *link_address_free(LinkAddress *a) {
637 if (!a)
638 return NULL;
639
623a4c97 640 if (a->link) {
74b2466e
LP
641 LIST_REMOVE(addresses, a->link->addresses, a);
642
623a4c97 643 if (a->llmnr_address_rr) {
623a4c97
LP
644 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
645 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
646 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
647 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
623a4c97
LP
648 }
649
650 if (a->llmnr_ptr_rr) {
651 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
652 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
653 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
654 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
623a4c97
LP
655 }
656 }
657
ec2c5e43
LP
658 dns_resource_record_unref(a->llmnr_address_rr);
659 dns_resource_record_unref(a->llmnr_ptr_rr);
660
74b2466e
LP
661 free(a);
662 return NULL;
663}
664
ec2c5e43 665void link_address_add_rrs(LinkAddress *a, bool force_remove) {
623a4c97
LP
666 int r;
667
668 assert(a);
669
ec2c5e43 670 if (a->family == AF_INET) {
623a4c97 671
4e945a6f
LP
672 if (!force_remove &&
673 link_address_relevant(a) &&
674 a->link->llmnr_ipv4_scope &&
af49ca27
LP
675 a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
676 a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
4e945a6f 677
78c6a153
LP
678 if (!a->link->manager->llmnr_host_ipv4_key) {
679 a->link->manager->llmnr_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->llmnr_hostname);
680 if (!a->link->manager->llmnr_host_ipv4_key) {
ec2c5e43
LP
681 r = -ENOMEM;
682 goto fail;
683 }
623a4c97 684 }
623a4c97 685
623a4c97 686 if (!a->llmnr_address_rr) {
78c6a153 687 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv4_key);
ec2c5e43
LP
688 if (!a->llmnr_address_rr) {
689 r = -ENOMEM;
690 goto fail;
691 }
692
693 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
694 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
695 }
696
ec2c5e43 697 if (!a->llmnr_ptr_rr) {
78c6a153 698 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
ec2c5e43
LP
699 if (r < 0)
700 goto fail;
623a4c97 701
ec2c5e43
LP
702 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
703 }
623a4c97 704
ec2c5e43 705 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
623a4c97 706 if (r < 0)
da927ba9 707 log_warning_errno(r, "Failed to add A record to LLMNR zone: %m");
623a4c97 708
ec2c5e43 709 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
623a4c97 710 if (r < 0)
da927ba9 711 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
623a4c97 712 } else {
ec2c5e43
LP
713 if (a->llmnr_address_rr) {
714 if (a->link->llmnr_ipv4_scope)
715 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
716 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
717 }
718
719 if (a->llmnr_ptr_rr) {
720 if (a->link->llmnr_ipv4_scope)
721 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
722 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
723 }
623a4c97
LP
724 }
725 }
726
ec2c5e43 727 if (a->family == AF_INET6) {
623a4c97 728
4e945a6f
LP
729 if (!force_remove &&
730 link_address_relevant(a) &&
731 a->link->llmnr_ipv6_scope &&
af49ca27
LP
732 a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
733 a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
4e945a6f 734
78c6a153
LP
735 if (!a->link->manager->llmnr_host_ipv6_key) {
736 a->link->manager->llmnr_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->llmnr_hostname);
737 if (!a->link->manager->llmnr_host_ipv6_key) {
ec2c5e43
LP
738 r = -ENOMEM;
739 goto fail;
740 }
623a4c97 741 }
623a4c97 742
623a4c97 743 if (!a->llmnr_address_rr) {
78c6a153 744 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv6_key);
ec2c5e43
LP
745 if (!a->llmnr_address_rr) {
746 r = -ENOMEM;
747 goto fail;
748 }
749
750 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
751 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
752 }
753
ec2c5e43 754 if (!a->llmnr_ptr_rr) {
78c6a153 755 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
ec2c5e43
LP
756 if (r < 0)
757 goto fail;
623a4c97 758
ec2c5e43
LP
759 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
760 }
623a4c97 761
ec2c5e43 762 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
623a4c97 763 if (r < 0)
da927ba9 764 log_warning_errno(r, "Failed to add AAAA record to LLMNR zone: %m");
623a4c97 765
ec2c5e43 766 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
623a4c97 767 if (r < 0)
da927ba9 768 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
623a4c97 769 } else {
ec2c5e43
LP
770 if (a->llmnr_address_rr) {
771 if (a->link->llmnr_ipv6_scope)
772 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
773 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
774 }
775
776 if (a->llmnr_ptr_rr) {
777 if (a->link->llmnr_ipv6_scope)
778 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
779 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
780 }
623a4c97
LP
781 }
782 }
783
784 return;
785
786fail:
da927ba9 787 log_debug_errno(r, "Failed to update address RRs: %m");
623a4c97
LP
788}
789
1c4baffc 790int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) {
74b2466e
LP
791 int r;
792 assert(a);
793 assert(m);
794
795 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
796 if (r < 0)
797 return r;
798
1716f6dc 799 sd_rtnl_message_addr_get_scope(m, &a->scope);
74b2466e 800
1716f6dc 801 link_allocate_scopes(a->link);
ec2c5e43 802 link_add_rrs(a->link, false);
623a4c97 803
74b2466e
LP
804 return 0;
805}
806
807bool link_address_relevant(LinkAddress *a) {
808 assert(a);
809
7b85d72f 810 if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))
74b2466e
LP
811 return false;
812
813 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
814 return false;
815
816 return true;
817}