]>
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"
27 #include "resolved-link.h"
29 int link_new(Manager
*m
, Link
**ret
, int ifindex
) {
30 _cleanup_(link_freep
) Link
*l
= NULL
;
36 r
= hashmap_ensure_allocated(&m
->links
, NULL
);
45 l
->llmnr_support
= SUPPORT_YES
;
47 r
= hashmap_put(m
->links
, INT_TO_PTR(ifindex
), l
);
60 Link
*link_free(Link
*l
) {
65 link_address_free(l
->addresses
);
68 hashmap_remove(l
->manager
->links
, INT_TO_PTR(l
->ifindex
));
70 while (l
->dns_servers
) {
71 DnsServer
*s
= l
->dns_servers
;
73 LIST_REMOVE(servers
, l
->dns_servers
, s
);
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
;
162 r
= sd_network_link_get_dns(l
->ifindex
, &nameservers
);
166 LIST_FOREACH(servers
, s
, l
->dns_servers
)
169 STRV_FOREACH(nameserver
, nameservers
) {
170 union in_addr_union a
;
173 r
= in_addr_from_string_auto(*nameserver
, &family
, &a
);
177 s
= link_find_dns_server(l
, family
, &a
);
181 r
= dns_server_new(l
->manager
, NULL
, DNS_SERVER_LINK
, l
, family
, &a
);
187 LIST_FOREACH_SAFE(servers
, s
, nx
, l
->dns_servers
)
189 LIST_REMOVE(servers
, l
->dns_servers
, s
);
196 while (l
->dns_servers
) {
199 LIST_REMOVE(servers
, l
->dns_servers
, s
);
206 static int link_update_llmnr_support(Link
*l
) {
207 _cleanup_free_
char *b
= NULL
;
212 r
= sd_network_link_get_llmnr(l
->ifindex
, &b
);
216 r
= parse_boolean(b
);
218 if (streq(b
, "resolve"))
219 l
->llmnr_support
= SUPPORT_RESOLVE
;
224 l
->llmnr_support
= SUPPORT_YES
;
226 l
->llmnr_support
= SUPPORT_NO
;
231 l
->llmnr_support
= SUPPORT_YES
;
235 static int link_update_domains(Link
*l
) {
238 if (!l
->unicast_scope
)
241 strv_free(l
->unicast_scope
->domains
);
242 l
->unicast_scope
->domains
= NULL
;
244 r
= sd_network_link_get_domains(l
->ifindex
,
245 &l
->unicast_scope
->domains
);
252 int link_update_monitor(Link
*l
) {
255 link_update_dns_servers(l
);
256 link_update_llmnr_support(l
);
257 link_allocate_scopes(l
);
258 link_update_domains(l
);
259 link_add_rrs(l
, false);
264 bool link_relevant(Link
*l
, int family
) {
265 _cleanup_free_
char *state
= NULL
;
270 /* A link is relevant if it isn't a loopback or pointopoint
271 * device, has a link beat, can do multicast and has at least
272 * one relevant IP address */
274 if (l
->flags
& (IFF_LOOPBACK
|IFF_POINTOPOINT
|IFF_DORMANT
))
277 if ((l
->flags
& (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
)) != (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
))
280 sd_network_link_get_operational_state(l
->ifindex
, &state
);
281 if (state
&& !STR_IN_SET(state
, "unknown", "degraded", "routable"))
284 LIST_FOREACH(addresses
, a
, l
->addresses
)
285 if (a
->family
== family
&& link_address_relevant(a
))
291 LinkAddress
*link_find_address(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
296 LIST_FOREACH(addresses
, a
, l
->addresses
)
297 if (a
->family
== family
&& in_addr_equal(family
, &a
->in_addr
, in_addr
))
303 DnsServer
* link_find_dns_server(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
308 LIST_FOREACH(servers
, s
, l
->dns_servers
)
309 if (s
->family
== family
&& in_addr_equal(family
, &s
->address
, in_addr
))
314 DnsServer
* link_set_dns_server(Link
*l
, DnsServer
*s
) {
317 if (l
->current_dns_server
== s
)
321 _cleanup_free_
char *ip
= NULL
;
323 in_addr_to_string(s
->family
, &s
->address
, &ip
);
324 log_info("Switching to DNS server %s for interface %s.", strna(ip
), l
->name
);
327 l
->current_dns_server
= s
;
329 if (l
->unicast_scope
)
330 dns_cache_flush(&l
->unicast_scope
->cache
);
335 DnsServer
*link_get_dns_server(Link
*l
) {
338 if (!l
->current_dns_server
)
339 link_set_dns_server(l
, l
->dns_servers
);
341 return l
->current_dns_server
;
344 void link_next_dns_server(Link
*l
) {
347 if (!l
->current_dns_server
)
350 if (l
->current_dns_server
->servers_next
) {
351 link_set_dns_server(l
, l
->current_dns_server
->servers_next
);
355 link_set_dns_server(l
, l
->dns_servers
);
358 int link_address_new(Link
*l
, LinkAddress
**ret
, int family
, const union in_addr_union
*in_addr
) {
364 a
= new0(LinkAddress
, 1);
369 a
->in_addr
= *in_addr
;
372 LIST_PREPEND(addresses
, l
->addresses
, a
);
380 LinkAddress
*link_address_free(LinkAddress
*a
) {
385 LIST_REMOVE(addresses
, a
->link
->addresses
, a
);
387 if (a
->llmnr_address_rr
) {
388 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
389 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
390 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
391 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
394 if (a
->llmnr_ptr_rr
) {
395 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
396 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
397 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
398 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
402 dns_resource_record_unref(a
->llmnr_address_rr
);
403 dns_resource_record_unref(a
->llmnr_ptr_rr
);
409 void link_address_add_rrs(LinkAddress
*a
, bool force_remove
) {
414 if (a
->family
== AF_INET
) {
417 link_address_relevant(a
) &&
418 a
->link
->llmnr_ipv4_scope
&&
419 a
->link
->llmnr_support
== SUPPORT_YES
&&
420 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
422 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
423 a
->link
->manager
->llmnr_host_ipv4_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, a
->link
->manager
->llmnr_hostname
);
424 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
430 if (!a
->llmnr_address_rr
) {
431 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv4_key
);
432 if (!a
->llmnr_address_rr
) {
437 a
->llmnr_address_rr
->a
.in_addr
= a
->in_addr
.in
;
438 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
441 if (!a
->llmnr_ptr_rr
) {
442 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
446 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
449 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_address_rr
, true);
451 log_warning_errno(r
, "Failed to add A record to LLMNR zone: %m");
453 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_ptr_rr
, false);
455 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
457 if (a
->llmnr_address_rr
) {
458 if (a
->link
->llmnr_ipv4_scope
)
459 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
460 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
463 if (a
->llmnr_ptr_rr
) {
464 if (a
->link
->llmnr_ipv4_scope
)
465 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
466 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
471 if (a
->family
== AF_INET6
) {
474 link_address_relevant(a
) &&
475 a
->link
->llmnr_ipv6_scope
&&
476 a
->link
->llmnr_support
== SUPPORT_YES
&&
477 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
479 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
480 a
->link
->manager
->llmnr_host_ipv6_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, a
->link
->manager
->llmnr_hostname
);
481 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
487 if (!a
->llmnr_address_rr
) {
488 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv6_key
);
489 if (!a
->llmnr_address_rr
) {
494 a
->llmnr_address_rr
->aaaa
.in6_addr
= a
->in_addr
.in6
;
495 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
498 if (!a
->llmnr_ptr_rr
) {
499 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
503 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
506 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_address_rr
, true);
508 log_warning_errno(r
, "Failed to add AAAA record to LLMNR zone: %m");
510 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_ptr_rr
, false);
512 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
514 if (a
->llmnr_address_rr
) {
515 if (a
->link
->llmnr_ipv6_scope
)
516 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
517 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
520 if (a
->llmnr_ptr_rr
) {
521 if (a
->link
->llmnr_ipv6_scope
)
522 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
523 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
531 log_debug_errno(r
, "Failed to update address RRs: %m");
534 int link_address_update_rtnl(LinkAddress
*a
, sd_netlink_message
*m
) {
539 r
= sd_rtnl_message_addr_get_flags(m
, &a
->flags
);
543 sd_rtnl_message_addr_get_scope(m
, &a
->scope
);
545 link_allocate_scopes(a
->link
);
546 link_add_rrs(a
->link
, false);
551 bool link_address_relevant(LinkAddress
*a
) {
554 if (a
->flags
& (IFA_F_DEPRECATED
|IFA_F_TENTATIVE
))
557 if (IN_SET(a
->scope
, RT_SCOPE_HOST
, RT_SCOPE_NOWHERE
))