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 #define DEFAULT_TTL (10)
30 static void link_address_add_rrs(LinkAddress *a);
32 int link_new(Manager *m, Link **ret, int ifindex) {
33 _cleanup_(link_freep) Link *l = NULL;
39 r = hashmap_ensure_allocated(&m->links, NULL, NULL);
49 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
62 Link *link_free(Link *l) {
68 link_address_free(l->addresses);
71 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
73 dns_scope_free(l->unicast_scope);
74 dns_scope_free(l->llmnr_ipv4_scope);
75 dns_scope_free(l->llmnr_ipv6_scope);
77 while (l->dns_servers)
78 dns_server_free(l->dns_servers);
84 static void link_allocate_scopes(Link *l) {
90 if (!l->unicast_scope) {
91 r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
93 log_warning("Failed to allocate DNS scope: %s", strerror(-r));
96 l->unicast_scope = dns_scope_free(l->unicast_scope);
98 if (link_relevant(l, AF_INET) && l->manager->use_llmnr) {
99 if (!l->llmnr_ipv4_scope) {
100 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
102 log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
105 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
107 if (link_relevant(l, AF_INET6) && l->manager->use_llmnr) {
108 if (!l->llmnr_ipv6_scope) {
109 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
111 log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
114 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
117 static void link_add_rrs(Link *l) {
120 LIST_FOREACH(addresses, a, l->addresses)
121 link_address_add_rrs(a);
124 int link_update_rtnl(Link *l, sd_rtnl_message *m) {
125 const char *n = NULL;
131 r = sd_rtnl_message_link_get_flags(m, &l->flags);
135 sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
137 if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
138 strncpy(l->name, n, sizeof(l->name));
139 char_array_0(l->name);
142 link_allocate_scopes(l);
148 static int link_update_dns_servers(Link *l) {
149 _cleanup_strv_free_ char **nameservers = NULL;
156 LIST_FOREACH(servers, s, l->dns_servers)
159 r = sd_network_get_dns(l->ifindex, &nameservers);
163 STRV_FOREACH(nameserver, nameservers) {
164 union in_addr_union a;
167 r = in_addr_from_string_auto(*nameserver, &family, &a);
171 s = link_find_dns_server(l, family, &a);
175 r = dns_server_new(l->manager, NULL, l, family, &a);
181 LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
188 while (l->dns_servers)
189 dns_server_free(l->dns_servers);
194 int link_update_monitor(Link *l) {
197 link_update_dns_servers(l);
198 link_allocate_scopes(l);
204 bool link_relevant(Link *l, int family) {
205 _cleanup_free_ char *state = NULL;
210 /* A link is relevant if it isn't a loopback device and has at
211 * least one relevant IP address */
213 if (l->flags & IFF_LOOPBACK)
216 sd_network_get_link_operational_state(l->ifindex, &state);
217 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
220 LIST_FOREACH(addresses, a, l->addresses)
221 if (a->family == family && link_address_relevant(a))
227 LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
232 LIST_FOREACH(addresses, a, l->addresses)
233 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
239 DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) {
244 LIST_FOREACH(servers, s, l->dns_servers)
245 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
250 DnsServer *link_get_dns_server(Link *l) {
253 if (!l->current_dns_server)
254 l->current_dns_server = l->dns_servers;
256 return l->current_dns_server;
259 void link_next_dns_server(Link *l) {
262 /* Switch to the next DNS server */
264 if (!l->current_dns_server) {
265 l->current_dns_server = l->dns_servers;
266 if (l->current_dns_server)
270 if (!l->current_dns_server)
273 if (l->current_dns_server->servers_next) {
274 l->current_dns_server = l->current_dns_server->servers_next;
278 l->current_dns_server = l->dns_servers;
281 int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
287 a = new0(LinkAddress, 1);
292 a->in_addr = *in_addr;
295 LIST_PREPEND(addresses, l->addresses, a);
303 LinkAddress *link_address_free(LinkAddress *a) {
308 LIST_REMOVE(addresses, a->link->addresses, a);
310 if (a->llmnr_address_rr) {
312 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
313 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
314 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
315 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
317 dns_resource_record_unref(a->llmnr_address_rr);
320 if (a->llmnr_ptr_rr) {
321 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
322 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
323 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
324 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
326 dns_resource_record_unref(a->llmnr_ptr_rr);
334 static void link_address_add_rrs(LinkAddress *a) {
339 if (a->family == AF_INET && a->link->llmnr_ipv4_scope) {
341 if (!a->link->manager->host_ipv4_key) {
342 a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
343 if (!a->link->manager->host_ipv4_key) {
349 if (!a->llmnr_address_rr) {
350 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
351 if (!a->llmnr_address_rr) {
356 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
357 a->llmnr_address_rr->ttl = DEFAULT_TTL;
360 if (!a->llmnr_ptr_rr) {
361 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
365 a->llmnr_ptr_rr->ttl = DEFAULT_TTL;
368 if (link_address_relevant(a)) {
369 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
373 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
377 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
378 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
382 if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope) {
384 if (!a->link->manager->host_ipv6_key) {
385 a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
386 if (!a->link->manager->host_ipv6_key) {
392 if (!a->llmnr_address_rr) {
393 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
394 if (!a->llmnr_address_rr) {
399 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
400 a->llmnr_address_rr->ttl = DEFAULT_TTL;
403 if (!a->llmnr_ptr_rr) {
404 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
408 a->llmnr_ptr_rr->ttl = DEFAULT_TTL;
411 if (link_address_relevant(a)) {
412 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
416 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
420 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
421 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
428 log_debug("Failed to update address RRs: %s", strerror(-r));
431 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
436 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
440 sd_rtnl_message_addr_get_scope(m, &a->scope);
442 link_allocate_scopes(a->link);
443 link_add_rrs(a->link);
448 bool link_address_relevant(LinkAddress *a) {
451 if (a->flags & IFA_F_DEPRECATED)
454 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))