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_free_ struct in_addr *nameservers = NULL;
137 _cleanup_free_ struct in6_addr *nameservers6 = NULL;
143 LIST_FOREACH(servers, s, l->dns_servers)
146 n = sd_network_get_dns(l->ifindex, &nameservers);
152 for (i = 0; i < n; i++) {
153 union in_addr_union a = { .in = nameservers[i] };
155 s = link_find_dns_server(l, AF_INET, &a);
159 r = dns_server_new(l->manager, NULL, l, AF_INET, &a);
165 n = sd_network_get_dns6(l->ifindex, &nameservers6);
171 for (i = 0; i < n; i++) {
172 union in_addr_union a = { .in6 = nameservers6[i] };
174 s = link_find_dns_server(l, AF_INET6, &a);
178 r = dns_server_new(l->manager, NULL, l, AF_INET6, &a);
184 LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
191 while (l->dns_servers)
192 dns_server_free(l->dns_servers);
197 int link_update_monitor(Link *l) {
200 link_update_dns_servers(l);
201 link_allocate_scopes(l);
206 bool link_relevant(Link *l, int family) {
207 _cleanup_free_ char *state = NULL;
212 /* A link is relevant if it isn't a loopback device and has at
213 * least one relevant IP address */
215 if (l->flags & IFF_LOOPBACK)
218 sd_network_get_link_operational_state(l->ifindex, &state);
219 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
222 LIST_FOREACH(addresses, a, l->addresses)
223 if (a->family == family && link_address_relevant(a))
229 LinkAddress *link_find_address(Link *l, int family, union in_addr_union *in_addr) {
234 LIST_FOREACH(addresses, a, l->addresses)
235 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
241 DnsServer* link_find_dns_server(Link *l, int family, union in_addr_union *in_addr) {
246 LIST_FOREACH(servers, s, l->dns_servers)
247 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
253 DnsServer *link_get_dns_server(Link *l) {
256 if (!l->current_dns_server)
257 l->current_dns_server = l->dns_servers;
259 return l->current_dns_server;
262 void link_next_dns_server(Link *l) {
265 /* Switch to the next DNS server */
267 if (!l->current_dns_server) {
268 l->current_dns_server = l->dns_servers;
269 if (l->current_dns_server)
273 if (!l->current_dns_server)
276 if (l->current_dns_server->servers_next) {
277 l->current_dns_server = l->current_dns_server->servers_next;
281 l->current_dns_server = l->dns_servers;
284 int link_address_new(Link *l, LinkAddress **ret, int family, union in_addr_union *in_addr) {
290 a = new0(LinkAddress, 1);
295 a->in_addr = *in_addr;
298 LIST_PREPEND(addresses, l->addresses, a);
306 LinkAddress *link_address_free(LinkAddress *a) {
311 LIST_REMOVE(addresses, a->link->addresses, a);
317 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
322 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
326 sd_rtnl_message_addr_get_scope(m, &a->scope);
328 link_allocate_scopes(a->link);
332 bool link_address_relevant(LinkAddress *a) {
335 if (a->flags & IFA_F_DEPRECATED)
338 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))