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