]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-link.c
resolved: SPF records
[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 "strv.h"
26 #include "resolved-link.h"
27
28 static void link_address_add_rrs(LinkAddress *a);
29
30 int link_new(Manager *m, Link **ret, int ifindex) {
31 _cleanup_(link_freep) Link *l = NULL;
32 int r;
33
34 assert(m);
35 assert(ifindex > 0);
36
37 r = hashmap_ensure_allocated(&m->links, NULL, NULL);
38 if (r < 0)
39 return r;
40
41 l = new0(Link, 1);
42 if (!l)
43 return -ENOMEM;
44
45 l->ifindex = ifindex;
46
47 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
48 if (r < 0)
49 return r;
50
51 l->manager = m;
52
53 if (ret)
54 *ret = l;
55 l = NULL;
56
57 return 0;
58 }
59
60 Link *link_free(Link *l) {
61
62 if (!l)
63 return NULL;
64
65 while (l->addresses)
66 link_address_free(l->addresses);
67
68 if (l->manager)
69 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
70
71 dns_scope_free(l->unicast_scope);
72 dns_scope_free(l->llmnr_ipv4_scope);
73 dns_scope_free(l->llmnr_ipv6_scope);
74
75 while (l->dns_servers)
76 dns_server_free(l->dns_servers);
77
78 free(l);
79 return NULL;
80 }
81
82 static void link_allocate_scopes(Link *l) {
83 int r;
84
85 assert(l);
86
87 if (l->dns_servers) {
88 if (!l->unicast_scope) {
89 r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
90 if (r < 0)
91 log_warning("Failed to allocate DNS scope: %s", strerror(-r));
92 }
93 } else
94 l->unicast_scope = dns_scope_free(l->unicast_scope);
95
96 if (link_relevant(l, AF_INET) && (l->flags & IFF_MULTICAST) && l->manager->use_llmnr) {
97 if (!l->llmnr_ipv4_scope) {
98 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
99 if (r < 0)
100 log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
101 }
102 } else
103 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
104
105 if (link_relevant(l, AF_INET6) && (l->flags & IFF_MULTICAST) && l->manager->use_llmnr) {
106 if (!l->llmnr_ipv6_scope) {
107 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
108 if (r < 0)
109 log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
110 }
111 } else
112 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
113 }
114
115 static void link_add_rrs(Link *l) {
116 LinkAddress *a;
117
118 LIST_FOREACH(addresses, a, l->addresses)
119 link_address_add_rrs(a);
120 }
121
122 int link_update_rtnl(Link *l, sd_rtnl_message *m) {
123 const char *n = NULL;
124 int r;
125
126 assert(l);
127 assert(m);
128
129 r = sd_rtnl_message_link_get_flags(m, &l->flags);
130 if (r < 0)
131 return r;
132
133 sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
134
135 if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
136 strncpy(l->name, n, sizeof(l->name));
137 char_array_0(l->name);
138 }
139
140 link_allocate_scopes(l);
141 link_add_rrs(l);
142
143 return 0;
144 }
145
146 static int link_update_dns_servers(Link *l) {
147 _cleanup_strv_free_ char **nameservers = NULL;
148 char **nameserver;
149 DnsServer *s, *nx;
150 int r;
151
152 assert(l);
153
154 LIST_FOREACH(servers, s, l->dns_servers)
155 s->marked = true;
156
157 r = sd_network_get_dns(l->ifindex, &nameservers);
158 if (r < 0)
159 goto clear;
160
161 STRV_FOREACH(nameserver, nameservers) {
162 union in_addr_union a;
163 int family;
164
165 r = in_addr_from_string_auto(*nameserver, &family, &a);
166 if (r < 0)
167 goto clear;
168
169 s = link_find_dns_server(l, family, &a);
170 if (s)
171 s->marked = false;
172 else {
173 r = dns_server_new(l->manager, NULL, l, family, &a);
174 if (r < 0)
175 goto clear;
176 }
177 }
178
179 LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
180 if (s->marked)
181 dns_server_free(s);
182
183 return 0;
184
185 clear:
186 while (l->dns_servers)
187 dns_server_free(l->dns_servers);
188
189 return r;
190 }
191
192 int link_update_monitor(Link *l) {
193 assert(l);
194
195 link_update_dns_servers(l);
196 link_allocate_scopes(l);
197 link_add_rrs(l);
198
199 return 0;
200 }
201
202 bool link_relevant(Link *l, int family) {
203 _cleanup_free_ char *state = NULL;
204 LinkAddress *a;
205
206 assert(l);
207
208 /* A link is relevant if it isn't a loopback device and has at
209 * least one relevant IP address */
210
211 if (l->flags & IFF_LOOPBACK)
212 return false;
213
214 sd_network_get_link_operational_state(l->ifindex, &state);
215 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
216 return false;
217
218 LIST_FOREACH(addresses, a, l->addresses)
219 if (a->family == family && link_address_relevant(a))
220 return true;
221
222 return false;
223 }
224
225 LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
226 LinkAddress *a;
227
228 assert(l);
229
230 LIST_FOREACH(addresses, a, l->addresses)
231 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
232 return a;
233
234 return NULL;
235 }
236
237 DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) {
238 DnsServer *s;
239
240 assert(l);
241
242 LIST_FOREACH(servers, s, l->dns_servers)
243 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
244 return s;
245 return NULL;
246 }
247
248 DnsServer *link_get_dns_server(Link *l) {
249 assert(l);
250
251 if (!l->current_dns_server)
252 l->current_dns_server = l->dns_servers;
253
254 return l->current_dns_server;
255 }
256
257 void link_next_dns_server(Link *l) {
258 assert(l);
259
260 /* Switch to the next DNS server */
261
262 if (!l->current_dns_server) {
263 l->current_dns_server = l->dns_servers;
264 if (l->current_dns_server)
265 return;
266 }
267
268 if (!l->current_dns_server)
269 return;
270
271 if (l->current_dns_server->servers_next) {
272 l->current_dns_server = l->current_dns_server->servers_next;
273 return;
274 }
275
276 l->current_dns_server = l->dns_servers;
277 }
278
279 int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
280 LinkAddress *a;
281
282 assert(l);
283 assert(in_addr);
284
285 a = new0(LinkAddress, 1);
286 if (!a)
287 return -ENOMEM;
288
289 a->family = family;
290 a->in_addr = *in_addr;
291
292 a->link = l;
293 LIST_PREPEND(addresses, l->addresses, a);
294
295 if (ret)
296 *ret = a;
297
298 return 0;
299 }
300
301 LinkAddress *link_address_free(LinkAddress *a) {
302 if (!a)
303 return NULL;
304
305 if (a->link) {
306 LIST_REMOVE(addresses, a->link->addresses, a);
307
308 if (a->llmnr_address_rr) {
309
310 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
311 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
312 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
313 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
314
315 dns_resource_record_unref(a->llmnr_address_rr);
316 }
317
318 if (a->llmnr_ptr_rr) {
319 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
320 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
321 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
322 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
323
324 dns_resource_record_unref(a->llmnr_ptr_rr);
325 }
326 }
327
328 free(a);
329 return NULL;
330 }
331
332 static void link_address_add_rrs(LinkAddress *a) {
333 int r;
334
335 assert(a);
336
337 if (a->family == AF_INET && a->link->llmnr_ipv4_scope) {
338
339 if (!a->link->manager->host_ipv4_key) {
340 a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
341 if (!a->link->manager->host_ipv4_key) {
342 r = -ENOMEM;
343 goto fail;
344 }
345 }
346
347 if (!a->llmnr_address_rr) {
348 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
349 if (!a->llmnr_address_rr) {
350 r = -ENOMEM;
351 goto fail;
352 }
353
354 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
355 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
356 }
357
358 if (!a->llmnr_ptr_rr) {
359 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
360 if (r < 0)
361 goto fail;
362
363 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
364 }
365
366 if (link_address_relevant(a)) {
367 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
368 if (r < 0)
369 goto fail;
370
371 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
372 if (r < 0)
373 goto fail;
374 } else {
375 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
376 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
377 }
378 }
379
380 if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope) {
381
382 if (!a->link->manager->host_ipv6_key) {
383 a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
384 if (!a->link->manager->host_ipv6_key) {
385 r = -ENOMEM;
386 goto fail;
387 }
388 }
389
390 if (!a->llmnr_address_rr) {
391 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
392 if (!a->llmnr_address_rr) {
393 r = -ENOMEM;
394 goto fail;
395 }
396
397 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
398 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
399 }
400
401 if (!a->llmnr_ptr_rr) {
402 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
403 if (r < 0)
404 goto fail;
405
406 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
407 }
408
409 if (link_address_relevant(a)) {
410 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
411 if (r < 0)
412 goto fail;
413
414 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
415 if (r < 0)
416 goto fail;
417 } else {
418 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
419 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
420 }
421 }
422
423 return;
424
425 fail:
426 log_debug("Failed to update address RRs: %s", strerror(-r));
427 }
428
429 int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
430 int r;
431 assert(a);
432 assert(m);
433
434 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
435 if (r < 0)
436 return r;
437
438 sd_rtnl_message_addr_get_scope(m, &a->scope);
439
440 link_allocate_scopes(a->link);
441 link_add_rrs(a->link);
442
443 return 0;
444 }
445
446 bool link_address_relevant(LinkAddress *a) {
447 assert(a);
448
449 if (a->flags & IFA_F_DEPRECATED)
450 return false;
451
452 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
453 return false;
454
455 return true;
456 }