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