]>
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"
28 #include "string-util.h"
31 int link_new(Manager
*m
, Link
**ret
, int ifindex
) {
32 _cleanup_(link_freep
) Link
*l
= NULL
;
38 r
= hashmap_ensure_allocated(&m
->links
, NULL
);
47 l
->llmnr_support
= SUPPORT_YES
;
49 r
= hashmap_put(m
->links
, INT_TO_PTR(ifindex
), l
);
62 Link
*link_free(Link
*l
) {
67 link_address_free(l
->addresses
);
70 hashmap_remove(l
->manager
->links
, INT_TO_PTR(l
->ifindex
));
72 while (l
->dns_servers
) {
73 DnsServer
*s
= l
->dns_servers
;
75 LIST_REMOVE(servers
, l
->dns_servers
, s
);
79 dns_scope_free(l
->unicast_scope
);
80 dns_scope_free(l
->llmnr_ipv4_scope
);
81 dns_scope_free(l
->llmnr_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
);
125 void link_add_rrs(Link
*l
, bool force_remove
) {
128 LIST_FOREACH(addresses
, a
, l
->addresses
)
129 link_address_add_rrs(a
, force_remove
);
132 int link_update_rtnl(Link
*l
, sd_netlink_message
*m
) {
133 const char *n
= NULL
;
139 r
= sd_rtnl_message_link_get_flags(m
, &l
->flags
);
143 sd_netlink_message_read_u32(m
, IFLA_MTU
, &l
->mtu
);
145 if (sd_netlink_message_read_string(m
, IFLA_IFNAME
, &n
) >= 0) {
146 strncpy(l
->name
, n
, sizeof(l
->name
)-1);
147 char_array_0(l
->name
);
150 link_allocate_scopes(l
);
151 link_add_rrs(l
, false);
156 static int link_update_dns_servers(Link
*l
) {
157 _cleanup_strv_free_
char **nameservers
= NULL
;
164 r
= sd_network_link_get_dns(l
->ifindex
, &nameservers
);
168 LIST_FOREACH(servers
, s
, l
->dns_servers
)
171 STRV_FOREACH(nameserver
, nameservers
) {
172 union in_addr_union a
;
175 r
= in_addr_from_string_auto(*nameserver
, &family
, &a
);
179 s
= link_find_dns_server(l
, family
, &a
);
183 r
= dns_server_new(l
->manager
, NULL
, DNS_SERVER_LINK
, l
, family
, &a
);
189 LIST_FOREACH_SAFE(servers
, s
, nx
, l
->dns_servers
)
191 LIST_REMOVE(servers
, l
->dns_servers
, s
);
198 while (l
->dns_servers
) {
201 LIST_REMOVE(servers
, l
->dns_servers
, s
);
208 static int link_update_llmnr_support(Link
*l
) {
209 _cleanup_free_
char *b
= NULL
;
214 r
= sd_network_link_get_llmnr(l
->ifindex
, &b
);
218 r
= parse_boolean(b
);
220 if (streq(b
, "resolve"))
221 l
->llmnr_support
= SUPPORT_RESOLVE
;
226 l
->llmnr_support
= SUPPORT_YES
;
228 l
->llmnr_support
= SUPPORT_NO
;
233 l
->llmnr_support
= SUPPORT_YES
;
237 static int link_update_domains(Link
*l
) {
240 if (!l
->unicast_scope
)
243 l
->unicast_scope
->domains
= strv_free(l
->unicast_scope
->domains
);
245 r
= sd_network_link_get_domains(l
->ifindex
,
246 &l
->unicast_scope
->domains
);
253 int link_update_monitor(Link
*l
) {
256 link_update_dns_servers(l
);
257 link_update_llmnr_support(l
);
258 link_allocate_scopes(l
);
259 link_update_domains(l
);
260 link_add_rrs(l
, false);
265 bool link_relevant(Link
*l
, int family
) {
266 _cleanup_free_
char *state
= NULL
;
271 /* A link is relevant if it isn't a loopback or pointopoint
272 * device, has a link beat, can do multicast and has at least
273 * one relevant IP address */
275 if (l
->flags
& (IFF_LOOPBACK
|IFF_POINTOPOINT
|IFF_DORMANT
))
278 if ((l
->flags
& (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
)) != (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
))
281 sd_network_link_get_operational_state(l
->ifindex
, &state
);
282 if (state
&& !STR_IN_SET(state
, "unknown", "degraded", "routable"))
285 LIST_FOREACH(addresses
, a
, l
->addresses
)
286 if (a
->family
== family
&& link_address_relevant(a
))
292 LinkAddress
*link_find_address(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
297 LIST_FOREACH(addresses
, a
, l
->addresses
)
298 if (a
->family
== family
&& in_addr_equal(family
, &a
->in_addr
, in_addr
))
304 DnsServer
* link_find_dns_server(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
309 LIST_FOREACH(servers
, s
, l
->dns_servers
)
310 if (s
->family
== family
&& in_addr_equal(family
, &s
->address
, in_addr
))
315 DnsServer
* link_set_dns_server(Link
*l
, DnsServer
*s
) {
318 if (l
->current_dns_server
== s
)
322 _cleanup_free_
char *ip
= NULL
;
324 in_addr_to_string(s
->family
, &s
->address
, &ip
);
325 log_info("Switching to DNS server %s for interface %s.", strna(ip
), l
->name
);
328 l
->current_dns_server
= s
;
330 if (l
->unicast_scope
)
331 dns_cache_flush(&l
->unicast_scope
->cache
);
336 DnsServer
*link_get_dns_server(Link
*l
) {
339 if (!l
->current_dns_server
)
340 link_set_dns_server(l
, l
->dns_servers
);
342 return l
->current_dns_server
;
345 void link_next_dns_server(Link
*l
) {
348 if (!l
->current_dns_server
)
351 if (l
->current_dns_server
->servers_next
) {
352 link_set_dns_server(l
, l
->current_dns_server
->servers_next
);
356 link_set_dns_server(l
, l
->dns_servers
);
359 int link_address_new(Link
*l
, LinkAddress
**ret
, int family
, const union in_addr_union
*in_addr
) {
365 a
= new0(LinkAddress
, 1);
370 a
->in_addr
= *in_addr
;
373 LIST_PREPEND(addresses
, l
->addresses
, a
);
381 LinkAddress
*link_address_free(LinkAddress
*a
) {
386 LIST_REMOVE(addresses
, a
->link
->addresses
, a
);
388 if (a
->llmnr_address_rr
) {
389 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
390 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
391 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
392 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
395 if (a
->llmnr_ptr_rr
) {
396 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
397 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
398 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
399 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
403 dns_resource_record_unref(a
->llmnr_address_rr
);
404 dns_resource_record_unref(a
->llmnr_ptr_rr
);
410 void link_address_add_rrs(LinkAddress
*a
, bool force_remove
) {
415 if (a
->family
== AF_INET
) {
418 link_address_relevant(a
) &&
419 a
->link
->llmnr_ipv4_scope
&&
420 a
->link
->llmnr_support
== SUPPORT_YES
&&
421 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
423 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
424 a
->link
->manager
->llmnr_host_ipv4_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, a
->link
->manager
->llmnr_hostname
);
425 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
431 if (!a
->llmnr_address_rr
) {
432 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv4_key
);
433 if (!a
->llmnr_address_rr
) {
438 a
->llmnr_address_rr
->a
.in_addr
= a
->in_addr
.in
;
439 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
442 if (!a
->llmnr_ptr_rr
) {
443 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
447 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
450 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_address_rr
, true);
452 log_warning_errno(r
, "Failed to add A record to LLMNR zone: %m");
454 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_ptr_rr
, false);
456 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
458 if (a
->llmnr_address_rr
) {
459 if (a
->link
->llmnr_ipv4_scope
)
460 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
461 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
464 if (a
->llmnr_ptr_rr
) {
465 if (a
->link
->llmnr_ipv4_scope
)
466 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
467 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
472 if (a
->family
== AF_INET6
) {
475 link_address_relevant(a
) &&
476 a
->link
->llmnr_ipv6_scope
&&
477 a
->link
->llmnr_support
== SUPPORT_YES
&&
478 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
480 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
481 a
->link
->manager
->llmnr_host_ipv6_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, a
->link
->manager
->llmnr_hostname
);
482 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
488 if (!a
->llmnr_address_rr
) {
489 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv6_key
);
490 if (!a
->llmnr_address_rr
) {
495 a
->llmnr_address_rr
->aaaa
.in6_addr
= a
->in_addr
.in6
;
496 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
499 if (!a
->llmnr_ptr_rr
) {
500 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
504 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
507 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_address_rr
, true);
509 log_warning_errno(r
, "Failed to add AAAA record to LLMNR zone: %m");
511 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_ptr_rr
, false);
513 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
515 if (a
->llmnr_address_rr
) {
516 if (a
->link
->llmnr_ipv6_scope
)
517 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
518 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
521 if (a
->llmnr_ptr_rr
) {
522 if (a
->link
->llmnr_ipv6_scope
)
523 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
524 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
532 log_debug_errno(r
, "Failed to update address RRs: %m");
535 int link_address_update_rtnl(LinkAddress
*a
, sd_netlink_message
*m
) {
540 r
= sd_rtnl_message_addr_get_flags(m
, &a
->flags
);
544 sd_rtnl_message_addr_get_scope(m
, &a
->scope
);
546 link_allocate_scopes(a
->link
);
547 link_add_rrs(a
->link
, false);
552 bool link_address_relevant(LinkAddress
*a
) {
555 if (a
->flags
& (IFA_F_DEPRECATED
|IFA_F_TENTATIVE
))
558 if (IN_SET(a
->scope
, RT_SCOPE_HOST
, RT_SCOPE_NOWHERE
))