Coverage Report

Created: 2025-06-24 06:40

/src/systemd/src/libsystemd-network/sd-ndisc-router.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
/***
3
  Copyright © 2014 Intel Corporation. All rights reserved.
4
***/
5
6
#include <netinet/icmp6.h>
7
8
#include "sd-ndisc.h"
9
10
#include "alloc-util.h"
11
#include "ndisc-internal.h"
12
#include "ndisc-router-internal.h"
13
#include "set.h"
14
#include "string-table.h"
15
#include "string-util.h"
16
17
163
static sd_ndisc_router* ndisc_router_free(sd_ndisc_router *rt) {
18
163
        if (!rt)
19
0
                return NULL;
20
21
163
        icmp6_packet_unref(rt->packet);
22
163
        set_free(rt->options);
23
163
        return mfree(rt);
24
163
}
25
26
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router, sd_ndisc_router, ndisc_router_free);
27
28
163
sd_ndisc_router* ndisc_router_new(ICMP6Packet *packet) {
29
163
        sd_ndisc_router *rt;
30
31
163
        assert(packet);
32
33
163
        rt = new(sd_ndisc_router, 1);
34
163
        if (!rt)
35
0
                return NULL;
36
37
163
        *rt = (sd_ndisc_router) {
38
163
                .n_ref = 1,
39
163
                .packet = icmp6_packet_ref(packet),
40
163
                .iterator = ITERATOR_FIRST,
41
163
        };
42
43
163
        return rt;
44
163
}
45
46
0
int sd_ndisc_router_set_sender_address(sd_ndisc_router *rt, const struct in6_addr *addr) {
47
0
        assert_return(rt, -EINVAL);
48
49
0
        return icmp6_packet_set_sender_address(rt->packet, addr);
50
0
}
51
52
0
int sd_ndisc_router_get_sender_address(sd_ndisc_router *rt, struct in6_addr *ret) {
53
0
        assert_return(rt, -EINVAL);
54
55
0
        return icmp6_packet_get_sender_address(rt->packet, ret);
56
0
}
57
58
0
int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret) {
59
0
        assert_return(rt, -EINVAL);
60
0
        assert_return(ret, -EINVAL);
61
62
0
        return icmp6_packet_get_timestamp(rt->packet, clock, ret);
63
0
}
64
65
#define DEFINE_GET_TIMESTAMP(name)                                      \
66
        int sd_ndisc_router_##name##_timestamp(                         \
67
                        sd_ndisc_router *rt,                            \
68
                        clockid_t clock,                                \
69
0
                        uint64_t *ret) {                                \
70
0
                                                                        \
71
0
                usec_t s, t;                                            \
72
0
                int r;                                                  \
73
0
                                                                        \
74
0
                assert_return(rt, -EINVAL);                             \
75
0
                assert_return(ret, -EINVAL);                            \
76
0
                                                                        \
77
0
                r = sd_ndisc_router_##name(rt, &s);                     \
78
0
                if (r < 0)                                              \
79
0
                        return r;                                       \
80
0
                                                                        \
81
0
                r = sd_ndisc_router_get_timestamp(rt, clock, &t);       \
82
0
                if (r < 0)                                              \
83
0
                        return r;                                       \
84
0
                                                                        \
85
0
                *ret = time_span_to_stamp(s, t);                        \
86
0
                return 0;                                               \
87
0
        }
Unexecuted instantiation: sd_ndisc_router_get_lifetime_timestamp
Unexecuted instantiation: sd_ndisc_router_prefix_get_valid_lifetime_timestamp
Unexecuted instantiation: sd_ndisc_router_prefix_get_preferred_lifetime_timestamp
Unexecuted instantiation: sd_ndisc_router_route_get_lifetime_timestamp
Unexecuted instantiation: sd_ndisc_router_rdnss_get_lifetime_timestamp
Unexecuted instantiation: sd_ndisc_router_dnssl_get_lifetime_timestamp
Unexecuted instantiation: sd_ndisc_router_prefix64_get_lifetime_timestamp
Unexecuted instantiation: sd_ndisc_router_encrypted_dns_get_lifetime_timestamp
88
89
DEFINE_GET_TIMESTAMP(get_lifetime);
90
DEFINE_GET_TIMESTAMP(prefix_get_valid_lifetime);
91
DEFINE_GET_TIMESTAMP(prefix_get_preferred_lifetime);
92
DEFINE_GET_TIMESTAMP(route_get_lifetime);
93
DEFINE_GET_TIMESTAMP(rdnss_get_lifetime);
94
DEFINE_GET_TIMESTAMP(dnssl_get_lifetime);
95
DEFINE_GET_TIMESTAMP(prefix64_get_lifetime);
96
DEFINE_GET_TIMESTAMP(encrypted_dns_get_lifetime);
97
98
163
int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) {
99
163
        const struct nd_router_advert *a;
100
163
        int r;
101
102
163
        assert(rt);
103
163
        assert(rt->packet);
104
105
163
        if (rt->packet->raw_size < sizeof(struct nd_router_advert))
106
5
                return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
107
158
                                       "Too small to be a router advertisement, ignoring.");
108
109
158
        a = (const struct nd_router_advert*) rt->packet->raw_packet;
110
158
        assert(a->nd_ra_type == ND_ROUTER_ADVERT);
111
158
        assert(a->nd_ra_code == 0);
112
113
158
        rt->hop_limit = a->nd_ra_curhoplimit;
114
158
        rt->flags = a->nd_ra_flags_reserved; /* the first 8 bits */
115
158
        rt->lifetime_usec = be16_sec_to_usec(a->nd_ra_router_lifetime, /* max_as_infinity = */ false);
116
158
        rt->reachable_time_usec = be32_msec_to_usec(a->nd_ra_reachable, /* max_as_infinity = */ false);
117
158
        rt->retransmission_time_usec = be32_msec_to_usec(a->nd_ra_retransmit, /* max_as_infinity = */ false);
118
119
        /* RFC 4191 section 2.2
120
         * Prf (Default Router Preference)
121
         * 2-bit signed integer. Indicates whether to prefer this router over other default routers. If the
122
         * Router Lifetime is zero, the preference value MUST be set to (00) by the sender and MUST be
123
         * ignored by the receiver. If the Reserved (10) value is received, the receiver MUST treat the value
124
         * as if it were (00). */
125
158
        rt->preference = (rt->flags >> 3) & 3;
126
158
        if (rt->preference == SD_NDISC_PREFERENCE_RESERVED)
127
11
                rt->preference = SD_NDISC_PREFERENCE_MEDIUM;
128
129
158
        r = ndisc_parse_options(rt->packet, &rt->options);
130
158
        if (r < 0)
131
15
                return log_ndisc_errno(nd, r, "Failed to parse NDisc options in router advertisement message, ignoring: %m");
132
133
143
        return 0;
134
158
}
135
136
0
int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) {
137
0
        assert_return(rt, -EINVAL);
138
0
        assert_return(ret, -EINVAL);
139
140
0
        *ret = rt->hop_limit;
141
0
        return 0;
142
0
}
143
144
0
int sd_ndisc_router_get_reachable_time(sd_ndisc_router *rt, uint64_t *ret) {
145
0
        assert_return(rt, -EINVAL);
146
0
        assert_return(ret, -EINVAL);
147
148
0
        *ret = rt->reachable_time_usec;
149
0
        return 0;
150
0
}
151
152
0
int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret) {
153
0
        assert_return(rt, -EINVAL);
154
0
        assert_return(ret, -EINVAL);
155
156
0
        *ret = rt->retransmission_time_usec;
157
0
        return 0;
158
0
}
159
160
0
int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret) {
161
0
        assert_return(rt, -EINVAL);
162
0
        assert_return(ret, -EINVAL);
163
164
0
        sd_ndisc_option *p = ndisc_option_get_by_type(rt->options, SD_NDISC_OPTION_FLAGS_EXTENSION);
165
166
0
        *ret = rt->flags | (p ? p->extended_flags : 0);
167
0
        return 0;
168
0
}
169
170
0
int ndisc_router_flags_to_string(uint64_t flags, char **ret) {
171
0
        _cleanup_free_ char *s = NULL;
172
173
0
        assert(ret);
174
175
0
        if (FLAGS_SET(flags, ND_RA_FLAG_MANAGED) &&
176
0
            !strextend_with_separator(&s, ", ", "managed"))
177
0
                return -ENOMEM;
178
179
0
        if (FLAGS_SET(flags, ND_RA_FLAG_OTHER) &&
180
0
            !strextend_with_separator(&s, ", ", "other"))
181
0
                return -ENOMEM;
182
183
0
        if (FLAGS_SET(flags, ND_RA_FLAG_HOME_AGENT) &&
184
0
            !strextend_with_separator(&s, ", ", "home-agent"))
185
0
                return -ENOMEM;
186
187
0
        *ret = TAKE_PTR(s);
188
0
        return 0;
189
0
}
190
191
0
int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret) {
192
0
        assert_return(rt, -EINVAL);
193
194
0
        if (ret)
195
0
                *ret = rt->lifetime_usec;
196
197
0
        return rt->lifetime_usec > 0; /* Indicate if the router is still valid or not. */
198
0
}
199
200
0
int sd_ndisc_router_get_preference(sd_ndisc_router *rt, uint8_t *ret) {
201
0
        assert_return(rt, -EINVAL);
202
0
        assert_return(ret, -EINVAL);
203
204
0
        *ret = rt->preference;
205
0
        return 0;
206
0
}
207
208
static const char* const ndisc_router_preference_table[] = {
209
        [SD_NDISC_PREFERENCE_LOW]      = "low",
210
        [SD_NDISC_PREFERENCE_MEDIUM]   = "medium",
211
        [SD_NDISC_PREFERENCE_HIGH]     = "high",
212
        [SD_NDISC_PREFERENCE_RESERVED] = "reserved",
213
};
214
215
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(ndisc_router_preference, int);
216
217
0
int sd_ndisc_router_get_sender_mac(sd_ndisc_router *rt, struct ether_addr *ret) {
218
0
        assert_return(rt, -EINVAL);
219
220
0
        return ndisc_option_get_mac(rt->options, SD_NDISC_OPTION_SOURCE_LL_ADDRESS, ret);
221
0
}
222
223
0
int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret) {
224
0
        assert_return(rt, -EINVAL);
225
0
        assert_return(ret, -EINVAL);
226
227
0
        sd_ndisc_option *p = ndisc_option_get_by_type(rt->options, SD_NDISC_OPTION_MTU);
228
0
        if (!p)
229
0
                return -ENODATA;
230
231
0
        *ret = p->mtu;
232
0
        return 0;
233
0
}
234
235
0
int sd_ndisc_router_get_captive_portal(sd_ndisc_router *rt, const char **ret) {
236
0
        assert_return(rt, -EINVAL);
237
0
        assert_return(ret, -EINVAL);
238
239
0
        sd_ndisc_option *p = ndisc_option_get_by_type(rt->options, SD_NDISC_OPTION_CAPTIVE_PORTAL);
240
0
        if (!p)
241
0
                return -ENODATA;
242
243
0
        *ret = p->captive_portal;
244
0
        return 0;
245
0
}
246
247
0
int sd_ndisc_router_option_rewind(sd_ndisc_router *rt) {
248
0
        assert_return(rt, -EINVAL);
249
250
0
        rt->iterator = ITERATOR_FIRST;
251
0
        return sd_ndisc_router_option_next(rt);
252
0
}
253
254
0
int sd_ndisc_router_option_next(sd_ndisc_router *rt) {
255
0
        assert_return(rt, -EINVAL);
256
257
0
        return set_iterate(rt->options, &rt->iterator, (void**) &rt->current_option);
258
0
}
259
260
0
int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret) {
261
0
        assert_return(rt, -EINVAL);
262
0
        assert_return(ret, -EINVAL);
263
264
0
        if (!rt->current_option)
265
0
                return -ENODATA;
266
267
0
        *ret = rt->current_option->type;
268
0
        return 0;
269
0
}
270
271
0
int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type) {
272
0
        uint8_t t;
273
0
        int r;
274
275
0
        assert_return(rt, -EINVAL);
276
277
0
        r = sd_ndisc_router_option_get_type(rt, &t);
278
0
        if (r < 0)
279
0
                return r;
280
281
0
        return t == type;
282
0
}
283
284
0
int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const uint8_t **ret, size_t *ret_size) {
285
0
        assert_return(rt, -EINVAL);
286
287
0
        if (!rt->current_option)
288
0
                return -ENODATA;
289
290
0
        return ndisc_option_parse(rt->packet, rt->current_option->offset, NULL, ret_size, ret);
291
0
}
292
293
#define DEFINE_GETTER(name, type, element, element_type)                \
294
        int sd_ndisc_router_##name##_get_##element(                     \
295
                        sd_ndisc_router *rt,                            \
296
0
                        element_type *ret) {                            \
297
0
                                                                        \
298
0
                int r;                                                  \
299
0
                                                                        \
300
0
                assert_return(rt, -EINVAL);                             \
301
0
                assert_return(ret, -EINVAL);                            \
302
0
                                                                        \
303
0
                r = sd_ndisc_router_option_is_type(rt, type);           \
304
0
                if (r < 0)                                              \
305
0
                        return r;                                       \
306
0
                if (r == 0)                                             \
307
0
                        return -EMEDIUMTYPE;                            \
308
0
                                                                        \
309
0
                *ret = rt->current_option->name.element;                \
310
0
                return 0;                                               \
311
0
        }
Unexecuted instantiation: sd_ndisc_router_prefix_get_flags
Unexecuted instantiation: sd_ndisc_router_prefix_get_prefixlen
Unexecuted instantiation: sd_ndisc_router_prefix_get_address
Unexecuted instantiation: sd_ndisc_router_prefix_get_valid_lifetime
Unexecuted instantiation: sd_ndisc_router_prefix_get_preferred_lifetime
Unexecuted instantiation: sd_ndisc_router_route_get_preference
Unexecuted instantiation: sd_ndisc_router_route_get_prefixlen
Unexecuted instantiation: sd_ndisc_router_route_get_address
Unexecuted instantiation: sd_ndisc_router_route_get_lifetime
Unexecuted instantiation: sd_ndisc_router_rdnss_get_lifetime
Unexecuted instantiation: sd_ndisc_router_dnssl_get_domains
Unexecuted instantiation: sd_ndisc_router_dnssl_get_lifetime
Unexecuted instantiation: sd_ndisc_router_prefix64_get_prefixlen
Unexecuted instantiation: sd_ndisc_router_prefix64_get_prefix
Unexecuted instantiation: sd_ndisc_router_prefix64_get_lifetime
Unexecuted instantiation: sd_ndisc_router_encrypted_dns_get_lifetime
Unexecuted instantiation: sd_ndisc_router_encrypted_dns_get_resolver
312
313
DEFINE_GETTER(prefix, SD_NDISC_OPTION_PREFIX_INFORMATION, flags, uint8_t);
314
DEFINE_GETTER(prefix, SD_NDISC_OPTION_PREFIX_INFORMATION, prefixlen, uint8_t);
315
DEFINE_GETTER(prefix, SD_NDISC_OPTION_PREFIX_INFORMATION, address, struct in6_addr);
316
DEFINE_GETTER(prefix, SD_NDISC_OPTION_PREFIX_INFORMATION, valid_lifetime, uint64_t);
317
DEFINE_GETTER(prefix, SD_NDISC_OPTION_PREFIX_INFORMATION, preferred_lifetime, uint64_t);
318
319
DEFINE_GETTER(route, SD_NDISC_OPTION_ROUTE_INFORMATION, preference, uint8_t);
320
DEFINE_GETTER(route, SD_NDISC_OPTION_ROUTE_INFORMATION, prefixlen, uint8_t);
321
DEFINE_GETTER(route, SD_NDISC_OPTION_ROUTE_INFORMATION, address, struct in6_addr);
322
DEFINE_GETTER(route, SD_NDISC_OPTION_ROUTE_INFORMATION, lifetime, uint64_t);
323
324
DEFINE_GETTER(rdnss, SD_NDISC_OPTION_RDNSS, lifetime, uint64_t);
325
326
0
int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret) {
327
0
        int r;
328
329
0
        assert_return(rt, -EINVAL);
330
0
        assert_return(ret, -EINVAL);
331
332
0
        r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_RDNSS);
333
0
        if (r < 0)
334
0
                return r;
335
0
        if (r == 0)
336
0
                return -EMEDIUMTYPE;
337
338
0
        *ret = rt->current_option->rdnss.addresses;
339
0
        return (int) rt->current_option->rdnss.n_addresses;
340
0
}
341
342
DEFINE_GETTER(dnssl, SD_NDISC_OPTION_DNSSL, domains, char**);
343
DEFINE_GETTER(dnssl, SD_NDISC_OPTION_DNSSL, lifetime, uint64_t);
344
345
DEFINE_GETTER(prefix64, SD_NDISC_OPTION_PREF64, prefixlen, uint8_t);
346
DEFINE_GETTER(prefix64, SD_NDISC_OPTION_PREF64, prefix, struct in6_addr);
347
DEFINE_GETTER(prefix64, SD_NDISC_OPTION_PREF64, lifetime, uint64_t);
348
349
DEFINE_GETTER(encrypted_dns, SD_NDISC_OPTION_ENCRYPTED_DNS, lifetime, uint64_t);
350
DEFINE_GETTER(encrypted_dns, SD_NDISC_OPTION_ENCRYPTED_DNS, resolver, sd_dns_resolver*);