]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-radv.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[thirdparty/systemd.git] / src / network / networkd-radv.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright (C) 2017 Intel Corporation. All rights reserved.
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <netinet/icmp6.h>
22 #include <arpa/inet.h>
23
24 #include "networkd-address.h"
25 #include "networkd-manager.h"
26 #include "networkd-radv.h"
27 #include "parse-util.h"
28 #include "sd-radv.h"
29 #include "string-util.h"
30
31 int config_parse_router_prefix_delegation(
32 const char *unit,
33 const char *filename,
34 unsigned line,
35 const char *section,
36 unsigned section_line,
37 const char *lvalue,
38 int ltype,
39 const char *rvalue,
40 void *data,
41 void *userdata) {
42
43 Network *network = userdata;
44 int d;
45
46 assert(filename);
47 assert(section);
48 assert(lvalue);
49 assert(rvalue);
50 assert(data);
51
52 if (streq(rvalue, "static"))
53 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_STATIC;
54 else if (streq(rvalue, "dhcpv6"))
55 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_DHCP6;
56 else {
57 d = parse_boolean(rvalue);
58 if (d > 0)
59 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_BOTH;
60 else
61 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
62
63 if (d < 0)
64 log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Router prefix delegation '%s' is invalid, ignoring assignment: %m", rvalue);
65 }
66
67 return 0;
68 }
69
70 int config_parse_router_preference(const char *unit,
71 const char *filename,
72 unsigned line,
73 const char *section,
74 unsigned section_line,
75 const char *lvalue,
76 int ltype,
77 const char *rvalue,
78 void *data,
79 void *userdata) {
80 Network *network = userdata;
81
82 assert(filename);
83 assert(section);
84 assert(lvalue);
85 assert(rvalue);
86 assert(data);
87
88 if (streq(rvalue, "high"))
89 network->router_preference = SD_NDISC_PREFERENCE_HIGH;
90 else if (STR_IN_SET(rvalue, "medium", "normal", "default"))
91 network->router_preference = SD_NDISC_PREFERENCE_MEDIUM;
92 else if (streq(rvalue, "low"))
93 network->router_preference = SD_NDISC_PREFERENCE_LOW;
94 else
95 log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Router preference '%s' is invalid, ignoring assignment: %m", rvalue);
96
97 return 0;
98 }
99
100 void prefix_free(Prefix *prefix) {
101 if (!prefix)
102 return;
103
104 if (prefix->network) {
105 LIST_REMOVE(prefixes, prefix->network->static_prefixes, prefix);
106 assert(prefix->network->n_static_prefixes > 0);
107 prefix->network->n_static_prefixes--;
108
109 if (prefix->section)
110 hashmap_remove(prefix->network->prefixes_by_section,
111 prefix->section);
112 }
113
114 prefix->radv_prefix = sd_radv_prefix_unref(prefix->radv_prefix);
115
116 free(prefix);
117 }
118
119 int prefix_new(Prefix **ret) {
120 Prefix *prefix = NULL;
121
122 prefix = new0(Prefix, 1);
123 if (!prefix)
124 return -ENOMEM;
125
126 if (sd_radv_prefix_new(&prefix->radv_prefix) < 0)
127 return -ENOMEM;
128
129 *ret = TAKE_PTR(prefix);
130
131 return 0;
132 }
133
134 int prefix_new_static(Network *network, const char *filename,
135 unsigned section_line, Prefix **ret) {
136 _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
137 _cleanup_prefix_free_ Prefix *prefix = NULL;
138 int r;
139
140 assert(network);
141 assert(ret);
142 assert(!!filename == (section_line > 0));
143
144 if (filename) {
145 r = network_config_section_new(filename, section_line, &n);
146 if (r < 0)
147 return r;
148
149 if (section_line) {
150 prefix = hashmap_get(network->prefixes_by_section, n);
151 if (prefix) {
152 *ret = TAKE_PTR(prefix);
153
154 return 0;
155 }
156 }
157 }
158
159 r = prefix_new(&prefix);
160 if (r < 0)
161 return r;
162
163 if (filename) {
164 prefix->section = TAKE_PTR(n);
165
166 r = hashmap_put(network->prefixes_by_section, prefix->section,
167 prefix);
168 if (r < 0)
169 return r;
170 }
171
172 prefix->network = network;
173 LIST_APPEND(prefixes, network->static_prefixes, prefix);
174 network->n_static_prefixes++;
175
176 *ret = TAKE_PTR(prefix);
177
178 return 0;
179 }
180
181 int config_parse_prefix(const char *unit,
182 const char *filename,
183 unsigned line,
184 const char *section,
185 unsigned section_line,
186 const char *lvalue,
187 int ltype,
188 const char *rvalue,
189 void *data,
190 void *userdata) {
191
192 Network *network = userdata;
193 _cleanup_prefix_free_ Prefix *p = NULL;
194 uint8_t prefixlen = 64;
195 union in_addr_union in6addr;
196 int r;
197
198 assert(filename);
199 assert(section);
200 assert(lvalue);
201 assert(rvalue);
202 assert(data);
203
204 r = prefix_new_static(network, filename, section_line, &p);
205 if (r < 0)
206 return r;
207
208 r = in_addr_prefix_from_string(rvalue, AF_INET6, &in6addr, &prefixlen);
209 if (r < 0) {
210 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix is invalid, ignoring assignment: %s", rvalue);
211 return 0;
212 }
213
214 if (sd_radv_prefix_set_prefix(p->radv_prefix, &in6addr.in6, prefixlen) < 0)
215 return -EADDRNOTAVAIL;
216
217 log_syntax(unit, LOG_INFO, filename, line, r, "Found prefix %s", rvalue);
218
219 p = NULL;
220
221 return 0;
222 }
223
224 int config_parse_prefix_flags(const char *unit,
225 const char *filename,
226 unsigned line,
227 const char *section,
228 unsigned section_line,
229 const char *lvalue,
230 int ltype,
231 const char *rvalue,
232 void *data,
233 void *userdata) {
234 Network *network = userdata;
235 _cleanup_prefix_free_ Prefix *p = NULL;
236 int r, val;
237
238 assert(filename);
239 assert(section);
240 assert(lvalue);
241 assert(rvalue);
242 assert(data);
243
244 r = prefix_new_static(network, filename, section_line, &p);
245 if (r < 0)
246 return r;
247
248 r = parse_boolean(rvalue);
249 if (r < 0) {
250 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
251 return 0;
252 }
253
254 val = r;
255
256 if (streq(lvalue, "OnLink"))
257 r = sd_radv_prefix_set_onlink(p->radv_prefix, val);
258 else if (streq(lvalue, "AddressAutoconfiguration"))
259 r = sd_radv_prefix_set_address_autoconfiguration(p->radv_prefix, val);
260 if (r < 0)
261 return r;
262
263 p = NULL;
264
265 return 0;
266 }
267
268 int config_parse_prefix_lifetime(const char *unit,
269 const char *filename,
270 unsigned line,
271 const char *section,
272 unsigned section_line,
273 const char *lvalue,
274 int ltype,
275 const char *rvalue,
276 void *data,
277 void *userdata) {
278 Network *network = userdata;
279 _cleanup_prefix_free_ Prefix *p = NULL;
280 usec_t usec;
281 int r;
282
283 assert(filename);
284 assert(section);
285 assert(lvalue);
286 assert(rvalue);
287 assert(data);
288
289 r = prefix_new_static(network, filename, section_line, &p);
290 if (r < 0)
291 return r;
292
293 r = parse_sec(rvalue, &usec);
294 if (r < 0) {
295 log_syntax(unit, LOG_ERR, filename, line, r, "Lifetime is invalid, ignoring assignment: %s", rvalue);
296 return 0;
297 }
298
299 /* a value of 0xffffffff represents infinity */
300 if (streq(lvalue, "PreferredLifetimeSec"))
301 r = sd_radv_prefix_set_preferred_lifetime(p->radv_prefix,
302 DIV_ROUND_UP(usec, USEC_PER_SEC));
303 else if (streq(lvalue, "ValidLifetimeSec"))
304 r = sd_radv_prefix_set_valid_lifetime(p->radv_prefix,
305 DIV_ROUND_UP(usec, USEC_PER_SEC));
306 if (r < 0)
307 return r;
308
309 p = NULL;
310
311 return 0;
312 }
313
314 static int radv_get_ip6dns(Network *network, struct in6_addr **dns,
315 size_t *n_dns) {
316 _cleanup_free_ struct in6_addr *addresses = NULL;
317 size_t i, n_addresses = 0, n_allocated = 0;
318
319 assert(network);
320 assert(dns);
321 assert(n_dns);
322
323 for (i = 0; i < network->n_dns; i++) {
324 union in_addr_union *addr;
325
326 if (network->dns[i].family != AF_INET6)
327 continue;
328
329 addr = &network->dns[i].address;
330
331 if (in_addr_is_null(AF_INET6, addr) ||
332 in_addr_is_link_local(AF_INET6, addr) ||
333 in_addr_is_localhost(AF_INET6, addr))
334 continue;
335
336 if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
337 return -ENOMEM;
338
339 addresses[n_addresses++] = addr->in6;
340 }
341
342 if (addresses) {
343 *dns = TAKE_PTR(addresses);
344
345 *n_dns = n_addresses;
346 }
347
348 return n_addresses;
349 }
350
351 static int radv_set_dns(Link *link, Link *uplink) {
352 _cleanup_free_ struct in6_addr *dns = NULL;
353 size_t n_dns;
354 usec_t lifetime_usec;
355 int r;
356
357 if (!link->network->router_emit_dns)
358 return 0;
359
360 if (link->network->router_dns) {
361 dns = newdup(struct in6_addr, link->network->router_dns,
362 link->network->n_router_dns);
363 if (dns == NULL)
364 return -ENOMEM;
365
366 n_dns = link->network->n_router_dns;
367 lifetime_usec = link->network->router_dns_lifetime_usec;
368
369 goto set_dns;
370 }
371
372 lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
373
374 r = radv_get_ip6dns(link->network, &dns, &n_dns);
375 if (r > 0)
376 goto set_dns;
377
378 if (uplink) {
379 if (uplink->network == NULL) {
380 log_link_debug(uplink, "Cannot fetch DNS servers as uplink interface is not managed by us");
381 return 0;
382 }
383
384 r = radv_get_ip6dns(uplink->network, &dns, &n_dns);
385 if (r > 0)
386 goto set_dns;
387 }
388
389 return 0;
390
391 set_dns:
392 return sd_radv_set_rdnss(link->radv,
393 DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
394 dns, n_dns);
395 }
396
397 static int radv_set_domains(Link *link, Link *uplink) {
398 char **search_domains;
399 usec_t lifetime_usec;
400
401 if (!link->network->router_emit_domains)
402 return 0;
403
404 search_domains = link->network->router_search_domains;
405 lifetime_usec = link->network->router_dns_lifetime_usec;
406
407 if (search_domains)
408 goto set_domains;
409
410 lifetime_usec = SD_RADV_DEFAULT_DNS_LIFETIME_USEC;
411
412 search_domains = link->network->search_domains;
413 if (search_domains)
414 goto set_domains;
415
416 if (uplink) {
417 if (uplink->network == NULL) {
418 log_link_debug(uplink, "Cannot fetch DNS search domains as uplink interface is not managed by us");
419 return 0;
420 }
421
422 search_domains = uplink->network->search_domains;
423 if (search_domains)
424 goto set_domains;
425 }
426
427 return 0;
428
429 set_domains:
430 return sd_radv_set_dnssl(link->radv,
431 DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
432 search_domains);
433
434 }
435
436 int radv_emit_dns(Link *link) {
437 Link *uplink;
438 int r;
439
440 uplink = manager_find_uplink(link->manager, link);
441
442 r = radv_set_dns(link, uplink);
443 if (r < 0)
444 log_link_warning_errno(link, r, "Could not set RA DNS: %m");
445
446 r = radv_set_domains(link, uplink);
447 if (r < 0)
448 log_link_warning_errno(link, r, "Could not set RA Domains: %m");
449
450 return 0;
451 }
452
453 int radv_configure(Link *link) {
454 int r;
455 Prefix *p;
456
457 assert(link);
458 assert(link->network);
459
460 r = sd_radv_new(&link->radv);
461 if (r < 0)
462 return r;
463
464 r = sd_radv_attach_event(link->radv, NULL, 0);
465 if (r < 0)
466 return r;
467
468 r = sd_radv_set_mac(link->radv, &link->mac);
469 if (r < 0)
470 return r;
471
472 r = sd_radv_set_ifindex(link->radv, link->ifindex);
473 if (r < 0)
474 return r;
475
476 r = sd_radv_set_managed_information(link->radv, link->network->router_managed);
477 if (r < 0)
478 return r;
479
480 r = sd_radv_set_other_information(link->radv, link->network->router_other_information);
481 if (r < 0)
482 return r;
483
484 /* a value of 0xffffffff represents infinity, 0x0 means this host is
485 not a router */
486 r = sd_radv_set_router_lifetime(link->radv,
487 DIV_ROUND_UP(link->network->router_lifetime_usec, USEC_PER_SEC));
488 if (r < 0)
489 return r;
490
491 if (link->network->router_lifetime_usec > 0) {
492 r = sd_radv_set_preference(link->radv,
493 link->network->router_preference);
494 if (r < 0)
495 return r;
496 }
497
498 if (IN_SET(link->network->router_prefix_delegation,
499 RADV_PREFIX_DELEGATION_STATIC,
500 RADV_PREFIX_DELEGATION_BOTH)) {
501 LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
502 r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
503 if (r != -EEXIST && r < 0)
504 return r;
505 }
506 }
507
508 return radv_emit_dns(link);
509 }