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