]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-ndisc-router.c
man: document other keyname options for pam_systemd_loadkey
[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
14 static sd_ndisc_router* ndisc_router_free(sd_ndisc_router *rt) {
15 if (!rt)
16 return NULL;
17
18 icmp6_packet_unref(rt->packet);
19 set_free(rt->options);
20 return mfree(rt);
21 }
22
23 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router, sd_ndisc_router, ndisc_router_free);
24
25 sd_ndisc_router* ndisc_router_new(ICMP6Packet *packet) {
26 sd_ndisc_router *rt;
27
28 assert(packet);
29
30 rt = new(sd_ndisc_router, 1);
31 if (!rt)
32 return NULL;
33
34 *rt = (sd_ndisc_router) {
35 .n_ref = 1,
36 .packet = icmp6_packet_ref(packet),
37 .iterator = ITERATOR_FIRST,
38 };
39
40 return rt;
41 }
42
43 int sd_ndisc_router_set_sender_address(sd_ndisc_router *rt, const struct in6_addr *addr) {
44 assert_return(rt, -EINVAL);
45
46 return icmp6_packet_set_sender_address(rt->packet, addr);
47 }
48
49 int sd_ndisc_router_get_sender_address(sd_ndisc_router *rt, struct in6_addr *ret) {
50 assert_return(rt, -EINVAL);
51
52 return icmp6_packet_get_sender_address(rt->packet, ret);
53 }
54
55 int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret) {
56 assert_return(rt, -EINVAL);
57 assert_return(ret, -EINVAL);
58
59 return icmp6_packet_get_timestamp(rt->packet, clock, ret);
60 }
61
62 #define DEFINE_GET_TIMESTAMP(name) \
63 int sd_ndisc_router_##name##_timestamp( \
64 sd_ndisc_router *rt, \
65 clockid_t clock, \
66 uint64_t *ret) { \
67 \
68 usec_t s, t; \
69 int r; \
70 \
71 assert_return(rt, -EINVAL); \
72 assert_return(ret, -EINVAL); \
73 \
74 r = sd_ndisc_router_##name(rt, &s); \
75 if (r < 0) \
76 return r; \
77 \
78 r = sd_ndisc_router_get_timestamp(rt, clock, &t); \
79 if (r < 0) \
80 return r; \
81 \
82 *ret = time_span_to_stamp(s, t); \
83 return 0; \
84 }
85
86 DEFINE_GET_TIMESTAMP(get_lifetime);
87 DEFINE_GET_TIMESTAMP(prefix_get_valid_lifetime);
88 DEFINE_GET_TIMESTAMP(prefix_get_preferred_lifetime);
89 DEFINE_GET_TIMESTAMP(route_get_lifetime);
90 DEFINE_GET_TIMESTAMP(rdnss_get_lifetime);
91 DEFINE_GET_TIMESTAMP(dnssl_get_lifetime);
92 DEFINE_GET_TIMESTAMP(prefix64_get_lifetime);
93
94 int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) {
95 const struct nd_router_advert *a;
96 int r;
97
98 assert(rt);
99 assert(rt->packet);
100
101 if (rt->packet->raw_size < sizeof(struct nd_router_advert))
102 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
103 "Too small to be a router advertisement, ignoring.");
104
105 a = (const struct nd_router_advert*) rt->packet->raw_packet;
106 assert(a->nd_ra_type == ND_ROUTER_ADVERT);
107 assert(a->nd_ra_code == 0);
108
109 rt->hop_limit = a->nd_ra_curhoplimit;
110 rt->flags = a->nd_ra_flags_reserved; /* the first 8 bits */
111 rt->lifetime_usec = be16_sec_to_usec(a->nd_ra_router_lifetime, /* max_as_infinity = */ false);
112 rt->reachable_time_usec = be32_msec_to_usec(a->nd_ra_reachable, /* mas_as_infinity = */ false);
113 rt->retransmission_time_usec = be32_msec_to_usec(a->nd_ra_retransmit, /* max_as_infinity = */ false);
114
115 /* RFC 4191 section 2.2
116 * Prf (Default Router Preference)
117 * 2-bit signed integer. Indicates whether to prefer this router over other default routers. If the
118 * Router Lifetime is zero, the preference value MUST be set to (00) by the sender and MUST be
119 * ignored by the receiver. If the Reserved (10) value is received, the receiver MUST treat the value
120 * as if it were (00). */
121 rt->preference = (rt->flags >> 3) & 3;
122 if (rt->preference == SD_NDISC_PREFERENCE_RESERVED)
123 rt->preference = SD_NDISC_PREFERENCE_MEDIUM;
124
125 r = ndisc_parse_options(rt->packet, &rt->options);
126 if (r < 0)
127 return log_ndisc_errno(nd, r, "Failed to parse NDisc options in router advertisement message, ignoring: %m");
128
129 return 0;
130 }
131
132 int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) {
133 assert_return(rt, -EINVAL);
134 assert_return(ret, -EINVAL);
135
136 *ret = rt->hop_limit;
137 return 0;
138 }
139
140 int sd_ndisc_router_get_reachable_time(sd_ndisc_router *rt, uint64_t *ret) {
141 assert_return(rt, -EINVAL);
142 assert_return(ret, -EINVAL);
143
144 *ret = rt->reachable_time_usec;
145 return 0;
146 }
147
148 int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret) {
149 assert_return(rt, -EINVAL);
150 assert_return(ret, -EINVAL);
151
152 *ret = rt->retransmission_time_usec;
153 return 0;
154 }
155
156 int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret) {
157 assert_return(rt, -EINVAL);
158 assert_return(ret, -EINVAL);
159
160 sd_ndisc_option *p = ndisc_option_get_by_type(rt->options, SD_NDISC_OPTION_FLAGS_EXTENSION);
161
162 *ret = rt->flags | (p ? p->extended_flags : 0);
163 return 0;
164 }
165
166 int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret) {
167 assert_return(rt, -EINVAL);
168
169 if (ret)
170 *ret = rt->lifetime_usec;
171
172 return rt->lifetime_usec > 0; /* Indicate if the router is still valid or not. */
173 }
174
175 int sd_ndisc_router_get_preference(sd_ndisc_router *rt, uint8_t *ret) {
176 assert_return(rt, -EINVAL);
177 assert_return(ret, -EINVAL);
178
179 *ret = rt->preference;
180 return 0;
181 }
182
183 int sd_ndisc_router_get_sender_mac(sd_ndisc_router *rt, struct ether_addr *ret) {
184 assert_return(rt, -EINVAL);
185
186 return ndisc_option_get_mac(rt->options, SD_NDISC_OPTION_SOURCE_LL_ADDRESS, ret);
187 }
188
189 int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret) {
190 assert_return(rt, -EINVAL);
191 assert_return(ret, -EINVAL);
192
193 sd_ndisc_option *p = ndisc_option_get_by_type(rt->options, SD_NDISC_OPTION_MTU);
194 if (!p)
195 return -ENODATA;
196
197 *ret = p->mtu;
198 return 0;
199 }
200
201 int sd_ndisc_router_get_captive_portal(sd_ndisc_router *rt, const char **ret) {
202 assert_return(rt, -EINVAL);
203 assert_return(ret, -EINVAL);
204
205 sd_ndisc_option *p = ndisc_option_get_by_type(rt->options, SD_NDISC_OPTION_CAPTIVE_PORTAL);
206 if (!p)
207 return -ENODATA;
208
209 *ret = p->captive_portal;
210 return 0;
211 }
212
213 int sd_ndisc_router_option_rewind(sd_ndisc_router *rt) {
214 assert_return(rt, -EINVAL);
215
216 rt->iterator = ITERATOR_FIRST;
217 return sd_ndisc_router_option_next(rt);
218 }
219
220 int sd_ndisc_router_option_next(sd_ndisc_router *rt) {
221 assert_return(rt, -EINVAL);
222
223 return set_iterate(rt->options, &rt->iterator, (void**) &rt->current_option);
224 }
225
226 int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret) {
227 assert_return(rt, -EINVAL);
228 assert_return(ret, -EINVAL);
229
230 if (!rt->current_option)
231 return -ENODATA;
232
233 *ret = rt->current_option->type;
234 return 0;
235 }
236
237 int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type) {
238 uint8_t t;
239 int r;
240
241 assert_return(rt, -EINVAL);
242
243 r = sd_ndisc_router_option_get_type(rt, &t);
244 if (r < 0)
245 return r;
246
247 return t == type;
248 }
249
250 int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const uint8_t **ret, size_t *ret_size) {
251 assert_return(rt, -EINVAL);
252
253 if (!rt->current_option)
254 return -ENODATA;
255
256 return ndisc_option_parse(rt->packet, rt->current_option->offset, NULL, ret_size, ret);
257 }
258
259 #define DEFINE_GETTER(name, type, element, element_type) \
260 int sd_ndisc_router_##name##_get_##element( \
261 sd_ndisc_router *rt, \
262 element_type *ret) { \
263 \
264 int r; \
265 \
266 assert_return(rt, -EINVAL); \
267 assert_return(ret, -EINVAL); \
268 \
269 r = sd_ndisc_router_option_is_type(rt, type); \
270 if (r < 0) \
271 return r; \
272 if (r == 0) \
273 return -EMEDIUMTYPE; \
274 \
275 *ret = rt->current_option->name.element; \
276 return 0; \
277 }
278
279 DEFINE_GETTER(prefix, SD_NDISC_OPTION_PREFIX_INFORMATION, flags, uint8_t);
280 DEFINE_GETTER(prefix, SD_NDISC_OPTION_PREFIX_INFORMATION, prefixlen, uint8_t);
281 DEFINE_GETTER(prefix, SD_NDISC_OPTION_PREFIX_INFORMATION, address, struct in6_addr);
282 DEFINE_GETTER(prefix, SD_NDISC_OPTION_PREFIX_INFORMATION, valid_lifetime, uint64_t);
283 DEFINE_GETTER(prefix, SD_NDISC_OPTION_PREFIX_INFORMATION, preferred_lifetime, uint64_t);
284
285 DEFINE_GETTER(route, SD_NDISC_OPTION_ROUTE_INFORMATION, preference, uint8_t);
286 DEFINE_GETTER(route, SD_NDISC_OPTION_ROUTE_INFORMATION, prefixlen, uint8_t);
287 DEFINE_GETTER(route, SD_NDISC_OPTION_ROUTE_INFORMATION, address, struct in6_addr);
288 DEFINE_GETTER(route, SD_NDISC_OPTION_ROUTE_INFORMATION, lifetime, uint64_t);
289
290 DEFINE_GETTER(rdnss, SD_NDISC_OPTION_RDNSS, lifetime, uint64_t);
291
292 int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret) {
293 int r;
294
295 assert_return(rt, -EINVAL);
296 assert_return(ret, -EINVAL);
297
298 r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_RDNSS);
299 if (r < 0)
300 return r;
301 if (r == 0)
302 return -EMEDIUMTYPE;
303
304 *ret = rt->current_option->rdnss.addresses;
305 return (int) rt->current_option->rdnss.n_addresses;
306 }
307
308 DEFINE_GETTER(dnssl, SD_NDISC_OPTION_DNSSL, domains, char**);
309 DEFINE_GETTER(dnssl, SD_NDISC_OPTION_DNSSL, lifetime, uint64_t);
310
311 DEFINE_GETTER(prefix64, SD_NDISC_OPTION_PREF64, prefixlen, uint8_t);
312 DEFINE_GETTER(prefix64, SD_NDISC_OPTION_PREF64, prefix, struct in6_addr);
313 DEFINE_GETTER(prefix64, SD_NDISC_OPTION_PREF64, lifetime, uint64_t);