]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-ndisc.c
network: ndisc: remove old addresses and routes after at least one SLAAC address...
[thirdparty/systemd.git] / src / network / networkd-ndisc.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
a13c50e7 2/***
810adae9 3 Copyright © 2014 Intel Corporation. All rights reserved.
a13c50e7
TG
4***/
5
9d96e6c3 6#include <netinet/icmp6.h>
23f53b99 7#include <arpa/inet.h>
a13c50e7 8
a13c50e7
TG
9#include "sd-ndisc.h"
10
d909e4af 11#include "missing_network.h"
ca5ad760 12#include "networkd-dhcp6.h"
73854ba1 13#include "networkd-manager.h"
1e7a0e21 14#include "networkd-ndisc.h"
23f53b99 15#include "networkd-route.h"
ac24e418 16#include "string-table.h"
5f506a55 17#include "string-util.h"
51517f9e 18#include "strv.h"
1e7a0e21
LP
19
20#define NDISC_DNSSL_MAX 64U
21#define NDISC_RDNSS_MAX 64U
6554550f 22#define NDISC_PREFIX_LFT_MIN 7200U
fe307276 23
5f506a55
SS
24#define DAD_CONFLICTS_IDGEN_RETRIES_RFC7217 3
25
26/* https://tools.ietf.org/html/rfc5453 */
27/* https://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xml */
28
29#define SUBNET_ROUTER_ANYCAST_ADDRESS_RFC4291 ((struct in6_addr) { .s6_addr = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } })
30#define SUBNET_ROUTER_ANYCAST_PREFIXLEN 8
31#define RESERVED_IPV6_INTERFACE_IDENTIFIERS_ADDRESS_RFC4291 ((struct in6_addr) { .s6_addr = { 0x02, 0x00, 0x5E, 0xFF, 0xFE } })
32#define RESERVED_IPV6_INTERFACE_IDENTIFIERS_PREFIXLEN 5
33#define RESERVED_SUBNET_ANYCAST_ADDRESSES_RFC4291 ((struct in6_addr) { .s6_addr = { 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } })
34#define RESERVED_SUBNET_ANYCAST_PREFIXLEN 7
35
36#define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
37
69203fba
YW
38static int ndisc_remove_old(Link *link, bool force);
39
40static int ndisc_address_callback(Address *address) {
41 Address *a;
42 Iterator i;
43
44 assert(address);
45 assert(address->link);
46
47 /* Make this called only once */
48 SET_FOREACH(a, address->link->ndisc_addresses, i)
49 a->callback = NULL;
50
51 return ndisc_remove_old(address->link, true);
52}
53
54static int ndisc_remove_old(Link *link, bool force) {
55 Address *address;
56 Route *route;
57 Iterator i;
58 int k, r = 0;
59
60 assert(link);
61
62 if (!force) {
63 bool set_callback = !set_isempty(link->ndisc_addresses);
64
65 if (!link->ndisc_addresses_configured || !link->ndisc_routes_configured)
66 return 0;
67
68 SET_FOREACH(address, link->ndisc_addresses, i)
69 if (address_is_ready(address)) {
70 set_callback = false;
71 break;
72 }
73
74 if (set_callback) {
75 SET_FOREACH(address, link->ndisc_addresses, i)
76 address->callback = ndisc_address_callback;
77 return 0;
78 }
79 }
80
81 if (!set_isempty(link->ndisc_addresses_old) || !set_isempty(link->ndisc_routes_old))
82 log_link_debug(link, "Removing old NDisc addresses and routes.");
83
84 link_dirty(link);
85
86 SET_FOREACH(address, link->ndisc_addresses_old, i) {
87 k = address_remove(address, link, NULL);
88 if (k < 0)
89 r = k;
90 }
91
92 SET_FOREACH(route, link->ndisc_routes_old, i) {
93 k = route_remove(route, link, NULL);
94 if (k < 0)
95 r = k;
96 }
97
98 return r;
99}
100
d98c546d 101static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
3b015d40
TG
102 int r;
103
104 assert(link);
d98c546d 105 assert(link->ndisc_routes_messages > 0);
3b015d40 106
d98c546d 107 link->ndisc_routes_messages--;
3b015d40 108
4ff296b0
YW
109 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
110 return 1;
111
3b015d40 112 r = sd_netlink_message_get_errno(m);
4ff296b0 113 if (r < 0 && r != -EEXIST) {
d98c546d 114 log_link_message_error_errno(link, m, r, "Could not set NDisc route");
4ff296b0
YW
115 link_enter_failed(link);
116 return 1;
117 }
3b015d40 118
d98c546d
YW
119 if (link->ndisc_routes_messages == 0) {
120 log_link_debug(link, "NDisc routes set.");
121 link->ndisc_routes_configured = true;
69203fba
YW
122
123 r = ndisc_remove_old(link, false);
124 if (r < 0) {
125 link_enter_failed(link);
126 return 1;
127 }
128
3b015d40
TG
129 link_check_ready(link);
130 }
131
132 return 1;
133}
134
d98c546d 135static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
73854ba1
YW
136 int r;
137
138 assert(link);
d98c546d 139 assert(link->ndisc_addresses_messages > 0);
73854ba1 140
d98c546d 141 link->ndisc_addresses_messages--;
73854ba1 142
4ff296b0
YW
143 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
144 return 1;
145
73854ba1 146 r = sd_netlink_message_get_errno(m);
4ff296b0 147 if (r < 0 && r != -EEXIST) {
d98c546d 148 log_link_message_error_errno(link, m, r, "Could not set NDisc address");
4ff296b0
YW
149 link_enter_failed(link);
150 return 1;
151 } else if (r >= 0)
152 (void) manager_rtnl_process_address(rtnl, m, link->manager);
73854ba1 153
d98c546d
YW
154 if (link->ndisc_addresses_messages == 0) {
155 log_link_debug(link, "NDisc SLAAC addresses set.");
156 link->ndisc_addresses_configured = true;
69203fba
YW
157
158 r = ndisc_remove_old(link, false);
159 if (r < 0) {
160 link_enter_failed(link);
161 return 1;
162 }
163
4ff296b0
YW
164 r = link_request_set_routes(link);
165 if (r < 0) {
166 link_enter_failed(link);
167 return 1;
168 }
73854ba1
YW
169 }
170
171 return 1;
172}
173
69203fba
YW
174static int ndisc_route_configure(Route *route, Link *link) {
175 Route *ret;
176 int r;
177
178 assert(route);
179 assert(link);
180
181 r = route_configure(route, link, ndisc_route_handler, &ret);
182 if (r < 0)
183 return log_link_error_errno(link, r, "Failed to set NDisc route: %m");
184
185 link->ndisc_routes_messages++;
186
187 r = set_ensure_put(&link->ndisc_routes, &route_hash_ops, ret);
188 if (r < 0)
189 return log_link_error_errno(link, r, "Failed to store NDisc route: %m");
190
191 (void) set_remove(link->ndisc_routes_old, ret);
192
193 return 0;
194}
195
196static int ndisc_address_configure(Address *address, Link *link) {
197 Address *ret;
198 int r;
199
200 assert(address);
201 assert(link);
202
203 r = address_configure(address, link, ndisc_address_handler, true, &ret);
204 if (r < 0)
205 return log_link_error_errno(link, r, "Failed to set NDisc SLAAC address: %m");
206
207 link->ndisc_addresses_messages++;
208
209 r = set_ensure_put(&link->ndisc_addresses, &address_hash_ops, ret);
210 if (r < 0)
211 return log_link_error_errno(link, r, "Failed to store NDisc SLAAC address: %m");
212
213 (void) set_remove(link->ndisc_addresses_old, ret);
214
215 return 0;
216}
217
d5017c84 218static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
8e766630 219 _cleanup_(route_freep) Route *route = NULL;
ce2ea782 220 union in_addr_union gateway;
1e7a0e21
LP
221 uint16_t lifetime;
222 unsigned preference;
d6fceaf1 223 uint32_t mtu;
3b015d40 224 usec_t time_now;
13e8a49a 225 int r;
3b015d40 226
3b015d40 227 assert(link);
1e7a0e21 228 assert(rt);
3b015d40 229
1e7a0e21 230 r = sd_ndisc_router_get_lifetime(rt, &lifetime);
d5017c84 231 if (r < 0)
13e8a49a 232 return log_link_error_errno(link, r, "Failed to get gateway lifetime from RA: %m");
d5017c84 233
1e7a0e21 234 if (lifetime == 0) /* not a default router */
d5017c84 235 return 0;
1e7a0e21 236
ce2ea782 237 r = sd_ndisc_router_get_address(rt, &gateway.in6);
d5017c84 238 if (r < 0)
13e8a49a 239 return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
1e7a0e21 240
5eec0a08
YW
241 if (address_exists(link, AF_INET6, &gateway)) {
242 if (DEBUG_LOGGING) {
243 _cleanup_free_ char *buffer = NULL;
6d7c7615 244
5eec0a08
YW
245 (void) in_addr_to_string(AF_INET6, &gateway, &buffer);
246 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
247 strnull(buffer));
6d7c7615 248 }
5eec0a08 249 return 0;
ce2ea782 250 }
6d7c7615 251
1e7a0e21 252 r = sd_ndisc_router_get_preference(rt, &preference);
d5017c84 253 if (r < 0)
13e8a49a 254 return log_link_error_errno(link, r, "Failed to get default router preference from RA: %m");
1e7a0e21
LP
255
256 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84 257 if (r < 0)
13e8a49a 258 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21 259
d6fceaf1 260 r = sd_ndisc_router_get_mtu(rt, &mtu);
29b5ad08
JT
261 if (r == -ENODATA)
262 mtu = 0;
d5017c84 263 else if (r < 0)
13e8a49a 264 return log_link_error_errno(link, r, "Failed to get default router MTU from RA: %m");
d6fceaf1 265
1e7a0e21 266 r = route_new(&route);
d5017c84 267 if (r < 0)
13e8a49a 268 return log_oom();
1e7a0e21
LP
269
270 route->family = AF_INET6;
bdb9f580 271 route->table = link_get_ipv6_accept_ra_route_table(link);
1bf1bfd9 272 route->priority = link->network->dhcp6_route_metric;
1e7a0e21
LP
273 route->protocol = RTPROT_RA;
274 route->pref = preference;
ce2ea782 275 route->gw = gateway;
1e7a0e21 276 route->lifetime = time_now + lifetime * USEC_PER_SEC;
d6fceaf1 277 route->mtu = mtu;
1e7a0e21 278
69203fba 279 r = ndisc_route_configure(route, link);
13e8a49a
YW
280 if (r < 0)
281 return log_link_error_errno(link, r, "Could not set default route: %m");
d5017c84 282
1985c54f
YW
283 Route *route_gw;
284 LIST_FOREACH(routes, route_gw, link->network->static_routes) {
285 if (!route_gw->gateway_from_dhcp)
286 continue;
287
288 if (route_gw->family != AF_INET6)
289 continue;
290
291 route_gw->gw = gateway;
292
69203fba 293 r = ndisc_route_configure(route_gw, link);
13e8a49a
YW
294 if (r < 0)
295 return log_link_error_errno(link, r, "Could not set gateway: %m");
1985c54f
YW
296 }
297
d5017c84 298 return 0;
1e7a0e21
LP
299}
300
92ee90af
YW
301static bool stableprivate_address_is_valid(const struct in6_addr *addr) {
302 assert(addr);
303
304 /* According to rfc4291, generated address should not be in the following ranges. */
305
306 if (memcmp(addr, &SUBNET_ROUTER_ANYCAST_ADDRESS_RFC4291, SUBNET_ROUTER_ANYCAST_PREFIXLEN) == 0)
307 return false;
308
309 if (memcmp(addr, &RESERVED_IPV6_INTERFACE_IDENTIFIERS_ADDRESS_RFC4291, RESERVED_IPV6_INTERFACE_IDENTIFIERS_PREFIXLEN) == 0)
310 return false;
311
312 if (memcmp(addr, &RESERVED_SUBNET_ANYCAST_ADDRESSES_RFC4291, RESERVED_SUBNET_ANYCAST_PREFIXLEN) == 0)
313 return false;
314
315 return true;
316}
317
318static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr **ret) {
319 _cleanup_free_ struct in6_addr *addr = NULL;
320 sd_id128_t secret_key;
321 struct siphash state;
322 uint64_t rid;
323 size_t l;
324 int r;
325
326 /* According to rfc7217 section 5.1
327 * RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) */
328
329 r = sd_id128_get_machine_app_specific(NDISC_APP_ID, &secret_key);
330 if (r < 0)
331 return log_error_errno(r, "Failed to generate key: %m");
332
333 siphash24_init(&state, secret_key.bytes);
334
335 l = MAX(DIV_ROUND_UP(prefix_len, 8), 8);
336 siphash24_compress(prefix, l, &state);
337 siphash24_compress_string(link->ifname, &state);
338 siphash24_compress(&link->mac, sizeof(struct ether_addr), &state);
339 siphash24_compress(&dad_counter, sizeof(uint8_t), &state);
340
341 rid = htole64(siphash24_finalize(&state));
342
343 addr = new(struct in6_addr, 1);
344 if (!addr)
345 return log_oom();
346
347 memcpy(addr->s6_addr, prefix->s6_addr, l);
348 memcpy(addr->s6_addr + l, &rid, 16 - l);
349
350 if (!stableprivate_address_is_valid(addr)) {
351 *ret = NULL;
352 return 0;
353 }
354
355 *ret = TAKE_PTR(addr);
356 return 1;
357}
358
359static int ndisc_router_generate_addresses(Link *link, struct in6_addr *address, uint8_t prefixlen, Set **ret) {
c24c83dc 360 _cleanup_set_free_free_ Set *addresses = NULL;
5f506a55
SS
361 IPv6Token *j;
362 Iterator i;
363 int r;
364
5f506a55 365 assert(link);
c24c83dc
KF
366 assert(address);
367 assert(ret);
368
92ee90af 369 addresses = set_new(&in6_addr_hash_ops);
c24c83dc
KF
370 if (!addresses)
371 return log_oom();
5f506a55 372
2c621495 373 ORDERED_SET_FOREACH(j, link->network->ipv6_tokens, i) {
92ee90af 374 _cleanup_free_ struct in6_addr *new_address = NULL;
c24c83dc 375
5f506a55 376 if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE
92ee90af 377 && IN6_ARE_ADDR_EQUAL(&j->prefix, address)) {
0ddad04e
KF
378 /* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop
379 does not actually attempt Duplicate Address Detection; the counter will be incremented
380 only when the address generation algorithm produces an invalid address, and the loop
381 may exit with an address which ends up being unusable due to duplication on the link.
382 */
5f506a55 383 for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) {
92ee90af 384 r = make_stableprivate_address(link, &j->prefix, prefixlen, j->dad_counter, &new_address);
5f506a55 385 if (r < 0)
92ee90af
YW
386 return r;
387 if (r > 0)
c24c83dc 388 break;
5f506a55 389 }
e2c4070e 390 } else if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_STATIC) {
92ee90af
YW
391 new_address = new(struct in6_addr, 1);
392 if (!new_address)
393 return log_oom();
5f506a55 394
92ee90af
YW
395 memcpy(new_address->s6_addr, address->s6_addr, 8);
396 memcpy(new_address->s6_addr + 8, j->prefix.s6_addr + 8, 8);
397 }
c24c83dc 398
92ee90af 399 if (new_address) {
c24c83dc
KF
400 r = set_put(addresses, new_address);
401 if (r < 0)
13e8a49a 402 return log_link_error_errno(link, r, "Failed to store SLAAC address: %m");
92ee90af
YW
403 else if (r == 0)
404 log_link_debug_errno(link, r, "Generated SLAAC address is duplicated, ignoring.");
405 else
406 TAKE_PTR(new_address);
c24c83dc
KF
407 }
408 }
409
410 /* fall back to EUI-64 if no tokens provided addresses */
411 if (set_isempty(addresses)) {
92ee90af 412 _cleanup_free_ struct in6_addr *new_address = NULL;
c24c83dc 413
92ee90af
YW
414 new_address = newdup(struct in6_addr, address, 1);
415 if (!new_address)
c24c83dc
KF
416 return log_oom();
417
92ee90af 418 r = generate_ipv6_eui_64_address(link, new_address);
a781ddef
SS
419 if (r < 0)
420 return log_link_error_errno(link, r, "Failed to generate EUI64 address: %m");
421
c24c83dc
KF
422 r = set_put(addresses, new_address);
423 if (r < 0)
13e8a49a 424 return log_link_error_errno(link, r, "Failed to store SLAAC address: %m");
92ee90af 425
c24c83dc 426 TAKE_PTR(new_address);
5f506a55
SS
427 }
428
c24c83dc 429 *ret = TAKE_PTR(addresses);
5f506a55
SS
430
431 return 0;
432}
c24c83dc 433
d5017c84 434static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
5f506a55 435 uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
c24c83dc 436 _cleanup_set_free_free_ Set *addresses = NULL;
8e766630 437 _cleanup_(address_freep) Address *address = NULL;
92ee90af 438 struct in6_addr addr, *a;
1e7a0e21 439 unsigned prefixlen;
5f506a55 440 usec_t time_now;
c24c83dc 441 Iterator i;
1e7a0e21
LP
442 int r;
443
444 assert(link);
445 assert(rt);
446
6554550f 447 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84 448 if (r < 0)
13e8a49a 449 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
6554550f 450
1e7a0e21 451 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
d5017c84
YW
452 if (r < 0)
453 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
1e7a0e21
LP
454
455 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid);
d5017c84
YW
456 if (r < 0)
457 return log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");
1e7a0e21
LP
458
459 r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred);
d5017c84
YW
460 if (r < 0)
461 return log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");
3b015d40 462
92bdc3ff
SS
463 /* The preferred lifetime is never greater than the valid lifetime */
464 if (lifetime_preferred > lifetime_valid)
d5017c84 465 return 0;
92bdc3ff 466
92ee90af 467 r = sd_ndisc_router_prefix_get_address(rt, &addr);
d5017c84
YW
468 if (r < 0)
469 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
1e7a0e21 470
92ee90af 471 r = ndisc_router_generate_addresses(link, &addr, prefixlen, &addresses);
5f506a55 472 if (r < 0)
13e8a49a 473 return r;
c24c83dc 474
92ee90af
YW
475 r = address_new(&address);
476 if (r < 0)
477 return log_oom();
478
479 address->family = AF_INET6;
480 address->prefixlen = prefixlen;
481 address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
482 address->cinfo.ifa_prefered = lifetime_preferred;
483
c24c83dc 484 SET_FOREACH(a, addresses, i) {
13e8a49a
YW
485 Address *existing_address;
486
c24c83dc 487 /* see RFC4862 section 5.5.3.e */
92ee90af 488 r = address_get(link, AF_INET6, (union in_addr_union *) a, prefixlen, &existing_address);
c24c83dc
KF
489 if (r > 0) {
490 lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
491 if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
92ee90af 492 address->cinfo.ifa_valid = lifetime_valid;
c24c83dc 493 else if (lifetime_remaining <= NDISC_PREFIX_LFT_MIN)
92ee90af 494 address->cinfo.ifa_valid = lifetime_remaining;
c24c83dc 495 else
92ee90af 496 address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN;
c24c83dc 497 } else if (lifetime_valid > 0)
92ee90af 498 address->cinfo.ifa_valid = lifetime_valid;
6554550f 499 else
01c344bd 500 continue; /* see RFC4862 section 5.5.3.d */
6554550f 501
92ee90af 502 if (address->cinfo.ifa_valid == 0)
c24c83dc 503 continue;
3b015d40 504
92ee90af
YW
505 address->in_addr.in6 = *a;
506
69203fba 507 r = ndisc_address_configure(address, link);
13e8a49a
YW
508 if (r < 0)
509 return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
3b015d40 510 }
d5017c84
YW
511
512 return 0;
3b015d40
TG
513}
514
d5017c84 515static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
8e766630 516 _cleanup_(route_freep) Route *route = NULL;
3b015d40 517 usec_t time_now;
1e7a0e21
LP
518 uint32_t lifetime;
519 unsigned prefixlen;
3b015d40
TG
520 int r;
521
3b015d40 522 assert(link);
1e7a0e21 523 assert(rt);
3b015d40 524
1e7a0e21 525 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84 526 if (r < 0)
13e8a49a 527 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21
LP
528
529 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
d5017c84
YW
530 if (r < 0)
531 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
1e7a0e21
LP
532
533 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime);
d5017c84
YW
534 if (r < 0)
535 return log_link_error_errno(link, r, "Failed to get prefix lifetime: %m");
3b015d40
TG
536
537 r = route_new(&route);
d5017c84 538 if (r < 0)
13e8a49a 539 return log_oom();
3b015d40 540
3b015d40 541 route->family = AF_INET6;
bdb9f580 542 route->table = link_get_ipv6_accept_ra_route_table(link);
1bf1bfd9 543 route->priority = link->network->dhcp6_route_metric;
3b015d40
TG
544 route->protocol = RTPROT_RA;
545 route->flags = RTM_F_PREFIX;
3b015d40
TG
546 route->dst_prefixlen = prefixlen;
547 route->lifetime = time_now + lifetime * USEC_PER_SEC;
548
1e7a0e21 549 r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6);
d5017c84
YW
550 if (r < 0)
551 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
1e7a0e21 552
69203fba 553 r = ndisc_route_configure(route, link);
13e8a49a
YW
554 if (r < 0)
555 return log_link_error_errno(link, r, "Could not set prefix route: %m");;
d5017c84
YW
556
557 return 0;
3b015d40
TG
558}
559
d5017c84 560static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
8e766630 561 _cleanup_(route_freep) Route *route = NULL;
1e7a0e21
LP
562 struct in6_addr gateway;
563 uint32_t lifetime;
564 unsigned preference, prefixlen;
fe307276 565 usec_t time_now;
7a695d8e 566 int r;
a13c50e7
TG
567
568 assert(link);
a13c50e7 569
1e7a0e21 570 r = sd_ndisc_router_route_get_lifetime(rt, &lifetime);
d5017c84 571 if (r < 0)
13e8a49a 572 return log_link_error_errno(link, r, "Failed to get gateway lifetime from RA: %m");
d5017c84 573
1e7a0e21 574 if (lifetime == 0)
d5017c84 575 return 0;
a13c50e7 576
1e7a0e21 577 r = sd_ndisc_router_get_address(rt, &gateway);
d5017c84 578 if (r < 0)
13e8a49a 579 return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
3b015d40 580
1e7a0e21 581 r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
d5017c84 582 if (r < 0)
13e8a49a 583 return log_link_error_errno(link, r, "Failed to get route prefix length: %m");
1e7a0e21
LP
584
585 r = sd_ndisc_router_route_get_preference(rt, &preference);
d5017c84 586 if (r < 0)
13e8a49a 587 return log_link_error_errno(link, r, "Failed to get default router preference from RA: %m");
1e7a0e21
LP
588
589 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84 590 if (r < 0)
13e8a49a 591 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
3b015d40
TG
592
593 r = route_new(&route);
d5017c84 594 if (r < 0)
13e8a49a 595 return log_oom();
3b015d40 596
3b015d40 597 route->family = AF_INET6;
bdb9f580 598 route->table = link_get_ipv6_accept_ra_route_table(link);
1bf1bfd9 599 route->priority = link->network->dhcp6_route_metric;
3b015d40 600 route->protocol = RTPROT_RA;
1e7a0e21
LP
601 route->pref = preference;
602 route->gw.in6 = gateway;
603 route->dst_prefixlen = prefixlen;
3b015d40
TG
604 route->lifetime = time_now + lifetime * USEC_PER_SEC;
605
1e7a0e21 606 r = sd_ndisc_router_route_get_address(rt, &route->dst.in6);
d5017c84
YW
607 if (r < 0)
608 return log_link_error_errno(link, r, "Failed to get route address: %m");
1e7a0e21 609
69203fba 610 r = ndisc_route_configure(route, link);
13e8a49a
YW
611 if (r < 0)
612 return log_link_error_errno(link, r, "Could not set additional route: %m");
d5017c84
YW
613
614 return 0;
9d96e6c3 615}
a13c50e7 616
7a08d314 617static void ndisc_rdnss_hash_func(const NDiscRDNSS *x, struct siphash *state) {
1e7a0e21
LP
618 siphash24_compress(&x->address, sizeof(x->address), state);
619}
620
7a08d314 621static int ndisc_rdnss_compare_func(const NDiscRDNSS *a, const NDiscRDNSS *b) {
1e7a0e21
LP
622 return memcmp(&a->address, &b->address, sizeof(a->address));
623}
624
7a08d314 625DEFINE_PRIVATE_HASH_OPS(ndisc_rdnss_hash_ops, NDiscRDNSS, ndisc_rdnss_hash_func, ndisc_rdnss_compare_func);
1e7a0e21 626
d5017c84 627static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
1e7a0e21
LP
628 uint32_t lifetime;
629 const struct in6_addr *a;
630 usec_t time_now;
13e8a49a 631 int n, r;
1e7a0e21
LP
632
633 assert(link);
634 assert(rt);
635
636 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84 637 if (r < 0)
13e8a49a 638 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21
LP
639
640 r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime);
d5017c84 641 if (r < 0)
13e8a49a 642 return log_link_error_errno(link, r, "Failed to get RDNSS lifetime: %m");
1e7a0e21
LP
643
644 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
d5017c84 645 if (n < 0)
13e8a49a 646 return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m");
1e7a0e21 647
13e8a49a 648 for (int i = 0; i < n; i++) {
d5017c84 649 _cleanup_free_ NDiscRDNSS *x = NULL;
1e7a0e21 650 NDiscRDNSS d = {
d5017c84
YW
651 .address = a[i],
652 }, *y;
1e7a0e21
LP
653
654 if (lifetime == 0) {
655 (void) set_remove(link->ndisc_rdnss, &d);
656 link_dirty(link);
657 continue;
658 }
659
d5017c84
YW
660 y = set_get(link->ndisc_rdnss, &d);
661 if (y) {
662 y->valid_until = time_now + lifetime * USEC_PER_SEC;
1e7a0e21
LP
663 continue;
664 }
665
666 ndisc_vacuum(link);
667
668 if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
669 log_link_warning(link, "Too many RDNSS records per link, ignoring.");
670 continue;
671 }
672
d5017c84
YW
673 x = new(NDiscRDNSS, 1);
674 if (!x)
675 return log_oom();
1e7a0e21 676
d5017c84
YW
677 *x = (NDiscRDNSS) {
678 .address = a[i],
679 .valid_until = time_now + lifetime * USEC_PER_SEC,
680 };
1e7a0e21 681
35e601d4 682 r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
d5017c84
YW
683 if (r < 0)
684 return log_oom();
1e7a0e21 685 assert(r > 0);
35e601d4 686
1e7a0e21
LP
687 link_dirty(link);
688 }
d5017c84
YW
689
690 return 0;
1e7a0e21
LP
691}
692
7a08d314 693static void ndisc_dnssl_hash_func(const NDiscDNSSL *x, struct siphash *state) {
f281fc1e 694 siphash24_compress_string(NDISC_DNSSL_DOMAIN(x), state);
1e7a0e21
LP
695}
696
7a08d314 697static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) {
1e7a0e21
LP
698 return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
699}
700
7a08d314 701DEFINE_PRIVATE_HASH_OPS(ndisc_dnssl_hash_ops, NDiscDNSSL, ndisc_dnssl_hash_func, ndisc_dnssl_compare_func);
1e7a0e21 702
13e8a49a 703static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
1e7a0e21
LP
704 _cleanup_strv_free_ char **l = NULL;
705 uint32_t lifetime;
706 usec_t time_now;
707 char **i;
708 int r;
709
710 assert(link);
711 assert(rt);
712
713 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
13e8a49a
YW
714 if (r < 0)
715 return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21
LP
716
717 r = sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime);
13e8a49a
YW
718 if (r < 0)
719 return log_link_error_errno(link, r, "Failed to get DNSSL lifetime: %m");
1e7a0e21
LP
720
721 r = sd_ndisc_router_dnssl_get_domains(rt, &l);
13e8a49a
YW
722 if (r < 0)
723 return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m");
1e7a0e21
LP
724
725 STRV_FOREACH(i, l) {
13e8a49a 726 _cleanup_free_ NDiscDNSSL *s = NULL;
1e7a0e21
LP
727 NDiscDNSSL *x;
728
a34349e7 729 s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*i) + 1);
13e8a49a
YW
730 if (!s)
731 return log_oom();
a34349e7
DM
732
733 strcpy(NDISC_DNSSL_DOMAIN(s), *i);
1e7a0e21
LP
734
735 if (lifetime == 0) {
a34349e7 736 (void) set_remove(link->ndisc_dnssl, s);
1e7a0e21
LP
737 link_dirty(link);
738 continue;
739 }
740
a34349e7 741 x = set_get(link->ndisc_dnssl, s);
1e7a0e21
LP
742 if (x) {
743 x->valid_until = time_now + lifetime * USEC_PER_SEC;
744 continue;
745 }
746
747 ndisc_vacuum(link);
748
749 if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
750 log_link_warning(link, "Too many DNSSL records per link, ignoring.");
751 continue;
752 }
753
a34349e7 754 s->valid_until = time_now + lifetime * USEC_PER_SEC;
1e7a0e21 755
35e601d4 756 r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
13e8a49a
YW
757 if (r < 0)
758 return log_oom();
1e7a0e21 759 assert(r > 0);
de7fef4b 760
1e7a0e21
LP
761 link_dirty(link);
762 }
13e8a49a
YW
763
764 return 0;
1e7a0e21
LP
765}
766
e8c9b5b0 767static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
1e7a0e21 768 assert(link);
55d3fdcf 769 assert(link->network);
1e7a0e21
LP
770 assert(rt);
771
13e8a49a 772 for (int r = sd_ndisc_router_option_rewind(rt); ; r = sd_ndisc_router_option_next(rt)) {
1e7a0e21
LP
773 uint8_t type;
774
e8c9b5b0 775 if (r < 0)
13e8a49a 776 return log_link_error_errno(link, r, "Failed to iterate through options: %m");
1e7a0e21 777 if (r == 0) /* EOF */
13e8a49a 778 return 0;
1e7a0e21
LP
779
780 r = sd_ndisc_router_option_get_type(rt, &type);
e8c9b5b0 781 if (r < 0)
13e8a49a 782 return log_link_error_errno(link, r, "Failed to get RA option type: %m");
1e7a0e21
LP
783
784 switch (type) {
785
786 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
55d3fdcf 787 union in_addr_union a;
1e7a0e21
LP
788 uint8_t flags;
789
55d3fdcf
YW
790 r = sd_ndisc_router_prefix_get_address(rt, &a.in6);
791 if (r < 0)
792 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
793
6b000af4 794 if (set_contains(link->network->ndisc_deny_listed_prefix, &a.in6)) {
55d3fdcf
YW
795 if (DEBUG_LOGGING) {
796 _cleanup_free_ char *b = NULL;
797
798 (void) in_addr_to_string(AF_INET6, &a, &b);
6b000af4 799 log_link_debug(link, "Prefix '%s' is deny-listed, ignoring", strna(b));
55d3fdcf 800 }
55d3fdcf
YW
801 break;
802 }
803
1e7a0e21 804 r = sd_ndisc_router_prefix_get_flags(rt, &flags);
e8c9b5b0 805 if (r < 0)
13e8a49a 806 return log_link_error_errno(link, r, "Failed to get RA prefix flags: %m");
1e7a0e21 807
87d8a4de 808 if (link->network->ipv6_accept_ra_use_onlink_prefix &&
13e8a49a
YW
809 FLAGS_SET(flags, ND_OPT_PI_FLAG_ONLINK)) {
810 r = ndisc_router_process_onlink_prefix(link, rt);
811 if (r < 0)
812 return r;
813 }
062c2eea 814
87d8a4de 815 if (link->network->ipv6_accept_ra_use_autonomous_prefix &&
13e8a49a
YW
816 FLAGS_SET(flags, ND_OPT_PI_FLAG_AUTO)) {
817 r = ndisc_router_process_autonomous_prefix(link, rt);
818 if (r < 0)
819 return r;
820 }
1e7a0e21
LP
821 break;
822 }
823
824 case SD_NDISC_OPTION_ROUTE_INFORMATION:
13e8a49a
YW
825 r = ndisc_router_process_route(link, rt);
826 if (r < 0)
827 return r;
1e7a0e21
LP
828 break;
829
830 case SD_NDISC_OPTION_RDNSS:
13e8a49a
YW
831 if (link->network->ipv6_accept_ra_use_dns) {
832 r = ndisc_router_process_rdnss(link, rt);
833 if (r < 0)
834 return r;
835 }
1e7a0e21
LP
836 break;
837
838 case SD_NDISC_OPTION_DNSSL:
13e8a49a
YW
839 if (link->network->ipv6_accept_ra_use_dns) {
840 r = ndisc_router_process_dnssl(link, rt);
841 if (r < 0)
842 return r;
843 }
1e7a0e21
LP
844 break;
845 }
1e7a0e21
LP
846 }
847}
848
d5017c84 849static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
69203fba
YW
850 Address *address;
851 Route *route;
1e7a0e21 852 uint64_t flags;
86e2be7b 853 int r;
1e7a0e21
LP
854
855 assert(link);
856 assert(link->network);
857 assert(link->manager);
858 assert(rt);
859
69203fba
YW
860 link->ndisc_addresses_configured = false;
861 link->ndisc_routes_configured = false;
862
863 link_dirty(link);
864
865 while ((address = set_steal_first(link->ndisc_addresses))) {
866 r = set_ensure_put(&link->ndisc_addresses_old, &address_hash_ops, address);
867 if (r < 0)
868 return log_link_error_errno(link, r, "Failed to store old NDisc SLAAC address: %m");
869 }
870
871 while ((route = set_steal_first(link->ndisc_routes))) {
872 r = set_ensure_put(&link->ndisc_routes_old, &route_hash_ops, route);
873 if (r < 0)
874 return log_link_error_errno(link, r, "Failed to store old NDisc route: %m");
875 }
876
1e7a0e21 877 r = sd_ndisc_router_get_flags(rt, &flags);
d5017c84 878 if (r < 0)
13e8a49a 879 return log_link_error_errno(link, r, "Failed to get RA flags: %m");
1e7a0e21 880
ac24e418
SS
881 if ((flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER) && link->network->ipv6_accept_ra_start_dhcp6_client)) {
882
883 if (link->network->ipv6_accept_ra_start_dhcp6_client == IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS)
884 r = dhcp6_request_address(link, false);
885 else
886 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
887 r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
1e7a0e21 888 if (r < 0 && r != -EBUSY)
13e8a49a 889 return log_link_error_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
69203fba 890 else
1e7a0e21
LP
891 log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
892 }
893
13e8a49a
YW
894 r = ndisc_router_process_default(link, rt);
895 if (r < 0)
896 return r;
897 r = ndisc_router_process_options(link, rt);
898 if (r < 0)
899 return r;
d5017c84 900
69203fba
YW
901 if (link->ndisc_addresses_messages == 0)
902 link->ndisc_addresses_configured = true;
903 else {
904 log_link_debug(link, "Setting SLAAC addresses.");
905
906 /* address_handler calls link_request_set_routes() and link_request_set_nexthop().
907 * Before they are called, the related flags must be cleared. Otherwise, the link
908 * becomes configured state before routes are configured. */
909 link->static_routes_configured = false;
910 link->static_nexthops_configured = false;
911 }
912
913 if (link->ndisc_routes_messages == 0)
914 link->ndisc_routes_configured = true;
915 else
916 log_link_debug(link, "Setting NDisc routes.");
917
918 r = ndisc_remove_old(link, false);
919 if (r < 0)
920 return r;
921
922 if (link->ndisc_addresses_configured && link->ndisc_routes_configured)
923 link_check_ready(link);
924 else
925 link_set_state(link, LINK_STATE_CONFIGURING);
926
927 return 0;
1e7a0e21
LP
928}
929
930static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
9d96e6c3 931 Link *link = userdata;
13e8a49a 932 int r;
a13c50e7 933
9d96e6c3 934 assert(link);
a13c50e7 935
9d96e6c3
TG
936 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
937 return;
a13c50e7 938
9d96e6c3 939 switch (event) {
1e7a0e21
LP
940
941 case SD_NDISC_EVENT_ROUTER:
13e8a49a
YW
942 r = ndisc_router_handler(link, rt);
943 if (r < 0) {
944 link_enter_failed(link);
945 return;
946 }
1e7a0e21
LP
947 break;
948
9d96e6c3 949 case SD_NDISC_EVENT_TIMEOUT:
a8c10331 950 log_link_debug(link, "NDisc handler get timeout event");
3336e946
YW
951 if (link->ndisc_addresses_messages == 0 && link->ndisc_routes_messages == 0) {
952 link->ndisc_addresses_configured = true;
953 link->ndisc_routes_configured = true;
954 link_check_ready(link);
955 }
9d96e6c3
TG
956 break;
957 default:
a8c10331 958 assert_not_reached("Unknown NDisc event");
a13c50e7
TG
959 }
960}
961
962int ndisc_configure(Link *link) {
963 int r;
964
1e7a0e21
LP
965 assert(link);
966
967 r = sd_ndisc_new(&link->ndisc);
968 if (r < 0)
969 return r;
a13c50e7 970
1e7a0e21 971 r = sd_ndisc_attach_event(link->ndisc, NULL, 0);
a13c50e7
TG
972 if (r < 0)
973 return r;
974
1e7a0e21 975 r = sd_ndisc_set_mac(link->ndisc, &link->mac);
a13c50e7
TG
976 if (r < 0)
977 return r;
978
1e7a0e21 979 r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
a13c50e7
TG
980 if (r < 0)
981 return r;
982
1e7a0e21 983 r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link);
a13c50e7
TG
984 if (r < 0)
985 return r;
986
1e7a0e21
LP
987 return 0;
988}
989
990void ndisc_vacuum(Link *link) {
991 NDiscRDNSS *r;
992 NDiscDNSSL *d;
993 Iterator i;
994 usec_t time_now;
995
996 assert(link);
997
998 /* Removes all RDNSS and DNSSL entries whose validity time has passed */
999
1000 time_now = now(clock_boottime_or_monotonic());
1001
1002 SET_FOREACH(r, link->ndisc_rdnss, i)
1003 if (r->valid_until < time_now) {
02affb4e 1004 free(set_remove(link->ndisc_rdnss, r));
1e7a0e21
LP
1005 link_dirty(link);
1006 }
a13c50e7 1007
1e7a0e21
LP
1008 SET_FOREACH(d, link->ndisc_dnssl, i)
1009 if (d->valid_until < time_now) {
02affb4e 1010 free(set_remove(link->ndisc_dnssl, d));
1e7a0e21
LP
1011 link_dirty(link);
1012 }
a13c50e7 1013}
c69305ff
LP
1014
1015void ndisc_flush(Link *link) {
1016 assert(link);
1017
1018 /* Removes all RDNSS and DNSSL entries, without exception */
1019
1020 link->ndisc_rdnss = set_free_free(link->ndisc_rdnss);
1021 link->ndisc_dnssl = set_free_free(link->ndisc_dnssl);
1022}
e520ce64 1023
5f506a55
SS
1024int ipv6token_new(IPv6Token **ret) {
1025 IPv6Token *p;
1026
1027 p = new(IPv6Token, 1);
1028 if (!p)
1029 return -ENOMEM;
1030
1031 *p = (IPv6Token) {
1032 .address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_NONE,
1033 };
1034
1035 *ret = TAKE_PTR(p);
1036
1037 return 0;
1038}
1039
2c621495
YW
1040static void ipv6_token_hash_func(const IPv6Token *p, struct siphash *state) {
1041 siphash24_compress(&p->address_generation_type, sizeof(p->address_generation_type), state);
1042 siphash24_compress(&p->prefix, sizeof(p->prefix), state);
1043}
1044
1045static int ipv6_token_compare_func(const IPv6Token *a, const IPv6Token *b) {
1046 int r;
1047
1048 r = CMP(a->address_generation_type, b->address_generation_type);
1049 if (r != 0)
1050 return r;
1051
1052 return memcmp(&a->prefix, &b->prefix, sizeof(struct in6_addr));
1053}
1054
1055DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
5f506a55 1056 ipv6_token_hash_ops,
5f506a55 1057 IPv6Token,
2c621495
YW
1058 ipv6_token_hash_func,
1059 ipv6_token_compare_func,
5f506a55
SS
1060 free);
1061
6b000af4 1062int config_parse_ndisc_deny_listed_prefix(
e520ce64
SS
1063 const char *unit,
1064 const char *filename,
1065 unsigned line,
1066 const char *section,
1067 unsigned section_line,
1068 const char *lvalue,
1069 int ltype,
1070 const char *rvalue,
1071 void *data,
1072 void *userdata) {
1073
1074 Network *network = data;
1075 const char *p;
1076 int r;
1077
1078 assert(filename);
1079 assert(lvalue);
1080 assert(rvalue);
1081 assert(data);
1082
1083 if (isempty(rvalue)) {
6b000af4 1084 network->ndisc_deny_listed_prefix = set_free_free(network->ndisc_deny_listed_prefix);
e520ce64
SS
1085 return 0;
1086 }
1087
1088 for (p = rvalue;;) {
1089 _cleanup_free_ char *n = NULL;
1090 _cleanup_free_ struct in6_addr *a = NULL;
1091 union in_addr_union ip;
1092
1093 r = extract_first_word(&p, &n, NULL, 0);
d96edb2c
YW
1094 if (r == -ENOMEM)
1095 return log_oom();
e520ce64 1096 if (r < 0) {
d96edb2c 1097 log_syntax(unit, LOG_WARNING, filename, line, r,
a8c10331 1098 "Failed to parse NDisc deny-listed prefix, ignoring assignment: %s",
e520ce64
SS
1099 rvalue);
1100 return 0;
1101 }
1102 if (r == 0)
1103 return 0;
1104
1105 r = in_addr_from_string(AF_INET6, n, &ip);
1106 if (r < 0) {
d96edb2c 1107 log_syntax(unit, LOG_WARNING, filename, line, r,
a8c10331 1108 "NDisc deny-listed prefix is invalid, ignoring assignment: %s", n);
e520ce64
SS
1109 continue;
1110 }
1111
6b000af4 1112 if (set_contains(network->ndisc_deny_listed_prefix, &ip.in6))
e4443f9b
YW
1113 continue;
1114
e520ce64
SS
1115 a = newdup(struct in6_addr, &ip.in6, 1);
1116 if (!a)
1117 return log_oom();
1118
6b000af4 1119 r = set_ensure_consume(&network->ndisc_deny_listed_prefix, &in6_addr_hash_ops, TAKE_PTR(a));
35e601d4
ZJS
1120 if (r < 0)
1121 return log_oom();
e520ce64 1122 }
e520ce64 1123}
5f506a55
SS
1124
1125int config_parse_address_generation_type(
1126 const char *unit,
1127 const char *filename,
1128 unsigned line,
1129 const char *section,
1130 unsigned section_line,
1131 const char *lvalue,
1132 int ltype,
1133 const char *rvalue,
1134 void *data,
1135 void *userdata) {
1136
1137 _cleanup_free_ IPv6Token *token = NULL;
5f506a55
SS
1138 union in_addr_union buffer;
1139 Network *network = data;
1140 const char *p;
1141 int r;
1142
1143 assert(filename);
1144 assert(lvalue);
1145 assert(rvalue);
1146 assert(data);
1147
1148 if (isempty(rvalue)) {
2c621495 1149 network->ipv6_tokens = ordered_set_free(network->ipv6_tokens);
5f506a55
SS
1150 return 0;
1151 }
1152
5f506a55
SS
1153 r = ipv6token_new(&token);
1154 if (r < 0)
1155 return log_oom();
1156
b751c3e7 1157 if ((p = startswith(rvalue, "static:")))
e2c4070e 1158 token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_STATIC;
b751c3e7 1159 else if ((p = startswith(rvalue, "prefixstable:")))
5f506a55
SS
1160 token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE;
1161 else {
e2c4070e 1162 token->address_generation_type = IPV6_TOKEN_ADDRESS_GENERATION_STATIC;
5f506a55 1163 p = rvalue;
f0c1ad30
YW
1164 }
1165
5f506a55
SS
1166 r = in_addr_from_string(AF_INET6, p, &buffer);
1167 if (r < 0) {
d96edb2c 1168 log_syntax(unit, LOG_WARNING, filename, line, r,
5f506a55
SS
1169 "Failed to parse IPv6 %s, ignoring: %s", lvalue, rvalue);
1170 return 0;
1171 }
1172
1173 if (in_addr_is_null(AF_INET6, &buffer)) {
d96edb2c 1174 log_syntax(unit, LOG_WARNING, filename, line, 0,
5f506a55
SS
1175 "IPv6 %s cannot be the ANY address, ignoring: %s", lvalue, rvalue);
1176 return 0;
1177 }
1178
1179 token->prefix = buffer.in6;
1180
2c621495 1181 r = ordered_set_ensure_allocated(&network->ipv6_tokens, &ipv6_token_hash_ops);
5f506a55
SS
1182 if (r < 0)
1183 return log_oom();
1184
2c621495
YW
1185 r = ordered_set_put(network->ipv6_tokens, token);
1186 if (r == -EEXIST)
1187 log_syntax(unit, LOG_DEBUG, filename, line, r,
1188 "IPv6 token '%s' is duplicated, ignoring: %m", rvalue);
1189 else if (r < 0)
d96edb2c 1190 log_syntax(unit, LOG_WARNING, filename, line, r,
2c621495
YW
1191 "Failed to store IPv6 token '%s', ignoring: %m", rvalue);
1192 else
1193 TAKE_PTR(token);
5f506a55
SS
1194
1195 return 0;
1196}
ac24e418
SS
1197
1198DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_start_dhcp6_client, ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
1199 "Failed to parse DHCPv6Client= setting")
1200static const char* const ipv6_accept_ra_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
1201 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO] = "no",
1202 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",
1203 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES] = "yes",
1204};
1205
1206DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);