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