]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-link.c
resolved: add a DNS client stub resolver
[thirdparty/systemd.git] / src / resolve / resolved-link.c
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"
25 #include "dhcp-lease-internal.h"
26 #include "strv.h"
27 #include "resolved-link.h"
28
29 int link_new(Manager *m, Link **ret, int ifindex) {
30 _cleanup_(link_freep) Link *l = NULL;
31 int r;
32
33 assert(m);
34 assert(ifindex > 0);
35
36 r = hashmap_ensure_allocated(&m->links, NULL, NULL);
37 if (r < 0)
38 return r;
39
40 l = new0(Link, 1);
41 if (!l)
42 return -ENOMEM;
43
44 l->ifindex = ifindex;
45
46 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
47 if (r < 0)
48 return r;
49
50 l->manager = m;
51
52 if (ret)
53 *ret = l;
54 l = NULL;
55
56 return 0;
57 }
58
59 Link *link_free(Link *l) {
60
61 if (!l)
62 return NULL;
63
64 while (l->addresses)
65 link_address_free(l->addresses);
66
67 if (l->manager)
68 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
69
70 dns_scope_free(l->unicast_scope);
71 dns_scope_free(l->mdns_ipv4_scope);
72 dns_scope_free(l->mdns_ipv6_scope);
73
74 while (l->dhcp_dns_servers)
75 dns_server_free(l->dhcp_dns_servers);
76
77 while (l->link_dns_servers)
78 dns_server_free(l->link_dns_servers);
79
80 free(l);
81 return NULL;
82 }
83
84 int link_update_rtnl(Link *l, sd_rtnl_message *m) {
85 int r;
86
87 assert(l);
88 assert(m);
89
90 r = sd_rtnl_message_link_get_flags(m, &l->flags);
91 if (r < 0)
92 return r;
93
94 return 0;
95 }
96
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;
100 DnsServer *s, *nx;
101 unsigned i;
102 size_t n;
103 int r;
104
105 assert(l);
106
107 r = sd_network_dhcp_use_dns(l->ifindex);
108 if (r <= 0)
109 goto clear;
110
111 r = sd_network_get_dhcp_lease(l->ifindex, &lease);
112 if (r < 0)
113 goto clear;
114
115 LIST_FOREACH(servers, s, l->dhcp_dns_servers)
116 s->marked = true;
117
118 r = sd_dhcp_lease_get_dns(lease, &nameservers, &n);
119 if (r < 0)
120 goto clear;
121
122 for (i = 0; i < n; i++) {
123 union in_addr_union a = { .in = nameservers[i] };
124
125 s = link_find_dns_server(l, DNS_SERVER_DHCP, AF_INET, &a);
126 if (s)
127 s->marked = false;
128 else {
129 r = dns_server_new(l->manager, NULL, DNS_SERVER_DHCP, l, AF_INET, &a);
130 if (r < 0)
131 goto clear;
132 }
133 }
134
135 LIST_FOREACH_SAFE(servers, s, nx, l->dhcp_dns_servers)
136 if (s->marked)
137 dns_server_free(s);
138
139 return 0;
140
141 clear:
142 while (l->dhcp_dns_servers)
143 dns_server_free(l->dhcp_dns_servers);
144
145 return r;
146 }
147
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;
151 DnsServer *s, *nx;
152 unsigned i;
153 size_t n;
154 int r;
155
156 assert(l);
157
158 LIST_FOREACH(servers, s, l->link_dns_servers)
159 s->marked = true;
160
161 r = sd_network_get_dns(l->ifindex, &nameservers, &n);
162 if (r < 0)
163 goto clear;
164
165 for (i = 0; i < n; i++) {
166 union in_addr_union a = { .in = nameservers[i] };
167
168 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET, &a);
169 if (s)
170 s->marked = false;
171 else {
172 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET, &a);
173 if (r < 0)
174 goto clear;
175 }
176 }
177
178 r = sd_network_get_dns6(l->ifindex, &nameservers6, &n);
179 if (r < 0)
180 goto clear;
181
182 for (i = 0; i < n; i++) {
183 union in_addr_union a = { .in6 = nameservers6[i] };
184
185 s = link_find_dns_server(l, DNS_SERVER_LINK, AF_INET6, &a);
186 if (s)
187 s->marked = false;
188 else {
189 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, AF_INET6, &a);
190 if (r < 0)
191 goto clear;
192 }
193 }
194
195 LIST_FOREACH_SAFE(servers, s, nx, l->link_dns_servers)
196 if (s->marked)
197 dns_server_free(s);
198
199 return 0;
200
201 clear:
202 while (l->link_dns_servers)
203 dns_server_free(l->link_dns_servers);
204
205 return r;
206 }
207
208 int link_update_monitor(Link *l) {
209 assert(l);
210
211 free(l->operational_state);
212 l->operational_state = NULL;
213
214 sd_network_get_link_operational_state(l->ifindex, &l->operational_state);
215
216 update_dhcp_dns_servers(l);
217 update_link_dns_servers(l);
218
219 return 0;
220 }
221
222 bool link_relevant(Link *l) {
223 LinkAddress *a;
224
225 assert(l);
226
227 /* A link is relevant if it isn't a loopback device and has at
228 * least one relevant IP address */
229
230 if (l->flags & IFF_LOOPBACK)
231 return false;
232
233 if (l->operational_state && !STR_IN_SET(l->operational_state, "unknown", "degraded", "routable"))
234 return false;
235
236 LIST_FOREACH(addresses, a, l->addresses)
237 if (link_address_relevant(a))
238 return true;
239
240 return false;
241 }
242
243 LinkAddress *link_find_address(Link *l, unsigned char family, union in_addr_union *in_addr) {
244 LinkAddress *a;
245
246 assert(l);
247
248 LIST_FOREACH(addresses, a, l->addresses) {
249
250 if (a->family == family &&
251 in_addr_equal(family, &a->in_addr, in_addr))
252 return a;
253 }
254
255 return NULL;
256 }
257
258 DnsServer* link_find_dns_server(Link *l, DnsServerSource source, unsigned char family, union in_addr_union *in_addr) {
259 DnsServer *first, *s;
260
261 assert(l);
262
263 first = source == DNS_SERVER_DHCP ? l->dhcp_dns_servers : l->link_dns_servers;
264
265 LIST_FOREACH(servers, s, first) {
266
267 if (s->family == family &&
268 in_addr_equal(family, &s->address, in_addr))
269 return s;
270 }
271
272 return NULL;
273 }
274
275 DnsServer *link_get_dns_server(Link *l) {
276 assert(l);
277
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;
282
283 return l->current_dns_server;
284 }
285
286 void link_next_dns_server(Link *l) {
287 assert(l);
288
289 /* Switch to the next DNS server */
290
291 if (!l->current_dns_server) {
292 l->current_dns_server = l->link_dns_servers;
293 if (l->current_dns_server)
294 return;
295 }
296
297 if (!l->current_dns_server) {
298 l->current_dns_server = l->dhcp_dns_servers;
299 if (l->current_dns_server)
300 return;
301 }
302
303 if (!l->current_dns_server)
304 return;
305
306 if (l->current_dns_server->servers_next) {
307 l->current_dns_server = l->current_dns_server->servers_next;
308 return;
309 }
310
311 if (l->current_dns_server->source == DNS_SERVER_LINK)
312 l->current_dns_server = l->dhcp_dns_servers;
313 else {
314 assert(l->current_dns_server->source == DNS_SERVER_DHCP);
315 l->current_dns_server = l->link_dns_servers;
316 }
317 }
318
319 int link_address_new(Link *l, LinkAddress **ret, unsigned char family, union in_addr_union *in_addr) {
320 LinkAddress *a;
321
322 assert(l);
323 assert(in_addr);
324
325 a = new0(LinkAddress, 1);
326 if (!a)
327 return -ENOMEM;
328
329 a->family = family;
330 a->in_addr = *in_addr;
331
332 a->link = l;
333 LIST_PREPEND(addresses, l->addresses, a);
334
335 if (ret)
336 *ret = a;
337
338 return 0;
339 }
340
341 LinkAddress *link_address_free(LinkAddress *a) {
342 if (!a)
343 return NULL;
344
345 if (a->link)
346 LIST_REMOVE(addresses, a->link->addresses, a);
347
348 free(a);
349 return NULL;
350 }
351
352 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
353 int r;
354 assert(a);
355 assert(m);
356
357 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
358 if (r < 0)
359 return r;
360
361 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
362 if (r < 0)
363 return r;
364
365 return 0;
366 }
367
368 bool link_address_relevant(LinkAddress *a) {
369 assert(a);
370
371 if (a->flags & IFA_F_DEPRECATED)
372 return false;
373
374 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
375 return false;
376
377 return true;
378 }