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 r = sd_network_get_dns(l->ifindex, &nameservers);
157 LIST_FOREACH(servers, s, l->dns_servers)
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 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);
264 l->current_dns_server = s;
266 if (l->unicast_scope)
267 dns_cache_flush(&l->unicast_scope->cache);
272 DnsServer *link_get_dns_server(Link *l) {
275 if (!l->current_dns_server)
276 link_set_dns_server(l, l->dns_servers);
278 return l->current_dns_server;
281 void link_next_dns_server(Link *l) {
284 if (!l->current_dns_server)
287 if (l->current_dns_server->servers_next) {
288 link_set_dns_server(l, l->current_dns_server->servers_next);
292 link_set_dns_server(l, l->dns_servers);
295 int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
301 a = new0(LinkAddress, 1);
306 a->in_addr = *in_addr;
309 LIST_PREPEND(addresses, l->addresses, a);
317 LinkAddress *link_address_free(LinkAddress *a) {
322 LIST_REMOVE(addresses, a->link->addresses, a);
324 if (a->llmnr_address_rr) {
325 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
326 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
327 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
328 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
331 if (a->llmnr_ptr_rr) {
332 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
333 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
334 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
335 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
339 dns_resource_record_unref(a->llmnr_address_rr);
340 dns_resource_record_unref(a->llmnr_ptr_rr);
346 void link_address_add_rrs(LinkAddress *a, bool force_remove) {
351 if (a->family == AF_INET) {
354 link_address_relevant(a) &&
355 a->link->llmnr_ipv4_scope &&
356 a->link->manager->llmnr_support == SUPPORT_YES) {
358 if (!a->link->manager->host_ipv4_key) {
359 a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
360 if (!a->link->manager->host_ipv4_key) {
366 if (!a->llmnr_address_rr) {
367 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
368 if (!a->llmnr_address_rr) {
373 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
374 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
377 if (!a->llmnr_ptr_rr) {
378 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
382 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
385 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
387 log_warning("Failed tp add A record to LLMNR zone: %s", strerror(-r));
389 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
391 log_warning("Failed tp add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
393 if (a->llmnr_address_rr) {
394 if (a->link->llmnr_ipv4_scope)
395 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
396 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
399 if (a->llmnr_ptr_rr) {
400 if (a->link->llmnr_ipv4_scope)
401 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
402 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
407 if (a->family == AF_INET6) {
410 link_address_relevant(a) &&
411 a->link->llmnr_ipv6_scope &&
412 a->link->manager->llmnr_support == SUPPORT_YES) {
414 if (!a->link->manager->host_ipv6_key) {
415 a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
416 if (!a->link->manager->host_ipv6_key) {
422 if (!a->llmnr_address_rr) {
423 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
424 if (!a->llmnr_address_rr) {
429 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
430 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
433 if (!a->llmnr_ptr_rr) {
434 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
438 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
441 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
443 log_warning("Failed to add AAAA record to LLMNR zone: %s", strerror(-r));
445 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
447 log_warning("Failed to add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
449 if (a->llmnr_address_rr) {
450 if (a->link->llmnr_ipv6_scope)
451 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
452 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
455 if (a->llmnr_ptr_rr) {
456 if (a->link->llmnr_ipv6_scope)
457 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
458 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
466 log_debug("Failed to update address RRs: %s", strerror(-r));
469 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
474 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
478 sd_rtnl_message_addr_get_scope(m, &a->scope);
480 link_allocate_scopes(a->link);
481 link_add_rrs(a->link, false);
486 bool link_address_relevant(LinkAddress *a) {
489 if (a->flags & IFA_F_DEPRECATED)
492 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))