]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-ndisc.c
network: ignore requested ipv6 route when ipv6 is disabled by sysctl
[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"
1e7a0e21 12#include "networkd-ndisc.h"
23f53b99 13#include "networkd-route.h"
51517f9e 14#include "strv.h"
1e7a0e21
LP
15
16#define NDISC_DNSSL_MAX 64U
17#define NDISC_RDNSS_MAX 64U
6554550f 18#define NDISC_PREFIX_LFT_MIN 7200U
fe307276 19
302a796f 20static int ndisc_netlink_message_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
3b015d40
TG
21 int r;
22
23 assert(link);
24 assert(link->ndisc_messages > 0);
25
313cefa1 26 link->ndisc_messages--;
3b015d40
TG
27
28 r = sd_netlink_message_get_errno(m);
7f676aa3 29 if (r < 0 && r != -EEXIST)
3b015d40 30 log_link_error_errno(link, r, "Could not set NDisc route or address: %m");
3b015d40
TG
31
32 if (link->ndisc_messages == 0) {
33 link->ndisc_configured = true;
34 link_check_ready(link);
35 }
36
37 return 1;
38}
39
d5017c84 40static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
8e766630 41 _cleanup_(route_freep) Route *route = NULL;
ce2ea782 42 union in_addr_union gateway;
1e7a0e21
LP
43 uint16_t lifetime;
44 unsigned preference;
d6fceaf1 45 uint32_t mtu;
3b015d40
TG
46 usec_t time_now;
47 int r;
6d7c7615
PF
48 Address *address;
49 Iterator i;
3b015d40 50
3b015d40 51 assert(link);
1e7a0e21 52 assert(rt);
3b015d40 53
1e7a0e21 54 r = sd_ndisc_router_get_lifetime(rt, &lifetime);
d5017c84
YW
55 if (r < 0)
56 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
57
1e7a0e21 58 if (lifetime == 0) /* not a default router */
d5017c84 59 return 0;
1e7a0e21 60
ce2ea782 61 r = sd_ndisc_router_get_address(rt, &gateway.in6);
d5017c84
YW
62 if (r < 0)
63 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
1e7a0e21 64
ce2ea782
YW
65 SET_FOREACH(address, link->addresses, i) {
66 if (address->family != AF_INET6)
67 continue;
68 if (in_addr_equal(AF_INET6, &gateway, &address->in_addr)) {
57e44707 69 _cleanup_free_ char *buffer = NULL;
6d7c7615 70
57e44707 71 (void) in_addr_to_string(AF_INET6, &address->in_addr, &buffer);
6d7c7615 72 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
57e44707 73 strnull(buffer));
d5017c84 74 return 0;
6d7c7615 75 }
ce2ea782 76 }
6d7c7615 77
ce2ea782
YW
78 SET_FOREACH(address, link->addresses_foreign, i) {
79 if (address->family != AF_INET6)
80 continue;
81 if (in_addr_equal(AF_INET6, &gateway, &address->in_addr)) {
57e44707 82 _cleanup_free_ char *buffer = NULL;
6d7c7615 83
57e44707 84 (void) in_addr_to_string(AF_INET6, &address->in_addr, &buffer);
6d7c7615 85 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
57e44707 86 strnull(buffer));
d5017c84 87 return 0;
6d7c7615 88 }
ce2ea782 89 }
6d7c7615 90
1e7a0e21 91 r = sd_ndisc_router_get_preference(rt, &preference);
d5017c84
YW
92 if (r < 0)
93 return log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
1e7a0e21
LP
94
95 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84
YW
96 if (r < 0)
97 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21 98
d6fceaf1 99 r = sd_ndisc_router_get_mtu(rt, &mtu);
29b5ad08
JT
100 if (r == -ENODATA)
101 mtu = 0;
d5017c84
YW
102 else if (r < 0)
103 return log_link_warning_errno(link, r, "Failed to get default router MTU from RA: %m");
d6fceaf1 104
1e7a0e21 105 r = route_new(&route);
d5017c84
YW
106 if (r < 0)
107 return log_link_error_errno(link, r, "Could not allocate route: %m");
1e7a0e21
LP
108
109 route->family = AF_INET6;
bdb9f580 110 route->table = link_get_ipv6_accept_ra_route_table(link);
91b8fd3c 111 route->priority = link->network->dhcp_route_metric;
1e7a0e21
LP
112 route->protocol = RTPROT_RA;
113 route->pref = preference;
ce2ea782 114 route->gw = gateway;
1e7a0e21 115 route->lifetime = time_now + lifetime * USEC_PER_SEC;
d6fceaf1 116 route->mtu = mtu;
1e7a0e21 117
10ff4eb6 118 r = route_configure(route, link, ndisc_netlink_message_handler);
1e7a0e21
LP
119 if (r < 0) {
120 log_link_warning_errno(link, r, "Could not set default route: %m");
121 link_enter_failed(link);
d5017c84 122 return r;
1e7a0e21 123 }
c4423317
YW
124 if (r > 0)
125 link->ndisc_messages++;
d5017c84
YW
126
127 return 0;
1e7a0e21
LP
128}
129
d5017c84 130static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
8e766630 131 _cleanup_(address_freep) Address *address = NULL;
6554550f
HW
132 Address *existing_address;
133 uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
134 usec_t time_now;
1e7a0e21
LP
135 unsigned prefixlen;
136 int r;
137
138 assert(link);
139 assert(rt);
140
6554550f 141 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84
YW
142 if (r < 0)
143 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
6554550f 144
1e7a0e21 145 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
d5017c84
YW
146 if (r < 0)
147 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
1e7a0e21
LP
148
149 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid);
d5017c84
YW
150 if (r < 0)
151 return log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");
1e7a0e21
LP
152
153 r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred);
d5017c84
YW
154 if (r < 0)
155 return log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");
3b015d40 156
92bdc3ff
SS
157 /* The preferred lifetime is never greater than the valid lifetime */
158 if (lifetime_preferred > lifetime_valid)
d5017c84 159 return 0;
92bdc3ff 160
3b015d40 161 r = address_new(&address);
d5017c84
YW
162 if (r < 0)
163 return log_link_error_errno(link, r, "Could not allocate address: %m");
3b015d40 164
3b015d40 165 address->family = AF_INET6;
1e7a0e21 166 r = sd_ndisc_router_prefix_get_address(rt, &address->in_addr.in6);
d5017c84
YW
167 if (r < 0)
168 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
1e7a0e21 169
3b015d40 170 if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0)
fb84d896 171 memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8);
3b015d40 172 else {
fe307276 173 /* see RFC4291 section 2.5.1 */
3a437557
NM
174 address->in_addr.in6.s6_addr[8] = link->mac.ether_addr_octet[0];
175 address->in_addr.in6.s6_addr[8] ^= 1 << 1;
176 address->in_addr.in6.s6_addr[9] = link->mac.ether_addr_octet[1];
177 address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2];
178 address->in_addr.in6.s6_addr[11] = 0xff;
179 address->in_addr.in6.s6_addr[12] = 0xfe;
180 address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3];
181 address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4];
182 address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5];
3b015d40
TG
183 }
184 address->prefixlen = prefixlen;
f217be19 185 address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
3b015d40 186 address->cinfo.ifa_prefered = lifetime_preferred;
6554550f
HW
187
188 /* see RFC4862 section 5.5.3.e */
189 r = address_get(link, address->family, &address->in_addr, address->prefixlen, &existing_address);
190 if (r > 0) {
191 lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
192 if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
193 address->cinfo.ifa_valid = lifetime_valid;
194 else if (lifetime_remaining <= NDISC_PREFIX_LFT_MIN)
195 address->cinfo.ifa_valid = lifetime_remaining;
196 else
197 address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN;
198 } else if (lifetime_valid > 0)
199 address->cinfo.ifa_valid = lifetime_valid;
200 else
d5017c84 201 return 0; /* see RFC4862 section 5.5.3.d */
6554550f
HW
202
203 if (address->cinfo.ifa_valid == 0)
d5017c84 204 return 0;
3b015d40 205
10ff4eb6 206 r = address_configure(address, link, ndisc_netlink_message_handler, true);
3b015d40
TG
207 if (r < 0) {
208 log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
209 link_enter_failed(link);
d5017c84 210 return r;
3b015d40 211 }
54a1a535
YW
212 if (r > 0)
213 link->ndisc_messages++;
d5017c84
YW
214
215 return 0;
3b015d40
TG
216}
217
d5017c84 218static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
8e766630 219 _cleanup_(route_freep) Route *route = NULL;
3b015d40 220 usec_t time_now;
1e7a0e21
LP
221 uint32_t lifetime;
222 unsigned prefixlen;
3b015d40
TG
223 int r;
224
3b015d40 225 assert(link);
1e7a0e21 226 assert(rt);
3b015d40 227
1e7a0e21 228 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84
YW
229 if (r < 0)
230 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21
LP
231
232 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
d5017c84
YW
233 if (r < 0)
234 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
1e7a0e21
LP
235
236 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime);
d5017c84
YW
237 if (r < 0)
238 return log_link_error_errno(link, r, "Failed to get prefix lifetime: %m");
3b015d40
TG
239
240 r = route_new(&route);
d5017c84
YW
241 if (r < 0)
242 return log_link_error_errno(link, r, "Could not allocate route: %m");
3b015d40 243
3b015d40 244 route->family = AF_INET6;
bdb9f580 245 route->table = link_get_ipv6_accept_ra_route_table(link);
91b8fd3c 246 route->priority = link->network->dhcp_route_metric;
3b015d40
TG
247 route->protocol = RTPROT_RA;
248 route->flags = RTM_F_PREFIX;
3b015d40
TG
249 route->dst_prefixlen = prefixlen;
250 route->lifetime = time_now + lifetime * USEC_PER_SEC;
251
1e7a0e21 252 r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6);
d5017c84
YW
253 if (r < 0)
254 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
1e7a0e21 255
10ff4eb6 256 r = route_configure(route, link, ndisc_netlink_message_handler);
3b015d40
TG
257 if (r < 0) {
258 log_link_warning_errno(link, r, "Could not set prefix route: %m");
259 link_enter_failed(link);
d5017c84 260 return r;
3b015d40 261 }
c4423317
YW
262 if (r > 0)
263 link->ndisc_messages++;
d5017c84
YW
264
265 return 0;
3b015d40
TG
266}
267
d5017c84 268static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
8e766630 269 _cleanup_(route_freep) Route *route = NULL;
1e7a0e21
LP
270 struct in6_addr gateway;
271 uint32_t lifetime;
272 unsigned preference, prefixlen;
fe307276 273 usec_t time_now;
7a695d8e 274 int r;
a13c50e7
TG
275
276 assert(link);
a13c50e7 277
1e7a0e21 278 r = sd_ndisc_router_route_get_lifetime(rt, &lifetime);
d5017c84
YW
279 if (r < 0)
280 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
281
1e7a0e21 282 if (lifetime == 0)
d5017c84 283 return 0;
a13c50e7 284
1e7a0e21 285 r = sd_ndisc_router_get_address(rt, &gateway);
d5017c84
YW
286 if (r < 0)
287 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
3b015d40 288
1e7a0e21 289 r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
d5017c84
YW
290 if (r < 0)
291 return log_link_warning_errno(link, r, "Failed to get route prefix length: %m");
1e7a0e21
LP
292
293 r = sd_ndisc_router_route_get_preference(rt, &preference);
d5017c84
YW
294 if (r < 0)
295 return log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
1e7a0e21
LP
296
297 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84
YW
298 if (r < 0)
299 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
3b015d40
TG
300
301 r = route_new(&route);
d5017c84
YW
302 if (r < 0)
303 return log_link_error_errno(link, r, "Could not allocate route: %m");
3b015d40 304
3b015d40 305 route->family = AF_INET6;
bdb9f580 306 route->table = link_get_ipv6_accept_ra_route_table(link);
3b015d40 307 route->protocol = RTPROT_RA;
1e7a0e21
LP
308 route->pref = preference;
309 route->gw.in6 = gateway;
310 route->dst_prefixlen = prefixlen;
3b015d40
TG
311 route->lifetime = time_now + lifetime * USEC_PER_SEC;
312
1e7a0e21 313 r = sd_ndisc_router_route_get_address(rt, &route->dst.in6);
d5017c84
YW
314 if (r < 0)
315 return log_link_error_errno(link, r, "Failed to get route address: %m");
1e7a0e21 316
10ff4eb6 317 r = route_configure(route, link, ndisc_netlink_message_handler);
3b015d40 318 if (r < 0) {
1e7a0e21 319 log_link_warning_errno(link, r, "Could not set additional route: %m");
3b015d40 320 link_enter_failed(link);
d5017c84 321 return r;
3b015d40 322 }
c4423317
YW
323 if (r > 0)
324 link->ndisc_messages++;
d5017c84
YW
325
326 return 0;
9d96e6c3 327}
a13c50e7 328
7a08d314 329static void ndisc_rdnss_hash_func(const NDiscRDNSS *x, struct siphash *state) {
1e7a0e21
LP
330 siphash24_compress(&x->address, sizeof(x->address), state);
331}
332
7a08d314 333static int ndisc_rdnss_compare_func(const NDiscRDNSS *a, const NDiscRDNSS *b) {
1e7a0e21
LP
334 return memcmp(&a->address, &b->address, sizeof(a->address));
335}
336
7a08d314 337DEFINE_PRIVATE_HASH_OPS(ndisc_rdnss_hash_ops, NDiscRDNSS, ndisc_rdnss_hash_func, ndisc_rdnss_compare_func);
1e7a0e21 338
d5017c84 339static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
1e7a0e21
LP
340 uint32_t lifetime;
341 const struct in6_addr *a;
342 usec_t time_now;
343 int i, n, r;
344
345 assert(link);
346 assert(rt);
347
348 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
d5017c84
YW
349 if (r < 0)
350 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
1e7a0e21
LP
351
352 r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime);
d5017c84
YW
353 if (r < 0)
354 return log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
1e7a0e21
LP
355
356 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
d5017c84
YW
357 if (n < 0)
358 return log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m");
1e7a0e21
LP
359
360 for (i = 0; i < n; i++) {
d5017c84 361 _cleanup_free_ NDiscRDNSS *x = NULL;
1e7a0e21 362 NDiscRDNSS d = {
d5017c84
YW
363 .address = a[i],
364 }, *y;
1e7a0e21
LP
365
366 if (lifetime == 0) {
367 (void) set_remove(link->ndisc_rdnss, &d);
368 link_dirty(link);
369 continue;
370 }
371
d5017c84
YW
372 y = set_get(link->ndisc_rdnss, &d);
373 if (y) {
374 y->valid_until = time_now + lifetime * USEC_PER_SEC;
1e7a0e21
LP
375 continue;
376 }
377
378 ndisc_vacuum(link);
379
380 if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
381 log_link_warning(link, "Too many RDNSS records per link, ignoring.");
382 continue;
383 }
384
385 r = set_ensure_allocated(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops);
d5017c84
YW
386 if (r < 0)
387 return log_oom();
1e7a0e21 388
d5017c84
YW
389 x = new(NDiscRDNSS, 1);
390 if (!x)
391 return log_oom();
1e7a0e21 392
d5017c84
YW
393 *x = (NDiscRDNSS) {
394 .address = a[i],
395 .valid_until = time_now + lifetime * USEC_PER_SEC,
396 };
1e7a0e21
LP
397
398 r = set_put(link->ndisc_rdnss, x);
d5017c84
YW
399 if (r < 0)
400 return log_oom();
401
402 TAKE_PTR(x);
1e7a0e21
LP
403
404 assert(r > 0);
405 link_dirty(link);
406 }
d5017c84
YW
407
408 return 0;
1e7a0e21
LP
409}
410
7a08d314 411static void ndisc_dnssl_hash_func(const NDiscDNSSL *x, struct siphash *state) {
1e7a0e21
LP
412 siphash24_compress(NDISC_DNSSL_DOMAIN(x), strlen(NDISC_DNSSL_DOMAIN(x)), state);
413}
414
7a08d314 415static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) {
1e7a0e21
LP
416 return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
417}
418
7a08d314 419DEFINE_PRIVATE_HASH_OPS(ndisc_dnssl_hash_ops, NDiscDNSSL, ndisc_dnssl_hash_func, ndisc_dnssl_compare_func);
1e7a0e21
LP
420
421static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
422 _cleanup_strv_free_ char **l = NULL;
423 uint32_t lifetime;
424 usec_t time_now;
425 char **i;
426 int r;
427
428 assert(link);
429 assert(rt);
430
431 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
432 if (r < 0) {
433 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
434 return;
435 }
436
437 r = sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime);
438 if (r < 0) {
439 log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
440 return;
441 }
442
443 r = sd_ndisc_router_dnssl_get_domains(rt, &l);
444 if (r < 0) {
445 log_link_warning_errno(link, r, "Failed to get RDNSS addresses: %m");
446 return;
447 }
448
449 STRV_FOREACH(i, l) {
a34349e7 450 _cleanup_free_ NDiscDNSSL *s;
1e7a0e21
LP
451 NDiscDNSSL *x;
452
a34349e7
DM
453 s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*i) + 1);
454 if (!s) {
455 log_oom();
456 return;
457 }
458
459 strcpy(NDISC_DNSSL_DOMAIN(s), *i);
1e7a0e21
LP
460
461 if (lifetime == 0) {
a34349e7 462 (void) set_remove(link->ndisc_dnssl, s);
1e7a0e21
LP
463 link_dirty(link);
464 continue;
465 }
466
a34349e7 467 x = set_get(link->ndisc_dnssl, s);
1e7a0e21
LP
468 if (x) {
469 x->valid_until = time_now + lifetime * USEC_PER_SEC;
470 continue;
471 }
472
473 ndisc_vacuum(link);
474
475 if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
476 log_link_warning(link, "Too many DNSSL records per link, ignoring.");
477 continue;
478 }
479
480 r = set_ensure_allocated(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops);
481 if (r < 0) {
482 log_oom();
483 return;
484 }
485
a34349e7 486 s->valid_until = time_now + lifetime * USEC_PER_SEC;
1e7a0e21 487
a34349e7 488 r = set_put(link->ndisc_dnssl, s);
1e7a0e21 489 if (r < 0) {
1e7a0e21
LP
490 log_oom();
491 return;
492 }
493
a34349e7 494 s = NULL;
1e7a0e21
LP
495 assert(r > 0);
496 link_dirty(link);
497 }
498}
499
e8c9b5b0 500static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
1e7a0e21
LP
501 int r;
502
503 assert(link);
504 assert(rt);
505
506 r = sd_ndisc_router_option_rewind(rt);
507 for (;;) {
508 uint8_t type;
509
e8c9b5b0
YW
510 if (r < 0)
511 return log_link_warning_errno(link, r, "Failed to iterate through options: %m");
1e7a0e21
LP
512 if (r == 0) /* EOF */
513 break;
514
515 r = sd_ndisc_router_option_get_type(rt, &type);
e8c9b5b0
YW
516 if (r < 0)
517 return log_link_warning_errno(link, r, "Failed to get RA option type: %m");
1e7a0e21
LP
518
519 switch (type) {
520
521 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
522 uint8_t flags;
523
524 r = sd_ndisc_router_prefix_get_flags(rt, &flags);
e8c9b5b0
YW
525 if (r < 0)
526 return log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
1e7a0e21 527
87d8a4de
YW
528 if (link->network->ipv6_accept_ra_use_onlink_prefix &&
529 FLAGS_SET(flags, ND_OPT_PI_FLAG_ONLINK))
530 (void) ndisc_router_process_onlink_prefix(link, rt);
062c2eea 531
87d8a4de
YW
532 if (link->network->ipv6_accept_ra_use_autonomous_prefix &&
533 FLAGS_SET(flags, ND_OPT_PI_FLAG_AUTO))
534 (void) ndisc_router_process_autonomous_prefix(link, rt);
1e7a0e21
LP
535
536 break;
537 }
538
539 case SD_NDISC_OPTION_ROUTE_INFORMATION:
d5017c84 540 (void) ndisc_router_process_route(link, rt);
1e7a0e21
LP
541 break;
542
543 case SD_NDISC_OPTION_RDNSS:
fe0252e5 544 if (link->network->ipv6_accept_ra_use_dns)
d5017c84 545 (void) ndisc_router_process_rdnss(link, rt);
1e7a0e21
LP
546 break;
547
548 case SD_NDISC_OPTION_DNSSL:
fe0252e5 549 if (link->network->ipv6_accept_ra_use_dns)
d5017c84 550 (void) ndisc_router_process_dnssl(link, rt);
1e7a0e21
LP
551 break;
552 }
553
554 r = sd_ndisc_router_option_next(rt);
555 }
e8c9b5b0
YW
556
557 return 0;
1e7a0e21
LP
558}
559
e520ce64
SS
560static int ndisc_prefix_is_black_listed(Link *link, sd_ndisc_router *rt) {
561 int r;
562
563 assert(link);
564 assert(link->network);
565 assert(rt);
566
567 for (r = sd_ndisc_router_option_rewind(rt); ; r = sd_ndisc_router_option_next(rt)) {
568 union in_addr_union a;
569 uint8_t type;
570
571 if (r < 0)
572 return log_link_warning_errno(link, r, "Failed to iterate through options: %m");
573 if (r == 0) /* EOF */
574 return false;
575
576 r = sd_ndisc_router_option_get_type(rt, &type);
577 if (r < 0)
578 return log_link_warning_errno(link, r, "Failed to get RA option type: %m");
579
580 if (type != SD_NDISC_OPTION_PREFIX_INFORMATION)
581 continue;
582
583 r = sd_ndisc_router_prefix_get_address(rt, &a.in6);
584 if (r < 0)
585 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
586
587 if (set_contains(link->network->ndisc_black_listed_prefix, &a.in6)) {
588 if (DEBUG_LOGGING) {
589 _cleanup_free_ char *b = NULL;
590
591 (void) in_addr_to_string(AF_INET6, &a, &b);
592 log_link_debug(link, "Prefix '%s' is black listed, ignoring", strna(b));
593 }
594
595 return true;
596 }
597 }
598}
599
d5017c84 600static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
1e7a0e21 601 uint64_t flags;
86e2be7b 602 int r;
1e7a0e21
LP
603
604 assert(link);
605 assert(link->network);
606 assert(link->manager);
607 assert(rt);
608
609 r = sd_ndisc_router_get_flags(rt, &flags);
d5017c84
YW
610 if (r < 0)
611 return log_link_warning_errno(link, r, "Failed to get RA flags: %m");
1e7a0e21
LP
612
613 if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) {
614 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
615 r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
616 if (r < 0 && r != -EBUSY)
617 log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
d5017c84 618 else {
1e7a0e21 619 log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
d5017c84
YW
620 r = 0;
621 }
1e7a0e21
LP
622 }
623
e520ce64
SS
624 if (ndisc_prefix_is_black_listed(link, rt) == 0) {
625 (void) ndisc_router_process_default(link, rt);
626 (void) ndisc_router_process_options(link, rt);
627 }
d5017c84
YW
628
629 return r;
1e7a0e21
LP
630}
631
632static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
9d96e6c3 633 Link *link = userdata;
a13c50e7 634
9d96e6c3 635 assert(link);
a13c50e7 636
9d96e6c3
TG
637 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
638 return;
a13c50e7 639
9d96e6c3 640 switch (event) {
1e7a0e21
LP
641
642 case SD_NDISC_EVENT_ROUTER:
d5017c84 643 (void) ndisc_router_handler(link, rt);
1e7a0e21
LP
644 break;
645
9d96e6c3 646 case SD_NDISC_EVENT_TIMEOUT:
962b0647
TG
647 link->ndisc_configured = true;
648 link_check_ready(link);
649
9d96e6c3
TG
650 break;
651 default:
652 log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
a13c50e7
TG
653 }
654}
655
656int ndisc_configure(Link *link) {
657 int r;
658
1e7a0e21
LP
659 assert(link);
660
661 r = sd_ndisc_new(&link->ndisc);
662 if (r < 0)
663 return r;
a13c50e7 664
1e7a0e21 665 r = sd_ndisc_attach_event(link->ndisc, NULL, 0);
a13c50e7
TG
666 if (r < 0)
667 return r;
668
1e7a0e21 669 r = sd_ndisc_set_mac(link->ndisc, &link->mac);
a13c50e7
TG
670 if (r < 0)
671 return r;
672
1e7a0e21 673 r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
a13c50e7
TG
674 if (r < 0)
675 return r;
676
1e7a0e21 677 r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link);
a13c50e7
TG
678 if (r < 0)
679 return r;
680
1e7a0e21
LP
681 return 0;
682}
683
684void ndisc_vacuum(Link *link) {
685 NDiscRDNSS *r;
686 NDiscDNSSL *d;
687 Iterator i;
688 usec_t time_now;
689
690 assert(link);
691
692 /* Removes all RDNSS and DNSSL entries whose validity time has passed */
693
694 time_now = now(clock_boottime_or_monotonic());
695
696 SET_FOREACH(r, link->ndisc_rdnss, i)
697 if (r->valid_until < time_now) {
02affb4e 698 free(set_remove(link->ndisc_rdnss, r));
1e7a0e21
LP
699 link_dirty(link);
700 }
a13c50e7 701
1e7a0e21
LP
702 SET_FOREACH(d, link->ndisc_dnssl, i)
703 if (d->valid_until < time_now) {
02affb4e 704 free(set_remove(link->ndisc_dnssl, d));
1e7a0e21
LP
705 link_dirty(link);
706 }
a13c50e7 707}
c69305ff
LP
708
709void ndisc_flush(Link *link) {
710 assert(link);
711
712 /* Removes all RDNSS and DNSSL entries, without exception */
713
714 link->ndisc_rdnss = set_free_free(link->ndisc_rdnss);
715 link->ndisc_dnssl = set_free_free(link->ndisc_dnssl);
716}
e520ce64
SS
717
718int config_parse_ndisc_black_listed_prefix(
719 const char *unit,
720 const char *filename,
721 unsigned line,
722 const char *section,
723 unsigned section_line,
724 const char *lvalue,
725 int ltype,
726 const char *rvalue,
727 void *data,
728 void *userdata) {
729
730 Network *network = data;
731 const char *p;
732 int r;
733
734 assert(filename);
735 assert(lvalue);
736 assert(rvalue);
737 assert(data);
738
739 if (isempty(rvalue)) {
740 network->ndisc_black_listed_prefix = set_free_free(network->ndisc_black_listed_prefix);
741 return 0;
742 }
743
744 for (p = rvalue;;) {
745 _cleanup_free_ char *n = NULL;
746 _cleanup_free_ struct in6_addr *a = NULL;
747 union in_addr_union ip;
748
749 r = extract_first_word(&p, &n, NULL, 0);
750 if (r < 0) {
751 log_syntax(unit, LOG_ERR, filename, line, r,
752 "Failed to parse NDISC black listed prefix, ignoring assignment: %s",
753 rvalue);
754 return 0;
755 }
756 if (r == 0)
757 return 0;
758
759 r = in_addr_from_string(AF_INET6, n, &ip);
760 if (r < 0) {
761 log_syntax(unit, LOG_ERR, filename, line, r,
762 "NDISC black listed prefix is invalid, ignoring assignment: %s", n);
763 continue;
764 }
765
766 r = set_ensure_allocated(&network->ndisc_black_listed_prefix, &in6_addr_hash_ops);
767 if (r < 0)
768 return log_oom();
769
770 a = newdup(struct in6_addr, &ip.in6, 1);
771 if (!a)
772 return log_oom();
773
774 r = set_put(network->ndisc_black_listed_prefix, a);
775 if (r < 0) {
776 if (r == -EEXIST)
777 log_syntax(unit, LOG_WARNING, filename, line, r,
778 "NDISC black listed prefixs is duplicated, ignoring assignment: %s", n);
779 else
780 log_syntax(unit, LOG_ERR, filename, line, r,
781 "Failed to store NDISC black listed prefix '%s', ignoring assignment: %m", n);
782 continue;
783 }
784
785 TAKE_PTR(a);
786 }
787
788 return 0;
789}