]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-ndisc-router.c
69fab9f6d0ba937872d7cfc3aa52742c3155a3c7
[thirdparty/systemd.git] / src / libsystemd-network / sd-ndisc-router.c
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 static sd_ndisc_router* ndisc_router_free(sd_ndisc_router *rt) {
18 if (!rt)
19 return NULL;
20
21 icmp6_packet_unref(rt->packet);
22 set_free(rt->options);
23 return mfree(rt);
24 }
25
26 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router, sd_ndisc_router, ndisc_router_free);
27
28 sd_ndisc_router* ndisc_router_new(ICMP6Packet *packet) {
29 sd_ndisc_router *rt;
30
31 assert(packet);
32
33 rt = new(sd_ndisc_router, 1);
34 if (!rt)
35 return NULL;
36
37 *rt = (sd_ndisc_router) {
38 .n_ref = 1,
39 .packet = icmp6_packet_ref(packet),
40 .iterator = ITERATOR_FIRST,
41 };
42
43 return rt;
44 }
45
46 int sd_ndisc_router_set_sender_address(sd_ndisc_router *rt, const struct in6_addr *addr) {
47 assert_return(rt, -EINVAL);
48
49 return icmp6_packet_set_sender_address(rt->packet, addr);
50 }
51
52 int sd_ndisc_router_get_sender_address(sd_ndisc_router *rt, struct in6_addr *ret) {
53 assert_return(rt, -EINVAL);
54
55 return icmp6_packet_get_sender_address(rt->packet, ret);
56 }
57
58 int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret) {
59 assert_return(rt, -EINVAL);
60 assert_return(ret, -EINVAL);
61
62 return icmp6_packet_get_timestamp(rt->packet, clock, ret);
63 }
64
65 #define DEFINE_GET_TIMESTAMP(name) \
66 int sd_ndisc_router_##name##_timestamp( \
67 sd_ndisc_router *rt, \
68 clockid_t clock, \
69 uint64_t *ret) { \
70 \
71 usec_t s, t; \
72 int r; \
73 \
74 assert_return(rt, -EINVAL); \
75 assert_return(ret, -EINVAL); \
76 \
77 r = sd_ndisc_router_##name(rt, &s); \
78 if (r < 0) \
79 return r; \
80 \
81 r = sd_ndisc_router_get_timestamp(rt, clock, &t); \
82 if (r < 0) \
83 return r; \
84 \
85 *ret = time_span_to_stamp(s, t); \
86 return 0; \
87 }
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 int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) {
99 const struct nd_router_advert *a;
100 int r;
101
102 assert(rt);
103 assert(rt->packet);
104
105 if (rt->packet->raw_size < sizeof(struct nd_router_advert))
106 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
107 "Too small to be a router advertisement, ignoring.");
108
109 a = (const struct nd_router_advert*) rt->packet->raw_packet;
110 assert(a->nd_ra_type == ND_ROUTER_ADVERT);
111 assert(a->nd_ra_code == 0);
112
113 rt->hop_limit = a->nd_ra_curhoplimit;
114 rt->flags = a->nd_ra_flags_reserved; /* the first 8 bits */
115 rt->lifetime_usec = be16_sec_to_usec(a->nd_ra_router_lifetime, /* max_as_infinity = */ false);
116 rt->reachable_time_usec = be32_msec_to_usec(a->nd_ra_reachable, /* max_as_infinity = */ false);
117 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 rt->preference = (rt->flags >> 3) & 3;
126 if (rt->preference == SD_NDISC_PREFERENCE_RESERVED)
127 rt->preference = SD_NDISC_PREFERENCE_MEDIUM;
128
129 r = ndisc_parse_options(rt->packet, &rt->options);
130 if (r < 0)
131 return log_ndisc_errno(nd, r, "Failed to parse NDisc options in router advertisement message, ignoring: %m");
132
133 return 0;
134 }
135
136 int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) {
137 assert_return(rt, -EINVAL);
138 assert_return(ret, -EINVAL);
139
140 *ret = rt->hop_limit;
141 return 0;
142 }
143
144 int sd_ndisc_router_get_reachable_time(sd_ndisc_router *rt, uint64_t *ret) {
145 assert_return(rt, -EINVAL);
146 assert_return(ret, -EINVAL);
147
148 *ret = rt->reachable_time_usec;
149 return 0;
150 }
151
152 int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret) {
153 assert_return(rt, -EINVAL);
154 assert_return(ret, -EINVAL);
155
156 *ret = rt->retransmission_time_usec;
157 return 0;
158 }
159
160 int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret) {
161 assert_return(rt, -EINVAL);
162 assert_return(ret, -EINVAL);
163
164 sd_ndisc_option *p = ndisc_option_get_by_type(rt->options, SD_NDISC_OPTION_FLAGS_EXTENSION);
165
166 *ret = rt->flags | (p ? p->extended_flags : 0);
167 return 0;
168 }
169
170 int ndisc_router_flags_to_string(uint64_t flags, char **ret) {
171 _cleanup_free_ char *s = NULL;
172
173 assert(ret);
174
175 if (FLAGS_SET(flags, ND_RA_FLAG_MANAGED) &&
176 !strextend_with_separator(&s, ", ", "managed"))
177 return -ENOMEM;
178
179 if (FLAGS_SET(flags, ND_RA_FLAG_OTHER) &&
180 !strextend_with_separator(&s, ", ", "other"))
181 return -ENOMEM;
182
183 if (FLAGS_SET(flags, ND_RA_FLAG_HOME_AGENT) &&
184 !strextend_with_separator(&s, ", ", "home-agent"))
185 return -ENOMEM;
186
187 *ret = TAKE_PTR(s);
188 return 0;
189 }
190
191 int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret) {
192 assert_return(rt, -EINVAL);
193
194 if (ret)
195 *ret = rt->lifetime_usec;
196
197 return rt->lifetime_usec > 0; /* Indicate if the router is still valid or not. */
198 }
199
200 int sd_ndisc_router_get_preference(sd_ndisc_router *rt, uint8_t *ret) {
201 assert_return(rt, -EINVAL);
202 assert_return(ret, -EINVAL);
203
204 *ret = rt->preference;
205 return 0;
206 }
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 int sd_ndisc_router_get_sender_mac(sd_ndisc_router *rt, struct ether_addr *ret) {
218 assert_return(rt, -EINVAL);
219
220 return ndisc_option_get_mac(rt->options, SD_NDISC_OPTION_SOURCE_LL_ADDRESS, ret);
221 }
222
223 int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret) {
224 assert_return(rt, -EINVAL);
225 assert_return(ret, -EINVAL);
226
227 sd_ndisc_option *p = ndisc_option_get_by_type(rt->options, SD_NDISC_OPTION_MTU);
228 if (!p)
229 return -ENODATA;
230
231 *ret = p->mtu;
232 return 0;
233 }
234
235 int sd_ndisc_router_get_captive_portal(sd_ndisc_router *rt, const char **ret) {
236 assert_return(rt, -EINVAL);
237 assert_return(ret, -EINVAL);
238
239 sd_ndisc_option *p = ndisc_option_get_by_type(rt->options, SD_NDISC_OPTION_CAPTIVE_PORTAL);
240 if (!p)
241 return -ENODATA;
242
243 *ret = p->captive_portal;
244 return 0;
245 }
246
247 int sd_ndisc_router_option_rewind(sd_ndisc_router *rt) {
248 assert_return(rt, -EINVAL);
249
250 rt->iterator = ITERATOR_FIRST;
251 return sd_ndisc_router_option_next(rt);
252 }
253
254 int sd_ndisc_router_option_next(sd_ndisc_router *rt) {
255 assert_return(rt, -EINVAL);
256
257 return set_iterate(rt->options, &rt->iterator, (void**) &rt->current_option);
258 }
259
260 int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret) {
261 assert_return(rt, -EINVAL);
262 assert_return(ret, -EINVAL);
263
264 if (!rt->current_option)
265 return -ENODATA;
266
267 *ret = rt->current_option->type;
268 return 0;
269 }
270
271 int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type) {
272 uint8_t t;
273 int r;
274
275 assert_return(rt, -EINVAL);
276
277 r = sd_ndisc_router_option_get_type(rt, &t);
278 if (r < 0)
279 return r;
280
281 return t == type;
282 }
283
284 int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const uint8_t **ret, size_t *ret_size) {
285 assert_return(rt, -EINVAL);
286
287 if (!rt->current_option)
288 return -ENODATA;
289
290 return ndisc_option_parse(rt->packet, rt->current_option->offset, NULL, ret_size, ret);
291 }
292
293 #define DEFINE_GETTER(name, type, element, element_type) \
294 int sd_ndisc_router_##name##_get_##element( \
295 sd_ndisc_router *rt, \
296 element_type *ret) { \
297 \
298 int r; \
299 \
300 assert_return(rt, -EINVAL); \
301 assert_return(ret, -EINVAL); \
302 \
303 r = sd_ndisc_router_option_is_type(rt, type); \
304 if (r < 0) \
305 return r; \
306 if (r == 0) \
307 return -EMEDIUMTYPE; \
308 \
309 *ret = rt->current_option->name.element; \
310 return 0; \
311 }
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 int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret) {
327 int r;
328
329 assert_return(rt, -EINVAL);
330 assert_return(ret, -EINVAL);
331
332 r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_RDNSS);
333 if (r < 0)
334 return r;
335 if (r == 0)
336 return -EMEDIUMTYPE;
337
338 *ret = rt->current_option->rdnss.addresses;
339 return (int) rt->current_option->rdnss.n_addresses;
340 }
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*);