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