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