]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-radv.c
network: replace udev_device by sd_device
[thirdparty/systemd.git] / src / network / networkd-radv.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
091214b6 2/***
810adae9 3 Copyright © 2017 Intel Corporation. All rights reserved.
091214b6
PF
4***/
5
6#include <netinet/icmp6.h>
7#include <arpa/inet.h>
8
9#include "networkd-address.h"
c555a358 10#include "networkd-manager.h"
091214b6 11#include "networkd-radv.h"
6e849e95 12#include "parse-util.h"
091214b6 13#include "sd-radv.h"
6e849e95 14#include "string-util.h"
51517f9e 15#include "strv.h"
6e849e95 16
9c3b99fe
YW
17int 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
56a23cb4
PF
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
6e849e95
PF
56int 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
86void 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
105int prefix_new(Prefix **ret) {
15b8332e 106 _cleanup_(prefix_freep) Prefix *prefix = NULL;
6e849e95
PF
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
ae2a15bc 115 *ret = TAKE_PTR(prefix);
6e849e95
PF
116
117 return 0;
118}
119
120int prefix_new_static(Network *network, const char *filename,
121 unsigned section_line, Prefix **ret) {
8e766630
LP
122 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
123 _cleanup_(prefix_freep) Prefix *prefix = NULL;
6e849e95
PF
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) {
1cc6c93a 138 *ret = TAKE_PTR(prefix);
6e849e95
PF
139
140 return 0;
141 }
142 }
143 }
144
145 r = prefix_new(&prefix);
146 if (r < 0)
147 return r;
148
149 if (filename) {
1cc6c93a 150 prefix->section = TAKE_PTR(n);
6e849e95
PF
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
1cc6c93a 162 *ret = TAKE_PTR(prefix);
6e849e95
PF
163
164 return 0;
165}
166
167int 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;
8e766630 179 _cleanup_(prefix_freep) Prefix *p = NULL;
6e849e95
PF
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
210int 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;
8e766630 221 _cleanup_(prefix_freep) Prefix *p = NULL;
6e849e95
PF
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
254int 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;
8e766630 265 _cleanup_(prefix_freep) Prefix *p = NULL;
6e849e95
PF
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}
091214b6 299
c555a358
PF
300static 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) {
ae2a15bc 329 *dns = TAKE_PTR(addresses);
c555a358
PF
330
331 *n_dns = n_addresses;
332 }
333
334 return n_addresses;
335}
336
337static 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) {
349a981d
PF
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
c555a358
PF
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
383static 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) {
349a981d
PF
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
c555a358
PF
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
422int 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
091214b6
PF
439int 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
301a2fb9
PF
470 /* a value of 0xffffffff represents infinity, 0x0 means this host is
471 not a router */
091214b6 472 r = sd_radv_set_router_lifetime(link->radv,
945e3225 473 DIV_ROUND_UP(link->network->router_lifetime_usec, USEC_PER_SEC));
091214b6
PF
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
56a23cb4
PF
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) {
d601b566 488 r = sd_radv_add_prefix(link->radv, p->radv_prefix, false);
56a23cb4
PF
489 if (r != -EEXIST && r < 0)
490 return r;
491 }
091214b6
PF
492 }
493
c555a358 494 return radv_emit_dns(link);
091214b6 495}