]>
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 l
->unicast_scope
->domains
= strv_free(l
->unicast_scope
->domains
);
243 r
= sd_network_link_get_domains(l
->ifindex
,
244 &l
->unicast_scope
->domains
);
251 int link_update_monitor(Link
*l
) {
254 link_update_dns_servers(l
);
255 link_update_llmnr_support(l
);
256 link_allocate_scopes(l
);
257 link_update_domains(l
);
258 link_add_rrs(l
, false);
263 bool link_relevant(Link
*l
, int family
) {
264 _cleanup_free_
char *state
= NULL
;
269 /* A link is relevant if it isn't a loopback or pointopoint
270 * device, has a link beat, can do multicast and has at least
271 * one relevant IP address */
273 if (l
->flags
& (IFF_LOOPBACK
|IFF_POINTOPOINT
|IFF_DORMANT
))
276 if ((l
->flags
& (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
)) != (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
))
279 sd_network_link_get_operational_state(l
->ifindex
, &state
);
280 if (state
&& !STR_IN_SET(state
, "unknown", "degraded", "routable"))
283 LIST_FOREACH(addresses
, a
, l
->addresses
)
284 if (a
->family
== family
&& link_address_relevant(a
))
290 LinkAddress
*link_find_address(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
295 LIST_FOREACH(addresses
, a
, l
->addresses
)
296 if (a
->family
== family
&& in_addr_equal(family
, &a
->in_addr
, in_addr
))
302 DnsServer
* link_find_dns_server(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
307 LIST_FOREACH(servers
, s
, l
->dns_servers
)
308 if (s
->family
== family
&& in_addr_equal(family
, &s
->address
, in_addr
))
313 DnsServer
* link_set_dns_server(Link
*l
, DnsServer
*s
) {
316 if (l
->current_dns_server
== s
)
320 _cleanup_free_
char *ip
= NULL
;
322 in_addr_to_string(s
->family
, &s
->address
, &ip
);
323 log_info("Switching to DNS server %s for interface %s.", strna(ip
), l
->name
);
326 l
->current_dns_server
= s
;
328 if (l
->unicast_scope
)
329 dns_cache_flush(&l
->unicast_scope
->cache
);
334 DnsServer
*link_get_dns_server(Link
*l
) {
337 if (!l
->current_dns_server
)
338 link_set_dns_server(l
, l
->dns_servers
);
340 return l
->current_dns_server
;
343 void link_next_dns_server(Link
*l
) {
346 if (!l
->current_dns_server
)
349 if (l
->current_dns_server
->servers_next
) {
350 link_set_dns_server(l
, l
->current_dns_server
->servers_next
);
354 link_set_dns_server(l
, l
->dns_servers
);
357 int link_address_new(Link
*l
, LinkAddress
**ret
, int family
, const union in_addr_union
*in_addr
) {
363 a
= new0(LinkAddress
, 1);
368 a
->in_addr
= *in_addr
;
371 LIST_PREPEND(addresses
, l
->addresses
, a
);
379 LinkAddress
*link_address_free(LinkAddress
*a
) {
384 LIST_REMOVE(addresses
, a
->link
->addresses
, a
);
386 if (a
->llmnr_address_rr
) {
387 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
388 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
389 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
390 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
393 if (a
->llmnr_ptr_rr
) {
394 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
395 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
396 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
397 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
401 dns_resource_record_unref(a
->llmnr_address_rr
);
402 dns_resource_record_unref(a
->llmnr_ptr_rr
);
408 void link_address_add_rrs(LinkAddress
*a
, bool force_remove
) {
413 if (a
->family
== AF_INET
) {
416 link_address_relevant(a
) &&
417 a
->link
->llmnr_ipv4_scope
&&
418 a
->link
->llmnr_support
== SUPPORT_YES
&&
419 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
421 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
422 a
->link
->manager
->llmnr_host_ipv4_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, a
->link
->manager
->llmnr_hostname
);
423 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
429 if (!a
->llmnr_address_rr
) {
430 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv4_key
);
431 if (!a
->llmnr_address_rr
) {
436 a
->llmnr_address_rr
->a
.in_addr
= a
->in_addr
.in
;
437 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
440 if (!a
->llmnr_ptr_rr
) {
441 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
445 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
448 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_address_rr
, true);
450 log_warning_errno(r
, "Failed to add A record to LLMNR zone: %m");
452 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_ptr_rr
, false);
454 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
456 if (a
->llmnr_address_rr
) {
457 if (a
->link
->llmnr_ipv4_scope
)
458 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
459 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
462 if (a
->llmnr_ptr_rr
) {
463 if (a
->link
->llmnr_ipv4_scope
)
464 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
465 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
470 if (a
->family
== AF_INET6
) {
473 link_address_relevant(a
) &&
474 a
->link
->llmnr_ipv6_scope
&&
475 a
->link
->llmnr_support
== SUPPORT_YES
&&
476 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
478 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
479 a
->link
->manager
->llmnr_host_ipv6_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, a
->link
->manager
->llmnr_hostname
);
480 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
486 if (!a
->llmnr_address_rr
) {
487 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv6_key
);
488 if (!a
->llmnr_address_rr
) {
493 a
->llmnr_address_rr
->aaaa
.in6_addr
= a
->in_addr
.in6
;
494 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
497 if (!a
->llmnr_ptr_rr
) {
498 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
502 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
505 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_address_rr
, true);
507 log_warning_errno(r
, "Failed to add AAAA record to LLMNR zone: %m");
509 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_ptr_rr
, false);
511 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
513 if (a
->llmnr_address_rr
) {
514 if (a
->link
->llmnr_ipv6_scope
)
515 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
516 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
519 if (a
->llmnr_ptr_rr
) {
520 if (a
->link
->llmnr_ipv6_scope
)
521 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
522 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
530 log_debug_errno(r
, "Failed to update address RRs: %m");
533 int link_address_update_rtnl(LinkAddress
*a
, sd_netlink_message
*m
) {
538 r
= sd_rtnl_message_addr_get_flags(m
, &a
->flags
);
542 sd_rtnl_message_addr_get_scope(m
, &a
->scope
);
544 link_allocate_scopes(a
->link
);
545 link_add_rrs(a
->link
, false);
550 bool link_address_relevant(LinkAddress
*a
) {
553 if (a
->flags
& (IFA_F_DEPRECATED
|IFA_F_TENTATIVE
))
556 if (IN_SET(a
->scope
, RT_SCOPE_HOST
, RT_SCOPE_NOWHERE
))