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 /* RFC 4795 Section 2.8. suggests a TTL of 30s by default */
29 #define LLMNR_DEFAULT_TTL (30)
31 static void link_address_add_rrs(LinkAddress *a);
33 int link_new(Manager *m, Link **ret, int ifindex) {
34 _cleanup_(link_freep) Link *l = NULL;
40 r = hashmap_ensure_allocated(&m->links, NULL, NULL);
50 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
63 Link *link_free(Link *l) {
69 link_address_free(l->addresses);
72 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
74 dns_scope_free(l->unicast_scope);
75 dns_scope_free(l->llmnr_ipv4_scope);
76 dns_scope_free(l->llmnr_ipv6_scope);
78 while (l->dns_servers)
79 dns_server_free(l->dns_servers);
85 static void link_allocate_scopes(Link *l) {
91 if (!l->unicast_scope) {
92 r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
94 log_warning("Failed to allocate DNS scope: %s", strerror(-r));
97 l->unicast_scope = dns_scope_free(l->unicast_scope);
99 if (link_relevant(l, AF_INET) && (l->flags & IFF_MULTICAST) && l->manager->use_llmnr) {
100 if (!l->llmnr_ipv4_scope) {
101 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
103 log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
106 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
108 if (link_relevant(l, AF_INET6) && (l->flags & IFF_MULTICAST) && l->manager->use_llmnr) {
109 if (!l->llmnr_ipv6_scope) {
110 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
112 log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
115 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
118 static void link_add_rrs(Link *l) {
121 LIST_FOREACH(addresses, a, l->addresses)
122 link_address_add_rrs(a);
125 int link_update_rtnl(Link *l, sd_rtnl_message *m) {
126 const char *n = NULL;
132 r = sd_rtnl_message_link_get_flags(m, &l->flags);
136 sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
138 if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
139 strncpy(l->name, n, sizeof(l->name));
140 char_array_0(l->name);
143 link_allocate_scopes(l);
149 static int link_update_dns_servers(Link *l) {
150 _cleanup_strv_free_ char **nameservers = NULL;
157 LIST_FOREACH(servers, s, l->dns_servers)
160 r = sd_network_get_dns(l->ifindex, &nameservers);
164 STRV_FOREACH(nameserver, nameservers) {
165 union in_addr_union a;
168 r = in_addr_from_string_auto(*nameserver, &family, &a);
172 s = link_find_dns_server(l, family, &a);
176 r = dns_server_new(l->manager, NULL, l, family, &a);
182 LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
189 while (l->dns_servers)
190 dns_server_free(l->dns_servers);
195 int link_update_monitor(Link *l) {
198 link_update_dns_servers(l);
199 link_allocate_scopes(l);
205 bool link_relevant(Link *l, int family) {
206 _cleanup_free_ char *state = NULL;
211 /* A link is relevant if it isn't a loopback device and has at
212 * least one relevant IP address */
214 if (l->flags & IFF_LOOPBACK)
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_get_dns_server(Link *l) {
254 if (!l->current_dns_server)
255 l->current_dns_server = l->dns_servers;
257 return l->current_dns_server;
260 void link_next_dns_server(Link *l) {
263 /* Switch to the next DNS server */
265 if (!l->current_dns_server) {
266 l->current_dns_server = l->dns_servers;
267 if (l->current_dns_server)
271 if (!l->current_dns_server)
274 if (l->current_dns_server->servers_next) {
275 l->current_dns_server = l->current_dns_server->servers_next;
279 l->current_dns_server = l->dns_servers;
282 int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
288 a = new0(LinkAddress, 1);
293 a->in_addr = *in_addr;
296 LIST_PREPEND(addresses, l->addresses, a);
304 LinkAddress *link_address_free(LinkAddress *a) {
309 LIST_REMOVE(addresses, a->link->addresses, a);
311 if (a->llmnr_address_rr) {
313 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
314 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
315 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
316 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
318 dns_resource_record_unref(a->llmnr_address_rr);
321 if (a->llmnr_ptr_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_ptr_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_ptr_rr);
327 dns_resource_record_unref(a->llmnr_ptr_rr);
335 static void link_address_add_rrs(LinkAddress *a) {
340 if (a->family == AF_INET && a->link->llmnr_ipv4_scope) {
342 if (!a->link->manager->host_ipv4_key) {
343 a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
344 if (!a->link->manager->host_ipv4_key) {
350 if (!a->llmnr_address_rr) {
351 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
352 if (!a->llmnr_address_rr) {
357 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
358 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
361 if (!a->llmnr_ptr_rr) {
362 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
366 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
369 if (link_address_relevant(a)) {
370 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
374 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
378 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
379 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
383 if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope) {
385 if (!a->link->manager->host_ipv6_key) {
386 a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
387 if (!a->link->manager->host_ipv6_key) {
393 if (!a->llmnr_address_rr) {
394 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
395 if (!a->llmnr_address_rr) {
400 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
401 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
404 if (!a->llmnr_ptr_rr) {
405 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
409 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
412 if (link_address_relevant(a)) {
413 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
417 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
421 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
422 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
429 log_debug("Failed to update address RRs: %s", strerror(-r));
432 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
437 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
441 sd_rtnl_message_addr_get_scope(m, &a->scope);
443 link_allocate_scopes(a->link);
444 link_add_rrs(a->link);
449 bool link_address_relevant(LinkAddress *a) {
452 if (a->flags & IFA_F_DEPRECATED)
455 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))