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 r = sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
101 static int update_dhcp_dns_servers(Link *l) {
102 _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
103 const struct in_addr *nameservers = NULL;
109 r = sd_network_dhcp_use_dns(l->ifindex);
113 r = sd_network_get_dhcp_lease(l->ifindex, &lease);
117 LIST_FOREACH(servers, s, l->dhcp_dns_servers)
120 n = sd_dhcp_lease_get_dns(lease, &nameservers);
126 for (i = 0; i < n; i++) {
127 union in_addr_union a = { .in = nameservers[i] };
129 s = link_find_dns_server(l, DNS_SERVER_DHCP, AF_INET, &a);
133 r = dns_server_new(l->manager, NULL, DNS_SERVER_DHCP, l, AF_INET, &a);
139 LIST_FOREACH_SAFE(servers, s, nx, l->dhcp_dns_servers)
146 while (l->dhcp_dns_servers)
147 dns_server_free(l->dhcp_dns_servers);
152 static int update_link_dns_servers(Link *l) {
153 _cleanup_free_ struct in_addr *nameservers = NULL;
154 _cleanup_free_ struct in6_addr *nameservers6 = NULL;
160 LIST_FOREACH(servers, s, l->link_dns_servers)
163 n = sd_network_get_dns(l->ifindex, &nameservers);
169 for (i = 0; i < n; i++) {
170 union in_addr_union a = { .in = nameservers[i] };
172 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET, &a);
176 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET, &a);
182 n = sd_network_get_dns6(l->ifindex, &nameservers6);
188 for (i = 0; i < n; i++) {
189 union in_addr_union a = { .in6 = nameservers6[i] };
191 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET6, &a);
195 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET6, &a);
201 LIST_FOREACH_SAFE(servers, s, nx, l->link_dns_servers)
208 while (l->link_dns_servers)
209 dns_server_free(l->link_dns_servers);
214 int link_update_monitor(Link *l) {
217 free(l->operational_state);
218 l->operational_state = NULL;
220 sd_network_get_link_operational_state(l->ifindex, &l->operational_state);
222 update_dhcp_dns_servers(l);
223 update_link_dns_servers(l);
228 bool link_relevant(Link *l) {
233 /* A link is relevant if it isn't a loopback device and has at
234 * least one relevant IP address */
236 if (l->flags & IFF_LOOPBACK)
239 if (l->operational_state && !STR_IN_SET(l->operational_state, "unknown", "degraded", "routable"))
242 LIST_FOREACH(addresses, a, l->addresses)
243 if (link_address_relevant(a))
249 LinkAddress *link_find_address(Link *l, unsigned char family, union in_addr_union *in_addr) {
254 LIST_FOREACH(addresses, a, l->addresses) {
256 if (a->family == family &&
257 in_addr_equal(family, &a->in_addr, in_addr))
264 DnsServer* link_find_dns_server(Link *l, DnsServerSource source, unsigned char family, union in_addr_union *in_addr) {
265 DnsServer *first, *s;
269 first = source == DNS_SERVER_DHCP ? l->dhcp_dns_servers : l->link_dns_servers;
271 LIST_FOREACH(servers, s, first) {
273 if (s->family == family &&
274 in_addr_equal(family, &s->address, in_addr))
281 DnsServer *link_get_dns_server(Link *l) {
284 if (!l->current_dns_server)
285 l->current_dns_server = l->link_dns_servers;
286 if (!l->current_dns_server)
287 l->current_dns_server = l->dhcp_dns_servers;
289 return l->current_dns_server;
292 void link_next_dns_server(Link *l) {
295 /* Switch to the next DNS server */
297 if (!l->current_dns_server) {
298 l->current_dns_server = l->link_dns_servers;
299 if (l->current_dns_server)
303 if (!l->current_dns_server) {
304 l->current_dns_server = l->dhcp_dns_servers;
305 if (l->current_dns_server)
309 if (!l->current_dns_server)
312 if (l->current_dns_server->servers_next) {
313 l->current_dns_server = l->current_dns_server->servers_next;
317 if (l->current_dns_server->source == DNS_SERVER_LINK)
318 l->current_dns_server = l->dhcp_dns_servers;
320 assert(l->current_dns_server->source == DNS_SERVER_DHCP);
321 l->current_dns_server = l->link_dns_servers;
325 int link_address_new(Link *l, LinkAddress **ret, unsigned char family, union in_addr_union *in_addr) {
331 a = new0(LinkAddress, 1);
336 a->in_addr = *in_addr;
339 LIST_PREPEND(addresses, l->addresses, a);
347 LinkAddress *link_address_free(LinkAddress *a) {
352 LIST_REMOVE(addresses, a->link->addresses, a);
358 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
363 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
367 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
374 bool link_address_relevant(LinkAddress *a) {
377 if (a->flags & IFA_F_DEPRECATED)
380 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))