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, 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 dns_scope_free(l->unicast_scope);
72 dns_scope_free(l->llmnr_ipv4_scope);
73 dns_scope_free(l->llmnr_ipv6_scope);
75 while (l->dns_servers)
76 dns_server_free(l->dns_servers);
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("Failed to allocate DNS scope: %s", strerror(-r));
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 l->manager->llmnr_ipv4_udp_fd >= 0) {
100 if (!l->llmnr_ipv4_scope) {
101 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
103 log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
106 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
108 if (link_relevant(l, AF_INET6) &&
109 l->llmnr_support != SUPPORT_NO &&
110 l->manager->llmnr_support != SUPPORT_NO &&
111 l->manager->llmnr_ipv6_udp_fd >= 0) {
112 if (!l->llmnr_ipv6_scope) {
113 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
115 log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
118 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
121 void link_add_rrs(Link *l, bool force_remove) {
124 LIST_FOREACH(addresses, a, l->addresses)
125 link_address_add_rrs(a, force_remove);
128 int link_update_rtnl(Link *l, sd_rtnl_message *m) {
129 const char *n = NULL;
135 r = sd_rtnl_message_link_get_flags(m, &l->flags);
139 sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
141 if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
142 strncpy(l->name, n, sizeof(l->name)-1);
143 char_array_0(l->name);
146 link_allocate_scopes(l);
147 link_add_rrs(l, false);
152 static int link_update_dns_servers(Link *l) {
153 _cleanup_strv_free_ char **nameservers = NULL;
160 r = sd_network_get_link_dns(l->ifindex, &nameservers);
164 LIST_FOREACH(servers, s, l->dns_servers)
167 STRV_FOREACH(nameserver, nameservers) {
168 union in_addr_union a;
171 r = in_addr_from_string_auto(*nameserver, &family, &a);
175 s = link_find_dns_server(l, family, &a);
179 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
185 LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
192 while (l->dns_servers)
193 dns_server_free(l->dns_servers);
198 static int link_update_llmnr_support(Link *l) {
199 _cleanup_free_ char *b = NULL;
204 r = sd_network_get_link_llmnr(l->ifindex, &b);
208 r = parse_boolean(b);
210 if (streq(b, "resolve"))
211 l->llmnr_support = SUPPORT_RESOLVE;
216 l->llmnr_support = SUPPORT_YES;
218 l->llmnr_support = SUPPORT_NO;
223 l->llmnr_support = SUPPORT_YES;
227 int link_update_monitor(Link *l) {
230 link_update_dns_servers(l);
231 link_update_llmnr_support(l);
232 link_allocate_scopes(l);
233 link_add_rrs(l, false);
238 bool link_relevant(Link *l, int family) {
239 _cleanup_free_ char *state = NULL;
244 /* A link is relevant if it isn't a loopback or pointopoint
245 * device, has a link beat, can do multicast and has at least
246 * one relevant IP address */
248 if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT))
251 if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST))
254 sd_network_get_link_operational_state(l->ifindex, &state);
255 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
258 LIST_FOREACH(addresses, a, l->addresses)
259 if (a->family == family && link_address_relevant(a))
265 LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
270 LIST_FOREACH(addresses, a, l->addresses)
271 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
277 DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) {
282 LIST_FOREACH(servers, s, l->dns_servers)
283 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
288 DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
291 if (l->current_dns_server == s)
295 _cleanup_free_ char *ip = NULL;
297 in_addr_to_string(s->family, &s->address, &ip);
298 log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name);
301 l->current_dns_server = s;
303 if (l->unicast_scope)
304 dns_cache_flush(&l->unicast_scope->cache);
309 DnsServer *link_get_dns_server(Link *l) {
312 if (!l->current_dns_server)
313 link_set_dns_server(l, l->dns_servers);
315 return l->current_dns_server;
318 void link_next_dns_server(Link *l) {
321 if (!l->current_dns_server)
324 if (l->current_dns_server->servers_next) {
325 link_set_dns_server(l, l->current_dns_server->servers_next);
329 link_set_dns_server(l, l->dns_servers);
332 int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
338 a = new0(LinkAddress, 1);
343 a->in_addr = *in_addr;
346 LIST_PREPEND(addresses, l->addresses, a);
354 LinkAddress *link_address_free(LinkAddress *a) {
359 LIST_REMOVE(addresses, a->link->addresses, a);
361 if (a->llmnr_address_rr) {
362 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
363 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
364 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
365 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
368 if (a->llmnr_ptr_rr) {
369 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
370 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
371 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
372 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
376 dns_resource_record_unref(a->llmnr_address_rr);
377 dns_resource_record_unref(a->llmnr_ptr_rr);
383 void link_address_add_rrs(LinkAddress *a, bool force_remove) {
388 if (a->family == AF_INET) {
391 link_address_relevant(a) &&
392 a->link->llmnr_ipv4_scope &&
393 a->link->llmnr_support == SUPPORT_YES &&
394 a->link->manager->llmnr_support == SUPPORT_YES) {
396 if (!a->link->manager->host_ipv4_key) {
397 a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
398 if (!a->link->manager->host_ipv4_key) {
404 if (!a->llmnr_address_rr) {
405 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
406 if (!a->llmnr_address_rr) {
411 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
412 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
415 if (!a->llmnr_ptr_rr) {
416 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
420 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
423 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
425 log_warning("Failed to add A record to LLMNR zone: %s", strerror(-r));
427 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
429 log_warning("Failed to add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
431 if (a->llmnr_address_rr) {
432 if (a->link->llmnr_ipv4_scope)
433 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
434 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
437 if (a->llmnr_ptr_rr) {
438 if (a->link->llmnr_ipv4_scope)
439 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
440 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
445 if (a->family == AF_INET6) {
448 link_address_relevant(a) &&
449 a->link->llmnr_ipv6_scope &&
450 a->link->llmnr_support == SUPPORT_YES &&
451 a->link->manager->llmnr_support == SUPPORT_YES) {
453 if (!a->link->manager->host_ipv6_key) {
454 a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
455 if (!a->link->manager->host_ipv6_key) {
461 if (!a->llmnr_address_rr) {
462 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
463 if (!a->llmnr_address_rr) {
468 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
469 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
472 if (!a->llmnr_ptr_rr) {
473 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
477 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
480 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
482 log_warning("Failed to add AAAA record to LLMNR zone: %s", strerror(-r));
484 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
486 log_warning("Failed to add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
488 if (a->llmnr_address_rr) {
489 if (a->link->llmnr_ipv6_scope)
490 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
491 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
494 if (a->llmnr_ptr_rr) {
495 if (a->link->llmnr_ipv6_scope)
496 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
497 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
505 log_debug("Failed to update address RRs: %s", strerror(-r));
508 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
513 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
517 sd_rtnl_message_addr_get_scope(m, &a->scope);
519 link_allocate_scopes(a->link);
520 link_add_rrs(a->link, false);
525 bool link_address_relevant(LinkAddress *a) {
528 if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))
531 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))