]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-link.c
barrier: fix race in test-code
[thirdparty/systemd.git] / src / resolve / resolved-link.c
CommitLineData
74b2466e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
22#include <net/if.h>
23
24#include "sd-network.h"
74b2466e
LP
25#include "strv.h"
26#include "resolved-link.h"
27
28int link_new(Manager *m, Link **ret, int ifindex) {
29 _cleanup_(link_freep) Link *l = NULL;
30 int r;
31
32 assert(m);
33 assert(ifindex > 0);
34
35 r = hashmap_ensure_allocated(&m->links, NULL, NULL);
36 if (r < 0)
37 return r;
38
39 l = new0(Link, 1);
40 if (!l)
41 return -ENOMEM;
42
43 l->ifindex = ifindex;
44
45 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
46 if (r < 0)
47 return r;
48
49 l->manager = m;
50
51 if (ret)
52 *ret = l;
53 l = NULL;
54
55 return 0;
56}
57
58Link *link_free(Link *l) {
59
60 if (!l)
61 return NULL;
62
63 while (l->addresses)
64 link_address_free(l->addresses);
65
66 if (l->manager)
67 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
68
69 dns_scope_free(l->unicast_scope);
1716f6dc
LP
70 dns_scope_free(l->llmnr_ipv4_scope);
71 dns_scope_free(l->llmnr_ipv6_scope);
74b2466e 72
6073b6f2
TG
73 while (l->dns_servers)
74 dns_server_free(l->dns_servers);
74b2466e
LP
75
76 free(l);
77 return NULL;
1716f6dc
LP
78}
79
80static void link_allocate_scopes(Link *l) {
81 int r;
82
83 assert(l);
84
6073b6f2 85 if (l->dns_servers) {
1716f6dc
LP
86 if (!l->unicast_scope) {
87 r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
88 if (r < 0)
89 log_warning("Failed to allocate DNS scope: %s", strerror(-r));
90 }
91 } else
92 l->unicast_scope = dns_scope_free(l->unicast_scope);
93
94 if (link_relevant(l, AF_INET) && l->manager->use_llmnr) {
95 if (!l->llmnr_ipv4_scope) {
96 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
97 if (r < 0)
98 log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
99 }
100 } else
101 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
102
103 if (link_relevant(l, AF_INET6) && l->manager->use_llmnr) {
104 if (!l->llmnr_ipv6_scope) {
105 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
106 if (r < 0)
107 log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
108 }
109 } else
110 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
111}
74b2466e
LP
112
113int link_update_rtnl(Link *l, sd_rtnl_message *m) {
1716f6dc 114 const char *n = NULL;
74b2466e
LP
115 int r;
116
117 assert(l);
118 assert(m);
119
120 r = sd_rtnl_message_link_get_flags(m, &l->flags);
121 if (r < 0)
122 return r;
123
c5ed9316 124 sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
1716f6dc
LP
125
126 if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
127 strncpy(l->name, n, sizeof(l->name));
128 char_array_0(l->name);
129 }
130
131 link_allocate_scopes(l);
74b2466e
LP
132 return 0;
133}
134
6073b6f2 135static int link_update_dns_servers(Link *l) {
6f4dedb2
TG
136 _cleanup_strv_free_ char **nameservers = NULL;
137 char **nameserver;
74b2466e 138 DnsServer *s, *nx;
6f4dedb2 139 int r;
74b2466e
LP
140
141 assert(l);
142
6073b6f2 143 LIST_FOREACH(servers, s, l->dns_servers)
74b2466e
LP
144 s->marked = true;
145
6f4dedb2
TG
146 r = sd_network_get_dns(l->ifindex, &nameservers);
147 if (r < 0)
74b2466e 148 goto clear;
74b2466e 149
6f4dedb2
TG
150 STRV_FOREACH(nameserver, nameservers) {
151 union in_addr_union a;
152 int family;
74b2466e 153
6f4dedb2
TG
154 r = in_addr_from_string_auto(*nameserver, &family, &a);
155 if (r < 0)
156 goto clear;
74b2466e 157
6f4dedb2 158 s = link_find_dns_server(l, family, &a);
74b2466e
LP
159 if (s)
160 s->marked = false;
161 else {
6f4dedb2 162 r = dns_server_new(l->manager, NULL, l, family, &a);
74b2466e
LP
163 if (r < 0)
164 goto clear;
165 }
166 }
167
6073b6f2 168 LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
74b2466e
LP
169 if (s->marked)
170 dns_server_free(s);
171
172 return 0;
173
174clear:
6073b6f2
TG
175 while (l->dns_servers)
176 dns_server_free(l->dns_servers);
74b2466e
LP
177
178 return r;
179}
180
181int link_update_monitor(Link *l) {
182 assert(l);
183
6073b6f2 184 link_update_dns_servers(l);
1716f6dc 185 link_allocate_scopes(l);
74b2466e
LP
186
187 return 0;
188}
189
0dd25fb9 190bool link_relevant(Link *l, int family) {
1716f6dc 191 _cleanup_free_ char *state = NULL;
74b2466e
LP
192 LinkAddress *a;
193
194 assert(l);
195
196 /* A link is relevant if it isn't a loopback device and has at
197 * least one relevant IP address */
198
199 if (l->flags & IFF_LOOPBACK)
200 return false;
201
1716f6dc
LP
202 sd_network_get_link_operational_state(l->ifindex, &state);
203 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
74b2466e
LP
204 return false;
205
206 LIST_FOREACH(addresses, a, l->addresses)
1716f6dc 207 if (a->family == family && link_address_relevant(a))
74b2466e
LP
208 return true;
209
210 return false;
211}
212
0dd25fb9 213LinkAddress *link_find_address(Link *l, int family, union in_addr_union *in_addr) {
74b2466e
LP
214 LinkAddress *a;
215
216 assert(l);
217
1716f6dc
LP
218 LIST_FOREACH(addresses, a, l->addresses)
219 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
74b2466e 220 return a;
74b2466e
LP
221
222 return NULL;
223}
224
6073b6f2
TG
225DnsServer* link_find_dns_server(Link *l, int family, union in_addr_union *in_addr) {
226 DnsServer *s;
74b2466e
LP
227
228 assert(l);
229
6073b6f2 230 LIST_FOREACH(servers, s, l->dns_servers)
1716f6dc 231 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
74b2466e 232 return s;
74b2466e
LP
233
234 return NULL;
235}
236
237DnsServer *link_get_dns_server(Link *l) {
238 assert(l);
239
240 if (!l->current_dns_server)
6073b6f2 241 l->current_dns_server = l->dns_servers;
74b2466e
LP
242
243 return l->current_dns_server;
244}
245
246void link_next_dns_server(Link *l) {
247 assert(l);
248
249 /* Switch to the next DNS server */
250
251 if (!l->current_dns_server) {
6073b6f2 252 l->current_dns_server = l->dns_servers;
74b2466e
LP
253 if (l->current_dns_server)
254 return;
255 }
256
257 if (!l->current_dns_server)
258 return;
259
260 if (l->current_dns_server->servers_next) {
261 l->current_dns_server = l->current_dns_server->servers_next;
262 return;
263 }
264
6073b6f2 265 l->current_dns_server = l->dns_servers;
74b2466e
LP
266}
267
0dd25fb9 268int link_address_new(Link *l, LinkAddress **ret, int family, union in_addr_union *in_addr) {
74b2466e
LP
269 LinkAddress *a;
270
271 assert(l);
272 assert(in_addr);
273
274 a = new0(LinkAddress, 1);
275 if (!a)
276 return -ENOMEM;
277
278 a->family = family;
279 a->in_addr = *in_addr;
280
281 a->link = l;
282 LIST_PREPEND(addresses, l->addresses, a);
283
284 if (ret)
285 *ret = a;
286
287 return 0;
288}
289
290LinkAddress *link_address_free(LinkAddress *a) {
291 if (!a)
292 return NULL;
293
294 if (a->link)
295 LIST_REMOVE(addresses, a->link->addresses, a);
296
297 free(a);
298 return NULL;
299}
300
301int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
302 int r;
303 assert(a);
304 assert(m);
305
306 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
307 if (r < 0)
308 return r;
309
1716f6dc 310 sd_rtnl_message_addr_get_scope(m, &a->scope);
74b2466e 311
1716f6dc 312 link_allocate_scopes(a->link);
74b2466e
LP
313 return 0;
314}
315
316bool link_address_relevant(LinkAddress *a) {
317 assert(a);
318
319 if (a->flags & IFA_F_DEPRECATED)
320 return false;
321
322 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
323 return false;
324
325 return true;
326}