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->mdns_ipv4_scope);
72 dns_scope_free(l->mdns_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 int link_update_rtnl(Link *l, sd_rtnl_message *m) {
90 r = sd_rtnl_message_link_get_flags(m, &l->flags);
94 sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
98 static int update_dhcp_dns_servers(Link *l) {
99 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
100 const struct in_addr *nameservers = NULL;
106 r = sd_network_dhcp_use_dns(l->ifindex);
110 r = sd_network_get_dhcp_lease(l->ifindex, &lease);
114 LIST_FOREACH(servers, s, l->dhcp_dns_servers)
117 n = sd_dhcp_lease_get_dns(lease, &nameservers);
123 for (i = 0; i < n; i++) {
124 union in_addr_union a = { .in = nameservers[i] };
126 s = link_find_dns_server(l, DNS_SERVER_DHCP, AF_INET, &a);
130 r = dns_server_new(l->manager, NULL, DNS_SERVER_DHCP, l, AF_INET, &a);
136 LIST_FOREACH_SAFE(servers, s, nx, l->dhcp_dns_servers)
143 while (l->dhcp_dns_servers)
144 dns_server_free(l->dhcp_dns_servers);
149 static int update_link_dns_servers(Link *l) {
150 _cleanup_free_ struct in_addr *nameservers = NULL;
151 _cleanup_free_ struct in6_addr *nameservers6 = NULL;
157 LIST_FOREACH(servers, s, l->link_dns_servers)
160 n = sd_network_get_dns(l->ifindex, &nameservers);
166 for (i = 0; i < n; i++) {
167 union in_addr_union a = { .in = nameservers[i] };
169 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET, &a);
173 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET, &a);
179 n = sd_network_get_dns6(l->ifindex, &nameservers6);
185 for (i = 0; i < n; i++) {
186 union in_addr_union a = { .in6 = nameservers6[i] };
188 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET6, &a);
192 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET6, &a);
198 LIST_FOREACH_SAFE(servers, s, nx, l->link_dns_servers)
205 while (l->link_dns_servers)
206 dns_server_free(l->link_dns_servers);
211 int link_update_monitor(Link *l) {
214 free(l->operational_state);
215 l->operational_state = NULL;
217 sd_network_get_link_operational_state(l->ifindex, &l->operational_state);
219 update_dhcp_dns_servers(l);
220 update_link_dns_servers(l);
225 bool link_relevant(Link *l) {
230 /* A link is relevant if it isn't a loopback device and has at
231 * least one relevant IP address */
233 if (l->flags & IFF_LOOPBACK)
236 if (l->operational_state && !STR_IN_SET(l->operational_state, "unknown", "degraded", "routable"))
239 LIST_FOREACH(addresses, a, l->addresses)
240 if (link_address_relevant(a))
246 LinkAddress *link_find_address(Link *l, unsigned char family, union in_addr_union *in_addr) {
251 LIST_FOREACH(addresses, a, l->addresses) {
253 if (a->family == family &&
254 in_addr_equal(family, &a->in_addr, in_addr))
261 DnsServer* link_find_dns_server(Link *l, DnsServerSource source, unsigned char family, union in_addr_union *in_addr) {
262 DnsServer *first, *s;
266 first = source == DNS_SERVER_DHCP ? l->dhcp_dns_servers : l->link_dns_servers;
268 LIST_FOREACH(servers, s, first) {
270 if (s->family == family &&
271 in_addr_equal(family, &s->address, in_addr))
278 DnsServer *link_get_dns_server(Link *l) {
281 if (!l->current_dns_server)
282 l->current_dns_server = l->link_dns_servers;
283 if (!l->current_dns_server)
284 l->current_dns_server = l->dhcp_dns_servers;
286 return l->current_dns_server;
289 void link_next_dns_server(Link *l) {
292 /* Switch to the next DNS server */
294 if (!l->current_dns_server) {
295 l->current_dns_server = l->link_dns_servers;
296 if (l->current_dns_server)
300 if (!l->current_dns_server) {
301 l->current_dns_server = l->dhcp_dns_servers;
302 if (l->current_dns_server)
306 if (!l->current_dns_server)
309 if (l->current_dns_server->servers_next) {
310 l->current_dns_server = l->current_dns_server->servers_next;
314 if (l->current_dns_server->source == DNS_SERVER_LINK)
315 l->current_dns_server = l->dhcp_dns_servers;
317 assert(l->current_dns_server->source == DNS_SERVER_DHCP);
318 l->current_dns_server = l->link_dns_servers;
322 int link_address_new(Link *l, LinkAddress **ret, unsigned char family, union in_addr_union *in_addr) {
328 a = new0(LinkAddress, 1);
333 a->in_addr = *in_addr;
336 LIST_PREPEND(addresses, l->addresses, a);
344 LinkAddress *link_address_free(LinkAddress *a) {
349 LIST_REMOVE(addresses, a->link->addresses, a);
355 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
360 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
364 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
371 bool link_address_relevant(LinkAddress *a) {
374 if (a->flags & IFA_F_DEPRECATED)
377 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))