]>
git.proxmox.com Git - 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
) {
66 link_address_free(l
->addresses
);
69 hashmap_remove(l
->manager
->links
, INT_TO_PTR(l
->ifindex
));
71 while (l
->dns_servers
)
72 dns_server_free(l
->dns_servers
);
74 dns_scope_free(l
->unicast_scope
);
75 dns_scope_free(l
->llmnr_ipv4_scope
);
76 dns_scope_free(l
->llmnr_ipv6_scope
);
82 static void link_allocate_scopes(Link
*l
) {
88 if (!l
->unicast_scope
) {
89 r
= dns_scope_new(l
->manager
, &l
->unicast_scope
, l
, DNS_PROTOCOL_DNS
, AF_UNSPEC
);
91 log_warning_errno(r
, "Failed to allocate DNS scope: %m");
94 l
->unicast_scope
= dns_scope_free(l
->unicast_scope
);
96 if (link_relevant(l
, AF_INET
) &&
97 l
->llmnr_support
!= SUPPORT_NO
&&
98 l
->manager
->llmnr_support
!= SUPPORT_NO
) {
99 if (!l
->llmnr_ipv4_scope
) {
100 r
= dns_scope_new(l
->manager
, &l
->llmnr_ipv4_scope
, l
, DNS_PROTOCOL_LLMNR
, AF_INET
);
102 log_warning_errno(r
, "Failed to allocate LLMNR IPv4 scope: %m");
105 l
->llmnr_ipv4_scope
= dns_scope_free(l
->llmnr_ipv4_scope
);
107 if (link_relevant(l
, AF_INET6
) &&
108 l
->llmnr_support
!= SUPPORT_NO
&&
109 l
->manager
->llmnr_support
!= SUPPORT_NO
&&
110 socket_ipv6_is_supported()) {
111 if (!l
->llmnr_ipv6_scope
) {
112 r
= dns_scope_new(l
->manager
, &l
->llmnr_ipv6_scope
, l
, DNS_PROTOCOL_LLMNR
, AF_INET6
);
114 log_warning_errno(r
, "Failed to allocate LLMNR IPv6 scope: %m");
117 l
->llmnr_ipv6_scope
= dns_scope_free(l
->llmnr_ipv6_scope
);
120 void link_add_rrs(Link
*l
, bool force_remove
) {
123 LIST_FOREACH(addresses
, a
, l
->addresses
)
124 link_address_add_rrs(a
, force_remove
);
127 int link_update_rtnl(Link
*l
, sd_rtnl_message
*m
) {
128 const char *n
= NULL
;
134 r
= sd_rtnl_message_link_get_flags(m
, &l
->flags
);
138 sd_rtnl_message_read_u32(m
, IFLA_MTU
, &l
->mtu
);
140 if (sd_rtnl_message_read_string(m
, IFLA_IFNAME
, &n
) >= 0) {
141 strncpy(l
->name
, n
, sizeof(l
->name
)-1);
142 char_array_0(l
->name
);
145 link_allocate_scopes(l
);
146 link_add_rrs(l
, false);
151 static int link_update_dns_servers(Link
*l
) {
152 _cleanup_strv_free_
char **nameservers
= NULL
;
159 r
= sd_network_link_get_dns(l
->ifindex
, &nameservers
);
163 LIST_FOREACH(servers
, s
, l
->dns_servers
)
166 STRV_FOREACH(nameserver
, nameservers
) {
167 union in_addr_union a
;
170 r
= in_addr_from_string_auto(*nameserver
, &family
, &a
);
174 s
= link_find_dns_server(l
, family
, &a
);
178 r
= dns_server_new(l
->manager
, NULL
, DNS_SERVER_LINK
, l
, family
, &a
);
184 LIST_FOREACH_SAFE(servers
, s
, nx
, l
->dns_servers
)
191 while (l
->dns_servers
)
192 dns_server_free(l
->dns_servers
);
197 static int link_update_llmnr_support(Link
*l
) {
198 _cleanup_free_
char *b
= NULL
;
203 r
= sd_network_link_get_llmnr(l
->ifindex
, &b
);
207 r
= parse_boolean(b
);
209 if (streq(b
, "resolve"))
210 l
->llmnr_support
= SUPPORT_RESOLVE
;
215 l
->llmnr_support
= SUPPORT_YES
;
217 l
->llmnr_support
= SUPPORT_NO
;
222 l
->llmnr_support
= SUPPORT_YES
;
226 static int link_update_domains(Link
*l
) {
229 if (!l
->unicast_scope
)
232 strv_free(l
->unicast_scope
->domains
);
233 l
->unicast_scope
->domains
= NULL
;
235 r
= sd_network_link_get_domains(l
->ifindex
,
236 &l
->unicast_scope
->domains
);
243 int link_update_monitor(Link
*l
) {
246 link_update_dns_servers(l
);
247 link_update_llmnr_support(l
);
248 link_allocate_scopes(l
);
249 link_update_domains(l
);
250 link_add_rrs(l
, false);
255 bool link_relevant(Link
*l
, int family
) {
256 _cleanup_free_
char *state
= NULL
;
261 /* A link is relevant if it isn't a loopback or pointopoint
262 * device, has a link beat, can do multicast and has at least
263 * one relevant IP address */
265 if (l
->flags
& (IFF_LOOPBACK
|IFF_POINTOPOINT
|IFF_DORMANT
))
268 if ((l
->flags
& (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
)) != (IFF_UP
|IFF_LOWER_UP
|IFF_MULTICAST
))
271 sd_network_link_get_operational_state(l
->ifindex
, &state
);
272 if (state
&& !STR_IN_SET(state
, "unknown", "degraded", "routable"))
275 LIST_FOREACH(addresses
, a
, l
->addresses
)
276 if (a
->family
== family
&& link_address_relevant(a
))
282 LinkAddress
*link_find_address(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
287 LIST_FOREACH(addresses
, a
, l
->addresses
)
288 if (a
->family
== family
&& in_addr_equal(family
, &a
->in_addr
, in_addr
))
294 DnsServer
* link_find_dns_server(Link
*l
, int family
, const union in_addr_union
*in_addr
) {
299 LIST_FOREACH(servers
, s
, l
->dns_servers
)
300 if (s
->family
== family
&& in_addr_equal(family
, &s
->address
, in_addr
))
305 DnsServer
* link_set_dns_server(Link
*l
, DnsServer
*s
) {
308 if (l
->current_dns_server
== s
)
312 _cleanup_free_
char *ip
= NULL
;
314 in_addr_to_string(s
->family
, &s
->address
, &ip
);
315 log_info("Switching to DNS server %s for interface %s.", strna(ip
), l
->name
);
318 l
->current_dns_server
= s
;
320 if (l
->unicast_scope
)
321 dns_cache_flush(&l
->unicast_scope
->cache
);
326 DnsServer
*link_get_dns_server(Link
*l
) {
329 if (!l
->current_dns_server
)
330 link_set_dns_server(l
, l
->dns_servers
);
332 return l
->current_dns_server
;
335 void link_next_dns_server(Link
*l
) {
338 if (!l
->current_dns_server
)
341 if (l
->current_dns_server
->servers_next
) {
342 link_set_dns_server(l
, l
->current_dns_server
->servers_next
);
346 link_set_dns_server(l
, l
->dns_servers
);
349 int link_address_new(Link
*l
, LinkAddress
**ret
, int family
, const union in_addr_union
*in_addr
) {
355 a
= new0(LinkAddress
, 1);
360 a
->in_addr
= *in_addr
;
363 LIST_PREPEND(addresses
, l
->addresses
, a
);
371 LinkAddress
*link_address_free(LinkAddress
*a
) {
376 LIST_REMOVE(addresses
, a
->link
->addresses
, a
);
378 if (a
->llmnr_address_rr
) {
379 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
380 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
381 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
382 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
385 if (a
->llmnr_ptr_rr
) {
386 if (a
->family
== AF_INET
&& a
->link
->llmnr_ipv4_scope
)
387 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
388 else if (a
->family
== AF_INET6
&& a
->link
->llmnr_ipv6_scope
)
389 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
393 dns_resource_record_unref(a
->llmnr_address_rr
);
394 dns_resource_record_unref(a
->llmnr_ptr_rr
);
400 void link_address_add_rrs(LinkAddress
*a
, bool force_remove
) {
405 if (a
->family
== AF_INET
) {
408 link_address_relevant(a
) &&
409 a
->link
->llmnr_ipv4_scope
&&
410 a
->link
->llmnr_support
== SUPPORT_YES
&&
411 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
413 if (!a
->link
->manager
->host_ipv4_key
) {
414 a
->link
->manager
->host_ipv4_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_A
, a
->link
->manager
->hostname
);
415 if (!a
->link
->manager
->host_ipv4_key
) {
421 if (!a
->llmnr_address_rr
) {
422 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->host_ipv4_key
);
423 if (!a
->llmnr_address_rr
) {
428 a
->llmnr_address_rr
->a
.in_addr
= a
->in_addr
.in
;
429 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
432 if (!a
->llmnr_ptr_rr
) {
433 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->hostname
);
437 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
440 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_address_rr
, true);
442 log_warning_errno(r
, "Failed to add A record to LLMNR zone: %m");
444 r
= dns_zone_put(&a
->link
->llmnr_ipv4_scope
->zone
, a
->link
->llmnr_ipv4_scope
, a
->llmnr_ptr_rr
, false);
446 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
448 if (a
->llmnr_address_rr
) {
449 if (a
->link
->llmnr_ipv4_scope
)
450 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_address_rr
);
451 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
454 if (a
->llmnr_ptr_rr
) {
455 if (a
->link
->llmnr_ipv4_scope
)
456 dns_zone_remove_rr(&a
->link
->llmnr_ipv4_scope
->zone
, a
->llmnr_ptr_rr
);
457 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
462 if (a
->family
== AF_INET6
) {
465 link_address_relevant(a
) &&
466 a
->link
->llmnr_ipv6_scope
&&
467 a
->link
->llmnr_support
== SUPPORT_YES
&&
468 a
->link
->manager
->llmnr_support
== SUPPORT_YES
) {
470 if (!a
->link
->manager
->host_ipv6_key
) {
471 a
->link
->manager
->host_ipv6_key
= dns_resource_key_new(DNS_CLASS_IN
, DNS_TYPE_AAAA
, a
->link
->manager
->hostname
);
472 if (!a
->link
->manager
->host_ipv6_key
) {
478 if (!a
->llmnr_address_rr
) {
479 a
->llmnr_address_rr
= dns_resource_record_new(a
->link
->manager
->host_ipv6_key
);
480 if (!a
->llmnr_address_rr
) {
485 a
->llmnr_address_rr
->aaaa
.in6_addr
= a
->in_addr
.in6
;
486 a
->llmnr_address_rr
->ttl
= LLMNR_DEFAULT_TTL
;
489 if (!a
->llmnr_ptr_rr
) {
490 r
= dns_resource_record_new_reverse(&a
->llmnr_ptr_rr
, a
->family
, &a
->in_addr
, a
->link
->manager
->hostname
);
494 a
->llmnr_ptr_rr
->ttl
= LLMNR_DEFAULT_TTL
;
497 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_address_rr
, true);
499 log_warning_errno(r
, "Failed to add AAAA record to LLMNR zone: %m");
501 r
= dns_zone_put(&a
->link
->llmnr_ipv6_scope
->zone
, a
->link
->llmnr_ipv6_scope
, a
->llmnr_ptr_rr
, false);
503 log_warning_errno(r
, "Failed to add IPv6 PTR record to LLMNR zone: %m");
505 if (a
->llmnr_address_rr
) {
506 if (a
->link
->llmnr_ipv6_scope
)
507 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_address_rr
);
508 a
->llmnr_address_rr
= dns_resource_record_unref(a
->llmnr_address_rr
);
511 if (a
->llmnr_ptr_rr
) {
512 if (a
->link
->llmnr_ipv6_scope
)
513 dns_zone_remove_rr(&a
->link
->llmnr_ipv6_scope
->zone
, a
->llmnr_ptr_rr
);
514 a
->llmnr_ptr_rr
= dns_resource_record_unref(a
->llmnr_ptr_rr
);
522 log_debug_errno(r
, "Failed to update address RRs: %m");
525 int link_address_update_rtnl(LinkAddress
*a
, sd_rtnl_message
*m
) {
530 r
= sd_rtnl_message_addr_get_flags(m
, &a
->flags
);
534 sd_rtnl_message_addr_get_scope(m
, &a
->scope
);
536 link_allocate_scopes(a
->link
);
537 link_add_rrs(a
->link
, false);
542 bool link_address_relevant(LinkAddress
*a
) {
545 if (a
->flags
& (IFA_F_DEPRECATED
|IFA_F_TENTATIVE
))
548 if (IN_SET(a
->scope
, RT_SCOPE_HOST
, RT_SCOPE_NOWHERE
))