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