]>
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 "parse-util.h"
28 #include "resolved-link.h"
29 #include "string-util.h"
32 int link_new(Manager
*m
, Link
**ret
, int ifindex
) {
33 _cleanup_(link_freep
) Link
*l
= NULL
;
39 r
= hashmap_ensure_allocated(&m
->links
, NULL
);
48 l
->llmnr_support
= SUPPORT_YES
;
50 r
= hashmap_put(m
->links
, INT_TO_PTR(ifindex
), l
);
63 Link
*link_free(Link
*l
) {
68 link_address_free(l
->addresses
);
71 hashmap_remove(l
->manager
->links
, INT_TO_PTR(l
->ifindex
));
73 while (l
->dns_servers
) {
74 DnsServer
*s
= l
->dns_servers
;
76 LIST_REMOVE(servers
, l
->dns_servers
, s
);
80 dns_scope_free(l
->unicast_scope
);
81 dns_scope_free(l
->llmnr_ipv4_scope
);
82 dns_scope_free(l
->llmnr_ipv6_scope
);
88 static void link_allocate_scopes(Link
*l
) {
94 if (!l
->unicast_scope
) {
95 r
= dns_scope_new(l
->manager
, &l
->unicast_scope
, l
, DNS_PROTOCOL_DNS
, AF_UNSPEC
);
97 log_warning_errno(r
, "Failed to allocate DNS scope: %m");
100 l
->unicast_scope
= dns_scope_free(l
->unicast_scope
);
102 if (link_relevant(l
, AF_INET
) &&
103 l
->llmnr_support
!= SUPPORT_NO
&&
104 l
->manager
->llmnr_support
!= SUPPORT_NO
) {
105 if (!l
->llmnr_ipv4_scope
) {
106 r
= dns_scope_new(l
->manager
, &l
->llmnr_ipv4_scope
, l
, DNS_PROTOCOL_LLMNR
, AF_INET
);
108 log_warning_errno(r
, "Failed to allocate LLMNR IPv4 scope: %m");
111 l
->llmnr_ipv4_scope
= dns_scope_free(l
->llmnr_ipv4_scope
);
113 if (link_relevant(l
, AF_INET6
) &&
114 l
->llmnr_support
!= SUPPORT_NO
&&
115 l
->manager
->llmnr_support
!= SUPPORT_NO
&&
116 socket_ipv6_is_supported()) {
117 if (!l
->llmnr_ipv6_scope
) {
118 r
= dns_scope_new(l
->manager
, &l
->llmnr_ipv6_scope
, l
, DNS_PROTOCOL_LLMNR
, AF_INET6
);
120 log_warning_errno(r
, "Failed to allocate LLMNR IPv6 scope: %m");
123 l
->llmnr_ipv6_scope
= dns_scope_free(l
->llmnr_ipv6_scope
);
126 void link_add_rrs(Link
*l
, bool force_remove
) {
129 LIST_FOREACH(addresses
, a
, l
->addresses
)
130 link_address_add_rrs(a
, force_remove
);
133 int link_update_rtnl(Link
*l
, sd_netlink_message
*m
) {
134 const char *n
= NULL
;
140 r
= sd_rtnl_message_link_get_flags(m
, &l
->flags
);
144 sd_netlink_message_read_u32(m
, IFLA_MTU
, &l
->mtu
);
146 if (sd_netlink_message_read_string(m
, IFLA_IFNAME
, &n
) >= 0) {
147 strncpy(l
->name
, n
, sizeof(l
->name
)-1);
148 char_array_0(l
->name
);
151 link_allocate_scopes(l
);
152 link_add_rrs(l
, false);
157 static int link_update_dns_servers(Link
*l
) {
158 _cleanup_strv_free_
char **nameservers
= NULL
;
165 r
= sd_network_link_get_dns(l
->ifindex
, &nameservers
);
169 LIST_FOREACH(servers
, s
, l
->dns_servers
)
172 STRV_FOREACH(nameserver
, nameservers
) {
173 union in_addr_union a
;
176 r
= in_addr_from_string_auto(*nameserver
, &family
, &a
);
180 s
= link_find_dns_server(l
, family
, &a
);
184 r
= dns_server_new(l
->manager
, NULL
, DNS_SERVER_LINK
, l
, family
, &a
);
190 LIST_FOREACH_SAFE(servers
, s
, nx
, l
->dns_servers
)
192 LIST_REMOVE(servers
, l
->dns_servers
, s
);
199 while (l
->dns_servers
) {
202 LIST_REMOVE(servers
, l
->dns_servers
, s
);
209 static int link_update_llmnr_support(Link
*l
) {
210 _cleanup_free_
char *b
= NULL
;
215 r
= sd_network_link_get_llmnr(l
->ifindex
, &b
);
219 r
= parse_boolean(b
);
221 if (streq(b
, "resolve"))
222 l
->llmnr_support
= SUPPORT_RESOLVE
;
227 l
->llmnr_support
= SUPPORT_YES
;
229 l
->llmnr_support
= SUPPORT_NO
;
234 l
->llmnr_support
= SUPPORT_YES
;
238 static int link_update_domains(Link
*l
) {
241 if (!l
->unicast_scope
)
244 l
->unicast_scope
->domains
= strv_free(l
->unicast_scope
->domains
);
246 r
= sd_network_link_get_domains(l
->ifindex
,
247 &l
->unicast_scope
->domains
);
254 int link_update_monitor(Link
*l
) {
257 link_update_dns_servers(l
);
258 link_update_llmnr_support(l
);
259 link_allocate_scopes(l
);
260 link_update_domains(l
);
261 link_add_rrs(l
, false);
266 bool link_relevant(Link
*l
, int family
) {
267 _cleanup_free_
char *state
= NULL
;
272 /* A link is relevant if it isn't a loopback or pointopoint
273 * device, has a link beat, can do multicast and has at least
274 * one relevant IP address */
276 if (l
->flags
& (IFF_LOOPBACK
|IFF_POINTOPOINT
|IFF_DORMANT
))
279 if ((l
->flags
& (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
)) != (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
))
282 sd_network_link_get_operational_state(l
->ifindex
, &state
);
283 if (state
&& !STR_IN_SET(state
, "unknown", "degraded", "routable"))
286 LIST_FOREACH(addresses
, a
, l
->addresses
)
287 if (a
->family
== family
&& link_address_relevant(a
))
293 LinkAddress
*link_find_address(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
298 LIST_FOREACH(addresses
, a
, l
->addresses
)
299 if (a
->family
== family
&& in_addr_equal(family
, &a
->in_addr
, in_addr
))
305 DnsServer
* link_find_dns_server(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
310 LIST_FOREACH(servers
, s
, l
->dns_servers
)
311 if (s
->family
== family
&& in_addr_equal(family
, &s
->address
, in_addr
))
316 DnsServer
* link_set_dns_server(Link
*l
, DnsServer
*s
) {
319 if (l
->current_dns_server
== s
)
323 _cleanup_free_
char *ip
= NULL
;
325 in_addr_to_string(s
->family
, &s
->address
, &ip
);
326 log_info("Switching to DNS server %s for interface %s.", strna(ip
), l
->name
);
329 l
->current_dns_server
= s
;
331 if (l
->unicast_scope
)
332 dns_cache_flush(&l
->unicast_scope
->cache
);
337 DnsServer
*link_get_dns_server(Link
*l
) {
340 if (!l
->current_dns_server
)
341 link_set_dns_server(l
, l
->dns_servers
);
343 return l
->current_dns_server
;
346 void link_next_dns_server(Link
*l
) {
349 if (!l
->current_dns_server
)
352 if (l
->current_dns_server
->servers_next
) {
353 link_set_dns_server(l
, l
->current_dns_server
->servers_next
);
357 link_set_dns_server(l
, l
->dns_servers
);
360 int link_address_new(Link
*l
, LinkAddress
**ret
, int family
, const union in_addr_union
*in_addr
) {
366 a
= new0(LinkAddress
, 1);
371 a
->in_addr
= *in_addr
;
374 LIST_PREPEND(addresses
, l
->addresses
, a
);
382 LinkAddress
*link_address_free(LinkAddress
*a
) {
387 LIST_REMOVE(addresses
, a
->link
->addresses
, a
);
389 if (a
->llmnr_address_rr
) {
390 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
391 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
392 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
393 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
396 if (a
->llmnr_ptr_rr
) {
397 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
398 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
399 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
400 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
404 dns_resource_record_unref(a
->llmnr_address_rr
);
405 dns_resource_record_unref(a
->llmnr_ptr_rr
);
411 void link_address_add_rrs(LinkAddress
*a
, bool force_remove
) {
416 if (a
->family
== AF_INET
) {
419 link_address_relevant(a
) &&
420 a
->link
->llmnr_ipv4_scope
&&
421 a
->link
->llmnr_support
== SUPPORT_YES
&&
422 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
424 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
425 a
->link
->manager
->llmnr_host_ipv4_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, a
->link
->manager
->llmnr_hostname
);
426 if (!a
->link
->manager
->llmnr_host_ipv4_key
) {
432 if (!a
->llmnr_address_rr
) {
433 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv4_key
);
434 if (!a
->llmnr_address_rr
) {
439 a
->llmnr_address_rr
->a
.in_addr
= a
->in_addr
.in
;
440 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
443 if (!a
->llmnr_ptr_rr
) {
444 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
448 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
451 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_address_rr
, true);
453 log_warning_errno(r
, "Failed to add A record to LLMNR zone: %m");
455 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_ptr_rr
, false);
457 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
459 if (a
->llmnr_address_rr
) {
460 if (a
->link
->llmnr_ipv4_scope
)
461 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
462 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
465 if (a
->llmnr_ptr_rr
) {
466 if (a
->link
->llmnr_ipv4_scope
)
467 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
468 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
473 if (a
->family
== AF_INET6
) {
476 link_address_relevant(a
) &&
477 a
->link
->llmnr_ipv6_scope
&&
478 a
->link
->llmnr_support
== SUPPORT_YES
&&
479 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
481 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
482 a
->link
->manager
->llmnr_host_ipv6_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, a
->link
->manager
->llmnr_hostname
);
483 if (!a
->link
->manager
->llmnr_host_ipv6_key
) {
489 if (!a
->llmnr_address_rr
) {
490 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->llmnr_host_ipv6_key
);
491 if (!a
->llmnr_address_rr
) {
496 a
->llmnr_address_rr
->aaaa
.in6_addr
= a
->in_addr
.in6
;
497 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
500 if (!a
->llmnr_ptr_rr
) {
501 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->llmnr_hostname
);
505 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
508 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_address_rr
, true);
510 log_warning_errno(r
, "Failed to add AAAA record to LLMNR zone: %m");
512 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_ptr_rr
, false);
514 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
516 if (a
->llmnr_address_rr
) {
517 if (a
->link
->llmnr_ipv6_scope
)
518 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
519 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
522 if (a
->llmnr_ptr_rr
) {
523 if (a
->link
->llmnr_ipv6_scope
)
524 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
525 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
533 log_debug_errno(r
, "Failed to update address RRs: %m");
536 int link_address_update_rtnl(LinkAddress
*a
, sd_netlink_message
*m
) {
541 r
= sd_rtnl_message_addr_get_flags(m
, &a
->flags
);
545 sd_rtnl_message_addr_get_scope(m
, &a
->scope
);
547 link_allocate_scopes(a
->link
);
548 link_add_rrs(a
->link
, false);
553 bool link_address_relevant(LinkAddress
*a
) {
556 if (a
->flags
& (IFA_F_DEPRECATED
|IFA_F_TENTATIVE
))
559 if (IN_SET(a
->scope
, RT_SCOPE_HOST
, RT_SCOPE_NOWHERE
))