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) && l->llmnr_support != SUPPORT_NO && l->manager->llmnr_support != SUPPORT_NO) {
97 if (!l->llmnr_ipv4_scope) {
98 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
100 log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
103 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
105 if (link_relevant(l, AF_INET6) && l->llmnr_support != SUPPORT_NO && l->manager->llmnr_support != SUPPORT_NO) {
106 if (!l->llmnr_ipv6_scope) {
107 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
109 log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
112 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
115 void link_add_rrs(Link *l, bool force_remove) {
118 LIST_FOREACH(addresses, a, l->addresses)
119 link_address_add_rrs(a, force_remove);
122 int link_update_rtnl(Link *l, sd_rtnl_message *m) {
123 const char *n = NULL;
129 r = sd_rtnl_message_link_get_flags(m, &l->flags);
133 sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
135 if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
136 strncpy(l->name, n, sizeof(l->name));
137 char_array_0(l->name);
140 link_allocate_scopes(l);
141 link_add_rrs(l, false);
146 static int link_update_dns_servers(Link *l) {
147 _cleanup_strv_free_ char **nameservers = NULL;
154 r = sd_network_get_dns(l->ifindex, &nameservers);
158 LIST_FOREACH(servers, s, l->dns_servers)
161 STRV_FOREACH(nameserver, nameservers) {
162 union in_addr_union a;
165 r = in_addr_from_string_auto(*nameserver, &family, &a);
169 s = link_find_dns_server(l, family, &a);
173 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
179 LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
186 while (l->dns_servers)
187 dns_server_free(l->dns_servers);
192 static int link_update_llmnr_support(Link *l) {
193 _cleanup_free_ char *b = NULL;
198 r = sd_network_get_llmnr(l->ifindex, &b);
202 r = parse_boolean(b);
204 if (streq(b, "resolve"))
205 l->llmnr_support = SUPPORT_RESOLVE;
210 l->llmnr_support = SUPPORT_YES;
212 l->llmnr_support = SUPPORT_NO;
217 l->llmnr_support = SUPPORT_YES;
221 int link_update_monitor(Link *l) {
224 link_update_dns_servers(l);
225 link_update_llmnr_support(l);
226 link_allocate_scopes(l);
227 link_add_rrs(l, false);
232 bool link_relevant(Link *l, int family) {
233 _cleanup_free_ char *state = NULL;
238 /* A link is relevant if it isn't a loopback or pointopoint
239 * device, has a link beat, can do multicast and has at least
240 * one relevant IP address */
242 if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT))
245 if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST))
248 sd_network_get_link_operational_state(l->ifindex, &state);
249 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
252 LIST_FOREACH(addresses, a, l->addresses)
253 if (a->family == family && link_address_relevant(a))
259 LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
264 LIST_FOREACH(addresses, a, l->addresses)
265 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
271 DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) {
276 LIST_FOREACH(servers, s, l->dns_servers)
277 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
282 DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
285 if (l->current_dns_server == s)
289 _cleanup_free_ char *ip = NULL;
291 in_addr_to_string(s->family, &s->address, &ip);
292 log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name);
295 l->current_dns_server = s;
297 if (l->unicast_scope)
298 dns_cache_flush(&l->unicast_scope->cache);
303 DnsServer *link_get_dns_server(Link *l) {
306 if (!l->current_dns_server)
307 link_set_dns_server(l, l->dns_servers);
309 return l->current_dns_server;
312 void link_next_dns_server(Link *l) {
315 if (!l->current_dns_server)
318 if (l->current_dns_server->servers_next) {
319 link_set_dns_server(l, l->current_dns_server->servers_next);
323 link_set_dns_server(l, l->dns_servers);
326 int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
332 a = new0(LinkAddress, 1);
337 a->in_addr = *in_addr;
340 LIST_PREPEND(addresses, l->addresses, a);
348 LinkAddress *link_address_free(LinkAddress *a) {
353 LIST_REMOVE(addresses, a->link->addresses, a);
355 if (a->llmnr_address_rr) {
356 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
357 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
358 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
359 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
362 if (a->llmnr_ptr_rr) {
363 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
364 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
365 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
366 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
370 dns_resource_record_unref(a->llmnr_address_rr);
371 dns_resource_record_unref(a->llmnr_ptr_rr);
377 void link_address_add_rrs(LinkAddress *a, bool force_remove) {
382 if (a->family == AF_INET) {
385 link_address_relevant(a) &&
386 a->link->llmnr_ipv4_scope &&
387 a->link->llmnr_support == SUPPORT_YES &&
388 a->link->manager->llmnr_support == SUPPORT_YES) {
390 if (!a->link->manager->host_ipv4_key) {
391 a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
392 if (!a->link->manager->host_ipv4_key) {
398 if (!a->llmnr_address_rr) {
399 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
400 if (!a->llmnr_address_rr) {
405 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
406 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
409 if (!a->llmnr_ptr_rr) {
410 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
414 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
417 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
419 log_warning("Failed tp add A record to LLMNR zone: %s", strerror(-r));
421 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
423 log_warning("Failed tp add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
425 if (a->llmnr_address_rr) {
426 if (a->link->llmnr_ipv4_scope)
427 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
428 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
431 if (a->llmnr_ptr_rr) {
432 if (a->link->llmnr_ipv4_scope)
433 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
434 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
439 if (a->family == AF_INET6) {
442 link_address_relevant(a) &&
443 a->link->llmnr_ipv6_scope &&
444 a->link->llmnr_support == SUPPORT_YES &&
445 a->link->manager->llmnr_support == SUPPORT_YES) {
447 if (!a->link->manager->host_ipv6_key) {
448 a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
449 if (!a->link->manager->host_ipv6_key) {
455 if (!a->llmnr_address_rr) {
456 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
457 if (!a->llmnr_address_rr) {
462 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
463 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
466 if (!a->llmnr_ptr_rr) {
467 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
471 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
474 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
476 log_warning("Failed to add AAAA record to LLMNR zone: %s", strerror(-r));
478 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
480 log_warning("Failed to add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
482 if (a->llmnr_address_rr) {
483 if (a->link->llmnr_ipv6_scope)
484 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
485 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
488 if (a->llmnr_ptr_rr) {
489 if (a->link->llmnr_ipv6_scope)
490 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
491 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
499 log_debug("Failed to update address RRs: %s", strerror(-r));
502 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
507 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
511 sd_rtnl_message_addr_get_scope(m, &a->scope);
513 link_allocate_scopes(a->link);
514 link_add_rrs(a->link, false);
519 bool link_address_relevant(LinkAddress *a) {
522 if (a->flags & IFA_F_DEPRECATED)
525 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))