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"
26 #include "resolved-link.h"
28 static void link_address_add_rrs(LinkAddress *a);
30 int link_new(Manager *m, Link **ret, int ifindex) {
31 _cleanup_(link_freep) Link *l = NULL;
37 r = hashmap_ensure_allocated(&m->links, NULL, NULL);
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->flags & IFF_MULTICAST) && l->manager->use_llmnr) {
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->flags & IFF_MULTICAST) && l->manager->use_llmnr) {
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 static void link_add_rrs(Link *l) {
118 LIST_FOREACH(addresses, a, l->addresses)
119 link_address_add_rrs(a);
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);
146 static int link_update_dns_servers(Link *l) {
147 _cleanup_strv_free_ char **nameservers = NULL;
154 LIST_FOREACH(servers, s, l->dns_servers)
157 r = sd_network_get_dns(l->ifindex, &nameservers);
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, 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 int link_update_monitor(Link *l) {
195 link_update_dns_servers(l);
196 link_allocate_scopes(l);
202 bool link_relevant(Link *l, int family) {
203 _cleanup_free_ char *state = NULL;
208 /* A link is relevant if it isn't a loopback device and has at
209 * least one relevant IP address */
211 if (l->flags & IFF_LOOPBACK)
214 sd_network_get_link_operational_state(l->ifindex, &state);
215 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
218 LIST_FOREACH(addresses, a, l->addresses)
219 if (a->family == family && link_address_relevant(a))
225 LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
230 LIST_FOREACH(addresses, a, l->addresses)
231 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
237 DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) {
242 LIST_FOREACH(servers, s, l->dns_servers)
243 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
248 DnsServer *link_get_dns_server(Link *l) {
251 if (!l->current_dns_server)
252 l->current_dns_server = l->dns_servers;
254 return l->current_dns_server;
257 void link_next_dns_server(Link *l) {
260 /* Switch to the next DNS server */
262 if (!l->current_dns_server) {
263 l->current_dns_server = l->dns_servers;
264 if (l->current_dns_server)
268 if (!l->current_dns_server)
271 if (l->current_dns_server->servers_next) {
272 l->current_dns_server = l->current_dns_server->servers_next;
276 l->current_dns_server = l->dns_servers;
279 int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
285 a = new0(LinkAddress, 1);
290 a->in_addr = *in_addr;
293 LIST_PREPEND(addresses, l->addresses, a);
301 LinkAddress *link_address_free(LinkAddress *a) {
306 LIST_REMOVE(addresses, a->link->addresses, a);
308 if (a->llmnr_address_rr) {
310 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
311 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
312 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
313 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
315 dns_resource_record_unref(a->llmnr_address_rr);
318 if (a->llmnr_ptr_rr) {
319 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
320 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
321 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
322 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
324 dns_resource_record_unref(a->llmnr_ptr_rr);
332 static void link_address_add_rrs(LinkAddress *a) {
337 if (a->family == AF_INET && a->link->llmnr_ipv4_scope) {
339 if (!a->link->manager->host_ipv4_key) {
340 a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
341 if (!a->link->manager->host_ipv4_key) {
347 if (!a->llmnr_address_rr) {
348 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
349 if (!a->llmnr_address_rr) {
354 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
355 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
358 if (!a->llmnr_ptr_rr) {
359 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
363 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
366 if (link_address_relevant(a)) {
367 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
371 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
375 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
376 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
380 if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope) {
382 if (!a->link->manager->host_ipv6_key) {
383 a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
384 if (!a->link->manager->host_ipv6_key) {
390 if (!a->llmnr_address_rr) {
391 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
392 if (!a->llmnr_address_rr) {
397 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
398 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
401 if (!a->llmnr_ptr_rr) {
402 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
406 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
409 if (link_address_relevant(a)) {
410 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
414 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
418 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
419 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
426 log_debug("Failed to update address RRs: %s", strerror(-r));
429 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
434 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
438 sd_rtnl_message_addr_get_scope(m, &a->scope);
440 link_allocate_scopes(a->link);
441 link_add_rrs(a->link);
446 bool link_address_relevant(LinkAddress *a) {
449 if (a->flags & IFA_F_DEPRECATED)
452 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))