]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-link.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
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.
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.
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/>.
24 #include "sd-network.h"
26 #include "alloc-util.h"
28 #include "parse-util.h"
29 #include "resolved-link.h"
30 #include "string-util.h"
33 int link_new(Manager
*m
, Link
**ret
, int ifindex
) {
34 _cleanup_(link_freep
) Link
*l
= NULL
;
40 r
= hashmap_ensure_allocated(&m
->links
, NULL
);
49 l
->llmnr_support
= SUPPORT_YES
;
51 r
= hashmap_put(m
->links
, INT_TO_PTR(ifindex
), l
);
64 Link
*link_free(Link
*l
) {
68 link_flush_dns_servers(l
);
69 dns_search_domain_unlink_all(l
->search_domains
);
72 link_address_free(l
->addresses
);
75 hashmap_remove(l
->manager
->links
, INT_TO_PTR(l
->ifindex
));
77 dns_scope_free(l
->unicast_scope
);
78 dns_scope_free(l
->llmnr_ipv4_scope
);
79 dns_scope_free(l
->llmnr_ipv6_scope
);
85 static void link_allocate_scopes(Link
*l
) {
91 if (!l
->unicast_scope
) {
92 r
= dns_scope_new(l
->manager
, &l
->unicast_scope
, l
, DNS_PROTOCOL_DNS
, AF_UNSPEC
);
94 log_warning_errno(r
, "Failed to allocate DNS scope: %m");
97 l
->unicast_scope
= dns_scope_free(l
->unicast_scope
);
99 if (link_relevant(l
, AF_INET
) &&
100 l
->llmnr_support
!= SUPPORT_NO
&&
101 l
->manager
->llmnr_support
!= SUPPORT_NO
) {
102 if (!l
->llmnr_ipv4_scope
) {
103 r
= dns_scope_new(l
->manager
, &l
->llmnr_ipv4_scope
, l
, DNS_PROTOCOL_LLMNR
, AF_INET
);
105 log_warning_errno(r
, "Failed to allocate LLMNR IPv4 scope: %m");
108 l
->llmnr_ipv4_scope
= dns_scope_free(l
->llmnr_ipv4_scope
);
110 if (link_relevant(l
, AF_INET6
) &&
111 l
->llmnr_support
!= SUPPORT_NO
&&
112 l
->manager
->llmnr_support
!= SUPPORT_NO
&&
113 socket_ipv6_is_supported()) {
114 if (!l
->llmnr_ipv6_scope
) {
115 r
= dns_scope_new(l
->manager
, &l
->llmnr_ipv6_scope
, l
, DNS_PROTOCOL_LLMNR
, AF_INET6
);
117 log_warning_errno(r
, "Failed to allocate LLMNR IPv6 scope: %m");
120 l
->llmnr_ipv6_scope
= dns_scope_free(l
->llmnr_ipv6_scope
);
123 void link_add_rrs(Link
*l
, bool force_remove
) {
126 LIST_FOREACH(addresses
, a
, l
->addresses
)
127 link_address_add_rrs(a
, force_remove
);
130 int link_update_rtnl(Link
*l
, sd_netlink_message
*m
) {
131 const char *n
= NULL
;
137 r
= sd_rtnl_message_link_get_flags(m
, &l
->flags
);
141 sd_netlink_message_read_u32(m
, IFLA_MTU
, &l
->mtu
);
143 if (sd_netlink_message_read_string(m
, IFLA_IFNAME
, &n
) >= 0) {
144 strncpy(l
->name
, n
, sizeof(l
->name
)-1);
145 char_array_0(l
->name
);
148 link_allocate_scopes(l
);
149 link_add_rrs(l
, false);
154 static int link_update_dns_servers(Link
*l
) {
155 _cleanup_strv_free_
char **nameservers
= NULL
;
161 r
= sd_network_link_get_dns(l
->ifindex
, &nameservers
);
165 link_mark_dns_servers(l
);
167 STRV_FOREACH(nameserver
, nameservers
) {
168 union in_addr_union a
;
172 r
= in_addr_from_string_auto(*nameserver
, &family
, &a
);
176 s
= link_find_dns_server(l
, family
, &a
);
178 dns_server_move_back_and_unmark(s
);
180 r
= dns_server_new(l
->manager
, NULL
, DNS_SERVER_LINK
, l
, family
, &a
);
186 link_flush_marked_dns_servers(l
);
190 link_flush_dns_servers(l
);
194 static int link_update_llmnr_support(Link
*l
) {
195 _cleanup_free_
char *b
= NULL
;
200 r
= sd_network_link_get_llmnr(l
->ifindex
, &b
);
204 r
= parse_boolean(b
);
206 if (streq(b
, "resolve"))
207 l
->llmnr_support
= SUPPORT_RESOLVE
;
212 l
->llmnr_support
= SUPPORT_YES
;
214 l
->llmnr_support
= SUPPORT_NO
;
219 l
->llmnr_support
= SUPPORT_YES
;
223 static int link_update_search_domains(Link
*l
) {
224 _cleanup_strv_free_
char **domains
= NULL
;
230 r
= sd_network_link_get_domains(l
->ifindex
, &domains
);
234 dns_search_domain_mark_all(l
->search_domains
);
236 STRV_FOREACH(i
, domains
) {
239 r
= dns_search_domain_find(l
->search_domains
, *i
, &d
);
244 dns_search_domain_move_back_and_unmark(d
);
246 r
= dns_search_domain_new(l
->manager
, NULL
, DNS_SEARCH_DOMAIN_LINK
, l
, *i
);
252 dns_search_domain_unlink_marked(l
->search_domains
);
256 dns_search_domain_unlink_all(l
->search_domains
);
260 int link_update_monitor(Link
*l
) {
265 link_update_dns_servers(l
);
266 link_update_llmnr_support(l
);
267 link_allocate_scopes(l
);
269 r
= link_update_search_domains(l
);
271 log_warning_errno(r
, "Failed to read search domains for interface %s, ignoring: %m", l
->name
);
273 link_add_rrs(l
, false);
278 bool link_relevant(Link
*l
, int family
) {
279 _cleanup_free_
char *state
= NULL
;
284 /* A link is relevant if it isn't a loopback or pointopoint
285 * device, has a link beat, can do multicast and has at least
286 * one relevant IP address */
288 if (l
->flags
& (IFF_LOOPBACK
|IFF_POINTOPOINT
|IFF_DORMANT
))
291 if ((l
->flags
& (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
)) != (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
))
294 sd_network_link_get_operational_state(l
->ifindex
, &state
);
295 if (state
&& !STR_IN_SET(state
, "unknown", "degraded", "routable"))
298 LIST_FOREACH(addresses
, a
, l
->addresses
)
299 if (a
->family
== family
&& link_address_relevant(a
))
305 LinkAddress
*link_find_address(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
310 LIST_FOREACH(addresses
, a
, l
->addresses
)
311 if (a
->family
== family
&& in_addr_equal(family
, &a
->in_addr
, in_addr
))
317 void link_flush_dns_servers(Link
*l
) {
320 while (l
->dns_servers
)
321 dns_server_unlink(l
->dns_servers
);
324 void link_flush_marked_dns_servers(Link
*l
) {
329 LIST_FOREACH_SAFE(servers
, s
, next
, l
->dns_servers
) {
333 dns_server_unlink(s
);
337 void link_mark_dns_servers(Link
*l
) {
342 LIST_FOREACH(servers
, s
, l
->dns_servers
)
346 DnsServer
* link_find_dns_server(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
352 LIST_FOREACH(servers
, s
, l
->dns_servers
)
353 if (s
->family
== family
&& in_addr_equal(family
, &s
->address
, in_addr
))
358 DnsServer
* link_set_dns_server(Link
*l
, DnsServer
*s
) {
361 if (l
->current_dns_server
== s
)
365 _cleanup_free_
char *ip
= NULL
;
367 in_addr_to_string(s
->family
, &s
->address
, &ip
);
368 log_info("Switching to DNS server %s for interface %s.", strna(ip
), l
->name
);
371 dns_server_unref(l
->current_dns_server
);
372 l
->current_dns_server
= dns_server_ref(s
);
374 if (l
->unicast_scope
)
375 dns_cache_flush(&l
->unicast_scope
->cache
);
380 DnsServer
*link_get_dns_server(Link
*l
) {
383 if (!l
->current_dns_server
)
384 link_set_dns_server(l
, l
->dns_servers
);
386 return l
->current_dns_server
;
389 void link_next_dns_server(Link
*l
) {
392 if (!l
->current_dns_server
)
395 /* Change to the next one, but make sure to follow the linked
396 * list only if this server is actually still linked. */
397 if (l
->current_dns_server
->linked
&& l
->current_dns_server
->servers_next
) {
398 link_set_dns_server(l
, l
->current_dns_server
->servers_next
);
402 link_set_dns_server(l
, l
->dns_servers
);
405 int link_address_new(Link
*l
, LinkAddress
**ret
, int family
, const union in_addr_union
*in_addr
) {
411 a
= new0(LinkAddress
, 1);
416 a
->in_addr
= *in_addr
;
419 LIST_PREPEND(addresses
, l
->addresses
, a
);
427 LinkAddress
*link_address_free(LinkAddress
*a
) {
432 LIST_REMOVE(addresses
, a
->link
->addresses
, a
);
434 if (a
->llmnr_address_rr
) {
435 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
436 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
437 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
438 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
441 if (a
->llmnr_ptr_rr
) {
442 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
443 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
444 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
445 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
449 dns_resource_record_unref(a
->llmnr_address_rr
);
450 dns_resource_record_unref(a
->llmnr_ptr_rr
);
456 void link_address_add_rrs(LinkAddress
*a
, bool force_remove
) {
461 if (a
->family
== AF_INET
) {
464 link_address_relevant(a
) &&
465 a
->link
->llmnr_ipv4_scope
&&
466 a
->link
->llmnr_support
== SUPPORT_YES
&&
467 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
469 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
470 a
->link
->manager
->llmnr_host_ipv4_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, a
->link
->manager
->llmnr_hostname
);
471 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
477 if (!a
->llmnr_address_rr
) {
478 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv4_key
);
479 if (!a
->llmnr_address_rr
) {
484 a
->llmnr_address_rr
->a
.in_addr
= a
->in_addr
.in
;
485 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
488 if (!a
->llmnr_ptr_rr
) {
489 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
493 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
496 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_address_rr
, true);
498 log_warning_errno(r
, "Failed to add A record to LLMNR zone: %m");
500 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_ptr_rr
, false);
502 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
504 if (a
->llmnr_address_rr
) {
505 if (a
->link
->llmnr_ipv4_scope
)
506 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
507 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
510 if (a
->llmnr_ptr_rr
) {
511 if (a
->link
->llmnr_ipv4_scope
)
512 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
513 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
518 if (a
->family
== AF_INET6
) {
521 link_address_relevant(a
) &&
522 a
->link
->llmnr_ipv6_scope
&&
523 a
->link
->llmnr_support
== SUPPORT_YES
&&
524 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
526 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
527 a
->link
->manager
->llmnr_host_ipv6_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, a
->link
->manager
->llmnr_hostname
);
528 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
534 if (!a
->llmnr_address_rr
) {
535 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv6_key
);
536 if (!a
->llmnr_address_rr
) {
541 a
->llmnr_address_rr
->aaaa
.in6_addr
= a
->in_addr
.in6
;
542 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
545 if (!a
->llmnr_ptr_rr
) {
546 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
550 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
553 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_address_rr
, true);
555 log_warning_errno(r
, "Failed to add AAAA record to LLMNR zone: %m");
557 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_ptr_rr
, false);
559 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
561 if (a
->llmnr_address_rr
) {
562 if (a
->link
->llmnr_ipv6_scope
)
563 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
564 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
567 if (a
->llmnr_ptr_rr
) {
568 if (a
->link
->llmnr_ipv6_scope
)
569 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
570 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
578 log_debug_errno(r
, "Failed to update address RRs: %m");
581 int link_address_update_rtnl(LinkAddress
*a
, sd_netlink_message
*m
) {
586 r
= sd_rtnl_message_addr_get_flags(m
, &a
->flags
);
590 sd_rtnl_message_addr_get_scope(m
, &a
->scope
);
592 link_allocate_scopes(a
->link
);
593 link_add_rrs(a
->link
, false);
598 bool link_address_relevant(LinkAddress
*a
) {
601 if (a
->flags
& (IFA_F_DEPRECATED
|IFA_F_TENTATIVE
))
604 if (IN_SET(a
->scope
, RT_SCOPE_HOST
, RT_SCOPE_NOWHERE
))