Coverage Report

Created: 2026-08-08 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/systemd/src/network/networkd-ndisc.c
Line
Count
Source
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
/***
3
  Copyright © 2014 Intel Corporation. All rights reserved.
4
***/
5
6
#include <linux/if_arp.h>
7
#include <linux/rtnetlink.h>
8
#include <netinet/icmp6.h>
9
10
#include "sd-ndisc.h"
11
12
#include "conf-parser.h"
13
#include "errno-util.h"
14
#include "event-util.h"
15
#include "missing-network.h"
16
#include "ndisc-router-internal.h"
17
#include "networkd-address.h"
18
#include "networkd-address-generation.h"
19
#include "networkd-dhcp6.h"
20
#include "networkd-ipv6ll.h"
21
#include "networkd-link.h"
22
#include "networkd-manager.h"
23
#include "networkd-ndisc.h"
24
#include "networkd-nexthop.h"
25
#include "networkd-queue.h"
26
#include "networkd-route.h"
27
#include "networkd-state-file.h"
28
#include "networkd-sysctl.h"
29
#include "ordered-set.h"
30
#include "set.h"
31
#include "siphash24.h"
32
#include "socket-util.h"
33
#include "string-table.h"
34
#include "string-util.h"
35
#include "strv.h"
36
#include "sysctl-util.h"
37
38
0
#define NDISC_DNSSL_MAX 64U
39
0
#define NDISC_RDNSS_MAX 64U
40
0
#define NDISC_ENCRYPTED_DNS_MAX 64U
41
/* Not defined in the RFC, but let's set an upper limit to make not consume much memory.
42
 * This should be safe as typically there should be at most 1 portal per network. */
43
0
#define NDISC_CAPTIVE_PORTAL_MAX 64U
44
/* Neither defined in the RFC. Just for safety. Otherwise, malformed messages can make clients trigger OOM.
45
 * Not sure if the threshold is high enough. Let's adjust later if not. */
46
0
#define NDISC_PREF64_MAX 64U
47
48
static int ndisc_drop_outdated(Link *link, const struct in6_addr *router, usec_t timestamp_usec);
49
50
0
char* ndisc_dnssl_domain(const NDiscDNSSL *n) {
51
0
        return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
52
0
}
53
54
0
bool link_ndisc_enabled(Link *link) {
55
0
        assert(link);
56
57
0
        if (!socket_ipv6_is_supported())
58
0
                return false;
59
60
0
        if (link->flags & IFF_LOOPBACK)
61
0
                return false;
62
63
0
        if (link->iftype == ARPHRD_CAN)
64
0
                return false;
65
66
0
        if (!link->network)
67
0
                return false;
68
69
0
        if (!link_multicast_enabled(link))
70
0
                return false;
71
72
0
        if (!link_ipv6ll_enabled_harder(link))
73
0
                return false;
74
75
        /* Honor explicitly specified value. */
76
0
        if (link->network->ndisc >= 0)
77
0
                return link->network->ndisc;
78
79
        /* Disable if RADV is enabled. */
80
0
        if (link_radv_enabled(link))
81
0
                return false;
82
83
        /* Accept RAs if IPv6 forwarding is disabled, and ignore RAs if IPv6 forwarding is enabled. */
84
0
        int t = link_get_ip_forwarding(link, AF_INET6);
85
0
        if (t >= 0)
86
0
                return !t;
87
88
        /* Otherwise, defaults to true. */
89
0
        return true;
90
0
}
91
92
3.30k
void network_adjust_ndisc(Network *network) {
93
3.30k
        assert(network);
94
95
3.30k
        if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6) &&
96
61
            !network_has_static_ipv6ll_address(network)) {
97
59
                if (network->ndisc > 0)
98
59
                        log_warning("%s: IPv6AcceptRA= is enabled but IPv6 link-local addressing is disabled or not supported. "
99
59
                                    "Disabling IPv6AcceptRA=.", network->filename);
100
59
                network->ndisc = false;
101
59
        }
102
103
        /* When RouterAllowList=, PrefixAllowList= or RouteAllowList= are specified, then
104
         * RouterDenyList=, PrefixDenyList= or RouteDenyList= are ignored, respectively. */
105
3.30k
        if (!set_isempty(network->ndisc_allow_listed_router))
106
0
                network->ndisc_deny_listed_router = set_free(network->ndisc_deny_listed_router);
107
3.30k
        if (!set_isempty(network->ndisc_allow_listed_prefix))
108
0
                network->ndisc_deny_listed_prefix = set_free(network->ndisc_deny_listed_prefix);
109
3.30k
        if (!set_isempty(network->ndisc_allow_listed_route_prefix))
110
0
                network->ndisc_deny_listed_route_prefix = set_free(network->ndisc_deny_listed_route_prefix);
111
3.30k
}
112
113
static int ndisc_check_ready(Link *link);
114
115
0
static int ndisc_address_ready_callback(Address *address) {
116
0
        Address *a;
117
118
0
        assert(address);
119
0
        assert(address->link);
120
121
0
        SET_FOREACH(a, address->link->addresses)
122
0
                if (a->source == NETWORK_CONFIG_SOURCE_NDISC)
123
0
                        a->callback = NULL;
124
125
0
        return ndisc_check_ready(address->link);
126
0
}
127
128
0
static int ndisc_check_ready(Link *link) {
129
0
        bool found = false, ready = false;
130
0
        Address *address;
131
132
0
        assert(link);
133
134
0
        if (link->ndisc_messages > 0) {
135
0
                log_link_debug(link, "%s(): SLAAC addresses and routes are not set.", __func__);
136
0
                return 0;
137
0
        }
138
139
0
        SET_FOREACH(address, link->addresses) {
140
0
                if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
141
0
                        continue;
142
143
0
                found = true;
144
145
0
                if (address_is_ready(address)) {
146
0
                        ready = true;
147
0
                        break;
148
0
                }
149
0
        }
150
151
0
        if (found && !ready) {
152
0
                SET_FOREACH(address, link->addresses)
153
0
                        if (address->source == NETWORK_CONFIG_SOURCE_NDISC)
154
0
                                address->callback = ndisc_address_ready_callback;
155
156
0
                log_link_debug(link, "%s(): no SLAAC address is ready.", __func__);
157
0
                return 0;
158
0
        }
159
160
0
        link->ndisc_configured = true;
161
0
        log_link_debug(link, "SLAAC addresses and routes set.");
162
163
0
        link_check_ready(link);
164
0
        return 0;
165
0
}
166
167
0
static int ndisc_remove_unused_nexthop(Link *link, NextHop *nexthop) {
168
0
        int r;
169
170
0
        assert(link);
171
0
        assert(link->manager);
172
0
        assert(link->ifindex > 0);
173
0
        assert(nexthop);
174
175
0
        if (nexthop->source != NETWORK_CONFIG_SOURCE_NDISC)
176
0
                return 0;
177
178
0
        if (nexthop->ifindex != link->ifindex)
179
0
                return 0;
180
181
0
        Route *route;
182
0
        SET_FOREACH(route, nexthop->routes)
183
0
                if (route_exists(route) || route_is_requesting(route))
184
0
                        return 0;
185
186
0
        Request *req;
187
0
        ORDERED_SET_FOREACH(req, link->manager->request_queue) {
188
0
                if (req->type != REQUEST_TYPE_ROUTE)
189
0
                        continue;
190
191
0
                route = ASSERT_PTR(req->userdata);
192
0
                if (route->nexthop_id == nexthop->id)
193
0
                        return 0;
194
0
        }
195
196
0
        r = nexthop_remove_and_cancel(nexthop, link->manager);
197
0
        if (r < 0)
198
0
                return log_link_debug_errno(link, r, "Failed to remove unused nexthop: %m");
199
200
0
        return 0;
201
0
}
202
203
0
static int ndisc_remove_unused_nexthop_by_id(Link *link, uint32_t id) {
204
0
        assert(link);
205
0
        assert(link->manager);
206
207
0
        if (id == 0)
208
0
                return 0;
209
210
0
        NextHop *nexthop;
211
0
        if (nexthop_get_by_id(link->manager, id, &nexthop) < 0)
212
0
                return 0;
213
214
0
        return ndisc_remove_unused_nexthop(link, nexthop);
215
0
}
216
217
0
static int ndisc_remove_unused_nexthops(Link *link) {
218
0
        int ret = 0;
219
220
0
        assert(link);
221
0
        assert(link->manager);
222
223
0
        NextHop *nexthop;
224
0
        HASHMAP_FOREACH(nexthop, link->manager->nexthops_by_id)
225
0
                RET_GATHER(ret, ndisc_remove_unused_nexthop(link, nexthop));
226
227
0
        return ret;
228
0
}
229
230
0
#define NDISC_NEXTHOP_APP_ID SD_ID128_MAKE(76,d2,0f,1f,76,1e,44,d1,97,3a,52,5c,05,68,b5,0d)
231
232
0
static uint32_t ndisc_generate_nexthop_id(const NextHop *nexthop, Link *link, sd_id128_t app_id, uint64_t trial) {
233
0
        assert(nexthop);
234
0
        assert(link);
235
236
0
        struct siphash state;
237
0
        siphash24_init(&state, app_id.bytes);
238
0
        siphash24_compress_typesafe(nexthop->protocol, &state);
239
0
        siphash24_compress_string(link->ifname, &state);
240
0
        siphash24_compress_typesafe(nexthop->gw.address.in6, &state);
241
0
        siphash24_compress_typesafe(nexthop->provider.in6, &state);
242
0
        uint64_t n = htole64(trial);
243
0
        siphash24_compress_typesafe(n, &state);
244
245
0
        uint64_t result = htole64(siphash24_finalize(&state));
246
0
        return (uint32_t) ((result & 0xffffffff) ^ (result >> 32));
247
0
}
248
249
0
static bool ndisc_nexthop_equal(const NextHop *a, const NextHop *b) {
250
0
        assert(a);
251
0
        assert(b);
252
253
0
        if (a->source != b->source)
254
0
                return false;
255
0
        if (a->protocol != b->protocol)
256
0
                return false;
257
0
        if (a->ifindex != b->ifindex)
258
0
                return false;
259
0
        if (!in6_addr_equal(&a->provider.in6, &b->provider.in6))
260
0
                return false;
261
0
        if (!in6_addr_equal(&a->gw.address.in6, &b->gw.address.in6))
262
0
                return false;
263
264
0
        return true;
265
0
}
266
267
0
static bool ndisc_take_nexthop_id(NextHop *nexthop, const NextHop *existing, Manager *manager) {
268
0
        assert(nexthop);
269
0
        assert(nexthop->id == 0);
270
0
        assert(existing);
271
0
        assert(existing->id > 0);
272
0
        assert(manager);
273
274
0
        if (!ndisc_nexthop_equal(nexthop, existing))
275
0
                return false;
276
277
0
        log_nexthop_debug(existing, "Found matching", manager);
278
0
        nexthop->id = existing->id;
279
0
        return true;
280
0
}
281
282
0
static int ndisc_nexthop_find_id(NextHop *nexthop, Link *link) {
283
0
        NextHop *n;
284
0
        Request *req;
285
0
        int r;
286
287
0
        assert(nexthop);
288
0
        assert(link);
289
0
        assert(link->manager);
290
291
0
        sd_id128_t app_id;
292
0
        r = sd_id128_get_machine_app_specific(NDISC_NEXTHOP_APP_ID, &app_id);
293
0
        if (r < 0)
294
0
                return r;
295
296
0
        uint32_t id = ndisc_generate_nexthop_id(nexthop, link, app_id, 0);
297
0
        if (nexthop_get_by_id(link->manager, id, &n) >= 0 &&
298
0
            ndisc_take_nexthop_id(nexthop, n, link->manager))
299
0
                return true;
300
0
        if (nexthop_get_request_by_id(link->manager, id, &req) >= 0 &&
301
0
            ndisc_take_nexthop_id(nexthop, req->userdata, link->manager))
302
0
                return true;
303
304
0
        HASHMAP_FOREACH(n, link->manager->nexthops_by_id)
305
0
                if (ndisc_take_nexthop_id(nexthop, n, link->manager))
306
0
                        return true;
307
308
0
        ORDERED_SET_FOREACH(req, link->manager->request_queue) {
309
0
                if (req->type != REQUEST_TYPE_NEXTHOP)
310
0
                        continue;
311
312
0
                if (ndisc_take_nexthop_id(nexthop, req->userdata, link->manager))
313
0
                        return true;
314
0
        }
315
316
0
        return false;
317
0
}
318
319
0
static int ndisc_nexthop_new(const Route *route, Link *link, NextHop **ret) {
320
0
        _cleanup_(nexthop_unrefp) NextHop *nexthop = NULL;
321
0
        int r;
322
323
0
        assert(route);
324
0
        assert(link);
325
0
        assert(ret);
326
327
0
        r = nexthop_new(&nexthop);
328
0
        if (r < 0)
329
0
                return r;
330
331
0
        nexthop->source = NETWORK_CONFIG_SOURCE_NDISC;
332
0
        nexthop->provider = route->provider;
333
0
        nexthop->protocol = route->protocol == RTPROT_REDIRECT ? RTPROT_REDIRECT : RTPROT_RA;
334
0
        nexthop->family = AF_INET6;
335
0
        nexthop->gw.address = route->nexthop.gw;
336
0
        nexthop->ifindex = link->ifindex;
337
338
0
        r = ndisc_nexthop_find_id(nexthop, link);
339
0
        if (r < 0)
340
0
                return r;
341
342
0
        *ret = TAKE_PTR(nexthop);
343
0
        return 0;
344
0
}
345
346
0
static int ndisc_nexthop_acquire_id(NextHop *nexthop, Link *link) {
347
0
        int r;
348
349
0
        assert(nexthop);
350
0
        assert(nexthop->id == 0);
351
0
        assert(link);
352
0
        assert(link->manager);
353
354
0
        sd_id128_t app_id;
355
0
        r = sd_id128_get_machine_app_specific(NDISC_NEXTHOP_APP_ID, &app_id);
356
0
        if (r < 0)
357
0
                return r;
358
359
0
        for (uint64_t trial = 0; trial < 100; trial++) {
360
0
                uint32_t id = ndisc_generate_nexthop_id(nexthop, link, app_id, trial);
361
0
                if (id == 0)
362
0
                        continue;
363
364
0
                if (set_contains(link->manager->nexthop_ids, UINT32_TO_PTR(id)))
365
0
                        continue; /* The ID is already used in a .network file. */
366
367
0
                if (nexthop_get_by_id(link->manager, id, NULL) >= 0)
368
0
                        continue; /* The ID is already used by an existing nexthop. */
369
370
0
                if (nexthop_get_request_by_id(link->manager, id, NULL) >= 0)
371
0
                        continue; /* The ID is already used by a nexthop being requested. */
372
373
0
                log_link_debug(link, "Generated new ndisc nexthop ID for %s with trial %"PRIu64": %"PRIu32,
374
0
                               IN6_ADDR_TO_STRING(&nexthop->gw.address.in6), trial, id);
375
0
                nexthop->id = id;
376
0
                return 0;
377
0
        }
378
379
0
        return log_link_debug_errno(link, SYNTHETIC_ERRNO(EBUSY), "Cannot find free nexthop ID for %s.",
380
0
                                    IN6_ADDR_TO_STRING(&nexthop->gw.address.in6));
381
0
}
382
383
0
static int ndisc_nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, NextHop *nexthop) {
384
0
        int r;
385
386
0
        assert(link);
387
0
        assert(nexthop);
388
389
0
        r = nexthop_configure_handler_internal(m, link, nexthop);
390
0
        if (r <= 0)
391
0
                return r;
392
393
0
        r = ndisc_check_ready(link);
394
0
        if (r < 0)
395
0
                link_enter_failed(link);
396
397
0
        return 1;
398
0
}
399
400
0
static int ndisc_request_nexthop(NextHop *nexthop, Link *link) {
401
0
        int r;
402
403
0
        assert(nexthop);
404
0
        assert(link);
405
406
0
        if (nexthop->id > 0)
407
0
                return 0;
408
409
0
        r = ndisc_nexthop_acquire_id(nexthop, link);
410
0
        if (r < 0)
411
0
                return r;
412
413
0
        r = link_request_nexthop(link, nexthop, &link->ndisc_messages, ndisc_nexthop_handler);
414
0
        if (r < 0)
415
0
                return r;
416
0
        if (r > 0)
417
0
                link->ndisc_configured = false;
418
419
0
        return 0;
420
0
}
421
422
0
static int ndisc_set_route_nexthop(Route *route, Link *link, bool request) {
423
0
        _cleanup_(nexthop_unrefp) NextHop *nexthop = NULL;
424
0
        int r;
425
426
0
        assert(route);
427
0
        assert(link);
428
0
        assert(link->manager);
429
430
0
        if (!link->manager->manage_foreign_nexthops)
431
0
                goto finalize;
432
433
0
        if (route->nexthop.family != AF_INET6 || in6_addr_is_null(&route->nexthop.gw.in6))
434
0
                goto finalize;
435
436
0
        r = ndisc_nexthop_new(route, link, &nexthop);
437
0
        if (r < 0)
438
0
                return r;
439
440
0
        if (nexthop->id == 0 && !request)
441
0
                goto finalize;
442
443
0
        r = ndisc_request_nexthop(nexthop, link);
444
0
        if (r < 0)
445
0
                return r;
446
447
0
        route->nexthop = (RouteNextHop) {};
448
0
        route->nexthop_id = nexthop->id;
449
450
0
finalize:
451
0
        return route_adjust_nexthops(route, link);
452
0
}
453
454
0
static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
455
0
        int r;
456
457
0
        assert(req);
458
0
        assert(link);
459
0
        assert(route);
460
461
0
        r = route_configure_handler_internal(m, req, route);
462
0
        if (r <= 0)
463
0
                return r;
464
465
0
        r = ndisc_check_ready(link);
466
0
        if (r < 0)
467
0
                link_enter_failed(link);
468
469
0
        return 1;
470
0
}
471
472
0
static void ndisc_set_route_priority(Link *link, Route *route) {
473
0
        assert(link);
474
0
        assert(route);
475
476
0
        if (route->priority_set)
477
0
                return; /* explicitly configured. */
478
479
0
        switch (route->pref) {
480
0
        case SD_NDISC_PREFERENCE_LOW:
481
0
                route->priority = link->network->ndisc_route_metric_low;
482
0
                break;
483
0
        case SD_NDISC_PREFERENCE_MEDIUM:
484
0
                route->priority = link->network->ndisc_route_metric_medium;
485
0
                break;
486
0
        case SD_NDISC_PREFERENCE_HIGH:
487
0
                route->priority = link->network->ndisc_route_metric_high;
488
0
                break;
489
0
        default:
490
0
                assert_not_reached();
491
0
        }
492
0
}
493
494
0
static int ndisc_request_route(Route *route, Link *link) {
495
0
        int r;
496
497
0
        assert(route);
498
0
        assert(link);
499
0
        assert(link->manager);
500
0
        assert(link->network);
501
502
0
        r = route_metric_set(&route->metric, RTAX_QUICKACK, link->network->ndisc_quickack);
503
0
        if (r < 0)
504
0
                return r;
505
506
0
        r = ndisc_set_route_nexthop(route, link, /* request= */ true);
507
0
        if (r < 0)
508
0
                return r;
509
510
0
        uint8_t pref, pref_original = route->pref;
511
0
        FOREACH_ARGUMENT(pref, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_MEDIUM, SD_NDISC_PREFERENCE_HIGH) {
512
0
                Route *existing;
513
0
                Request *req;
514
515
                /* If the preference is specified by the user config (that is, for semi-static routes),
516
                 * rather than RA, then only search conflicting routes that have the same preference. */
517
0
                if (route->pref_set && pref != pref_original)
518
0
                        continue;
519
520
0
                route->pref = pref;
521
0
                ndisc_set_route_priority(link, route);
522
523
                /* Note, here do not call route_remove_and_cancel() with 'route' directly, otherwise
524
                 * existing route(s) may be removed needlessly. */
525
526
                /* First, check if a conflicting route is already requested. If there is an existing route,
527
                 * and also an existing pending request, then the source may be updated by the request. So,
528
                 * we first need to check the source of the requested route. */
529
0
                if (route_get_request(link->manager, route, &req) >= 0) {
530
0
                        route->pref = pref_original;
531
0
                        ndisc_set_route_priority(link, route);
532
533
0
                        existing = ASSERT_PTR(req->userdata);
534
0
                        if (!route_can_update(link->manager, existing, route)) {
535
0
                                if (existing->source == NETWORK_CONFIG_SOURCE_STATIC) {
536
0
                                        log_link_debug(link, "Found a pending route request that conflicts with new request based on a received RA, ignoring request.");
537
0
                                        return 0;
538
0
                                }
539
540
0
                                log_link_debug(link, "Found a pending route request that conflicts with new request based on a received RA, cancelling.");
541
0
                                r = route_remove_and_cancel(existing, link->manager);
542
0
                                if (r < 0)
543
0
                                        return r;
544
0
                        }
545
0
                }
546
547
0
                route->pref = pref;
548
0
                ndisc_set_route_priority(link, route);
549
550
                /* Then, check if a conflicting route exists. */
551
0
                if (route_get(link->manager, route, &existing) >= 0) {
552
0
                        route->pref = pref_original;
553
0
                        ndisc_set_route_priority(link, route);
554
555
0
                        if (!route_can_update(link->manager, existing, route)) {
556
0
                                if (existing->source == NETWORK_CONFIG_SOURCE_STATIC) {
557
0
                                        log_link_debug(link, "Found an existing route that conflicts with new route based on a received RA, ignoring request.");
558
0
                                        return 0;
559
0
                                }
560
561
0
                                log_link_debug(link, "Found an existing route that conflicts with new route based on a received RA, removing.");
562
0
                                r = route_remove_and_cancel(existing, link->manager);
563
0
                                if (r < 0)
564
0
                                        return r;
565
0
                        }
566
0
                }
567
0
        }
568
569
        /* The preference (and priority) may be changed in the above loop. Restore it. */
570
0
        route->pref = pref_original;
571
0
        ndisc_set_route_priority(link, route);
572
573
0
        bool is_new = route_get(link->manager, route, NULL) < 0;
574
575
0
        r = link_request_route(link, route, &link->ndisc_messages, ndisc_route_handler);
576
0
        if (r < 0)
577
0
                return r;
578
0
        if (r > 0 && is_new)
579
0
                link->ndisc_configured = false;
580
581
0
        return 0;
582
0
}
583
584
0
static void ndisc_route_prepare(Route *route, Link *link) {
585
0
        assert(route);
586
0
        assert(link);
587
588
0
        route->source = NETWORK_CONFIG_SOURCE_NDISC;
589
590
0
        if (!route->table_set)
591
0
                route->table = link_get_ndisc_route_table(link);
592
0
}
593
594
0
static int ndisc_router_route_prepare(Route *route, Link *link, sd_ndisc_router *rt) {
595
0
        assert(route);
596
0
        assert(link);
597
0
        assert(rt);
598
599
0
        ndisc_route_prepare(route, link);
600
601
0
        if (!route->protocol_set)
602
0
                route->protocol = RTPROT_RA;
603
604
0
        return sd_ndisc_router_get_sender_address(rt, &route->provider.in6);
605
0
}
606
607
0
static int ndisc_request_router_route(Route *route, Link *link, sd_ndisc_router *rt) {
608
0
        int r;
609
610
0
        assert(route);
611
0
        assert(link);
612
0
        assert(rt);
613
614
0
        r = ndisc_router_route_prepare(route, link, rt);
615
0
        if (r < 0)
616
0
                return r;
617
618
0
        return ndisc_request_route(route, link);
619
0
}
620
621
0
static int ndisc_remove_route(Route *route, Link *link) {
622
0
        int r, ret = 0;
623
624
0
        assert(route);
625
0
        assert(link);
626
0
        assert(link->manager);
627
628
0
        r = ndisc_set_route_nexthop(route, link, /* request= */ false);
629
0
        if (r < 0)
630
0
                return r;
631
632
0
        uint8_t pref, pref_original = route->pref;
633
0
        FOREACH_ARGUMENT(pref, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_MEDIUM, SD_NDISC_PREFERENCE_HIGH) {
634
0
                Route *existing;
635
0
                Request *req;
636
637
                /* If the preference is specified by the user config (that is, for semi-static routes),
638
                 * rather than RA, then only search conflicting routes that have the same preference. */
639
0
                if (route->pref_set && pref != pref_original)
640
0
                        continue;
641
642
0
                route->pref = pref;
643
0
                ndisc_set_route_priority(link, route);
644
645
                /* Unfortunately, we cannot directly pass 'route' to route_remove_and_cancel() here, as the
646
                 * same or similar route may be configured or requested statically. */
647
648
                /* First, check if the route is already requested. If there is an existing route, and also an
649
                 * existing pending request, then the source may be updated by the request. So, we first need
650
                 * to check the source of the requested route. */
651
0
                if (route_get_request(link->manager, route, &req) >= 0) {
652
0
                        existing = ASSERT_PTR(req->userdata);
653
0
                        if (existing->source == NETWORK_CONFIG_SOURCE_STATIC)
654
0
                                continue;
655
656
0
                        RET_GATHER(ret, route_remove_and_cancel(existing, link->manager));
657
0
                }
658
659
                /* Then, check if the route exists. */
660
0
                if (route_get(link->manager, route, &existing) >= 0) {
661
0
                        if (existing->source == NETWORK_CONFIG_SOURCE_STATIC)
662
0
                                continue;
663
664
0
                        RET_GATHER(ret, route_remove_and_cancel(existing, link->manager));
665
0
                }
666
0
        }
667
668
0
        return RET_GATHER(ret, ndisc_remove_unused_nexthop_by_id(link, route->nexthop_id));
669
0
}
670
671
0
static int ndisc_remove_router_route(Route *route, Link *link, sd_ndisc_router *rt) {
672
0
        int r;
673
674
0
        assert(route);
675
0
        assert(link);
676
0
        assert(rt);
677
678
0
        r = ndisc_router_route_prepare(route, link, rt);
679
0
        if (r < 0)
680
0
                return r;
681
682
0
        return ndisc_remove_route(route, link);
683
0
}
684
685
0
static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
686
0
        int r;
687
688
0
        assert(link);
689
0
        assert(address);
690
691
0
        r = address_configure_handler_internal(m, link, address);
692
0
        if (r <= 0)
693
0
                return r;
694
695
0
        r = ndisc_check_ready(link);
696
0
        if (r < 0)
697
0
                link_enter_failed(link);
698
699
0
        return 1;
700
0
}
701
702
0
static int ndisc_request_address(Address *address, Link *link) {
703
0
        bool is_new;
704
0
        int r;
705
706
0
        assert(address);
707
0
        assert(link);
708
709
0
        address->source = NETWORK_CONFIG_SOURCE_NDISC;
710
711
0
        r = free_and_strdup_warn(&address->netlabel, link->network->ndisc_netlabel);
712
0
        if (r < 0)
713
0
                return r;
714
715
0
        Address *existing;
716
0
        if (address_get_harder(link, address, &existing) < 0)
717
0
                is_new = true;
718
0
        else if (address_can_update(existing, address))
719
0
                is_new = false;
720
0
        else if (existing->source == NETWORK_CONFIG_SOURCE_DHCP6) {
721
                /* SLAAC address is preferred over DHCPv6 address. */
722
0
                log_link_debug(link, "Conflicting DHCPv6 address %s exists, removing.",
723
0
                               IN_ADDR_PREFIX_TO_STRING(existing->family, &existing->in_addr, existing->prefixlen));
724
0
                r = address_remove(existing, link);
725
0
                if (r < 0)
726
0
                        return r;
727
728
0
                is_new = true;
729
0
        } else {
730
                /* Conflicting static address is configured?? */
731
0
                log_link_debug(link, "Conflicting address %s exists, ignoring request.",
732
0
                               IN_ADDR_PREFIX_TO_STRING(existing->family, &existing->in_addr, existing->prefixlen));
733
0
                return 0;
734
0
        }
735
736
0
        r = link_request_address(link, address, &link->ndisc_messages,
737
0
                                 ndisc_address_handler, NULL);
738
0
        if (r < 0)
739
0
                return r;
740
0
        if (r > 0 && is_new)
741
0
                link->ndisc_configured = false;
742
743
0
        return 0;
744
0
}
745
746
0
int ndisc_reconfigure_address(Address *address, Link *link) {
747
0
        int r;
748
749
0
        assert(address);
750
0
        assert(address->source == NETWORK_CONFIG_SOURCE_NDISC);
751
0
        assert(link);
752
753
0
        r = regenerate_address(address, link);
754
0
        if (r <= 0)
755
0
                return r;
756
757
0
        r = ndisc_request_address(address, link);
758
0
        if (r < 0)
759
0
                return r;
760
761
0
        if (!link->ndisc_configured)
762
0
                link_set_state(link, LINK_STATE_CONFIGURING);
763
764
0
        link_check_ready(link);
765
0
        return 0;
766
0
}
767
768
0
static int ndisc_redirect_route_new(sd_ndisc_redirect *rd, Route **ret) {
769
0
        _cleanup_(route_unrefp) Route *route = NULL;
770
0
        struct in6_addr gateway, destination;
771
0
        int r;
772
773
0
        assert(rd);
774
0
        assert(ret);
775
776
0
        r = sd_ndisc_redirect_get_target_address(rd, &gateway);
777
0
        if (r < 0)
778
0
                return r;
779
780
0
        r = sd_ndisc_redirect_get_destination_address(rd, &destination);
781
0
        if (r < 0)
782
0
                return r;
783
784
0
        r = route_new(&route);
785
0
        if (r < 0)
786
0
                return r;
787
788
0
        route->family = AF_INET6;
789
0
        if (!in6_addr_equal(&gateway, &destination)) {
790
0
                route->nexthop.gw.in6 = gateway;
791
0
                route->nexthop.family = AF_INET6;
792
0
        }
793
0
        route->dst.in6 = destination;
794
0
        route->dst_prefixlen = 128;
795
0
        route->protocol = RTPROT_REDIRECT;
796
797
0
        r = sd_ndisc_redirect_get_sender_address(rd, &route->provider.in6);
798
0
        if (r < 0)
799
0
                return r;
800
801
0
        *ret = TAKE_PTR(route);
802
0
        return 0;
803
0
}
804
805
0
static int ndisc_remove_redirect_route(Link *link, sd_ndisc_redirect *rd) {
806
0
        _cleanup_(route_unrefp) Route *route = NULL;
807
0
        int r;
808
809
0
        assert(link);
810
0
        assert(rd);
811
812
0
        r = ndisc_redirect_route_new(rd, &route);
813
0
        if (r < 0)
814
0
                return r;
815
816
0
        ndisc_route_prepare(route, link);
817
818
0
        return ndisc_remove_route(route, link);
819
0
}
820
821
0
static void ndisc_redirect_hash_func(const sd_ndisc_redirect *x, struct siphash *state) {
822
0
        struct in6_addr dest = {};
823
824
0
        assert(x);
825
0
        assert(state);
826
827
0
        (void) sd_ndisc_redirect_get_destination_address((sd_ndisc_redirect*) x, &dest);
828
829
0
        siphash24_compress_typesafe(dest, state);
830
0
}
831
832
0
static int ndisc_redirect_compare_func(const sd_ndisc_redirect *x, const sd_ndisc_redirect *y) {
833
0
        struct in6_addr dest_x = {}, dest_y = {};
834
835
0
        assert(x);
836
0
        assert(y);
837
838
0
        (void) sd_ndisc_redirect_get_destination_address((sd_ndisc_redirect*) x, &dest_x);
839
0
        (void) sd_ndisc_redirect_get_destination_address((sd_ndisc_redirect*) y, &dest_y);
840
841
0
        return memcmp(&dest_x, &dest_y, sizeof(dest_x));
842
0
}
843
844
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
845
                ndisc_redirect_hash_ops,
846
                sd_ndisc_redirect,
847
                ndisc_redirect_hash_func,
848
                ndisc_redirect_compare_func,
849
                sd_ndisc_redirect_unref);
850
851
0
static int ndisc_redirect_equal(sd_ndisc_redirect *x, sd_ndisc_redirect *y) {
852
0
        struct in6_addr a, b;
853
0
        int r;
854
855
0
        assert(x);
856
0
        assert(y);
857
858
0
        r = sd_ndisc_redirect_get_destination_address(x, &a);
859
0
        if (r < 0)
860
0
                return r;
861
862
0
        r = sd_ndisc_redirect_get_destination_address(y, &b);
863
0
        if (r < 0)
864
0
                return r;
865
866
0
        if (!in6_addr_equal(&a, &b))
867
0
                return false;
868
869
0
        r = sd_ndisc_redirect_get_target_address(x, &a);
870
0
        if (r < 0)
871
0
                return r;
872
873
0
        r = sd_ndisc_redirect_get_target_address(y, &b);
874
0
        if (r < 0)
875
0
                return r;
876
877
0
        return in6_addr_equal(&a, &b);
878
0
}
879
880
0
static int ndisc_redirect_drop_conflict(Link *link, sd_ndisc_redirect *rd) {
881
0
        _cleanup_(sd_ndisc_redirect_unrefp) sd_ndisc_redirect *existing = NULL;
882
0
        int r;
883
884
0
        assert(link);
885
0
        assert(rd);
886
887
0
        existing = set_remove(link->ndisc_redirects, rd);
888
0
        if (!existing)
889
0
                return 0;
890
891
0
        r = ndisc_redirect_equal(rd, existing);
892
0
        if (r != 0)
893
0
                return r;
894
895
0
        return ndisc_remove_redirect_route(link, existing);
896
0
}
897
898
0
static int ndisc_redirect_verify_sender(Link *link, sd_ndisc_redirect *rd) {
899
0
        int r;
900
901
0
        assert(link);
902
0
        assert(rd);
903
904
        /* RFC 4861 section 8.1
905
        * The IP source address of the Redirect is the same as the current first-hop router for the specified
906
        * ICMP Destination Address. */
907
908
0
        struct in6_addr sender;
909
0
        r = sd_ndisc_redirect_get_sender_address(rd, &sender);
910
0
        if (r < 0)
911
0
                return r;
912
913
        /* We will reuse the sender's router lifetime as the lifetime of the redirect route. Hence, if we
914
         * have not remembered an RA from the sender, refuse the Redirect message. */
915
0
        sd_ndisc_router *router = hashmap_get(link->ndisc_routers_by_sender, &sender);
916
0
        if (!router)
917
0
                return false;
918
919
0
        sd_ndisc_redirect *existing = set_get(link->ndisc_redirects, rd);
920
0
        if (existing) {
921
0
                struct in6_addr target, dest;
922
923
                /* If we have received Redirect message for the host, the sender must be the previous target. */
924
925
0
                r = sd_ndisc_redirect_get_target_address(existing, &target);
926
0
                if (r < 0)
927
0
                        return r;
928
929
0
                if (in6_addr_equal(&sender, &target))
930
0
                        return true;
931
932
                /* If the existing redirect route is on-link, that is, the destination and target address are
933
                 * equivalent, then also accept Redirect message from the current default router. This is not
934
                 * mentioned by the RFC, but without this, we cannot update on-link redirect route. */
935
0
                r = sd_ndisc_redirect_get_destination_address(existing, &dest);
936
0
                if (r < 0)
937
0
                        return r;
938
939
0
                if (!in6_addr_equal(&dest, &target))
940
0
                        return false;
941
0
        }
942
943
        /* Check if the sender is one of the known router with highest priority. */
944
0
        uint8_t preference;
945
0
        r = sd_ndisc_router_get_preference(router, &preference);
946
0
        if (r < 0)
947
0
                return r;
948
949
0
        if (preference == SD_NDISC_PREFERENCE_HIGH)
950
0
                return true;
951
952
0
        sd_ndisc_router *rt;
953
0
        HASHMAP_FOREACH(rt, link->ndisc_routers_by_sender) {
954
0
                if (rt == router)
955
0
                        continue;
956
957
0
                uint8_t pref;
958
0
                if (sd_ndisc_router_get_preference(rt, &pref) < 0)
959
0
                        continue;
960
961
0
                if (pref == SD_NDISC_PREFERENCE_HIGH ||
962
0
                    (pref == SD_NDISC_PREFERENCE_MEDIUM && preference == SD_NDISC_PREFERENCE_LOW))
963
0
                        return false;
964
0
        }
965
966
0
        return true;
967
0
}
968
969
0
static int ndisc_redirect_handler(Link *link, sd_ndisc_redirect *rd) {
970
0
        int r;
971
972
0
        assert(link);
973
0
        assert(link->network);
974
0
        assert(rd);
975
976
0
        if (!link->network->ndisc_use_redirect)
977
0
                return 0;
978
979
0
        usec_t now_usec;
980
0
        r = sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec);
981
0
        if (r < 0)
982
0
                return r;
983
984
0
        r = ndisc_drop_outdated(link, /* router= */ NULL, now_usec);
985
0
        if (r < 0)
986
0
                return r;
987
988
0
        r = ndisc_redirect_verify_sender(link, rd);
989
0
        if (r <= 0)
990
0
                return r;
991
992
        /* First, drop conflicting redirect route, if exists. */
993
0
        r = ndisc_redirect_drop_conflict(link, rd);
994
0
        if (r < 0)
995
0
                return r;
996
997
        /* Then, remember the received message. */
998
0
        r = set_ensure_put(&link->ndisc_redirects, &ndisc_redirect_hash_ops, rd);
999
0
        if (r < 0)
1000
0
                return r;
1001
1002
0
        sd_ndisc_redirect_ref(rd);
1003
1004
        /* Finally, request the corresponding route. */
1005
0
        _cleanup_(route_unrefp) Route *route = NULL;
1006
0
        r = ndisc_redirect_route_new(rd, &route);
1007
0
        if (r < 0)
1008
0
                return r;
1009
1010
0
        sd_ndisc_router *rt = hashmap_get(link->ndisc_routers_by_sender, &route->provider.in6);
1011
0
        if (!rt)
1012
0
                return -EADDRNOTAVAIL;
1013
1014
0
        r = sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &route->lifetime_usec);
1015
0
        if (r < 0)
1016
0
                return r;
1017
1018
0
        ndisc_route_prepare(route, link);
1019
1020
0
        return ndisc_request_route(route, link);
1021
0
}
1022
1023
0
static int ndisc_drop_redirect(Link *link, const struct in6_addr *router) {
1024
0
        int r, ret = 0;
1025
1026
0
        assert(link);
1027
1028
0
        sd_ndisc_redirect *rd;
1029
0
        SET_FOREACH(rd, link->ndisc_redirects) {
1030
0
                if (router) {
1031
0
                        struct in6_addr a;
1032
1033
0
                        if (!(sd_ndisc_redirect_get_sender_address(rd, &a) >= 0 && in6_addr_equal(&a, router)) &&
1034
0
                            !(sd_ndisc_redirect_get_target_address(rd, &a) >= 0 && in6_addr_equal(&a, router)))
1035
0
                                continue;
1036
0
                }
1037
1038
0
                r = ndisc_remove_redirect_route(link, rd);
1039
0
                if (r < 0)
1040
0
                        RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove redirect route, ignoring: %m"));
1041
1042
0
                sd_ndisc_redirect_unref(set_remove(link->ndisc_redirects, rd));
1043
0
        }
1044
1045
0
        return ret;
1046
0
}
1047
1048
0
static int ndisc_update_redirect_sender(Link *link, const struct in6_addr *original_address, const struct in6_addr *current_address) {
1049
0
        int r;
1050
1051
0
        assert(link);
1052
0
        assert(original_address);
1053
0
        assert(current_address);
1054
1055
0
        sd_ndisc_redirect *rd;
1056
0
        SET_FOREACH(rd, link->ndisc_redirects) {
1057
0
                struct in6_addr sender;
1058
1059
0
                r = sd_ndisc_redirect_get_sender_address(rd, &sender);
1060
0
                if (r < 0)
1061
0
                        return r;
1062
1063
0
                if (!in6_addr_equal(&sender, original_address))
1064
0
                        continue;
1065
1066
0
                r = sd_ndisc_redirect_set_sender_address(rd, current_address);
1067
0
                if (r < 0)
1068
0
                        return r;
1069
0
        }
1070
1071
0
        return 0;
1072
0
}
1073
1074
0
static int ndisc_router_drop_default(Link *link, sd_ndisc_router *rt) {
1075
0
        _cleanup_(route_unrefp) Route *route = NULL;
1076
0
        struct in6_addr gateway;
1077
0
        int r;
1078
1079
0
        assert(link);
1080
0
        assert(link->network);
1081
0
        assert(rt);
1082
1083
0
        r = sd_ndisc_router_get_sender_address(rt, &gateway);
1084
0
        if (r < 0)
1085
0
                return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
1086
1087
0
        r = route_new(&route);
1088
0
        if (r < 0)
1089
0
                return log_oom();
1090
1091
0
        route->family = AF_INET6;
1092
0
        route->nexthop.family = AF_INET6;
1093
0
        route->nexthop.gw.in6 = gateway;
1094
1095
0
        r = ndisc_remove_router_route(route, link, rt);
1096
0
        if (r < 0)
1097
0
                return log_link_warning_errno(link, r, "Failed to remove the default gateway configured by RA: %m");
1098
1099
0
        Route *route_gw;
1100
0
        HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
1101
0
                _cleanup_(route_unrefp) Route *tmp = NULL;
1102
1103
0
                if (route_gw->source != NETWORK_CONFIG_SOURCE_NDISC)
1104
0
                        continue;
1105
1106
0
                assert(route_gw->nexthop.family == AF_INET6);
1107
1108
0
                r = route_dup(route_gw, NULL, &tmp);
1109
0
                if (r < 0)
1110
0
                        return r;
1111
1112
0
                tmp->nexthop.gw.in6 = gateway;
1113
1114
0
                r = ndisc_remove_router_route(tmp, link, rt);
1115
0
                if (r < 0)
1116
0
                        return log_link_warning_errno(link, r, "Could not remove semi-static gateway: %m");
1117
0
        }
1118
1119
0
        return 0;
1120
0
}
1121
1122
0
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
1123
0
        usec_t lifetime_usec;
1124
0
        struct in6_addr gateway;
1125
0
        uint8_t preference;
1126
0
        int r;
1127
1128
0
        assert(link);
1129
0
        assert(link->network);
1130
0
        assert(rt);
1131
1132
        /* If the router lifetime is zero, the router should not be used as the default gateway. */
1133
0
        r = sd_ndisc_router_get_lifetime(rt, NULL);
1134
0
        if (r < 0)
1135
0
                return r;
1136
0
        if (r == 0)
1137
0
                return ndisc_router_drop_default(link, rt);
1138
1139
0
        if (!link->network->ndisc_use_gateway &&
1140
0
            hashmap_isempty(link->network->routes_by_section))
1141
0
                return 0;
1142
1143
0
        r = sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1144
0
        if (r < 0)
1145
0
                return log_link_warning_errno(link, r, "Failed to get gateway lifetime from RA: %m");
1146
1147
0
        r = sd_ndisc_router_get_sender_address(rt, &gateway);
1148
0
        if (r < 0)
1149
0
                return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
1150
1151
0
        r = sd_ndisc_router_get_preference(rt, &preference);
1152
0
        if (r < 0)
1153
0
                return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
1154
1155
0
        if (link->network->ndisc_use_gateway) {
1156
0
                _cleanup_(route_unrefp) Route *route = NULL;
1157
1158
0
                r = route_new(&route);
1159
0
                if (r < 0)
1160
0
                        return log_oom();
1161
1162
0
                route->family = AF_INET6;
1163
0
                route->pref = preference;
1164
0
                route->nexthop.family = AF_INET6;
1165
0
                route->nexthop.gw.in6 = gateway;
1166
0
                route->lifetime_usec = lifetime_usec;
1167
1168
0
                r = ndisc_request_router_route(route, link, rt);
1169
0
                if (r < 0)
1170
0
                        return log_link_warning_errno(link, r, "Could not request default route: %m");
1171
0
        }
1172
1173
0
        Route *route_gw;
1174
0
        HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
1175
0
                _cleanup_(route_unrefp) Route *route = NULL;
1176
1177
0
                if (route_gw->source != NETWORK_CONFIG_SOURCE_NDISC)
1178
0
                        continue;
1179
1180
0
                assert(route_gw->nexthop.family == AF_INET6);
1181
1182
0
                r = route_dup(route_gw, NULL, &route);
1183
0
                if (r < 0)
1184
0
                        return r;
1185
1186
0
                route->nexthop.gw.in6 = gateway;
1187
0
                if (!route->pref_set)
1188
0
                        route->pref = preference;
1189
0
                route->lifetime_usec = lifetime_usec;
1190
1191
0
                r = ndisc_request_router_route(route, link, rt);
1192
0
                if (r < 0)
1193
0
                        return log_link_warning_errno(link, r, "Could not request gateway: %m");
1194
0
        }
1195
1196
0
        return 0;
1197
0
}
1198
1199
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
1200
                ndisc_router_hash_ops,
1201
                struct in6_addr,
1202
                in6_addr_hash_func,
1203
                in6_addr_compare_func,
1204
                sd_ndisc_router,
1205
                sd_ndisc_router_unref);
1206
1207
0
static int ndisc_update_router_address(Link *link, const struct in6_addr *original_address, const struct in6_addr *current_address) {
1208
0
        _cleanup_(sd_ndisc_router_unrefp) sd_ndisc_router *rt = NULL;
1209
0
        int r;
1210
1211
0
        assert(link);
1212
0
        assert(original_address);
1213
0
        assert(current_address);
1214
1215
0
        rt = hashmap_remove(link->ndisc_routers_by_sender, original_address);
1216
0
        if (!rt)
1217
0
                return 0;
1218
1219
        /* If we already received an RA from the new address, then forget the RA from the old address. */
1220
0
        if (hashmap_contains(link->ndisc_routers_by_sender, current_address))
1221
0
                return 0;
1222
1223
        /* Otherwise, update the sender address of the previously received RA. */
1224
0
        r = sd_ndisc_router_set_sender_address(rt, current_address);
1225
0
        if (r < 0)
1226
0
                return r;
1227
1228
0
        r = hashmap_put(link->ndisc_routers_by_sender, &rt->packet->sender_address, rt);
1229
0
        if (r < 0)
1230
0
                return r;
1231
1232
0
        TAKE_PTR(rt);
1233
0
        return 0;
1234
0
}
1235
1236
0
static int ndisc_drop_router_one(Link *link, sd_ndisc_router *rt, usec_t timestamp_usec) {
1237
0
        usec_t lifetime_usec;
1238
0
        int r;
1239
1240
0
        assert(link);
1241
0
        assert(rt);
1242
0
        assert(rt->packet);
1243
1244
0
        r = sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1245
0
        if (r < 0)
1246
0
                return r;
1247
1248
0
        if (lifetime_usec > timestamp_usec)
1249
0
                return 0;
1250
1251
0
        r = ndisc_drop_redirect(link, &rt->packet->sender_address);
1252
1253
0
        sd_ndisc_router_unref(hashmap_remove(link->ndisc_routers_by_sender, &rt->packet->sender_address));
1254
1255
0
        return r;
1256
0
}
1257
1258
0
static int ndisc_drop_routers(Link *link, const struct in6_addr *router, usec_t timestamp_usec) {
1259
0
        sd_ndisc_router *rt;
1260
0
        int ret = 0;
1261
1262
0
        assert(link);
1263
1264
0
        if (router) {
1265
0
                rt = hashmap_get(link->ndisc_routers_by_sender, router);
1266
0
                if (!rt)
1267
0
                        return 0;
1268
1269
0
                return ndisc_drop_router_one(link, rt, timestamp_usec);
1270
0
        }
1271
1272
0
        HASHMAP_FOREACH_KEY(rt, router, link->ndisc_routers_by_sender)
1273
0
                RET_GATHER(ret, ndisc_drop_router_one(link, rt, timestamp_usec));
1274
1275
0
        return ret;
1276
0
}
1277
1278
0
static int ndisc_remember_router(Link *link, sd_ndisc_router *rt) {
1279
0
        int r;
1280
1281
0
        assert(link);
1282
0
        assert(rt);
1283
0
        assert(rt->packet);
1284
1285
0
        sd_ndisc_router_unref(hashmap_remove(link->ndisc_routers_by_sender, &rt->packet->sender_address));
1286
1287
        /* Remember RAs with non-zero lifetime. */
1288
0
        r = sd_ndisc_router_get_lifetime(rt, NULL);
1289
0
        if (r <= 0)
1290
0
                return r;
1291
1292
0
        r = hashmap_ensure_put(&link->ndisc_routers_by_sender, &ndisc_router_hash_ops, &rt->packet->sender_address, rt);
1293
0
        if (r < 0)
1294
0
                return r;
1295
1296
0
        sd_ndisc_router_ref(rt);
1297
0
        return 0;
1298
0
}
1299
1300
0
static int ndisc_router_process_reachable_time(Link *link, sd_ndisc_router *rt) {
1301
0
        usec_t reachable_time, msec;
1302
0
        int r;
1303
1304
0
        assert(link);
1305
0
        assert(link->manager);
1306
0
        assert(link->network);
1307
0
        assert(rt);
1308
1309
0
        if (!link->network->ndisc_use_reachable_time)
1310
0
                return 0;
1311
1312
0
        r = sd_ndisc_router_get_reachable_time(rt, &reachable_time);
1313
0
        if (r < 0)
1314
0
                return log_link_warning_errno(link, r, "Failed to get reachable time from RA: %m");
1315
1316
        /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */
1317
0
        if (!timestamp_is_set(reachable_time))
1318
0
                return 0;
1319
1320
0
        msec = DIV_ROUND_UP(reachable_time, USEC_PER_MSEC);
1321
0
        if (msec <= 0 || msec > UINT32_MAX) {
1322
0
                log_link_debug(link, "Failed to get reachable time from RA - out of range (%"PRIu64"), ignoring", msec);
1323
0
                return 0;
1324
0
        }
1325
1326
        /* Set the reachable time for Neighbor Solicitations. */
1327
0
        r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "base_reachable_time_ms", (uint32_t) msec, manager_get_sysctl_shadow(link->manager));
1328
0
        if (r < 0)
1329
0
                log_link_warning_errno(link, r, "Failed to apply neighbor reachable time (%"PRIu64"), ignoring: %m", msec);
1330
1331
0
        return 0;
1332
0
}
1333
1334
0
static int ndisc_router_process_retransmission_time(Link *link, sd_ndisc_router *rt) {
1335
0
        usec_t retrans_time, msec;
1336
0
        int r;
1337
1338
0
        assert(link);
1339
0
        assert(link->manager);
1340
0
        assert(link->network);
1341
0
        assert(rt);
1342
1343
0
        if (!link->network->ndisc_use_retransmission_time)
1344
0
                return 0;
1345
1346
0
        r = sd_ndisc_router_get_retransmission_time(rt, &retrans_time);
1347
0
        if (r < 0)
1348
0
                return log_link_warning_errno(link, r, "Failed to get retransmission time from RA: %m");
1349
1350
        /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */
1351
0
        if (!timestamp_is_set(retrans_time))
1352
0
                return 0;
1353
1354
0
        msec = DIV_ROUND_UP(retrans_time, USEC_PER_MSEC);
1355
0
        if (msec <= 0 || msec > UINT32_MAX) {
1356
0
                log_link_debug(link, "Failed to get retransmission time from RA - out of range (%"PRIu64"), ignoring", msec);
1357
0
                return 0;
1358
0
        }
1359
1360
        /* Set the retransmission time for Neighbor Solicitations. */
1361
0
        r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", (uint32_t) msec, manager_get_sysctl_shadow(link->manager));
1362
0
        if (r < 0)
1363
0
                log_link_warning_errno(link, r, "Failed to apply neighbor retransmission time (%"PRIu64"), ignoring: %m", msec);
1364
1365
0
        return 0;
1366
0
}
1367
1368
0
static int ndisc_router_process_hop_limit(Link *link, sd_ndisc_router *rt) {
1369
0
        uint8_t hop_limit;
1370
0
        int r;
1371
1372
0
        assert(link);
1373
0
        assert(link->manager);
1374
0
        assert(link->network);
1375
0
        assert(rt);
1376
1377
0
        if (!link->network->ndisc_use_hop_limit)
1378
0
                return 0;
1379
1380
0
        r = sd_ndisc_router_get_hop_limit(rt, &hop_limit);
1381
0
        if (r < 0)
1382
0
                return log_link_warning_errno(link, r, "Failed to get hop limit from RA: %m");
1383
1384
        /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4):
1385
         *
1386
         * A Router Advertisement field (e.g., Cur Hop Limit, Reachable Time, and Retrans Timer) may contain
1387
         * a value denoting that it is unspecified. In such cases, the parameter should be ignored and the
1388
         * host should continue using whatever value it is already using. In particular, a host MUST NOT
1389
         * interpret the unspecified value as meaning change back to the default value that was in use before
1390
         * the first Router Advertisement was received.
1391
         *
1392
         * If the received Cur Hop Limit value is non-zero, the host SHOULD set
1393
         * its CurHopLimit variable to the received value. */
1394
0
        if (hop_limit <= 0)
1395
0
                return 0;
1396
1397
0
        r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "hop_limit", (uint32_t) hop_limit, manager_get_sysctl_shadow(link->manager));
1398
0
        if (r < 0)
1399
0
                log_link_warning_errno(link, r, "Failed to apply hop_limit (%u), ignoring: %m", hop_limit);
1400
1401
0
        return 0;
1402
0
}
1403
1404
0
static int ndisc_router_process_mtu(Link *link, sd_ndisc_router *rt) {
1405
0
        uint32_t mtu;
1406
0
        int r;
1407
1408
0
        assert(link);
1409
0
        assert(link->network);
1410
0
        assert(rt);
1411
1412
0
        if (!link->network->ndisc_use_mtu)
1413
0
                return 0;
1414
1415
0
        r = sd_ndisc_router_get_mtu(rt, &mtu);
1416
0
        if (r == -ENODATA)
1417
0
                return 0;
1418
0
        if (r < 0)
1419
0
                return log_link_warning_errno(link, r, "Failed to get MTU from RA: %m");
1420
1421
0
        link->ndisc_mtu = mtu;
1422
1423
0
        (void) link_set_ipv6_mtu(link, LOG_DEBUG);
1424
1425
0
        return 0;
1426
0
}
1427
1428
0
static int ndisc_address_set_lifetime(Address *address, Link *link, sd_ndisc_router *rt) {
1429
0
        Address *existing;
1430
0
        usec_t t;
1431
0
        int r;
1432
1433
0
        assert(address);
1434
0
        assert(link);
1435
0
        assert(rt);
1436
1437
        /* This is mostly based on RFC 4862 section 5.5.3 (e). However, the definition of 'RemainingLifetime'
1438
         * is ambiguous, and there is no clear explanation when the address is not assigned yet. If we assume
1439
         * that 'RemainingLifetime' is zero in that case, then IPv6 Core Conformance test [v6LC.3.2.5 Part C]
1440
         * fails. So, in such case, we skip the conditions about 'RemainingLifetime'. */
1441
1442
0
        r = sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_BOOTTIME, &address->lifetime_valid_usec);
1443
0
        if (r < 0)
1444
0
                return r;
1445
1446
0
        r = sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt, CLOCK_BOOTTIME, &address->lifetime_preferred_usec);
1447
0
        if (r < 0)
1448
0
                return r;
1449
1450
        /* RFC 4862 section 5.5.3 (e)
1451
         * 1. If the received Valid Lifetime is greater than 2 hours or greater than RemainingLifetime,
1452
         *    set the valid lifetime of the corresponding address to the advertised Valid Lifetime. */
1453
0
        r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &t);
1454
0
        if (r < 0)
1455
0
                return r;
1456
1457
0
        if (t > 2 * USEC_PER_HOUR)
1458
0
                return 0;
1459
1460
0
        if (address_get(link, address, &existing) < 0 || existing->source != NETWORK_CONFIG_SOURCE_NDISC)
1461
0
                return 0;
1462
1463
0
        if (address->lifetime_valid_usec > existing->lifetime_valid_usec)
1464
0
                return 0;
1465
1466
        /* 2. If RemainingLifetime is less than or equal to 2 hours, ignore the Prefix Information option
1467
         *    with regards to the valid lifetime, unless the Router Advertisement from which this option was
1468
         *    obtained has been authenticated (e.g., via Secure Neighbor Discovery [RFC3971]). If the Router
1469
         *    Advertisement was authenticated, the valid lifetime of the corresponding address should be set
1470
         *    to the Valid Lifetime in the received option.
1471
         *
1472
         * Currently, authentication is not supported. So check the lifetime of the existing address. */
1473
0
        r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &t);
1474
0
        if (r < 0)
1475
0
                return r;
1476
1477
0
        if (existing->lifetime_valid_usec <= usec_add(t, 2 * USEC_PER_HOUR)) {
1478
0
                address->lifetime_valid_usec = existing->lifetime_valid_usec;
1479
0
                return 0;
1480
0
        }
1481
1482
        /* 3. Otherwise, reset the valid lifetime of the corresponding address to 2 hours. */
1483
0
        address->lifetime_valid_usec = usec_add(t, 2 * USEC_PER_HOUR);
1484
0
        return 0;
1485
0
}
1486
1487
0
static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
1488
0
        usec_t lifetime_valid_usec, lifetime_preferred_usec;
1489
0
        struct in6_addr prefix, router;
1490
0
        uint8_t prefixlen;
1491
0
        int r;
1492
1493
0
        assert(link);
1494
0
        assert(link->network);
1495
0
        assert(rt);
1496
1497
0
        if (!link->network->ndisc_use_autonomous_prefix)
1498
0
                return 0;
1499
1500
0
        r = sd_ndisc_router_get_sender_address(rt, &router);
1501
0
        if (r < 0)
1502
0
                return log_link_warning_errno(link, r, "Failed to get router address: %m");
1503
1504
0
        r = sd_ndisc_router_prefix_get_address(rt, &prefix);
1505
0
        if (r < 0)
1506
0
                return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
1507
1508
0
        r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
1509
0
        if (r < 0)
1510
0
                return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
1511
1512
        /* ndisc_generate_addresses() below requires the prefix length <= 64. */
1513
0
        if (prefixlen > 64) {
1514
0
                log_link_debug(link, "Prefix is longer than 64, ignoring autonomous prefix %s.",
1515
0
                               IN6_ADDR_PREFIX_TO_STRING(&prefix, prefixlen));
1516
0
                return 0;
1517
0
        }
1518
1519
0
        r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid_usec);
1520
0
        if (r < 0)
1521
0
                return log_link_warning_errno(link, r, "Failed to get prefix valid lifetime: %m");
1522
1523
0
        r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred_usec);
1524
0
        if (r < 0)
1525
0
                return log_link_warning_errno(link, r, "Failed to get prefix preferred lifetime: %m");
1526
1527
        /* RFC 4862 section 5.5.3 (c)
1528
         * If the preferred lifetime is greater than the valid lifetime, silently ignore the Prefix
1529
         * Information option. */
1530
0
        if (lifetime_preferred_usec > lifetime_valid_usec)
1531
0
                return 0;
1532
1533
0
        _cleanup_hashmap_free_ Hashmap *tokens_by_address = NULL;
1534
0
        r = ndisc_generate_addresses(link, &prefix, prefixlen, &tokens_by_address);
1535
0
        if (r < 0)
1536
0
                return log_link_warning_errno(link, r, "Failed to generate SLAAC addresses: %m");
1537
1538
0
        IPv6Token *token;
1539
0
        struct in6_addr *a;
1540
0
        HASHMAP_FOREACH_KEY(token, a, tokens_by_address) {
1541
0
                _cleanup_(address_unrefp) Address *address = NULL;
1542
1543
0
                r = address_new(&address);
1544
0
                if (r < 0)
1545
0
                        return log_oom();
1546
1547
0
                address->provider.in6 = router;
1548
0
                address->family = AF_INET6;
1549
0
                address->in_addr.in6 = *a;
1550
0
                address->prefixlen = prefixlen;
1551
0
                address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
1552
0
                address->token = ipv6_token_ref(token);
1553
1554
0
                r = ndisc_address_set_lifetime(address, link, rt);
1555
0
                if (r < 0)
1556
0
                        return log_link_warning_errno(link, r, "Failed to set lifetime of SLAAC address: %m");
1557
1558
0
                assert(address->lifetime_preferred_usec <= address->lifetime_valid_usec);
1559
1560
0
                r = ndisc_request_address(address, link);
1561
0
                if (r < 0)
1562
0
                        return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
1563
0
        }
1564
1565
0
        return 0;
1566
0
}
1567
1568
0
static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
1569
0
        _cleanup_(route_unrefp) Route *route = NULL;
1570
0
        uint8_t prefixlen, preference;
1571
0
        usec_t lifetime_usec;
1572
0
        struct in6_addr prefix;
1573
0
        int r;
1574
1575
0
        assert(link);
1576
0
        assert(link->network);
1577
0
        assert(rt);
1578
1579
0
        if (!link->network->ndisc_use_onlink_prefix)
1580
0
                return 0;
1581
1582
0
        r = sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1583
0
        if (r < 0)
1584
0
                return log_link_warning_errno(link, r, "Failed to get prefix lifetime: %m");
1585
1586
0
        r = sd_ndisc_router_prefix_get_address(rt, &prefix);
1587
0
        if (r < 0)
1588
0
                return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
1589
1590
0
        r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
1591
0
        if (r < 0)
1592
0
                return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
1593
1594
        /* Prefix Information option does not have preference, hence we use the 'main' preference here */
1595
0
        r = sd_ndisc_router_get_preference(rt, &preference);
1596
0
        if (r < 0)
1597
0
                return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
1598
1599
0
        r = route_new(&route);
1600
0
        if (r < 0)
1601
0
                return log_oom();
1602
1603
0
        route->family = AF_INET6;
1604
0
        route->dst.in6 = prefix;
1605
0
        route->dst_prefixlen = prefixlen;
1606
0
        route->pref = preference;
1607
0
        route->lifetime_usec = lifetime_usec;
1608
1609
        /* RFC 4861 section 6.3.4:
1610
         * - If the prefix is not already present in the Prefix List, and the Prefix Information option's
1611
         *   Valid Lifetime field is non-zero, create a new entry for the prefix and initialize its
1612
         *   invalidation timer to the Valid Lifetime value in the Prefix Information option.
1613
         *
1614
         * - If the prefix is already present in the host's Prefix List as the result of a previously
1615
         *   received advertisement, reset its invalidation timer to the Valid Lifetime value in the Prefix
1616
         *   Information option. If the new Lifetime value is zero, timeout the prefix immediately. */
1617
0
        if (lifetime_usec == 0) {
1618
0
                r = ndisc_remove_router_route(route, link, rt);
1619
0
                if (r < 0)
1620
0
                        return log_link_warning_errno(link, r, "Failed to remove prefix route: %m");
1621
0
        } else {
1622
0
                r = ndisc_request_router_route(route, link, rt);
1623
0
                if (r < 0)
1624
0
                        return log_link_warning_errno(link, r, "Failed to request prefix route: %m");
1625
0
        }
1626
1627
0
        return 0;
1628
0
}
1629
1630
0
static int ndisc_router_process_prefix(Link *link, sd_ndisc_router *rt, bool zero_lifetime) {
1631
0
        uint8_t flags, prefixlen;
1632
0
        struct in6_addr a;
1633
0
        int r;
1634
1635
0
        assert(link);
1636
0
        assert(link->network);
1637
0
        assert(rt);
1638
1639
0
        usec_t lifetime_usec;
1640
0
        r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_usec);
1641
0
        if (r < 0)
1642
0
                return log_link_warning_errno(link, r, "Failed to get prefix lifetime: %m");
1643
1644
0
        if ((lifetime_usec == 0) != zero_lifetime)
1645
0
                return 0;
1646
1647
0
        r = sd_ndisc_router_prefix_get_address(rt, &a);
1648
0
        if (r < 0)
1649
0
                return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
1650
1651
        /* RFC 4861 Section 4.6.2:
1652
         * A router SHOULD NOT send a prefix option for the link-local prefix and a host SHOULD ignore such
1653
         * a prefix option. */
1654
0
        if (in6_addr_is_link_local(&a)) {
1655
0
                log_link_debug(link, "Received link-local prefix, ignoring prefix.");
1656
0
                return 0;
1657
0
        }
1658
1659
0
        r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
1660
0
        if (r < 0)
1661
0
                return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
1662
1663
0
        if (in6_prefix_is_filtered(&a, prefixlen, link->network->ndisc_allow_listed_prefix, link->network->ndisc_deny_listed_prefix)) {
1664
0
                if (set_isempty(link->network->ndisc_allow_listed_prefix))
1665
0
                        log_link_debug(link, "Prefix '%s' is in deny list, ignoring.",
1666
0
                                       IN6_ADDR_PREFIX_TO_STRING(&a, prefixlen));
1667
0
                else
1668
0
                        log_link_debug(link, "Prefix '%s' is not in allow list, ignoring.",
1669
0
                                       IN6_ADDR_PREFIX_TO_STRING(&a, prefixlen));
1670
0
                return 0;
1671
0
        }
1672
1673
0
        r = sd_ndisc_router_prefix_get_flags(rt, &flags);
1674
0
        if (r < 0)
1675
0
                return log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
1676
1677
0
        if (FLAGS_SET(flags, ND_OPT_PI_FLAG_ONLINK)) {
1678
0
                r = ndisc_router_process_onlink_prefix(link, rt);
1679
0
                if (r < 0)
1680
0
                        return r;
1681
0
        }
1682
1683
0
        if (FLAGS_SET(flags, ND_OPT_PI_FLAG_AUTO)) {
1684
0
                r = ndisc_router_process_autonomous_prefix(link, rt);
1685
0
                if (r < 0)
1686
0
                        return r;
1687
0
        }
1688
1689
0
        return 0;
1690
0
}
1691
1692
0
static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt, bool zero_lifetime) {
1693
0
        _cleanup_(route_unrefp) Route *route = NULL;
1694
0
        uint8_t preference, prefixlen;
1695
0
        struct in6_addr gateway, dst;
1696
0
        usec_t lifetime_usec;
1697
0
        int r;
1698
1699
0
        assert(link);
1700
1701
0
        if (!link->network->ndisc_use_route_prefix)
1702
0
                return 0;
1703
1704
0
        r = sd_ndisc_router_route_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1705
0
        if (r < 0)
1706
0
                return log_link_warning_errno(link, r, "Failed to get route lifetime from RA: %m");
1707
1708
0
        if ((lifetime_usec == 0) != zero_lifetime)
1709
0
                return 0;
1710
1711
0
        r = sd_ndisc_router_route_get_address(rt, &dst);
1712
0
        if (r < 0)
1713
0
                return log_link_warning_errno(link, r, "Failed to get route destination address: %m");
1714
1715
0
        r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
1716
0
        if (r < 0)
1717
0
                return log_link_warning_errno(link, r, "Failed to get route prefix length: %m");
1718
1719
0
        if (in6_prefix_is_filtered(&dst, prefixlen,
1720
0
                                   link->network->ndisc_allow_listed_route_prefix,
1721
0
                                   link->network->ndisc_deny_listed_route_prefix)) {
1722
0
                if (set_isempty(link->network->ndisc_allow_listed_route_prefix))
1723
0
                        log_link_debug(link, "Route prefix '%s' is in deny list, ignoring.",
1724
0
                                       IN6_ADDR_PREFIX_TO_STRING(&dst, prefixlen));
1725
0
                else
1726
0
                        log_link_debug(link, "Route prefix '%s' is not in allow list, ignoring.",
1727
0
                                       IN6_ADDR_PREFIX_TO_STRING(&dst, prefixlen));
1728
0
                return 0;
1729
0
        }
1730
1731
0
        r = sd_ndisc_router_get_sender_address(rt, &gateway);
1732
0
        if (r < 0)
1733
0
                return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
1734
1735
0
        if (link_get_ipv6_address(link, &gateway, NULL) >= 0) {
1736
0
                if (DEBUG_LOGGING)
1737
0
                        log_link_debug(link, "Advertised route gateway %s is local to the link, ignoring route",
1738
0
                                       IN6_ADDR_TO_STRING(&gateway));
1739
0
                return 0;
1740
0
        }
1741
1742
0
        r = sd_ndisc_router_route_get_preference(rt, &preference);
1743
0
        if (r < 0)
1744
0
                return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
1745
1746
0
        r = route_new(&route);
1747
0
        if (r < 0)
1748
0
                return log_oom();
1749
1750
0
        route->family = AF_INET6;
1751
0
        route->pref = preference;
1752
0
        route->nexthop.gw.in6 = gateway;
1753
0
        route->nexthop.family = AF_INET6;
1754
0
        route->dst.in6 = dst;
1755
0
        route->dst_prefixlen = prefixlen;
1756
0
        route->lifetime_usec = lifetime_usec;
1757
1758
0
        if (lifetime_usec != 0) {
1759
0
                r = ndisc_request_router_route(route, link, rt);
1760
0
                if (r < 0)
1761
0
                        return log_link_warning_errno(link, r, "Could not request additional route: %m");
1762
0
        } else {
1763
0
                r = ndisc_remove_router_route(route, link, rt);
1764
0
                if (r < 0)
1765
0
                        return log_link_warning_errno(link, r, "Could not remove additional route with zero lifetime: %m");
1766
0
        }
1767
1768
0
        return 0;
1769
0
}
1770
1771
0
static void ndisc_rdnss_hash_func(const NDiscRDNSS *x, struct siphash *state) {
1772
0
        siphash24_compress_typesafe(x->address, state);
1773
0
}
1774
1775
0
static int ndisc_rdnss_compare_func(const NDiscRDNSS *a, const NDiscRDNSS *b) {
1776
0
        return memcmp(&a->address, &b->address, sizeof(a->address));
1777
0
}
1778
1779
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1780
                ndisc_rdnss_hash_ops,
1781
                NDiscRDNSS,
1782
                ndisc_rdnss_hash_func,
1783
                ndisc_rdnss_compare_func,
1784
                free);
1785
1786
0
static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt, bool zero_lifetime) {
1787
0
        usec_t lifetime_usec;
1788
0
        const struct in6_addr *a;
1789
0
        struct in6_addr router;
1790
0
        bool updated = false, logged_about_too_many = false;
1791
0
        int n, r;
1792
1793
0
        assert(link);
1794
0
        assert(link->network);
1795
0
        assert(rt);
1796
1797
0
        if (!link_get_use_dns(link, NETWORK_CONFIG_SOURCE_NDISC))
1798
0
                return 0;
1799
1800
0
        r = sd_ndisc_router_get_sender_address(rt, &router);
1801
0
        if (r < 0)
1802
0
                return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
1803
1804
0
        r = sd_ndisc_router_rdnss_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1805
0
        if (r < 0)
1806
0
                return log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
1807
1808
0
        if ((lifetime_usec == 0) != zero_lifetime)
1809
0
                return 0;
1810
1811
0
        n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
1812
0
        if (n < 0)
1813
0
                return log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m");
1814
1815
0
        for (int j = 0; j < n; j++) {
1816
0
                _cleanup_free_ NDiscRDNSS *x = NULL;
1817
0
                NDiscRDNSS *rdnss, d = {
1818
0
                        .address = a[j],
1819
0
                };
1820
1821
0
                if (lifetime_usec == 0) {
1822
                        /* The entry is outdated. */
1823
0
                        free(set_remove(link->ndisc_rdnss, &d));
1824
0
                        updated = true;
1825
0
                        continue;
1826
0
                }
1827
1828
0
                rdnss = set_get(link->ndisc_rdnss, &d);
1829
0
                if (rdnss) {
1830
0
                        rdnss->router = router;
1831
0
                        rdnss->lifetime_usec = lifetime_usec;
1832
0
                        continue;
1833
0
                }
1834
1835
0
                if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
1836
0
                        if (!logged_about_too_many)
1837
0
                                log_link_warning(link, "Too many RDNSS records per link. Only first %u records will be used.", NDISC_RDNSS_MAX);
1838
0
                        logged_about_too_many = true;
1839
0
                        continue;
1840
0
                }
1841
1842
0
                x = new(NDiscRDNSS, 1);
1843
0
                if (!x)
1844
0
                        return log_oom();
1845
1846
0
                *x = (NDiscRDNSS) {
1847
0
                        .address = a[j],
1848
0
                        .router = router,
1849
0
                        .lifetime_usec = lifetime_usec,
1850
0
                };
1851
1852
0
                r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
1853
0
                if (r < 0)
1854
0
                        return log_oom();
1855
0
                assert(r > 0);
1856
1857
0
                updated = true;
1858
0
        }
1859
1860
0
        if (updated)
1861
0
                link_dirty(link);
1862
1863
0
        return 0;
1864
0
}
1865
1866
0
static void ndisc_dnssl_hash_func(const NDiscDNSSL *x, struct siphash *state) {
1867
0
        siphash24_compress_string(ndisc_dnssl_domain(x), state);
1868
0
}
1869
1870
0
static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) {
1871
0
        return strcmp(ndisc_dnssl_domain(a), ndisc_dnssl_domain(b));
1872
0
}
1873
1874
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1875
                ndisc_dnssl_hash_ops,
1876
                NDiscDNSSL,
1877
                ndisc_dnssl_hash_func,
1878
                ndisc_dnssl_compare_func,
1879
                free);
1880
1881
0
static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt, bool zero_lifetime) {
1882
0
        char **l;
1883
0
        usec_t lifetime_usec;
1884
0
        struct in6_addr router;
1885
0
        bool updated = false, logged_about_too_many = false;
1886
0
        int r;
1887
1888
0
        assert(link);
1889
0
        assert(link->network);
1890
0
        assert(rt);
1891
1892
0
        if (link_get_use_domains(link, NETWORK_CONFIG_SOURCE_NDISC) <= 0)
1893
0
                return 0;
1894
1895
0
        r = sd_ndisc_router_get_sender_address(rt, &router);
1896
0
        if (r < 0)
1897
0
                return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
1898
1899
0
        r = sd_ndisc_router_dnssl_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1900
0
        if (r < 0)
1901
0
                return log_link_warning_errno(link, r, "Failed to get DNSSL lifetime: %m");
1902
1903
0
        if ((lifetime_usec == 0) != zero_lifetime)
1904
0
                return 0;
1905
1906
0
        r = sd_ndisc_router_dnssl_get_domains(rt, &l);
1907
0
        if (r < 0)
1908
0
                return log_link_warning_errno(link, r, "Failed to get DNSSL addresses: %m");
1909
1910
0
        STRV_FOREACH(j, l) {
1911
0
                _cleanup_free_ NDiscDNSSL *s = NULL;
1912
0
                NDiscDNSSL *dnssl;
1913
1914
                /* Silence static analyzers */
1915
0
                assert(strlen(*j) <= SIZE_MAX - ALIGN(sizeof(NDiscDNSSL)) - 1);
1916
0
                s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*j) + 1);
1917
0
                if (!s)
1918
0
                        return log_oom();
1919
1920
0
                strcpy(ndisc_dnssl_domain(s), *j);
1921
1922
0
                if (lifetime_usec == 0) {
1923
                        /* The entry is outdated. */
1924
0
                        free(set_remove(link->ndisc_dnssl, s));
1925
0
                        updated = true;
1926
0
                        continue;
1927
0
                }
1928
1929
0
                dnssl = set_get(link->ndisc_dnssl, s);
1930
0
                if (dnssl) {
1931
0
                        dnssl->router = router;
1932
0
                        dnssl->lifetime_usec = lifetime_usec;
1933
0
                        continue;
1934
0
                }
1935
1936
0
                if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
1937
0
                        if (!logged_about_too_many)
1938
0
                                log_link_warning(link, "Too many DNSSL records per link. Only first %u records will be used.", NDISC_DNSSL_MAX);
1939
0
                        logged_about_too_many = true;
1940
0
                        continue;
1941
0
                }
1942
1943
0
                s->router = router;
1944
0
                s->lifetime_usec = lifetime_usec;
1945
1946
0
                r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
1947
0
                if (r < 0)
1948
0
                        return log_oom();
1949
0
                assert(r > 0);
1950
1951
0
                updated = true;
1952
0
        }
1953
1954
0
        if (updated)
1955
0
                link_dirty(link);
1956
1957
0
        return 0;
1958
0
}
1959
1960
0
static NDiscCaptivePortal* ndisc_captive_portal_free(NDiscCaptivePortal *x) {
1961
0
        if (!x)
1962
0
                return NULL;
1963
1964
0
        free(x->captive_portal);
1965
0
        return mfree(x);
1966
0
}
1967
1968
DEFINE_TRIVIAL_CLEANUP_FUNC(NDiscCaptivePortal*, ndisc_captive_portal_free);
1969
1970
0
static void ndisc_captive_portal_hash_func(const NDiscCaptivePortal *x, struct siphash *state) {
1971
0
        assert(x);
1972
0
        siphash24_compress_string(x->captive_portal, state);
1973
0
}
1974
1975
0
static int ndisc_captive_portal_compare_func(const NDiscCaptivePortal *a, const NDiscCaptivePortal *b) {
1976
0
        assert(a);
1977
0
        assert(b);
1978
0
        return strcmp_ptr(a->captive_portal, b->captive_portal);
1979
0
}
1980
1981
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1982
                ndisc_captive_portal_hash_ops,
1983
                NDiscCaptivePortal,
1984
                ndisc_captive_portal_hash_func,
1985
                ndisc_captive_portal_compare_func,
1986
                ndisc_captive_portal_free);
1987
1988
0
static int ndisc_router_process_captive_portal(Link *link, sd_ndisc_router *rt, bool zero_lifetime) {
1989
0
        _cleanup_(ndisc_captive_portal_freep) NDiscCaptivePortal *new_entry = NULL;
1990
0
        _cleanup_free_ char *captive_portal = NULL;
1991
0
        const char *uri;
1992
0
        usec_t lifetime_usec;
1993
0
        NDiscCaptivePortal *exist;
1994
0
        struct in6_addr router;
1995
0
        int r;
1996
1997
0
        assert(link);
1998
0
        assert(link->network);
1999
0
        assert(rt);
2000
2001
0
        if (!link->network->ndisc_use_captive_portal)
2002
0
                return 0;
2003
2004
0
        r = sd_ndisc_router_get_sender_address(rt, &router);
2005
0
        if (r < 0)
2006
0
                return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
2007
2008
        /* RFC 4861 section 4.2. states that the lifetime in the message header should be used only for the
2009
         * default gateway, but the captive portal option does not have a lifetime field, hence, we use the
2010
         * main lifetime for the portal. */
2011
0
        r = sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
2012
0
        if (r < 0)
2013
0
                return log_link_warning_errno(link, r, "Failed to get lifetime of RA message: %m");
2014
2015
0
        if ((lifetime_usec == 0) != zero_lifetime)
2016
0
                return 0;
2017
2018
0
        r = sd_ndisc_router_get_captive_portal(rt, &uri);
2019
0
        if (r < 0)
2020
0
                return log_link_warning_errno(link, r, "Failed to get captive portal from RA: %m");
2021
2022
0
        captive_portal = strdup(uri);
2023
0
        if (!captive_portal)
2024
0
                return log_oom();
2025
2026
0
        if (lifetime_usec == 0) {
2027
                /* Drop the portal with zero lifetime. */
2028
0
                ndisc_captive_portal_free(set_remove(link->ndisc_captive_portals,
2029
0
                                                     &(const NDiscCaptivePortal) {
2030
0
                                                             .captive_portal = captive_portal,
2031
0
                                                     }));
2032
0
                return 0;
2033
0
        }
2034
2035
0
        exist = set_get(link->ndisc_captive_portals,
2036
0
                        &(const NDiscCaptivePortal) {
2037
0
                                .captive_portal = captive_portal,
2038
0
                        });
2039
0
        if (exist) {
2040
                /* update existing entry */
2041
0
                exist->router = router;
2042
0
                exist->lifetime_usec = lifetime_usec;
2043
0
                return 1;
2044
0
        }
2045
2046
0
        if (set_size(link->ndisc_captive_portals) >= NDISC_CAPTIVE_PORTAL_MAX) {
2047
0
                NDiscCaptivePortal *c, *target = NULL;
2048
2049
                /* Find the portal who has the minimal lifetime and drop it to store new one. */
2050
0
                SET_FOREACH(c, link->ndisc_captive_portals)
2051
0
                        if (!target || c->lifetime_usec < target->lifetime_usec)
2052
0
                                target = c;
2053
2054
0
                assert(target);
2055
0
                assert_se(set_remove(link->ndisc_captive_portals, target) == target);
2056
0
                ndisc_captive_portal_free(target);
2057
0
        }
2058
2059
0
        new_entry = new(NDiscCaptivePortal, 1);
2060
0
        if (!new_entry)
2061
0
                return log_oom();
2062
2063
0
        *new_entry = (NDiscCaptivePortal) {
2064
0
                .router = router,
2065
0
                .lifetime_usec = lifetime_usec,
2066
0
                .captive_portal = TAKE_PTR(captive_portal),
2067
0
        };
2068
2069
0
        r = set_ensure_put(&link->ndisc_captive_portals, &ndisc_captive_portal_hash_ops, new_entry);
2070
0
        if (r < 0)
2071
0
                return log_oom();
2072
0
        assert(r > 0);
2073
0
        TAKE_PTR(new_entry);
2074
2075
0
        link_dirty(link);
2076
0
        return 1;
2077
0
}
2078
2079
0
static void ndisc_pref64_hash_func(const NDiscPREF64 *x, struct siphash *state) {
2080
0
        assert(x);
2081
2082
0
        siphash24_compress_typesafe(x->prefix_len, state);
2083
0
        siphash24_compress_typesafe(x->prefix, state);
2084
0
}
2085
2086
0
static int ndisc_pref64_compare_func(const NDiscPREF64 *a, const NDiscPREF64 *b) {
2087
0
        int r;
2088
2089
0
        assert(a);
2090
0
        assert(b);
2091
2092
0
        r = CMP(a->prefix_len, b->prefix_len);
2093
0
        if (r != 0)
2094
0
                return r;
2095
2096
0
        return memcmp(&a->prefix, &b->prefix, sizeof(a->prefix));
2097
0
}
2098
2099
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
2100
                ndisc_pref64_hash_ops,
2101
                NDiscPREF64,
2102
                ndisc_pref64_hash_func,
2103
                ndisc_pref64_compare_func,
2104
0
                mfree);
2105
2106
0
static int ndisc_router_process_pref64(Link *link, sd_ndisc_router *rt, bool zero_lifetime) {
2107
0
        _cleanup_free_ NDiscPREF64 *new_entry = NULL;
2108
0
        usec_t lifetime_usec;
2109
0
        struct in6_addr a, router;
2110
0
        uint8_t prefix_len;
2111
0
        NDiscPREF64 *exist;
2112
0
        int r;
2113
2114
0
        assert(link);
2115
0
        assert(link->network);
2116
0
        assert(rt);
2117
2118
0
        if (!link->network->ndisc_use_pref64)
2119
0
                return 0;
2120
2121
0
        r = sd_ndisc_router_get_sender_address(rt, &router);
2122
0
        if (r < 0)
2123
0
                return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
2124
2125
0
        r = sd_ndisc_router_prefix64_get_prefix(rt, &a);
2126
0
        if (r < 0)
2127
0
                return log_link_warning_errno(link, r, "Failed to get pref64 prefix: %m");
2128
2129
0
        r = sd_ndisc_router_prefix64_get_prefixlen(rt, &prefix_len);
2130
0
        if (r < 0)
2131
0
                return log_link_warning_errno(link, r, "Failed to get pref64 prefix length: %m");
2132
2133
0
        r = sd_ndisc_router_prefix64_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
2134
0
        if (r < 0)
2135
0
                return log_link_warning_errno(link, r, "Failed to get pref64 prefix lifetime: %m");
2136
2137
0
        if ((lifetime_usec == 0) != zero_lifetime)
2138
0
                return 0;
2139
2140
0
        if (lifetime_usec == 0) {
2141
0
                free(set_remove(link->ndisc_pref64,
2142
0
                                &(NDiscPREF64) {
2143
0
                                        .prefix = a,
2144
0
                                        .prefix_len = prefix_len
2145
0
                                }));
2146
0
                return 0;
2147
0
        }
2148
2149
0
        exist = set_get(link->ndisc_pref64,
2150
0
                        &(NDiscPREF64) {
2151
0
                                .prefix = a,
2152
0
                                .prefix_len = prefix_len
2153
0
                });
2154
0
        if (exist) {
2155
                /* update existing entry */
2156
0
                exist->router = router;
2157
0
                exist->lifetime_usec = lifetime_usec;
2158
0
                return 0;
2159
0
        }
2160
2161
0
        if (set_size(link->ndisc_pref64) >= NDISC_PREF64_MAX) {
2162
0
                log_link_debug(link, "Too many PREF64 records received. Only first %u records will be used.", NDISC_PREF64_MAX);
2163
0
                return 0;
2164
0
        }
2165
2166
0
        new_entry = new(NDiscPREF64, 1);
2167
0
        if (!new_entry)
2168
0
                return log_oom();
2169
2170
0
        *new_entry = (NDiscPREF64) {
2171
0
                .router = router,
2172
0
                .lifetime_usec = lifetime_usec,
2173
0
                .prefix = a,
2174
0
                .prefix_len = prefix_len,
2175
0
        };
2176
2177
0
        r = set_ensure_put(&link->ndisc_pref64, &ndisc_pref64_hash_ops, new_entry);
2178
0
        if (r < 0)
2179
0
                return log_oom();
2180
2181
0
        assert(r > 0);
2182
0
        TAKE_PTR(new_entry);
2183
2184
0
        return 0;
2185
0
}
2186
2187
0
static NDiscDNR* ndisc_dnr_free(NDiscDNR *x) {
2188
0
        if (!x)
2189
0
                return NULL;
2190
2191
0
        sd_dns_resolver_done(&x->resolver);
2192
0
        return mfree(x);
2193
0
}
2194
2195
DEFINE_TRIVIAL_CLEANUP_FUNC(NDiscDNR*, ndisc_dnr_free);
2196
2197
0
static int ndisc_dnr_compare_func(const NDiscDNR *a, const NDiscDNR *b) {
2198
0
        return CMP(a->resolver.priority, b->resolver.priority) ||
2199
0
                strcmp_ptr(a->resolver.auth_name, b->resolver.auth_name) ||
2200
0
                CMP(a->resolver.transports, b->resolver.transports) ||
2201
0
                CMP(a->resolver.port, b->resolver.port) ||
2202
0
                strcmp_ptr(a->resolver.dohpath, b->resolver.dohpath) ||
2203
0
                CMP(a->resolver.family, b->resolver.family) ||
2204
0
                CMP(a->resolver.n_addrs, b->resolver.n_addrs) ||
2205
0
                memcmp(a->resolver.addrs, b->resolver.addrs, sizeof(a->resolver.addrs[0]) * a->resolver.n_addrs) != 0;
2206
0
}
2207
2208
0
static void ndisc_dnr_hash_func(const NDiscDNR *x, struct siphash *state) {
2209
0
        assert(x);
2210
2211
0
        siphash24_compress_resolver(&x->resolver, state);
2212
0
}
2213
2214
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
2215
                ndisc_dnr_hash_ops,
2216
                NDiscDNR,
2217
                ndisc_dnr_hash_func,
2218
                ndisc_dnr_compare_func,
2219
                ndisc_dnr_free);
2220
2221
0
static int sd_dns_resolver_copy(const sd_dns_resolver *a, sd_dns_resolver *b) {
2222
0
        int r;
2223
2224
0
        assert(a);
2225
0
        assert(b);
2226
2227
0
        _cleanup_(sd_dns_resolver_done) sd_dns_resolver c = {
2228
0
                .priority = a->priority,
2229
0
                .transports = a->transports,
2230
0
                .port = a->port,
2231
                /* .auth_name */
2232
0
                .family = a->family,
2233
                /* .addrs */
2234
                /* .n_addrs */
2235
                /* .dohpath */
2236
0
        };
2237
2238
        /* auth_name */
2239
0
        r = strdup_to(&c.auth_name, a->auth_name);
2240
0
        if (r < 0)
2241
0
                return r;
2242
2243
        /* addrs, n_addrs */
2244
0
        c.addrs = newdup(union in_addr_union, a->addrs, a->n_addrs);
2245
0
        if (!c.addrs)
2246
0
                return -ENOMEM;
2247
0
        c.n_addrs = a->n_addrs;
2248
2249
        /* dohpath */
2250
0
        r = strdup_to(&c.dohpath, a->dohpath);
2251
0
        if (r < 0)
2252
0
                return r;
2253
2254
0
        *b = TAKE_STRUCT(c);
2255
0
        return 0;
2256
0
}
2257
2258
0
static int ndisc_router_process_encrypted_dns(Link *link, sd_ndisc_router *rt, bool zero_lifetime) {
2259
0
        int r;
2260
2261
0
        assert(link);
2262
0
        assert(link->network);
2263
0
        assert(rt);
2264
2265
0
        struct in6_addr router;
2266
0
        usec_t lifetime_usec;
2267
0
        sd_dns_resolver *res;
2268
0
        _cleanup_(ndisc_dnr_freep) NDiscDNR *new_entry = NULL;
2269
2270
0
        if (!link_get_use_dnr(link, NETWORK_CONFIG_SOURCE_NDISC))
2271
0
                return 0;
2272
2273
0
        r = sd_ndisc_router_get_sender_address(rt, &router);
2274
0
        if (r < 0)
2275
0
                return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
2276
2277
0
        r = sd_ndisc_router_encrypted_dns_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
2278
0
        if (r < 0)
2279
0
                return log_link_warning_errno(link, r, "Failed to get lifetime of RA message: %m");
2280
2281
0
        if ((lifetime_usec == 0) != zero_lifetime)
2282
0
                return 0;
2283
2284
0
        r = sd_ndisc_router_encrypted_dns_get_resolver(rt, &res);
2285
0
        if (r < 0)
2286
0
                return log_link_warning_errno(link, r, "Failed to get encrypted dns resolvers: %m");
2287
2288
0
        NDiscDNR *dnr, d = { .resolver = *res };
2289
0
        if (lifetime_usec == 0) {
2290
0
                dnr = set_remove(link->ndisc_dnr, &d);
2291
0
                if (dnr) {
2292
0
                        ndisc_dnr_free(dnr);
2293
0
                        link_dirty(link);
2294
0
                }
2295
0
                return 0;
2296
0
        }
2297
2298
0
        dnr = set_get(link->ndisc_dnr, &d);
2299
0
        if (dnr) {
2300
0
                dnr->router = router;
2301
0
                dnr->lifetime_usec = lifetime_usec;
2302
0
                return 0;
2303
0
        }
2304
2305
0
        if (set_size(link->ndisc_dnr) >= NDISC_ENCRYPTED_DNS_MAX) {
2306
0
                log_link_warning(link, "Too many Encrypted DNS records received. Only first %u records will be used.", NDISC_ENCRYPTED_DNS_MAX);
2307
0
                return 0;
2308
0
        }
2309
2310
0
        new_entry = new(NDiscDNR, 1);
2311
0
        if (!new_entry)
2312
0
                return log_oom();
2313
2314
0
        *new_entry = (NDiscDNR) {
2315
0
                .router = router,
2316
                /* .resolver, */
2317
0
                .lifetime_usec = lifetime_usec,
2318
0
        };
2319
0
        r = sd_dns_resolver_copy(res, &new_entry->resolver);
2320
0
        if (r < 0)
2321
0
                return log_oom();
2322
2323
        /* Not sorted by priority */
2324
0
        r = set_ensure_put(&link->ndisc_dnr, &ndisc_dnr_hash_ops, new_entry);
2325
0
        if (r < 0)
2326
0
                return log_oom();
2327
2328
0
        assert(r > 0);
2329
0
        TAKE_PTR(new_entry);
2330
2331
0
        link_dirty(link);
2332
2333
0
        return 0;
2334
0
}
2335
2336
0
static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt, bool zero_lifetime) {
2337
0
        size_t n_captive_portal = 0;
2338
0
        int r;
2339
2340
0
        assert(link);
2341
0
        assert(link->network);
2342
0
        assert(rt);
2343
2344
0
        for (r = sd_ndisc_router_option_rewind(rt); ; r = sd_ndisc_router_option_next(rt)) {
2345
0
                uint8_t type;
2346
2347
0
                if (r < 0)
2348
0
                        return log_link_warning_errno(link, r, "Failed to iterate through options: %m");
2349
0
                if (r == 0) /* EOF */
2350
0
                        return 0;
2351
2352
0
                r = sd_ndisc_router_option_get_type(rt, &type);
2353
0
                if (r < 0)
2354
0
                        return log_link_warning_errno(link, r, "Failed to get RA option type: %m");
2355
2356
0
                switch (type) {
2357
0
                case SD_NDISC_OPTION_PREFIX_INFORMATION:
2358
0
                        r = ndisc_router_process_prefix(link, rt, zero_lifetime);
2359
0
                        break;
2360
2361
0
                case SD_NDISC_OPTION_ROUTE_INFORMATION:
2362
0
                        r = ndisc_router_process_route(link, rt, zero_lifetime);
2363
0
                        break;
2364
2365
0
                case SD_NDISC_OPTION_RDNSS:
2366
0
                        r = ndisc_router_process_rdnss(link, rt, zero_lifetime);
2367
0
                        break;
2368
2369
0
                case SD_NDISC_OPTION_DNSSL:
2370
0
                        r = ndisc_router_process_dnssl(link, rt, zero_lifetime);
2371
0
                        break;
2372
0
                case SD_NDISC_OPTION_CAPTIVE_PORTAL:
2373
0
                        if (n_captive_portal > 0) {
2374
0
                                if (n_captive_portal == 1)
2375
0
                                        log_link_notice(link, "Received RA with multiple captive portals, only using the first one.");
2376
2377
0
                                n_captive_portal++;
2378
0
                                continue;
2379
0
                        }
2380
0
                        r = ndisc_router_process_captive_portal(link, rt, zero_lifetime);
2381
0
                        if (r > 0)
2382
0
                                n_captive_portal++;
2383
0
                        break;
2384
0
                case SD_NDISC_OPTION_PREF64:
2385
0
                        r = ndisc_router_process_pref64(link, rt, zero_lifetime);
2386
0
                        break;
2387
0
                case SD_NDISC_OPTION_ENCRYPTED_DNS:
2388
0
                        r = ndisc_router_process_encrypted_dns(link, rt, zero_lifetime);
2389
0
                        break;
2390
0
                }
2391
0
                if (r < 0 && r != -EBADMSG)
2392
0
                        return r;
2393
0
        }
2394
0
}
2395
2396
0
static int ndisc_drop_outdated(Link *link, const struct in6_addr *router, usec_t timestamp_usec) {
2397
0
        bool updated = false;
2398
0
        NDiscDNSSL *dnssl;
2399
0
        NDiscRDNSS *rdnss;
2400
0
        NDiscCaptivePortal *cp;
2401
0
        NDiscPREF64 *p64;
2402
0
        NDiscDNR *dnr;
2403
0
        Address *address;
2404
0
        Route *route;
2405
0
        int r, ret = 0;
2406
2407
0
        assert(link);
2408
0
        assert(link->manager);
2409
2410
        /* If an address or friends is already assigned, but not valid anymore, then refuse to update it,
2411
         * and let's immediately remove it.
2412
         * See RFC4862, section 5.5.3.e. But the following logic is deviated from RFC4862 by honoring all
2413
         * valid lifetimes to improve the reaction of SLAAC to renumbering events.
2414
         * See draft-ietf-6man-slaac-renum-02, section 4.2. */
2415
2416
0
        r = ndisc_drop_routers(link, router, timestamp_usec);
2417
0
        if (r < 0)
2418
0
                RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to drop outdated default router, ignoring: %m"));
2419
2420
0
        SET_FOREACH(route, link->manager->routes) {
2421
0
                if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
2422
0
                        continue;
2423
2424
0
                if (!route_is_bound_to_link(route, link))
2425
0
                        continue;
2426
2427
0
                if (route->protocol == RTPROT_REDIRECT)
2428
0
                        continue; /* redirect route will be dropped by ndisc_drop_redirect(). */
2429
2430
0
                if (route->lifetime_usec > timestamp_usec)
2431
0
                        continue; /* the route is still valid */
2432
2433
0
                if (router && !in6_addr_equal(&route->provider.in6, router))
2434
0
                        continue;
2435
2436
0
                r = route_remove_and_cancel(route, link->manager);
2437
0
                if (r < 0)
2438
0
                        RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC route, ignoring: %m"));
2439
0
        }
2440
2441
0
        RET_GATHER(ret, ndisc_remove_unused_nexthops(link));
2442
2443
0
        SET_FOREACH(address, link->addresses) {
2444
0
                if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
2445
0
                        continue;
2446
2447
0
                if (address->lifetime_valid_usec > timestamp_usec)
2448
0
                        continue; /* the address is still valid */
2449
2450
0
                if (router && !in6_addr_equal(&address->provider.in6, router))
2451
0
                        continue;
2452
2453
0
                r = address_remove_and_cancel(address, link);
2454
0
                if (r < 0)
2455
0
                        RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC address, ignoring: %m"));
2456
0
        }
2457
2458
0
        SET_FOREACH(rdnss, link->ndisc_rdnss) {
2459
0
                if (rdnss->lifetime_usec > timestamp_usec)
2460
0
                        continue; /* the DNS server is still valid */
2461
2462
0
                if (router && !in6_addr_equal(&rdnss->router, router))
2463
0
                        continue;
2464
2465
0
                free(set_remove(link->ndisc_rdnss, rdnss));
2466
0
                updated = true;
2467
0
        }
2468
2469
0
        SET_FOREACH(dnssl, link->ndisc_dnssl) {
2470
0
                if (dnssl->lifetime_usec > timestamp_usec)
2471
0
                        continue; /* the DNS domain is still valid */
2472
2473
0
                if (router && !in6_addr_equal(&dnssl->router, router))
2474
0
                        continue;
2475
2476
0
                free(set_remove(link->ndisc_dnssl, dnssl));
2477
0
                updated = true;
2478
0
        }
2479
2480
0
        SET_FOREACH(cp, link->ndisc_captive_portals) {
2481
0
                if (cp->lifetime_usec > timestamp_usec)
2482
0
                        continue; /* the captive portal is still valid */
2483
2484
0
                if (router && !in6_addr_equal(&cp->router, router))
2485
0
                        continue;
2486
2487
0
                ndisc_captive_portal_free(set_remove(link->ndisc_captive_portals, cp));
2488
0
                updated = true;
2489
0
        }
2490
2491
0
        SET_FOREACH(p64, link->ndisc_pref64) {
2492
0
                if (p64->lifetime_usec > timestamp_usec)
2493
0
                        continue; /* the pref64 prefix is still valid */
2494
2495
0
                if (router && !in6_addr_equal(&p64->router, router))
2496
0
                        continue;
2497
2498
0
                free(set_remove(link->ndisc_pref64, p64));
2499
                /* The pref64 prefix is not exported through the state file, hence it is not necessary to set
2500
                 * the 'updated' flag. */
2501
0
        }
2502
2503
0
        SET_FOREACH(dnr, link->ndisc_dnr) {
2504
0
                if (dnr->lifetime_usec > timestamp_usec)
2505
0
                        continue; /* The resolver is still valid */
2506
2507
0
                ndisc_dnr_free(set_remove(link->ndisc_dnr, dnr));
2508
0
                updated = true;
2509
0
        }
2510
2511
0
        RET_GATHER(ret, link_request_stacked_netdevs(link, NETDEV_LOCAL_ADDRESS_SLAAC));
2512
2513
0
        if (updated)
2514
0
                link_dirty(link);
2515
2516
0
        return ret;
2517
0
}
2518
2519
static int ndisc_setup_expire(Link *link);
2520
2521
0
static int ndisc_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
2522
0
        Link *link = ASSERT_PTR(userdata);
2523
0
        usec_t now_usec;
2524
2525
0
        assert(link->manager);
2526
2527
0
        assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
2528
2529
0
        (void) ndisc_drop_outdated(link, /* router= */ NULL, now_usec);
2530
0
        (void) ndisc_setup_expire(link);
2531
0
        return 0;
2532
0
}
2533
2534
0
static int ndisc_setup_expire(Link *link) {
2535
0
        usec_t lifetime_usec = USEC_INFINITY;
2536
0
        NDiscCaptivePortal *cp;
2537
0
        NDiscDNSSL *dnssl;
2538
0
        NDiscRDNSS *rdnss;
2539
0
        NDiscPREF64 *p64;
2540
0
        NDiscDNR *dnr;
2541
0
        Address *address;
2542
0
        Route *route;
2543
0
        int r;
2544
2545
0
        assert(link);
2546
0
        assert(link->manager);
2547
2548
0
        sd_ndisc_router *rt;
2549
0
        HASHMAP_FOREACH(rt, link->ndisc_routers_by_sender) {
2550
0
                usec_t t;
2551
2552
0
                if (sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &t) < 0)
2553
0
                        continue;
2554
2555
0
                lifetime_usec = MIN(lifetime_usec, t);
2556
0
        }
2557
2558
0
        SET_FOREACH(route, link->manager->routes) {
2559
0
                if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
2560
0
                        continue;
2561
2562
0
                if (!route_is_bound_to_link(route, link))
2563
0
                        continue;
2564
2565
0
                if (!route_exists(route))
2566
0
                        continue;
2567
2568
0
                lifetime_usec = MIN(lifetime_usec, route->lifetime_usec);
2569
0
        }
2570
2571
0
        SET_FOREACH(address, link->addresses) {
2572
0
                if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
2573
0
                        continue;
2574
2575
0
                if (!address_exists(address))
2576
0
                        continue;
2577
2578
0
                lifetime_usec = MIN(lifetime_usec, address->lifetime_valid_usec);
2579
0
        }
2580
2581
0
        SET_FOREACH(rdnss, link->ndisc_rdnss)
2582
0
                lifetime_usec = MIN(lifetime_usec, rdnss->lifetime_usec);
2583
2584
0
        SET_FOREACH(dnssl, link->ndisc_dnssl)
2585
0
                lifetime_usec = MIN(lifetime_usec, dnssl->lifetime_usec);
2586
2587
0
        SET_FOREACH(cp, link->ndisc_captive_portals)
2588
0
                lifetime_usec = MIN(lifetime_usec, cp->lifetime_usec);
2589
2590
0
        SET_FOREACH(p64, link->ndisc_pref64)
2591
0
                lifetime_usec = MIN(lifetime_usec, p64->lifetime_usec);
2592
2593
0
        SET_FOREACH(dnr, link->ndisc_dnr)
2594
0
                lifetime_usec = MIN(lifetime_usec, dnr->lifetime_usec);
2595
2596
0
        if (lifetime_usec == USEC_INFINITY)
2597
0
                return 0;
2598
2599
0
        r = event_reset_time(link->manager->event, &link->ndisc_expire, CLOCK_BOOTTIME,
2600
0
                             lifetime_usec, 0, ndisc_expire_handler, link, 0, "ndisc-expiration", true);
2601
0
        if (r < 0)
2602
0
                return log_link_warning_errno(link, r, "Failed to update expiration timer for ndisc: %m");
2603
2604
0
        return 0;
2605
0
}
2606
2607
0
static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) {
2608
0
        int r;
2609
2610
0
        assert(link);
2611
0
        assert(link->network);
2612
2613
0
        switch (link->network->ndisc_start_dhcp6_client) {
2614
0
        case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO:
2615
0
                return 0;
2616
2617
0
        case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES: {
2618
0
                uint64_t flags;
2619
2620
0
                r = sd_ndisc_router_get_flags(rt, &flags);
2621
0
                if (r < 0)
2622
0
                        return log_link_warning_errno(link, r, "Failed to get RA flags: %m");
2623
2624
0
                if ((flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) == 0)
2625
0
                        return 0;
2626
2627
                /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags.
2628
                 * Note, if both "managed" and "other configuration" bits are set, then ignore
2629
                 * "other configuration" bit. See RFC 4861. */
2630
0
                r = dhcp6_start_on_ra(link, !(flags & ND_RA_FLAG_MANAGED));
2631
0
                break;
2632
0
        }
2633
0
        case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS:
2634
                /* When IPv6AcceptRA.DHCPv6Client=always, start dhcp6 client in solicit mode
2635
                 * even if the router flags have neither M nor O flags. */
2636
0
                r = dhcp6_start_on_ra(link, /* information_request= */ false);
2637
0
                break;
2638
2639
0
        default:
2640
0
                assert_not_reached();
2641
0
        }
2642
2643
0
        if (r < 0)
2644
0
                return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
2645
2646
0
        log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
2647
0
        return 0;
2648
0
}
2649
2650
0
static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
2651
0
        struct in6_addr router;
2652
0
        usec_t timestamp_usec;
2653
0
        int r;
2654
2655
0
        assert(link);
2656
0
        assert(link->network);
2657
0
        assert(link->manager);
2658
0
        assert(rt);
2659
2660
0
        r = sd_ndisc_router_get_sender_address(rt, &router);
2661
0
        if (r == -ENODATA) {
2662
0
                log_link_debug(link, "Received RA without router address, ignoring.");
2663
0
                return 0;
2664
0
        }
2665
0
        if (r < 0)
2666
0
                return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
2667
2668
0
        if (in6_prefix_is_filtered(&router, 128, link->network->ndisc_allow_listed_router, link->network->ndisc_deny_listed_router)) {
2669
0
                if (!set_isempty(link->network->ndisc_allow_listed_router))
2670
0
                        log_link_debug(link, "Router %s is not in allow list, ignoring.", IN6_ADDR_TO_STRING(&router));
2671
0
                else
2672
0
                        log_link_debug(link, "Router %s is in deny list, ignoring.", IN6_ADDR_TO_STRING(&router));
2673
0
                return 0;
2674
0
        }
2675
2676
0
        r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &timestamp_usec);
2677
0
        if (r == -ENODATA) {
2678
0
                log_link_debug(link, "Received RA without timestamp, ignoring.");
2679
0
                return 0;
2680
0
        }
2681
0
        if (r < 0)
2682
0
                return r;
2683
2684
0
        r = ndisc_drop_outdated(link, /* router= */ NULL, timestamp_usec);
2685
0
        if (r < 0)
2686
0
                return r;
2687
2688
0
        r = ndisc_remember_router(link, rt);
2689
0
        if (r < 0)
2690
0
                return r;
2691
2692
0
        r = ndisc_start_dhcp6_client(link, rt);
2693
0
        if (r < 0)
2694
0
                return r;
2695
2696
0
        r = ndisc_router_process_reachable_time(link, rt);
2697
0
        if (r < 0)
2698
0
                return r;
2699
2700
0
        r = ndisc_router_process_retransmission_time(link, rt);
2701
0
        if (r < 0)
2702
0
                return r;
2703
2704
0
        r = ndisc_router_process_hop_limit(link, rt);
2705
0
        if (r < 0)
2706
0
                return r;
2707
2708
0
        r = ndisc_router_process_mtu(link, rt);
2709
0
        if (r < 0)
2710
0
                return r;
2711
2712
0
        r = ndisc_router_process_options(link, rt, /* zero_lifetime= */ true);
2713
0
        if (r < 0)
2714
0
                return r;
2715
2716
0
        r = ndisc_router_process_default(link, rt);
2717
0
        if (r < 0)
2718
0
                return r;
2719
2720
0
        r = ndisc_router_process_options(link, rt, /* zero_lifetime= */ false);
2721
0
        if (r < 0)
2722
0
                return r;
2723
2724
0
        r = ndisc_setup_expire(link);
2725
0
        if (r < 0)
2726
0
                return r;
2727
2728
0
        if (sd_ndisc_router_get_lifetime(rt, NULL) <= 0)
2729
0
                (void) ndisc_drop_redirect(link, &router);
2730
2731
0
        if (link->ndisc_messages == 0)
2732
0
                link->ndisc_configured = true;
2733
0
        else
2734
0
                log_link_debug(link, "Setting SLAAC addresses and router.");
2735
2736
0
        if (!link->ndisc_configured)
2737
0
                link_set_state(link, LINK_STATE_CONFIGURING);
2738
2739
0
        link_check_ready(link);
2740
0
        return 0;
2741
0
}
2742
2743
0
static int ndisc_neighbor_handle_non_router_message(Link *link, sd_ndisc_neighbor *na) {
2744
0
        struct in6_addr address;
2745
0
        int r;
2746
2747
0
        assert(link);
2748
0
        assert(na);
2749
2750
        /* Received Neighbor Advertisement message without Router flag. The node might have been a router,
2751
         * and now it is not. Let's drop all configurations based on RAs sent from the node. */
2752
2753
0
        r = sd_ndisc_neighbor_get_target_address(na, &address);
2754
0
        if (r == -ENODATA)
2755
0
                return 0;
2756
0
        if (r < 0)
2757
0
                return r;
2758
2759
        /* Remove the routes configured by Redirect messages. */
2760
0
        r = ndisc_drop_redirect(link, &address);
2761
2762
        /* Also remove the default gateway via the host, but keep the configurations based on the RA options. */
2763
0
        _cleanup_(sd_ndisc_router_unrefp) sd_ndisc_router *rt = hashmap_remove(link->ndisc_routers_by_sender, &address);
2764
0
        if (rt)
2765
0
                RET_GATHER(r, ndisc_router_drop_default(link, rt));
2766
2767
0
        return r;
2768
0
}
2769
2770
0
static int ndisc_neighbor_handle_router_message(Link *link, sd_ndisc_neighbor *na) {
2771
0
        struct in6_addr current_address, original_address;
2772
0
        int r;
2773
2774
0
        assert(link);
2775
0
        assert(link->manager);
2776
0
        assert(na);
2777
2778
        /* Received Neighbor Advertisement message with Router flag. If the router address is changed, update
2779
         * the provider field of configurations. */
2780
2781
0
        r = sd_ndisc_neighbor_get_sender_address(na, &current_address);
2782
0
        if (r == -ENODATA)
2783
0
                return 0;
2784
0
        if (r < 0)
2785
0
                return r;
2786
2787
0
        r = sd_ndisc_neighbor_get_target_address(na, &original_address);
2788
0
        if (r == -ENODATA)
2789
0
                return 0;
2790
0
        if (r < 0)
2791
0
                return r;
2792
2793
0
        if (in6_addr_equal(&current_address, &original_address))
2794
0
                return 0; /* the router address is not changed */
2795
2796
0
        r = ndisc_update_router_address(link, &original_address, &current_address);
2797
0
        if (r < 0)
2798
0
                return r;
2799
2800
0
        r = ndisc_update_redirect_sender(link, &original_address, &current_address);
2801
0
        if (r < 0)
2802
0
                return r;
2803
2804
0
        Route *route;
2805
0
        SET_FOREACH(route, link->manager->routes) {
2806
0
                if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
2807
0
                        continue;
2808
2809
0
                if (!route_is_bound_to_link(route, link))
2810
0
                        continue;
2811
2812
0
                if (!in6_addr_equal(&route->provider.in6, &original_address))
2813
0
                        continue;
2814
2815
0
                route->provider.in6 = current_address;
2816
0
        }
2817
2818
0
        Address *address;
2819
0
        SET_FOREACH(address, link->addresses) {
2820
0
                if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
2821
0
                        continue;
2822
2823
0
                if (!in6_addr_equal(&address->provider.in6, &original_address))
2824
0
                        continue;
2825
2826
0
                address->provider.in6 = current_address;
2827
0
        }
2828
2829
0
        NDiscRDNSS *rdnss;
2830
0
        SET_FOREACH(rdnss, link->ndisc_rdnss) {
2831
0
                if (!in6_addr_equal(&rdnss->router, &original_address))
2832
0
                        continue;
2833
2834
0
                rdnss->router = current_address;
2835
0
        }
2836
2837
0
        NDiscDNSSL *dnssl;
2838
0
        SET_FOREACH(dnssl, link->ndisc_dnssl) {
2839
0
                if (!in6_addr_equal(&dnssl->router, &original_address))
2840
0
                        continue;
2841
2842
0
                dnssl->router = current_address;
2843
0
        }
2844
2845
0
        NDiscCaptivePortal *cp;
2846
0
        SET_FOREACH(cp, link->ndisc_captive_portals) {
2847
0
                if (!in6_addr_equal(&cp->router, &original_address))
2848
0
                        continue;
2849
2850
0
                cp->router = current_address;
2851
0
        }
2852
2853
0
        NDiscPREF64 *p64;
2854
0
        SET_FOREACH(p64, link->ndisc_pref64) {
2855
0
                if (!in6_addr_equal(&p64->router, &original_address))
2856
0
                        continue;
2857
2858
0
                p64->router = current_address;
2859
0
        }
2860
2861
0
        NDiscDNR *dnr;
2862
0
        SET_FOREACH(dnr, link->ndisc_dnr) {
2863
0
                if (!in6_addr_equal(&dnr->router, &original_address))
2864
0
                        continue;
2865
2866
0
                dnr->router = current_address;
2867
0
        }
2868
2869
0
        return 0;
2870
0
}
2871
2872
0
static int ndisc_neighbor_handler(Link *link, sd_ndisc_neighbor *na) {
2873
0
        int r;
2874
2875
0
        assert(link);
2876
0
        assert(na);
2877
2878
0
        r = sd_ndisc_neighbor_is_router(na);
2879
0
        if (r < 0)
2880
0
                return r;
2881
0
        if (r == 0)
2882
0
                r = ndisc_neighbor_handle_non_router_message(link, na);
2883
0
        else
2884
0
                r = ndisc_neighbor_handle_router_message(link, na);
2885
0
        if (r < 0)
2886
0
                return r;
2887
2888
0
        return 0;
2889
0
}
2890
2891
0
static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata) {
2892
0
        Link *link = ASSERT_PTR(userdata);
2893
0
        int r;
2894
2895
0
        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
2896
0
                return;
2897
2898
0
        switch (event) {
2899
2900
0
        case SD_NDISC_EVENT_ROUTER:
2901
0
                r = ndisc_router_handler(link, ASSERT_PTR(message));
2902
0
                if (r < 0 && r != -EBADMSG) {
2903
0
                        link_enter_failed(link);
2904
0
                        return;
2905
0
                }
2906
0
                break;
2907
2908
0
        case SD_NDISC_EVENT_NEIGHBOR:
2909
0
                r = ndisc_neighbor_handler(link, ASSERT_PTR(message));
2910
0
                if (r < 0 && r != -EBADMSG) {
2911
0
                        link_enter_failed(link);
2912
0
                        return;
2913
0
                }
2914
0
                break;
2915
2916
0
        case SD_NDISC_EVENT_REDIRECT:
2917
0
                r = ndisc_redirect_handler(link, ASSERT_PTR(message));
2918
0
                if (r < 0 && r != -EBADMSG) {
2919
0
                        log_link_warning_errno(link, r, "Failed to process Redirect message: %m");
2920
0
                        link_enter_failed(link);
2921
0
                        return;
2922
0
                }
2923
0
                break;
2924
2925
0
        case SD_NDISC_EVENT_TIMEOUT:
2926
0
                log_link_debug(link, "NDisc handler get timeout event");
2927
0
                if (link->ndisc_messages == 0) {
2928
0
                        link->ndisc_configured = true;
2929
0
                        link_check_ready(link);
2930
0
                }
2931
0
                break;
2932
2933
0
        default:
2934
0
                log_link_debug(link, "Received unsupported NDisc event, ignoring.");
2935
0
        }
2936
0
}
2937
2938
0
static int ndisc_configure(Link *link) {
2939
0
        int r;
2940
2941
0
        assert(link);
2942
2943
0
        if (!link_ndisc_enabled(link))
2944
0
                return 0;
2945
2946
0
        if (link->ndisc)
2947
0
                return -EBUSY; /* Already configured. */
2948
2949
0
        r = sd_ndisc_new(&link->ndisc);
2950
0
        if (r < 0)
2951
0
                return r;
2952
2953
0
        r = sd_ndisc_attach_event(link->ndisc, link->manager->event, 0);
2954
0
        if (r < 0)
2955
0
                return r;
2956
2957
0
        if (link->hw_addr.length == ETH_ALEN) {
2958
0
                r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.ether);
2959
0
                if (r < 0)
2960
0
                        return r;
2961
0
        }
2962
2963
0
        r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
2964
0
        if (r < 0)
2965
0
                return r;
2966
2967
0
        r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link);
2968
0
        if (r < 0)
2969
0
                return r;
2970
2971
0
        return 0;
2972
0
}
2973
2974
0
int ndisc_start(Link *link) {
2975
0
        int r;
2976
2977
0
        assert(link);
2978
2979
0
        if (!link->ndisc || !link->dhcp6_client)
2980
0
                return 0;
2981
2982
0
        if (!link_has_carrier(link))
2983
0
                return 0;
2984
2985
0
        if (in6_addr_is_null(&link->ipv6ll_address))
2986
0
                return 0;
2987
2988
0
        r = sd_ndisc_set_link_local_address(link->ndisc, &link->ipv6ll_address);
2989
0
        if (r < 0)
2990
0
                return r;
2991
2992
0
        log_link_debug(link, "Discovering IPv6 routers");
2993
2994
0
        r = sd_ndisc_start(link->ndisc);
2995
0
        if (r < 0)
2996
0
                return r;
2997
2998
0
        return 1;
2999
0
}
3000
3001
0
static int ndisc_process_request(Request *req, Link *link, void *userdata) {
3002
0
        int r;
3003
3004
0
        assert(link);
3005
3006
0
        if (!link_is_ready_to_configure(link, /* allow_unmanaged= */ false))
3007
0
                return 0;
3008
3009
0
        r = ndisc_configure(link);
3010
0
        if (r < 0)
3011
0
                return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Discovery: %m");
3012
3013
0
        r = ndisc_start(link);
3014
0
        if (r < 0)
3015
0
                return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
3016
3017
0
        log_link_debug(link, "IPv6 Router Discovery is configured%s.",
3018
0
                       r > 0 ? " and started" : "");
3019
0
        return 1;
3020
0
}
3021
3022
0
int link_request_ndisc(Link *link) {
3023
0
        int r;
3024
3025
0
        assert(link);
3026
3027
0
        if (!link_ndisc_enabled(link))
3028
0
                return 0;
3029
3030
0
        if (link->ndisc)
3031
0
                return 0;
3032
3033
0
        r = link_queue_request(link, REQUEST_TYPE_NDISC, ndisc_process_request, NULL);
3034
0
        if (r < 0)
3035
0
                return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Discovery: %m");
3036
3037
0
        log_link_debug(link, "Requested configuring of the IPv6 Router Discovery.");
3038
0
        return 0;
3039
0
}
3040
3041
0
int link_drop_ndisc_config(Link *link, Network *network) {
3042
0
        int r, ret = 0;
3043
3044
0
        assert(link);
3045
0
        assert(link->network);
3046
3047
0
        if (link->network == network)
3048
0
                return 0; /* .network file is unchanged. It is not necessary to reconfigure the client. */
3049
3050
0
        if (!link_ndisc_enabled(link)) {
3051
                /* NDisc is disabled. Stop the client if it is running and flush configs. */
3052
0
                ret = ndisc_stop(link);
3053
0
                ndisc_flush(link);
3054
0
                link->ndisc = sd_ndisc_unref(link->ndisc);
3055
0
                return ret;
3056
0
        }
3057
3058
        /* Even if the client was previously enabled and also enabled in the new .network file, detailed
3059
         * settings for the client may be different. Let's unref() the client. */
3060
0
        link->ndisc = sd_ndisc_unref(link->ndisc);
3061
3062
        /* Get if NDisc was enabled or not. */
3063
0
        Network *current = link->network;
3064
0
        link->network = network;
3065
0
        bool enabled = link_ndisc_enabled(link);
3066
0
        link->network = current;
3067
3068
        /* If previously explicitly disabled, there should be nothing to drop.
3069
         * If we do not know the previous setting of the client, e.g. when networkd is restarted, in that
3070
         * case we do not have the previous .network file assigned to the interface, then  let's assume no
3071
         * detailed configuration is changed. Hopefully, unmatching configurations will be dropped after
3072
         * their lifetime. */
3073
0
        if (!enabled)
3074
0
                return 0;
3075
3076
0
        assert(network);
3077
3078
        /* Redirect messages will be ignored. Drop configurations based on the previously received redirect
3079
         * messages. */
3080
0
        if (!network->ndisc_use_redirect)
3081
0
                (void) ndisc_drop_redirect(link, /* router= */ NULL);
3082
3083
        /* If one of the route setting is changed, drop all routes. */
3084
0
        if (link->network->ndisc_use_gateway != network->ndisc_use_gateway ||
3085
0
            link->network->ndisc_use_route_prefix != network->ndisc_use_route_prefix ||
3086
0
            link->network->ndisc_use_onlink_prefix != network->ndisc_use_onlink_prefix ||
3087
0
            link->network->ndisc_quickack != network->ndisc_quickack ||
3088
0
            link->network->ndisc_route_metric_high != network->ndisc_route_metric_high ||
3089
0
            link->network->ndisc_route_metric_medium != network->ndisc_route_metric_medium ||
3090
0
            link->network->ndisc_route_metric_low != network->ndisc_route_metric_low ||
3091
0
            !set_equal(link->network->ndisc_deny_listed_router, network->ndisc_deny_listed_router) ||
3092
0
            !set_equal(link->network->ndisc_allow_listed_router, network->ndisc_allow_listed_router) ||
3093
0
            !set_equal(link->network->ndisc_deny_listed_prefix, network->ndisc_deny_listed_prefix) ||
3094
0
            !set_equal(link->network->ndisc_allow_listed_prefix, network->ndisc_allow_listed_prefix) ||
3095
0
            !set_equal(link->network->ndisc_deny_listed_route_prefix, network->ndisc_deny_listed_route_prefix) ||
3096
0
            !set_equal(link->network->ndisc_allow_listed_route_prefix, network->ndisc_allow_listed_route_prefix)) {
3097
0
                Route *route;
3098
0
                SET_FOREACH(route, link->manager->routes) {
3099
0
                        if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
3100
0
                                continue;
3101
3102
0
                        if (!route_is_bound_to_link(route, link))
3103
0
                                continue;
3104
3105
0
                        if (route->protocol == RTPROT_REDIRECT)
3106
0
                                continue; /* redirect route is handled by ndisc_drop_redirect(). */
3107
3108
0
                        r = route_remove_and_cancel(route, link->manager);
3109
0
                        if (r < 0)
3110
0
                                RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove SLAAC route, ignoring: %m"));
3111
0
                }
3112
3113
0
                RET_GATHER(ret, ndisc_remove_unused_nexthops(link));
3114
0
        }
3115
3116
        /* If SLAAC address is disabled, drop all addresses. */
3117
0
        if (!network->ndisc_use_autonomous_prefix ||
3118
0
            !set_equal(link->network->ndisc_tokens, network->ndisc_tokens) ||
3119
0
            !set_equal(link->network->ndisc_deny_listed_prefix, network->ndisc_deny_listed_prefix) ||
3120
0
            !set_equal(link->network->ndisc_allow_listed_prefix, network->ndisc_allow_listed_prefix)) {
3121
0
                Address *address;
3122
0
                SET_FOREACH(address, link->addresses) {
3123
0
                        if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
3124
0
                                continue;
3125
3126
0
                        r = address_remove_and_cancel(address, link);
3127
0
                        if (r < 0)
3128
0
                                RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove SLAAC address, ignoring: %m"));
3129
0
                }
3130
0
        }
3131
3132
0
        if (!network->ndisc_use_mtu)
3133
0
                link->ndisc_mtu = 0;
3134
3135
0
        return ret;
3136
0
}
3137
3138
0
int ndisc_stop(Link *link) {
3139
0
        assert(link);
3140
3141
0
        link->ndisc_expire = sd_event_source_disable_unref(link->ndisc_expire);
3142
3143
0
        return sd_ndisc_stop(link->ndisc);
3144
0
}
3145
3146
0
void ndisc_flush(Link *link) {
3147
0
        assert(link);
3148
3149
        /* Remove all addresses, routes, RDNSS, DNSSL, DNR, and Captive Portal entries, without exception. */
3150
0
        (void) ndisc_drop_outdated(link, /* router= */ NULL, /* timestamp_usec= */ USEC_INFINITY);
3151
0
        (void) ndisc_drop_redirect(link, /* router= */ NULL);
3152
3153
0
        link->ndisc_routers_by_sender = hashmap_free(link->ndisc_routers_by_sender);
3154
0
        link->ndisc_rdnss = set_free(link->ndisc_rdnss);
3155
0
        link->ndisc_dnssl = set_free(link->ndisc_dnssl);
3156
0
        link->ndisc_captive_portals = set_free(link->ndisc_captive_portals);
3157
0
        link->ndisc_pref64 = set_free(link->ndisc_pref64);
3158
0
        link->ndisc_redirects = set_free(link->ndisc_redirects);
3159
0
        link->ndisc_dnr = set_free(link->ndisc_dnr);
3160
0
        link->ndisc_mtu = 0;
3161
0
}
3162
3163
static const char* const ndisc_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
3164
        [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO]     = "no",
3165
        [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",
3166
        [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES]    = "yes",
3167
};
3168
3169
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(ndisc_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);
3170
3171
DEFINE_CONFIG_PARSE_ENUM(config_parse_ndisc_start_dhcp6_client, ndisc_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client);