]>
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 dns_server_unlink_marked(l
->dns_servers
);
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
);
80 dns_scope_free(l
->mdns_ipv4_scope
);
81 dns_scope_free(l
->mdns_ipv6_scope
);
87 static void link_allocate_scopes(Link
*l
) {
93 if (!l
->unicast_scope
) {
94 r
= dns_scope_new(l
->manager
, &l
->unicast_scope
, l
, DNS_PROTOCOL_DNS
, AF_UNSPEC
);
96 log_warning_errno(r
, "Failed to allocate DNS scope: %m");
99 l
->unicast_scope
= dns_scope_free(l
->unicast_scope
);
101 if (link_relevant(l
, AF_INET
) &&
102 l
->llmnr_support
!= SUPPORT_NO
&&
103 l
->manager
->llmnr_support
!= SUPPORT_NO
) {
104 if (!l
->llmnr_ipv4_scope
) {
105 r
= dns_scope_new(l
->manager
, &l
->llmnr_ipv4_scope
, l
, DNS_PROTOCOL_LLMNR
, AF_INET
);
107 log_warning_errno(r
, "Failed to allocate LLMNR IPv4 scope: %m");
110 l
->llmnr_ipv4_scope
= dns_scope_free(l
->llmnr_ipv4_scope
);
112 if (link_relevant(l
, AF_INET6
) &&
113 l
->llmnr_support
!= SUPPORT_NO
&&
114 l
->manager
->llmnr_support
!= SUPPORT_NO
&&
115 socket_ipv6_is_supported()) {
116 if (!l
->llmnr_ipv6_scope
) {
117 r
= dns_scope_new(l
->manager
, &l
->llmnr_ipv6_scope
, l
, DNS_PROTOCOL_LLMNR
, AF_INET6
);
119 log_warning_errno(r
, "Failed to allocate LLMNR IPv6 scope: %m");
122 l
->llmnr_ipv6_scope
= dns_scope_free(l
->llmnr_ipv6_scope
);
124 if (link_relevant(l
, AF_INET
) &&
125 l
->mdns_support
!= SUPPORT_NO
&&
126 l
->manager
->mdns_support
!= SUPPORT_NO
) {
127 if (!l
->mdns_ipv4_scope
) {
128 r
= dns_scope_new(l
->manager
, &l
->mdns_ipv4_scope
, l
, DNS_PROTOCOL_MDNS
, AF_INET
);
130 log_warning_errno(r
, "Failed to allocate mDNS IPv4 scope: %m");
133 l
->mdns_ipv4_scope
= dns_scope_free(l
->mdns_ipv4_scope
);
135 if (link_relevant(l
, AF_INET6
) &&
136 l
->mdns_support
!= SUPPORT_NO
&&
137 l
->manager
->mdns_support
!= SUPPORT_NO
) {
138 if (!l
->mdns_ipv6_scope
) {
139 r
= dns_scope_new(l
->manager
, &l
->mdns_ipv6_scope
, l
, DNS_PROTOCOL_MDNS
, AF_INET6
);
141 log_warning_errno(r
, "Failed to allocate mDNS IPv6 scope: %m");
144 l
->mdns_ipv6_scope
= dns_scope_free(l
->mdns_ipv6_scope
);
147 void link_add_rrs(Link
*l
, bool force_remove
) {
150 LIST_FOREACH(addresses
, a
, l
->addresses
)
151 link_address_add_rrs(a
, force_remove
);
154 int link_update_rtnl(Link
*l
, sd_netlink_message
*m
) {
155 const char *n
= NULL
;
161 r
= sd_rtnl_message_link_get_flags(m
, &l
->flags
);
165 sd_netlink_message_read_u32(m
, IFLA_MTU
, &l
->mtu
);
167 if (sd_netlink_message_read_string(m
, IFLA_IFNAME
, &n
) >= 0) {
168 strncpy(l
->name
, n
, sizeof(l
->name
)-1);
169 char_array_0(l
->name
);
172 link_allocate_scopes(l
);
173 link_add_rrs(l
, false);
178 static int link_update_dns_servers(Link
*l
) {
179 _cleanup_strv_free_
char **nameservers
= NULL
;
185 r
= sd_network_link_get_dns(l
->ifindex
, &nameservers
);
193 dns_server_mark_all(l
->dns_servers
);
195 STRV_FOREACH(nameserver
, nameservers
) {
196 union in_addr_union a
;
200 r
= in_addr_from_string_auto(*nameserver
, &family
, &a
);
204 s
= dns_server_find(l
->dns_servers
, family
, &a
);
206 dns_server_move_back_and_unmark(s
);
208 r
= dns_server_new(l
->manager
, NULL
, DNS_SERVER_LINK
, l
, family
, &a
);
214 dns_server_unlink_marked(l
->dns_servers
);
218 dns_server_unlink_all(l
->dns_servers
);
222 static int link_update_llmnr_support(Link
*l
) {
223 _cleanup_free_
char *b
= NULL
;
228 r
= sd_network_link_get_llmnr(l
->ifindex
, &b
);
236 r
= parse_boolean(b
);
238 if (streq(b
, "resolve"))
239 l
->llmnr_support
= SUPPORT_RESOLVE
;
244 l
->llmnr_support
= SUPPORT_YES
;
246 l
->llmnr_support
= SUPPORT_NO
;
251 l
->llmnr_support
= SUPPORT_YES
;
255 static int link_update_search_domains(Link
*l
) {
256 _cleanup_strv_free_
char **domains
= NULL
;
262 r
= sd_network_link_get_domains(l
->ifindex
, &domains
);
264 /* networkd knows nothing about this interface, and that's fine. */
271 dns_search_domain_mark_all(l
->search_domains
);
273 STRV_FOREACH(i
, domains
) {
276 r
= dns_search_domain_find(l
->search_domains
, *i
, &d
);
281 dns_search_domain_move_back_and_unmark(d
);
283 r
= dns_search_domain_new(l
->manager
, NULL
, DNS_SEARCH_DOMAIN_LINK
, l
, *i
);
289 dns_search_domain_unlink_marked(l
->search_domains
);
293 dns_search_domain_unlink_all(l
->search_domains
);
297 int link_update_monitor(Link
*l
) {
302 link_update_dns_servers(l
);
303 link_update_llmnr_support(l
);
304 link_allocate_scopes(l
);
306 r
= link_update_search_domains(l
);
308 log_warning_errno(r
, "Failed to read search domains for interface %s, ignoring: %m", l
->name
);
310 link_add_rrs(l
, false);
315 bool link_relevant(Link
*l
, int family
) {
316 _cleanup_free_
char *state
= NULL
;
321 /* A link is relevant if it isn't a loopback or pointopoint
322 * device, has a link beat, can do multicast and has at least
323 * one relevant IP address */
325 if (l
->flags
& (IFF_LOOPBACK
|IFF_POINTOPOINT
|IFF_DORMANT
))
328 if ((l
->flags
& (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
)) != (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
))
331 sd_network_link_get_operational_state(l
->ifindex
, &state
);
332 if (state
&& !STR_IN_SET(state
, "unknown", "degraded", "routable"))
335 LIST_FOREACH(addresses
, a
, l
->addresses
)
336 if (a
->family
== family
&& link_address_relevant(a
))
342 LinkAddress
*link_find_address(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
347 LIST_FOREACH(addresses
, a
, l
->addresses
)
348 if (a
->family
== family
&& in_addr_equal(family
, &a
->in_addr
, in_addr
))
354 DnsServer
* link_set_dns_server(Link
*l
, DnsServer
*s
) {
357 if (l
->current_dns_server
== s
)
361 _cleanup_free_
char *ip
= NULL
;
363 in_addr_to_string(s
->family
, &s
->address
, &ip
);
364 log_info("Switching to DNS server %s for interface %s.", strna(ip
), l
->name
);
367 dns_server_unref(l
->current_dns_server
);
368 l
->current_dns_server
= dns_server_ref(s
);
370 if (l
->unicast_scope
)
371 dns_cache_flush(&l
->unicast_scope
->cache
);
376 DnsServer
*link_get_dns_server(Link
*l
) {
379 if (!l
->current_dns_server
)
380 link_set_dns_server(l
, l
->dns_servers
);
382 return l
->current_dns_server
;
385 void link_next_dns_server(Link
*l
) {
388 if (!l
->current_dns_server
)
391 /* Change to the next one, but make sure to follow the linked
392 * list only if this server is actually still linked. */
393 if (l
->current_dns_server
->linked
&& l
->current_dns_server
->servers_next
) {
394 link_set_dns_server(l
, l
->current_dns_server
->servers_next
);
398 link_set_dns_server(l
, l
->dns_servers
);
401 int link_address_new(Link
*l
, LinkAddress
**ret
, int family
, const union in_addr_union
*in_addr
) {
407 a
= new0(LinkAddress
, 1);
412 a
->in_addr
= *in_addr
;
415 LIST_PREPEND(addresses
, l
->addresses
, a
);
423 LinkAddress
*link_address_free(LinkAddress
*a
) {
428 LIST_REMOVE(addresses
, a
->link
->addresses
, a
);
430 if (a
->llmnr_address_rr
) {
431 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
432 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
433 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
434 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
437 if (a
->llmnr_ptr_rr
) {
438 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
439 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
440 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
441 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
445 dns_resource_record_unref(a
->llmnr_address_rr
);
446 dns_resource_record_unref(a
->llmnr_ptr_rr
);
452 void link_address_add_rrs(LinkAddress
*a
, bool force_remove
) {
457 if (a
->family
== AF_INET
) {
460 link_address_relevant(a
) &&
461 a
->link
->llmnr_ipv4_scope
&&
462 a
->link
->llmnr_support
== SUPPORT_YES
&&
463 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
465 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
466 a
->link
->manager
->llmnr_host_ipv4_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, a
->link
->manager
->llmnr_hostname
);
467 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
473 if (!a
->llmnr_address_rr
) {
474 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv4_key
);
475 if (!a
->llmnr_address_rr
) {
480 a
->llmnr_address_rr
->a
.in_addr
= a
->in_addr
.in
;
481 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
484 if (!a
->llmnr_ptr_rr
) {
485 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
489 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
492 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_address_rr
, true);
494 log_warning_errno(r
, "Failed to add A record to LLMNR zone: %m");
496 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_ptr_rr
, false);
498 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
500 if (a
->llmnr_address_rr
) {
501 if (a
->link
->llmnr_ipv4_scope
)
502 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
503 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
506 if (a
->llmnr_ptr_rr
) {
507 if (a
->link
->llmnr_ipv4_scope
)
508 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
509 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
514 if (a
->family
== AF_INET6
) {
517 link_address_relevant(a
) &&
518 a
->link
->llmnr_ipv6_scope
&&
519 a
->link
->llmnr_support
== SUPPORT_YES
&&
520 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
522 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
523 a
->link
->manager
->llmnr_host_ipv6_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, a
->link
->manager
->llmnr_hostname
);
524 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
530 if (!a
->llmnr_address_rr
) {
531 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv6_key
);
532 if (!a
->llmnr_address_rr
) {
537 a
->llmnr_address_rr
->aaaa
.in6_addr
= a
->in_addr
.in6
;
538 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
541 if (!a
->llmnr_ptr_rr
) {
542 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
546 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
549 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_address_rr
, true);
551 log_warning_errno(r
, "Failed to add AAAA record to LLMNR zone: %m");
553 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_ptr_rr
, false);
555 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
557 if (a
->llmnr_address_rr
) {
558 if (a
->link
->llmnr_ipv6_scope
)
559 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
560 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
563 if (a
->llmnr_ptr_rr
) {
564 if (a
->link
->llmnr_ipv6_scope
)
565 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
566 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
574 log_debug_errno(r
, "Failed to update address RRs: %m");
577 int link_address_update_rtnl(LinkAddress
*a
, sd_netlink_message
*m
) {
582 r
= sd_rtnl_message_addr_get_flags(m
, &a
->flags
);
586 sd_rtnl_message_addr_get_scope(m
, &a
->scope
);
588 link_allocate_scopes(a
->link
);
589 link_add_rrs(a
->link
, false);
594 bool link_address_relevant(LinkAddress
*a
) {
597 if (a
->flags
& (IFA_F_DEPRECATED
|IFA_F_TENTATIVE
))
600 if (IN_SET(a
->scope
, RT_SCOPE_HOST
, RT_SCOPE_NOWHERE
))