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 struct in_addr *nameservers = NULL;
111 r = sd_network_dhcp_use_dns(l->ifindex);
115 r = sd_network_get_dhcp_lease(l->ifindex, &lease);
119 LIST_FOREACH(servers, s, l->dhcp_dns_servers)
122 r = sd_dhcp_lease_get_dns(lease, &nameservers, &n);
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;
162 LIST_FOREACH(servers, s, l->link_dns_servers)
165 r = sd_network_get_dns(l->ifindex, &nameservers, &n);
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 r = sd_network_get_dns6(l->ifindex, &nameservers6, &n);
186 for (i = 0; i < n; i++) {
187 union in_addr_union a = { .in6 = nameservers6[i] };
189 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET6, &a);
193 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET6, &a);
199 LIST_FOREACH_SAFE(servers, s, nx, l->link_dns_servers)
206 while (l->link_dns_servers)
207 dns_server_free(l->link_dns_servers);
212 int link_update_monitor(Link *l) {
215 free(l->operational_state);
216 l->operational_state = NULL;
218 sd_network_get_link_operational_state(l->ifindex, &l->operational_state);
220 update_dhcp_dns_servers(l);
221 update_link_dns_servers(l);
226 bool link_relevant(Link *l) {
231 /* A link is relevant if it isn't a loopback device and has at
232 * least one relevant IP address */
234 if (l->flags & IFF_LOOPBACK)
237 if (l->operational_state && !STR_IN_SET(l->operational_state, "unknown", "degraded", "routable"))
240 LIST_FOREACH(addresses, a, l->addresses)
241 if (link_address_relevant(a))
247 LinkAddress *link_find_address(Link *l, unsigned char family, union in_addr_union *in_addr) {
252 LIST_FOREACH(addresses, a, l->addresses) {
254 if (a->family == family &&
255 in_addr_equal(family, &a->in_addr, in_addr))
262 DnsServer* link_find_dns_server(Link *l, DnsServerSource source, unsigned char family, union in_addr_union *in_addr) {
263 DnsServer *first, *s;
267 first = source == DNS_SERVER_DHCP ? l->dhcp_dns_servers : l->link_dns_servers;
269 LIST_FOREACH(servers, s, first) {
271 if (s->family == family &&
272 in_addr_equal(family, &s->address, in_addr))
279 DnsServer *link_get_dns_server(Link *l) {
282 if (!l->current_dns_server)
283 l->current_dns_server = l->link_dns_servers;
284 if (!l->current_dns_server)
285 l->current_dns_server = l->dhcp_dns_servers;
287 return l->current_dns_server;
290 void link_next_dns_server(Link *l) {
293 /* Switch to the next DNS server */
295 if (!l->current_dns_server) {
296 l->current_dns_server = l->link_dns_servers;
297 if (l->current_dns_server)
301 if (!l->current_dns_server) {
302 l->current_dns_server = l->dhcp_dns_servers;
303 if (l->current_dns_server)
307 if (!l->current_dns_server)
310 if (l->current_dns_server->servers_next) {
311 l->current_dns_server = l->current_dns_server->servers_next;
315 if (l->current_dns_server->source == DNS_SERVER_LINK)
316 l->current_dns_server = l->dhcp_dns_servers;
318 assert(l->current_dns_server->source == DNS_SERVER_DHCP);
319 l->current_dns_server = l->link_dns_servers;
323 int link_address_new(Link *l, LinkAddress **ret, unsigned char family, union in_addr_union *in_addr) {
329 a = new0(LinkAddress, 1);
334 a->in_addr = *in_addr;
337 LIST_PREPEND(addresses, l->addresses, a);
345 LinkAddress *link_address_free(LinkAddress *a) {
350 LIST_REMOVE(addresses, a->link->addresses, a);
356 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
361 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
365 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
372 bool link_address_relevant(LinkAddress *a) {
375 if (a->flags & IFA_F_DEPRECATED)
378 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))