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