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 int link_new(Manager *m, Link **ret, int ifindex) {
29 _cleanup_(link_freep) Link *l = NULL;
35 r = hashmap_ensure_allocated(&m->links, NULL, NULL);
45 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
58 Link *link_free(Link *l) {
64 link_address_free(l->addresses);
67 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
69 dns_scope_free(l->unicast_scope);
70 dns_scope_free(l->llmnr_ipv4_scope);
71 dns_scope_free(l->llmnr_ipv6_scope);
73 while (l->dns_servers)
74 dns_server_free(l->dns_servers);
80 static void link_allocate_scopes(Link *l) {
86 if (!l->unicast_scope) {
87 r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
89 log_warning("Failed to allocate DNS scope: %s", strerror(-r));
92 l->unicast_scope = dns_scope_free(l->unicast_scope);
94 if (link_relevant(l, AF_INET) && l->manager->use_llmnr) {
95 if (!l->llmnr_ipv4_scope) {
96 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
98 log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
101 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
103 if (link_relevant(l, AF_INET6) && l->manager->use_llmnr) {
104 if (!l->llmnr_ipv6_scope) {
105 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
107 log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
110 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
113 int link_update_rtnl(Link *l, sd_rtnl_message *m) {
114 const char *n = NULL;
120 r = sd_rtnl_message_link_get_flags(m, &l->flags);
124 sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
126 if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
127 strncpy(l->name, n, sizeof(l->name));
128 char_array_0(l->name);
131 link_allocate_scopes(l);
135 static int link_update_dns_servers(Link *l) {
136 _cleanup_strv_free_ char **nameservers = NULL;
143 LIST_FOREACH(servers, s, l->dns_servers)
146 r = sd_network_get_dns(l->ifindex, &nameservers);
150 STRV_FOREACH(nameserver, nameservers) {
151 union in_addr_union a;
154 r = in_addr_from_string_auto(*nameserver, &family, &a);
158 s = link_find_dns_server(l, family, &a);
162 r = dns_server_new(l->manager, NULL, l, family, &a);
168 LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
175 while (l->dns_servers)
176 dns_server_free(l->dns_servers);
181 int link_update_monitor(Link *l) {
184 link_update_dns_servers(l);
185 link_allocate_scopes(l);
190 bool link_relevant(Link *l, int family) {
191 _cleanup_free_ char *state = NULL;
196 /* A link is relevant if it isn't a loopback device and has at
197 * least one relevant IP address */
199 if (l->flags & IFF_LOOPBACK)
202 sd_network_get_link_operational_state(l->ifindex, &state);
203 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
206 LIST_FOREACH(addresses, a, l->addresses)
207 if (a->family == family && link_address_relevant(a))
213 LinkAddress *link_find_address(Link *l, int family, union in_addr_union *in_addr) {
218 LIST_FOREACH(addresses, a, l->addresses)
219 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
225 DnsServer* link_find_dns_server(Link *l, int family, union in_addr_union *in_addr) {
230 LIST_FOREACH(servers, s, l->dns_servers)
231 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
237 DnsServer *link_get_dns_server(Link *l) {
240 if (!l->current_dns_server)
241 l->current_dns_server = l->dns_servers;
243 return l->current_dns_server;
246 void link_next_dns_server(Link *l) {
249 /* Switch to the next DNS server */
251 if (!l->current_dns_server) {
252 l->current_dns_server = l->dns_servers;
253 if (l->current_dns_server)
257 if (!l->current_dns_server)
260 if (l->current_dns_server->servers_next) {
261 l->current_dns_server = l->current_dns_server->servers_next;
265 l->current_dns_server = l->dns_servers;
268 int link_address_new(Link *l, LinkAddress **ret, int family, union in_addr_union *in_addr) {
274 a = new0(LinkAddress, 1);
279 a->in_addr = *in_addr;
282 LIST_PREPEND(addresses, l->addresses, a);
290 LinkAddress *link_address_free(LinkAddress *a) {
295 LIST_REMOVE(addresses, a->link->addresses, a);
301 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
306 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
310 sd_rtnl_message_addr_get_scope(m, &a->scope);
312 link_allocate_scopes(a->link);
316 bool link_address_relevant(LinkAddress *a) {
319 if (a->flags & IFA_F_DEPRECATED)
322 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))