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"
25 #include "dhcp-lease-internal.h"
27 #include "resolved-link.h"
29 int link_new(Manager *m, Link **ret, int ifindex) {
30 _cleanup_(link_freep) Link *l = NULL;
36 r = hashmap_ensure_allocated(&m->links, NULL, NULL);
46 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
59 Link *link_free(Link *l) {
65 link_address_free(l->addresses);
68 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
70 dns_scope_free(l->unicast_scope);
71 dns_scope_free(l->llmnr_ipv4_scope);
72 dns_scope_free(l->llmnr_ipv6_scope);
74 while (l->dhcp_dns_servers)
75 dns_server_free(l->dhcp_dns_servers);
77 while (l->link_dns_servers)
78 dns_server_free(l->link_dns_servers);
84 static void link_allocate_scopes(Link *l) {
89 if (l->link_dns_servers || l->dhcp_dns_servers) {
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 int link_update_rtnl(Link *l, sd_rtnl_message *m) {
118 const char *n = NULL;
124 r = sd_rtnl_message_link_get_flags(m, &l->flags);
128 sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
130 if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
131 strncpy(l->name, n, sizeof(l->name));
132 char_array_0(l->name);
135 link_allocate_scopes(l);
139 static int link_update_link_dns_servers(Link *l) {
140 _cleanup_free_ struct in_addr *nameservers = NULL;
141 _cleanup_free_ struct in6_addr *nameservers6 = NULL;
147 LIST_FOREACH(servers, s, l->link_dns_servers)
150 n = sd_network_get_dns(l->ifindex, &nameservers);
156 for (i = 0; i < n; i++) {
157 union in_addr_union a = { .in = nameservers[i] };
159 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET, &a);
163 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET, &a);
169 n = sd_network_get_dns6(l->ifindex, &nameservers6);
175 for (i = 0; i < n; i++) {
176 union in_addr_union a = { .in6 = nameservers6[i] };
178 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET6, &a);
182 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET6, &a);
188 LIST_FOREACH_SAFE(servers, s, nx, l->link_dns_servers)
195 while (l->link_dns_servers)
196 dns_server_free(l->link_dns_servers);
201 int link_update_monitor(Link *l) {
204 link_update_link_dns_servers(l);
205 link_allocate_scopes(l);
210 bool link_relevant(Link *l, int family) {
211 _cleanup_free_ char *state = NULL;
216 /* A link is relevant if it isn't a loopback device and has at
217 * least one relevant IP address */
219 if (l->flags & IFF_LOOPBACK)
222 sd_network_get_link_operational_state(l->ifindex, &state);
223 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
226 LIST_FOREACH(addresses, a, l->addresses)
227 if (a->family == family && link_address_relevant(a))
233 LinkAddress *link_find_address(Link *l, int family, union in_addr_union *in_addr) {
238 LIST_FOREACH(addresses, a, l->addresses)
239 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
245 DnsServer* link_find_dns_server(Link *l, DnsServerSource source, int family, union in_addr_union *in_addr) {
246 DnsServer *first, *s;
250 first = source == DNS_SERVER_DHCP ? l->dhcp_dns_servers : l->link_dns_servers;
252 LIST_FOREACH(servers, s, first)
253 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
259 DnsServer *link_get_dns_server(Link *l) {
262 if (!l->current_dns_server)
263 l->current_dns_server = l->link_dns_servers;
264 if (!l->current_dns_server)
265 l->current_dns_server = l->dhcp_dns_servers;
267 return l->current_dns_server;
270 void link_next_dns_server(Link *l) {
273 /* Switch to the next DNS server */
275 if (!l->current_dns_server) {
276 l->current_dns_server = l->link_dns_servers;
277 if (l->current_dns_server)
281 if (!l->current_dns_server) {
282 l->current_dns_server = l->dhcp_dns_servers;
283 if (l->current_dns_server)
287 if (!l->current_dns_server)
290 if (l->current_dns_server->servers_next) {
291 l->current_dns_server = l->current_dns_server->servers_next;
295 if (l->current_dns_server->source == DNS_SERVER_LINK)
296 l->current_dns_server = l->dhcp_dns_servers;
298 assert(l->current_dns_server->source == DNS_SERVER_DHCP);
299 l->current_dns_server = l->link_dns_servers;
303 int link_address_new(Link *l, LinkAddress **ret, int family, union in_addr_union *in_addr) {
309 a = new0(LinkAddress, 1);
314 a->in_addr = *in_addr;
317 LIST_PREPEND(addresses, l->addresses, a);
325 LinkAddress *link_address_free(LinkAddress *a) {
330 LIST_REMOVE(addresses, a->link->addresses, a);
336 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
341 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
345 sd_rtnl_message_addr_get_scope(m, &a->scope);
347 link_allocate_scopes(a->link);
351 bool link_address_relevant(LinkAddress *a) {
354 if (a->flags & IFA_F_DEPRECATED)
357 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))