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);
97 static int update_dhcp_dns_servers(Link *l) {
98 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
99 _cleanup_free_ struct in_addr *nameservers = NULL;
107 r = sd_network_dhcp_use_dns(l->ifindex);
111 r = sd_network_get_dhcp_lease(l->ifindex, &lease);
115 LIST_FOREACH(servers, s, l->dhcp_dns_servers)
118 r = sd_dhcp_lease_get_dns(lease, &nameservers, &n);
122 for (i = 0; i < n; i++) {
123 union in_addr_union a = { .in = nameservers[i] };
125 s = link_find_dns_server(l, DNS_SERVER_DHCP, AF_INET, &a);
129 r = dns_server_new(l->manager, NULL, DNS_SERVER_DHCP, l, AF_INET, &a);
135 LIST_FOREACH_SAFE(servers, s, nx, l->dhcp_dns_servers)
142 while (l->dhcp_dns_servers)
143 dns_server_free(l->dhcp_dns_servers);
148 static int update_link_dns_servers(Link *l) {
149 _cleanup_free_ struct in_addr *nameservers = NULL;
150 _cleanup_free_ struct in6_addr *nameservers6 = NULL;
158 LIST_FOREACH(servers, s, l->link_dns_servers)
161 r = sd_network_get_dns(l->ifindex, &nameservers, &n);
165 for (i = 0; i < n; i++) {
166 union in_addr_union a = { .in = nameservers[i] };
168 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET, &a);
172 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET, &a);
178 r = sd_network_get_dns6(l->ifindex, &nameservers6, &n);
182 for (i = 0; i < n; i++) {
183 union in_addr_union a = { .in6 = nameservers6[i] };
185 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET6, &a);
189 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET6, &a);
195 LIST_FOREACH_SAFE(servers, s, nx, l->link_dns_servers)
202 while (l->link_dns_servers)
203 dns_server_free(l->link_dns_servers);
208 int link_update_monitor(Link *l) {
211 free(l->operational_state);
212 l->operational_state = NULL;
214 sd_network_get_link_operational_state(l->ifindex, &l->operational_state);
216 update_dhcp_dns_servers(l);
217 update_link_dns_servers(l);
222 bool link_relevant(Link *l) {
227 /* A link is relevant if it isn't a loopback device and has at
228 * least one relevant IP address */
230 if (l->flags & IFF_LOOPBACK)
233 if (l->operational_state && !STR_IN_SET(l->operational_state, "unknown", "degraded", "routable"))
236 LIST_FOREACH(addresses, a, l->addresses)
237 if (link_address_relevant(a))
243 LinkAddress *link_find_address(Link *l, unsigned char family, union in_addr_union *in_addr) {
248 LIST_FOREACH(addresses, a, l->addresses) {
250 if (a->family == family &&
251 in_addr_equal(family, &a->in_addr, in_addr))
258 DnsServer* link_find_dns_server(Link *l, DnsServerSource source, unsigned char family, union in_addr_union *in_addr) {
259 DnsServer *first, *s;
263 first = source == DNS_SERVER_DHCP ? l->dhcp_dns_servers : l->link_dns_servers;
265 LIST_FOREACH(servers, s, first) {
267 if (s->family == family &&
268 in_addr_equal(family, &s->address, in_addr))
275 DnsServer *link_get_dns_server(Link *l) {
278 if (!l->current_dns_server)
279 l->current_dns_server = l->link_dns_servers;
280 if (!l->current_dns_server)
281 l->current_dns_server = l->dhcp_dns_servers;
283 return l->current_dns_server;
286 void link_next_dns_server(Link *l) {
289 /* Switch to the next DNS server */
291 if (!l->current_dns_server) {
292 l->current_dns_server = l->link_dns_servers;
293 if (l->current_dns_server)
297 if (!l->current_dns_server) {
298 l->current_dns_server = l->dhcp_dns_servers;
299 if (l->current_dns_server)
303 if (!l->current_dns_server)
306 if (l->current_dns_server->servers_next) {
307 l->current_dns_server = l->current_dns_server->servers_next;
311 if (l->current_dns_server->source == DNS_SERVER_LINK)
312 l->current_dns_server = l->dhcp_dns_servers;
314 assert(l->current_dns_server->source == DNS_SERVER_DHCP);
315 l->current_dns_server = l->link_dns_servers;
319 int link_address_new(Link *l, LinkAddress **ret, unsigned char family, union in_addr_union *in_addr) {
325 a = new0(LinkAddress, 1);
330 a->in_addr = *in_addr;
333 LIST_PREPEND(addresses, l->addresses, a);
341 LinkAddress *link_address_free(LinkAddress *a) {
346 LIST_REMOVE(addresses, a->link->addresses, a);
352 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
357 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
361 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
368 bool link_address_relevant(LinkAddress *a) {
371 if (a->flags & IFA_F_DEPRECATED)
374 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))