]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-link.c
machine-id-setup: don't try to read UUID from VM/container manager if we operate...
[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 25#include "strv.h"
ec2c5e43 26#include "missing.h"
74b2466e
LP
27#include "resolved-link.h"
28
29int 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;
19b50b5b 45 l->llmnr_support = SUPPORT_YES;
74b2466e
LP
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
60Link *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);
1716f6dc
LP
72 dns_scope_free(l->llmnr_ipv4_scope);
73 dns_scope_free(l->llmnr_ipv6_scope);
74b2466e 74
6073b6f2
TG
75 while (l->dns_servers)
76 dns_server_free(l->dns_servers);
74b2466e
LP
77
78 free(l);
79 return NULL;
1716f6dc
LP
80}
81
82static void link_allocate_scopes(Link *l) {
83 int r;
84
85 assert(l);
86
6073b6f2 87 if (l->dns_servers) {
1716f6dc
LP
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
90ab5042
LP
96 if (link_relevant(l, AF_INET) &&
97 l->llmnr_support != SUPPORT_NO &&
db97a66a 98 l->manager->llmnr_support != SUPPORT_NO) {
1716f6dc
LP
99 if (!l->llmnr_ipv4_scope) {
100 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
101 if (r < 0)
102 log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
103 }
104 } else
105 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
106
90ab5042
LP
107 if (link_relevant(l, AF_INET6) &&
108 l->llmnr_support != SUPPORT_NO &&
109 l->manager->llmnr_support != SUPPORT_NO &&
db97a66a 110 socket_ipv6_is_supported()) {
1716f6dc
LP
111 if (!l->llmnr_ipv6_scope) {
112 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
113 if (r < 0)
114 log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
115 }
116 } else
117 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
118}
74b2466e 119
ec2c5e43 120void link_add_rrs(Link *l, bool force_remove) {
623a4c97
LP
121 LinkAddress *a;
122
123 LIST_FOREACH(addresses, a, l->addresses)
ec2c5e43 124 link_address_add_rrs(a, force_remove);
623a4c97
LP
125}
126
74b2466e 127int link_update_rtnl(Link *l, sd_rtnl_message *m) {
1716f6dc 128 const char *n = NULL;
74b2466e
LP
129 int r;
130
131 assert(l);
132 assert(m);
133
134 r = sd_rtnl_message_link_get_flags(m, &l->flags);
135 if (r < 0)
136 return r;
137
c5ed9316 138 sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
1716f6dc
LP
139
140 if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
cc7844e7 141 strncpy(l->name, n, sizeof(l->name)-1);
1716f6dc
LP
142 char_array_0(l->name);
143 }
144
145 link_allocate_scopes(l);
ec2c5e43 146 link_add_rrs(l, false);
623a4c97 147
74b2466e
LP
148 return 0;
149}
150
6073b6f2 151static int link_update_dns_servers(Link *l) {
6f4dedb2
TG
152 _cleanup_strv_free_ char **nameservers = NULL;
153 char **nameserver;
74b2466e 154 DnsServer *s, *nx;
6f4dedb2 155 int r;
74b2466e
LP
156
157 assert(l);
158
d6731e4c 159 r = sd_network_link_get_dns(l->ifindex, &nameservers);
6f4dedb2 160 if (r < 0)
74b2466e 161 goto clear;
74b2466e 162
5cb36f41
LP
163 LIST_FOREACH(servers, s, l->dns_servers)
164 s->marked = true;
165
6f4dedb2
TG
166 STRV_FOREACH(nameserver, nameservers) {
167 union in_addr_union a;
168 int family;
74b2466e 169
6f4dedb2
TG
170 r = in_addr_from_string_auto(*nameserver, &family, &a);
171 if (r < 0)
172 goto clear;
74b2466e 173
6f4dedb2 174 s = link_find_dns_server(l, family, &a);
74b2466e
LP
175 if (s)
176 s->marked = false;
177 else {
4e945a6f 178 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
74b2466e
LP
179 if (r < 0)
180 goto clear;
181 }
182 }
183
6073b6f2 184 LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
74b2466e
LP
185 if (s->marked)
186 dns_server_free(s);
187
188 return 0;
189
190clear:
6073b6f2
TG
191 while (l->dns_servers)
192 dns_server_free(l->dns_servers);
74b2466e
LP
193
194 return r;
195}
196
19b50b5b
LP
197static int link_update_llmnr_support(Link *l) {
198 _cleanup_free_ char *b = NULL;
199 int r;
200
201 assert(l);
202
d6731e4c 203 r = sd_network_link_get_llmnr(l->ifindex, &b);
19b50b5b
LP
204 if (r < 0)
205 goto clear;
206
207 r = parse_boolean(b);
208 if (r < 0) {
209 if (streq(b, "resolve"))
210 l->llmnr_support = SUPPORT_RESOLVE;
211 else
212 goto clear;
213
214 } else if (r > 0)
215 l->llmnr_support = SUPPORT_YES;
216 else
217 l->llmnr_support = SUPPORT_NO;
218
219 return 0;
220
221clear:
222 l->llmnr_support = SUPPORT_YES;
223 return r;
224}
225
bda2c408
TG
226static int link_update_domains(Link *l) {
227 int r;
228
229 if (!l->unicast_scope)
230 return 0;
231
232 strv_free(l->unicast_scope->domains);
233 l->unicast_scope->domains = NULL;
234
235 r = sd_network_link_get_domains(l->ifindex,
236 &l->unicast_scope->domains);
237 if (r < 0)
238 return r;
239
240 return 0;
241}
242
74b2466e
LP
243int link_update_monitor(Link *l) {
244 assert(l);
245
6073b6f2 246 link_update_dns_servers(l);
19b50b5b 247 link_update_llmnr_support(l);
1716f6dc 248 link_allocate_scopes(l);
bda2c408 249 link_update_domains(l);
ec2c5e43 250 link_add_rrs(l, false);
74b2466e
LP
251
252 return 0;
253}
254
0dd25fb9 255bool link_relevant(Link *l, int family) {
1716f6dc 256 _cleanup_free_ char *state = NULL;
74b2466e
LP
257 LinkAddress *a;
258
259 assert(l);
260
ec2c5e43
LP
261 /* A link is relevant if it isn't a loopback or pointopoint
262 * device, has a link beat, can do multicast and has at least
263 * one relevant IP address */
264
265 if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT))
266 return false;
74b2466e 267
ec2c5e43 268 if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST))
74b2466e
LP
269 return false;
270
d6731e4c 271 sd_network_link_get_operational_state(l->ifindex, &state);
1716f6dc 272 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
74b2466e
LP
273 return false;
274
275 LIST_FOREACH(addresses, a, l->addresses)
1716f6dc 276 if (a->family == family && link_address_relevant(a))
74b2466e
LP
277 return true;
278
279 return false;
280}
281
623a4c97 282LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
74b2466e
LP
283 LinkAddress *a;
284
285 assert(l);
286
1716f6dc
LP
287 LIST_FOREACH(addresses, a, l->addresses)
288 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
74b2466e 289 return a;
74b2466e
LP
290
291 return NULL;
292}
293
623a4c97 294DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) {
6073b6f2 295 DnsServer *s;
74b2466e
LP
296
297 assert(l);
298
6073b6f2 299 LIST_FOREACH(servers, s, l->dns_servers)
1716f6dc 300 if (s->family == family && in_addr_equal(family, &s->address, in_addr))
74b2466e 301 return s;
74b2466e
LP
302 return NULL;
303}
304
2c27fbca 305DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
4e945a6f
LP
306 assert(l);
307
308 if (l->current_dns_server == s)
309 return s;
310
311 if (s) {
312 _cleanup_free_ char *ip = NULL;
313
314 in_addr_to_string(s->family, &s->address, &ip);
315 log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name);
2c27fbca 316 }
4e945a6f
LP
317
318 l->current_dns_server = s;
2c27fbca
LP
319
320 if (l->unicast_scope)
321 dns_cache_flush(&l->unicast_scope->cache);
322
4e945a6f
LP
323 return s;
324}
325
74b2466e
LP
326DnsServer *link_get_dns_server(Link *l) {
327 assert(l);
328
329 if (!l->current_dns_server)
4e945a6f 330 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
331
332 return l->current_dns_server;
333}
334
335void link_next_dns_server(Link *l) {
336 assert(l);
337
74b2466e
LP
338 if (!l->current_dns_server)
339 return;
340
341 if (l->current_dns_server->servers_next) {
4e945a6f 342 link_set_dns_server(l, l->current_dns_server->servers_next);
74b2466e
LP
343 return;
344 }
345
4e945a6f 346 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
347}
348
623a4c97 349int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
74b2466e
LP
350 LinkAddress *a;
351
352 assert(l);
353 assert(in_addr);
354
355 a = new0(LinkAddress, 1);
356 if (!a)
357 return -ENOMEM;
358
359 a->family = family;
360 a->in_addr = *in_addr;
361
362 a->link = l;
363 LIST_PREPEND(addresses, l->addresses, a);
364
365 if (ret)
366 *ret = a;
367
368 return 0;
369}
370
371LinkAddress *link_address_free(LinkAddress *a) {
372 if (!a)
373 return NULL;
374
623a4c97 375 if (a->link) {
74b2466e
LP
376 LIST_REMOVE(addresses, a->link->addresses, a);
377
623a4c97 378 if (a->llmnr_address_rr) {
623a4c97
LP
379 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
380 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
381 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
382 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
623a4c97
LP
383 }
384
385 if (a->llmnr_ptr_rr) {
386 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
387 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
388 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
389 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
623a4c97
LP
390 }
391 }
392
ec2c5e43
LP
393 dns_resource_record_unref(a->llmnr_address_rr);
394 dns_resource_record_unref(a->llmnr_ptr_rr);
395
74b2466e
LP
396 free(a);
397 return NULL;
398}
399
ec2c5e43 400void link_address_add_rrs(LinkAddress *a, bool force_remove) {
623a4c97
LP
401 int r;
402
403 assert(a);
404
ec2c5e43 405 if (a->family == AF_INET) {
623a4c97 406
4e945a6f
LP
407 if (!force_remove &&
408 link_address_relevant(a) &&
409 a->link->llmnr_ipv4_scope &&
19b50b5b 410 a->link->llmnr_support == SUPPORT_YES &&
4e945a6f
LP
411 a->link->manager->llmnr_support == SUPPORT_YES) {
412
623a4c97 413 if (!a->link->manager->host_ipv4_key) {
ec2c5e43
LP
414 a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
415 if (!a->link->manager->host_ipv4_key) {
416 r = -ENOMEM;
417 goto fail;
418 }
623a4c97 419 }
623a4c97 420
623a4c97 421 if (!a->llmnr_address_rr) {
ec2c5e43
LP
422 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
423 if (!a->llmnr_address_rr) {
424 r = -ENOMEM;
425 goto fail;
426 }
427
428 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
429 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
430 }
431
ec2c5e43
LP
432 if (!a->llmnr_ptr_rr) {
433 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
434 if (r < 0)
435 goto fail;
623a4c97 436
ec2c5e43
LP
437 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
438 }
623a4c97 439
ec2c5e43 440 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
623a4c97 441 if (r < 0)
cc7844e7 442 log_warning("Failed to add A record to LLMNR zone: %s", strerror(-r));
623a4c97 443
ec2c5e43 444 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
623a4c97 445 if (r < 0)
cc7844e7 446 log_warning("Failed to add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
623a4c97 447 } else {
ec2c5e43
LP
448 if (a->llmnr_address_rr) {
449 if (a->link->llmnr_ipv4_scope)
450 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
451 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
452 }
453
454 if (a->llmnr_ptr_rr) {
455 if (a->link->llmnr_ipv4_scope)
456 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
457 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
458 }
623a4c97
LP
459 }
460 }
461
ec2c5e43 462 if (a->family == AF_INET6) {
623a4c97 463
4e945a6f
LP
464 if (!force_remove &&
465 link_address_relevant(a) &&
466 a->link->llmnr_ipv6_scope &&
19b50b5b 467 a->link->llmnr_support == SUPPORT_YES &&
4e945a6f
LP
468 a->link->manager->llmnr_support == SUPPORT_YES) {
469
623a4c97 470 if (!a->link->manager->host_ipv6_key) {
ec2c5e43
LP
471 a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
472 if (!a->link->manager->host_ipv6_key) {
473 r = -ENOMEM;
474 goto fail;
475 }
623a4c97 476 }
623a4c97 477
623a4c97 478 if (!a->llmnr_address_rr) {
ec2c5e43
LP
479 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
480 if (!a->llmnr_address_rr) {
481 r = -ENOMEM;
482 goto fail;
483 }
484
485 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
486 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
487 }
488
ec2c5e43
LP
489 if (!a->llmnr_ptr_rr) {
490 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
491 if (r < 0)
492 goto fail;
623a4c97 493
ec2c5e43
LP
494 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
495 }
623a4c97 496
ec2c5e43 497 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
623a4c97 498 if (r < 0)
ec2c5e43 499 log_warning("Failed to add AAAA record to LLMNR zone: %s", strerror(-r));
623a4c97 500
ec2c5e43 501 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
623a4c97 502 if (r < 0)
ec2c5e43 503 log_warning("Failed to add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
623a4c97 504 } else {
ec2c5e43
LP
505 if (a->llmnr_address_rr) {
506 if (a->link->llmnr_ipv6_scope)
507 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
508 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
509 }
510
511 if (a->llmnr_ptr_rr) {
512 if (a->link->llmnr_ipv6_scope)
513 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
514 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
515 }
623a4c97
LP
516 }
517 }
518
519 return;
520
521fail:
522 log_debug("Failed to update address RRs: %s", strerror(-r));
523}
524
74b2466e
LP
525int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
526 int r;
527 assert(a);
528 assert(m);
529
530 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
531 if (r < 0)
532 return r;
533
1716f6dc 534 sd_rtnl_message_addr_get_scope(m, &a->scope);
74b2466e 535
1716f6dc 536 link_allocate_scopes(a->link);
ec2c5e43 537 link_add_rrs(a->link, false);
623a4c97 538
74b2466e
LP
539 return 0;
540}
541
542bool link_address_relevant(LinkAddress *a) {
543 assert(a);
544
7b85d72f 545 if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))
74b2466e
LP
546 return false;
547
548 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
549 return false;
550
551 return true;
552}