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