]>
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
);
71 link_address_free(l
->addresses
);
74 hashmap_remove(l
->manager
->links
, INT_TO_PTR(l
->ifindex
));
76 dns_scope_free(l
->unicast_scope
);
77 dns_scope_free(l
->llmnr_ipv4_scope
);
78 dns_scope_free(l
->llmnr_ipv6_scope
);
84 static void link_allocate_scopes(Link
*l
) {
90 if (!l
->unicast_scope
) {
91 r
= dns_scope_new(l
->manager
, &l
->unicast_scope
, l
, DNS_PROTOCOL_DNS
, AF_UNSPEC
);
93 log_warning_errno(r
, "Failed to allocate DNS scope: %m");
96 l
->unicast_scope
= dns_scope_free(l
->unicast_scope
);
98 if (link_relevant(l
, AF_INET
) &&
99 l
->llmnr_support
!= SUPPORT_NO
&&
100 l
->manager
->llmnr_support
!= SUPPORT_NO
) {
101 if (!l
->llmnr_ipv4_scope
) {
102 r
= dns_scope_new(l
->manager
, &l
->llmnr_ipv4_scope
, l
, DNS_PROTOCOL_LLMNR
, AF_INET
);
104 log_warning_errno(r
, "Failed to allocate LLMNR IPv4 scope: %m");
107 l
->llmnr_ipv4_scope
= dns_scope_free(l
->llmnr_ipv4_scope
);
109 if (link_relevant(l
, AF_INET6
) &&
110 l
->llmnr_support
!= SUPPORT_NO
&&
111 l
->manager
->llmnr_support
!= SUPPORT_NO
&&
112 socket_ipv6_is_supported()) {
113 if (!l
->llmnr_ipv6_scope
) {
114 r
= dns_scope_new(l
->manager
, &l
->llmnr_ipv6_scope
, l
, DNS_PROTOCOL_LLMNR
, AF_INET6
);
116 log_warning_errno(r
, "Failed to allocate LLMNR IPv6 scope: %m");
119 l
->llmnr_ipv6_scope
= dns_scope_free(l
->llmnr_ipv6_scope
);
122 void link_add_rrs(Link
*l
, bool force_remove
) {
125 LIST_FOREACH(addresses
, a
, l
->addresses
)
126 link_address_add_rrs(a
, force_remove
);
129 int link_update_rtnl(Link
*l
, sd_netlink_message
*m
) {
130 const char *n
= NULL
;
136 r
= sd_rtnl_message_link_get_flags(m
, &l
->flags
);
140 sd_netlink_message_read_u32(m
, IFLA_MTU
, &l
->mtu
);
142 if (sd_netlink_message_read_string(m
, IFLA_IFNAME
, &n
) >= 0) {
143 strncpy(l
->name
, n
, sizeof(l
->name
)-1);
144 char_array_0(l
->name
);
147 link_allocate_scopes(l
);
148 link_add_rrs(l
, false);
153 static int link_update_dns_servers(Link
*l
) {
154 _cleanup_strv_free_
char **nameservers
= NULL
;
160 r
= sd_network_link_get_dns(l
->ifindex
, &nameservers
);
164 link_mark_dns_servers(l
);
166 STRV_FOREACH(nameserver
, nameservers
) {
167 union in_addr_union a
;
171 r
= in_addr_from_string_auto(*nameserver
, &family
, &a
);
175 s
= link_find_dns_server(l
, family
, &a
);
179 r
= dns_server_new(l
->manager
, NULL
, DNS_SERVER_LINK
, l
, family
, &a
);
185 link_flush_marked_dns_servers(l
);
189 link_flush_dns_servers(l
);
193 static int link_update_llmnr_support(Link
*l
) {
194 _cleanup_free_
char *b
= NULL
;
199 r
= sd_network_link_get_llmnr(l
->ifindex
, &b
);
203 r
= parse_boolean(b
);
205 if (streq(b
, "resolve"))
206 l
->llmnr_support
= SUPPORT_RESOLVE
;
211 l
->llmnr_support
= SUPPORT_YES
;
213 l
->llmnr_support
= SUPPORT_NO
;
218 l
->llmnr_support
= SUPPORT_YES
;
222 static int link_update_domains(Link
*l
) {
225 if (!l
->unicast_scope
)
228 l
->unicast_scope
->domains
= strv_free(l
->unicast_scope
->domains
);
230 r
= sd_network_link_get_domains(l
->ifindex
,
231 &l
->unicast_scope
->domains
);
238 int link_update_monitor(Link
*l
) {
241 link_update_dns_servers(l
);
242 link_update_llmnr_support(l
);
243 link_allocate_scopes(l
);
244 link_update_domains(l
);
245 link_add_rrs(l
, false);
250 bool link_relevant(Link
*l
, int family
) {
251 _cleanup_free_
char *state
= NULL
;
256 /* A link is relevant if it isn't a loopback or pointopoint
257 * device, has a link beat, can do multicast and has at least
258 * one relevant IP address */
260 if (l
->flags
& (IFF_LOOPBACK
|IFF_POINTOPOINT
|IFF_DORMANT
))
263 if ((l
->flags
& (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
)) != (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
))
266 sd_network_link_get_operational_state(l
->ifindex
, &state
);
267 if (state
&& !STR_IN_SET(state
, "unknown", "degraded", "routable"))
270 LIST_FOREACH(addresses
, a
, l
->addresses
)
271 if (a
->family
== family
&& link_address_relevant(a
))
277 LinkAddress
*link_find_address(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
282 LIST_FOREACH(addresses
, a
, l
->addresses
)
283 if (a
->family
== family
&& in_addr_equal(family
, &a
->in_addr
, in_addr
))
289 void link_flush_dns_servers(Link
*l
) {
292 while (l
->dns_servers
)
293 dns_server_unlink(l
->dns_servers
);
296 void link_flush_marked_dns_servers(Link
*l
) {
301 LIST_FOREACH_SAFE(servers
, s
, next
, l
->dns_servers
) {
305 dns_server_unlink(s
);
309 void link_mark_dns_servers(Link
*l
) {
314 LIST_FOREACH(servers
, s
, l
->dns_servers
)
318 DnsServer
* link_find_dns_server(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
324 LIST_FOREACH(servers
, s
, l
->dns_servers
)
325 if (s
->family
== family
&& in_addr_equal(family
, &s
->address
, in_addr
))
330 DnsServer
* link_set_dns_server(Link
*l
, DnsServer
*s
) {
333 if (l
->current_dns_server
== s
)
337 _cleanup_free_
char *ip
= NULL
;
339 in_addr_to_string(s
->family
, &s
->address
, &ip
);
340 log_info("Switching to DNS server %s for interface %s.", strna(ip
), l
->name
);
343 dns_server_unref(l
->current_dns_server
);
344 l
->current_dns_server
= dns_server_ref(s
);
346 if (l
->unicast_scope
)
347 dns_cache_flush(&l
->unicast_scope
->cache
);
352 DnsServer
*link_get_dns_server(Link
*l
) {
355 if (!l
->current_dns_server
)
356 link_set_dns_server(l
, l
->dns_servers
);
358 return l
->current_dns_server
;
361 void link_next_dns_server(Link
*l
) {
364 if (!l
->current_dns_server
)
367 /* Change to the next one, but make sure to follow the linked
368 * list only if this server is actually still linked. */
369 if (l
->current_dns_server
->linked
&& l
->current_dns_server
->servers_next
) {
370 link_set_dns_server(l
, l
->current_dns_server
->servers_next
);
374 link_set_dns_server(l
, l
->dns_servers
);
377 int link_address_new(Link
*l
, LinkAddress
**ret
, int family
, const union in_addr_union
*in_addr
) {
383 a
= new0(LinkAddress
, 1);
388 a
->in_addr
= *in_addr
;
391 LIST_PREPEND(addresses
, l
->addresses
, a
);
399 LinkAddress
*link_address_free(LinkAddress
*a
) {
404 LIST_REMOVE(addresses
, a
->link
->addresses
, a
);
406 if (a
->llmnr_address_rr
) {
407 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
408 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
409 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
410 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
413 if (a
->llmnr_ptr_rr
) {
414 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
415 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
416 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
417 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
421 dns_resource_record_unref(a
->llmnr_address_rr
);
422 dns_resource_record_unref(a
->llmnr_ptr_rr
);
428 void link_address_add_rrs(LinkAddress
*a
, bool force_remove
) {
433 if (a
->family
== AF_INET
) {
436 link_address_relevant(a
) &&
437 a
->link
->llmnr_ipv4_scope
&&
438 a
->link
->llmnr_support
== SUPPORT_YES
&&
439 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
441 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
442 a
->link
->manager
->llmnr_host_ipv4_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, a
->link
->manager
->llmnr_hostname
);
443 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
449 if (!a
->llmnr_address_rr
) {
450 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv4_key
);
451 if (!a
->llmnr_address_rr
) {
456 a
->llmnr_address_rr
->a
.in_addr
= a
->in_addr
.in
;
457 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
460 if (!a
->llmnr_ptr_rr
) {
461 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
465 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
468 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_address_rr
, true);
470 log_warning_errno(r
, "Failed to add A record to LLMNR zone: %m");
472 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_ptr_rr
, false);
474 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
476 if (a
->llmnr_address_rr
) {
477 if (a
->link
->llmnr_ipv4_scope
)
478 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
479 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
482 if (a
->llmnr_ptr_rr
) {
483 if (a
->link
->llmnr_ipv4_scope
)
484 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
485 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
490 if (a
->family
== AF_INET6
) {
493 link_address_relevant(a
) &&
494 a
->link
->llmnr_ipv6_scope
&&
495 a
->link
->llmnr_support
== SUPPORT_YES
&&
496 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
498 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
499 a
->link
->manager
->llmnr_host_ipv6_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, a
->link
->manager
->llmnr_hostname
);
500 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
506 if (!a
->llmnr_address_rr
) {
507 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv6_key
);
508 if (!a
->llmnr_address_rr
) {
513 a
->llmnr_address_rr
->aaaa
.in6_addr
= a
->in_addr
.in6
;
514 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
517 if (!a
->llmnr_ptr_rr
) {
518 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
522 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
525 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_address_rr
, true);
527 log_warning_errno(r
, "Failed to add AAAA record to LLMNR zone: %m");
529 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_ptr_rr
, false);
531 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
533 if (a
->llmnr_address_rr
) {
534 if (a
->link
->llmnr_ipv6_scope
)
535 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
536 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
539 if (a
->llmnr_ptr_rr
) {
540 if (a
->link
->llmnr_ipv6_scope
)
541 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
542 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
550 log_debug_errno(r
, "Failed to update address RRs: %m");
553 int link_address_update_rtnl(LinkAddress
*a
, sd_netlink_message
*m
) {
558 r
= sd_rtnl_message_addr_get_flags(m
, &a
->flags
);
562 sd_rtnl_message_addr_get_scope(m
, &a
->scope
);
564 link_allocate_scopes(a
->link
);
565 link_add_rrs(a
->link
, false);
570 bool link_address_relevant(LinkAddress
*a
) {
573 if (a
->flags
& (IFA_F_DEPRECATED
|IFA_F_TENTATIVE
))
576 if (IN_SET(a
->scope
, RT_SCOPE_HOST
, RT_SCOPE_NOWHERE
))