/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*); |