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);
46 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
59 Link *link_free(Link *l) {
65 link_address_free(l->addresses);
68 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
70 dns_scope_free(l->unicast_scope);
71 dns_scope_free(l->llmnr_ipv4_scope);
72 dns_scope_free(l->llmnr_ipv6_scope);
74 while (l->dns_servers)
75 dns_server_free(l->dns_servers);
81 static void link_allocate_scopes(Link *l) {
87 if (!l->unicast_scope) {
88 r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
90 log_warning("Failed to allocate DNS scope: %s", strerror(-r));
93 l->unicast_scope = dns_scope_free(l->unicast_scope);
95 if (link_relevant(l, AF_INET) && l->manager->llmnr_support != SUPPORT_NO) {
96 if (!l->llmnr_ipv4_scope) {
97 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
99 log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
102 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
104 if (link_relevant(l, AF_INET6) && l->manager->llmnr_support != SUPPORT_NO) {
105 if (!l->llmnr_ipv6_scope) {
106 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
108 log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
111 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
114 void link_add_rrs(Link *l, bool force_remove) {
117 LIST_FOREACH(addresses, a, l->addresses)
118 link_address_add_rrs(a, force_remove);
121 int link_update_rtnl(Link *l, sd_rtnl_message *m) {
122 const char *n = NULL;
128 r = sd_rtnl_message_link_get_flags(m, &l->flags);
132 sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
134 if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
135 strncpy(l->name, n, sizeof(l->name));
136 char_array_0(l->name);
139 link_allocate_scopes(l);
140 link_add_rrs(l, false);
145 static int link_update_dns_servers(Link *l) {
146 _cleanup_strv_free_ char **nameservers = NULL;
153 LIST_FOREACH(servers, s, l->dns_servers)
156 r = sd_network_get_dns(l->ifindex, &nameservers);
160 STRV_FOREACH(nameserver, nameservers) {
161 union in_addr_union a;
164 r = in_addr_from_string_auto(*nameserver, &family, &a);
168 s = link_find_dns_server(l, family, &a);
172 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
178 LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
185 while (l->dns_servers)
186 dns_server_free(l->dns_servers);
191 int link_update_monitor(Link *l) {
194 link_update_dns_servers(l);
195 link_allocate_scopes(l);
196 link_add_rrs(l, false);
201 bool link_relevant(Link *l, int family) {
202 _cleanup_free_ char *state = NULL;
207 /* A link is relevant if it isn't a loopback or pointopoint
208 * device, has a link beat, can do multicast and has at least
209 * one relevant IP address */
211 if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT))
214 if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST))
217 sd_network_get_link_operational_state(l->ifindex, &state);
218 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
221 LIST_FOREACH(addresses, a, l->addresses)
222 if (a->family == family && link_address_relevant(a))
228 LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
233 LIST_FOREACH(addresses, a, l->addresses)
234 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
240 DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) {
245 LIST_FOREACH(servers, s, l->dns_servers)
246 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
251 static DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
254 if (l->current_dns_server == s)
258 _cleanup_free_ char *ip = NULL;
260 in_addr_to_string(s->family, &s->address, &ip);
261 log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name);
263 log_info("No DNS server set for interface %s.", l->name);
265 l->current_dns_server = s;
269 DnsServer *link_get_dns_server(Link *l) {
272 if (!l->current_dns_server)
273 link_set_dns_server(l, l->dns_servers);
275 return l->current_dns_server;
278 void link_next_dns_server(Link *l) {
281 if (!l->current_dns_server)
284 if (l->current_dns_server->servers_next) {
285 link_set_dns_server(l, l->current_dns_server->servers_next);
289 link_set_dns_server(l, l->dns_servers);
292 int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
298 a = new0(LinkAddress, 1);
303 a->in_addr = *in_addr;
306 LIST_PREPEND(addresses, l->addresses, a);
314 LinkAddress *link_address_free(LinkAddress *a) {
319 LIST_REMOVE(addresses, a->link->addresses, a);
321 if (a->llmnr_address_rr) {
322 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
323 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
324 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
325 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
328 if (a->llmnr_ptr_rr) {
329 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
330 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
331 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
332 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
336 dns_resource_record_unref(a->llmnr_address_rr);
337 dns_resource_record_unref(a->llmnr_ptr_rr);
343 void link_address_add_rrs(LinkAddress *a, bool force_remove) {
348 if (a->family == AF_INET) {
351 link_address_relevant(a) &&
352 a->link->llmnr_ipv4_scope &&
353 a->link->manager->llmnr_support == SUPPORT_YES) {
355 if (!a->link->manager->host_ipv4_key) {
356 a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
357 if (!a->link->manager->host_ipv4_key) {
363 if (!a->llmnr_address_rr) {
364 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
365 if (!a->llmnr_address_rr) {
370 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
371 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
374 if (!a->llmnr_ptr_rr) {
375 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
379 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
382 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
384 log_warning("Failed tp add A record to LLMNR zone: %s", strerror(-r));
386 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
388 log_warning("Failed tp add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
390 if (a->llmnr_address_rr) {
391 if (a->link->llmnr_ipv4_scope)
392 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
393 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
396 if (a->llmnr_ptr_rr) {
397 if (a->link->llmnr_ipv4_scope)
398 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
399 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
404 if (a->family == AF_INET6) {
407 link_address_relevant(a) &&
408 a->link->llmnr_ipv6_scope &&
409 a->link->manager->llmnr_support == SUPPORT_YES) {
411 if (!a->link->manager->host_ipv6_key) {
412 a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
413 if (!a->link->manager->host_ipv6_key) {
419 if (!a->llmnr_address_rr) {
420 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
421 if (!a->llmnr_address_rr) {
426 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
427 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
430 if (!a->llmnr_ptr_rr) {
431 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
435 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
438 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
440 log_warning("Failed to add AAAA record to LLMNR zone: %s", strerror(-r));
442 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
444 log_warning("Failed to add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
446 if (a->llmnr_address_rr) {
447 if (a->link->llmnr_ipv6_scope)
448 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
449 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
452 if (a->llmnr_ptr_rr) {
453 if (a->link->llmnr_ipv6_scope)
454 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
455 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
463 log_debug("Failed to update address RRs: %s", strerror(-r));
466 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
471 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
475 sd_rtnl_message_addr_get_scope(m, &a->scope);
477 link_allocate_scopes(a->link);
478 link_add_rrs(a->link, false);
483 bool link_address_relevant(LinkAddress *a) {
486 if (a->flags & IFA_F_DEPRECATED)
489 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))