]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-radv.c
sd-radv: Implement Router Advertisement timeout handling
[thirdparty/systemd.git] / src / libsystemd-network / sd-radv.c
1 /***
2 This file is part of systemd.
3
4 Copyright (C) 2017 Intel Corporation. All rights reserved.
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <netinet/icmp6.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23
24 #include "sd-radv.h"
25
26 #include "macro.h"
27 #include "alloc-util.h"
28 #include "fd-util.h"
29 #include "icmp6-util.h"
30 #include "in-addr-util.h"
31 #include "radv-internal.h"
32 #include "socket-util.h"
33 #include "string-util.h"
34 #include "util.h"
35 #include "random-util.h"
36
37 _public_ int sd_radv_new(sd_radv **ret) {
38 _cleanup_(sd_radv_unrefp) sd_radv *ra = NULL;
39
40 assert_return(ret, -EINVAL);
41
42 ra = new0(sd_radv, 1);
43 if (!ra)
44 return -ENOMEM;
45
46 ra->n_ref = 1;
47
48 LIST_HEAD_INIT(ra->prefixes);
49
50 *ret = ra;
51 ra = NULL;
52
53 return 0;
54 }
55
56 _public_ int sd_radv_attach_event(sd_radv *ra, sd_event *event, int64_t priority) {
57 int r;
58
59 assert_return(ra, -EINVAL);
60 assert_return(!ra->event, -EBUSY);
61
62 if (event)
63 ra->event = sd_event_ref(event);
64 else {
65 r = sd_event_default(&ra->event);
66 if (r < 0)
67 return 0;
68 }
69
70 ra->event_priority = priority;
71
72 return 0;
73 }
74
75 _public_ int sd_radv_detach_event(sd_radv *ra) {
76
77 assert_return(ra, -EINVAL);
78
79 ra->event = sd_event_unref(ra->event);
80 return 0;
81 }
82
83 _public_ sd_event *sd_radv_get_event(sd_radv *ra) {
84 assert_return(ra, NULL);
85
86 return ra->event;
87 }
88
89 static void radv_reset(sd_radv *ra) {
90
91 ra->timeout_event_source =
92 sd_event_source_unref(ra->timeout_event_source);
93
94 ra->ra_sent = 0;
95 }
96
97 _public_ sd_radv *sd_radv_ref(sd_radv *ra) {
98 if (!ra)
99 return NULL;
100
101 assert(ra->n_ref > 0);
102 ra->n_ref++;
103
104 return ra;
105 }
106
107 _public_ sd_radv *sd_radv_unref(sd_radv *ra) {
108 if (!ra)
109 return NULL;
110
111 assert(ra->n_ref > 0);
112 ra->n_ref--;
113
114 if (ra->n_ref > 0)
115 return NULL;
116
117 while (ra->prefixes) {
118 sd_radv_prefix *p = ra->prefixes;
119
120 LIST_REMOVE(prefix, ra->prefixes, p);
121 sd_radv_prefix_unref(p);
122 }
123
124 radv_reset(ra);
125
126 sd_radv_detach_event(ra);
127 return mfree(ra);
128 }
129
130 static int radv_send(sd_radv *ra, const struct in6_addr *dst,
131 const uint32_t router_lifetime) {
132
133 return -ENOSYS;
134 }
135
136 static usec_t radv_compute_timeout(usec_t min, usec_t max) {
137 assert_return(min <= max, SD_RADV_DEFAULT_MIN_TIMEOUT_USEC);
138
139 return min + (random_u32() % (max - min));
140 }
141
142 static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
143 int r;
144 sd_radv *ra = userdata;
145 usec_t min_timeout = SD_RADV_DEFAULT_MIN_TIMEOUT_USEC;
146 usec_t max_timeout = SD_RADV_DEFAULT_MAX_TIMEOUT_USEC;
147 usec_t time_now, timeout;
148 char time_string[FORMAT_TIMESPAN_MAX];
149
150 assert(s);
151 assert(ra);
152 assert(ra->event);
153
154 ra->timeout_event_source = sd_event_source_unref(ra->timeout_event_source);
155
156 r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
157 if (r < 0)
158 goto fail;
159
160 r = radv_send(ra, NULL, ra->lifetime);
161 if (r < 0)
162 log_radv_warning_errno(r, "Unable to send Router Advertisement: %m");
163
164 /* RFC 4861, Section 6.2.4, sending initial Router Advertisements */
165 if (ra->ra_sent < SD_RADV_MAX_INITIAL_RTR_ADVERTISEMENTS) {
166 max_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC;
167 min_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC / 3;
168 }
169
170 timeout = radv_compute_timeout(min_timeout, max_timeout);
171
172 log_radv("Next Router Advertisement in %s",
173 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
174 timeout, USEC_PER_SEC));
175
176 r = sd_event_add_time(ra->event, &ra->timeout_event_source,
177 clock_boottime_or_monotonic(),
178 time_now + timeout, MSEC_PER_SEC,
179 radv_timeout, ra);
180 if (r < 0)
181 goto fail;
182
183 r = sd_event_source_set_priority(ra->timeout_event_source,
184 ra->event_priority);
185 if (r < 0)
186 goto fail;
187
188 r = sd_event_source_set_description(ra->timeout_event_source,
189 "radv-timeout");
190 if (r < 0)
191 goto fail;
192
193 ra->ra_sent++;
194
195 fail:
196 if (r < 0)
197 sd_radv_stop(ra);
198
199 return 0;
200 }
201
202 _public_ int sd_radv_stop(sd_radv *ra) {
203 int r;
204
205 assert_return(ra, -EINVAL);
206
207 log_radv("Stopping IPv6 Router Advertisement daemon");
208
209 /* RFC 4861, Section 6.2.5, send at least one Router Advertisement
210 with zero lifetime */
211 r = radv_send(ra, NULL, 0);
212 if (r < 0)
213 log_radv_warning_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
214
215 radv_reset(ra);
216 ra->state = SD_RADV_STATE_IDLE;
217
218 return 0;
219 }
220
221 _public_ int sd_radv_start(sd_radv *ra) {
222 int r = 0;
223
224 assert_return(ra, -EINVAL);
225 assert_return(ra->event, -EINVAL);
226 assert_return(ra->ifindex > 0, -EINVAL);
227
228 if (ra->state != SD_RADV_STATE_IDLE)
229 return 0;
230
231 r = sd_event_add_time(ra->event, &ra->timeout_event_source,
232 clock_boottime_or_monotonic(), 0, 0,
233 radv_timeout, ra);
234 if (r < 0)
235 goto fail;
236
237 r = sd_event_source_set_priority(ra->timeout_event_source,
238 ra->event_priority);
239 if (r < 0)
240 goto fail;
241
242 (void) sd_event_source_set_description(ra->timeout_event_source,
243 "radv-timeout");
244
245 ra->state = SD_RADV_STATE_ADVERTISING;
246
247 log_radv("Started IPv6 Router Advertisement daemon");
248
249 return 0;
250
251 fail:
252 radv_reset(ra);
253
254 return r;
255 }
256
257 _public_ int sd_radv_set_ifindex(sd_radv *ra, int ifindex) {
258 assert_return(ra, -EINVAL);
259 assert_return(ifindex >= -1, -EINVAL);
260
261 if (ra->state != SD_RADV_STATE_IDLE)
262 return -EBUSY;
263
264 ra->ifindex = ifindex;
265
266 return 0;
267 }
268
269 _public_ int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
270 assert_return(ra, -EINVAL);
271
272 if (ra->state != SD_RADV_STATE_IDLE)
273 return -EBUSY;
274
275 if (mac_addr)
276 ra->mac_addr = *mac_addr;
277 else
278 zero(ra->mac_addr);
279
280 return 0;
281 }
282
283 _public_ int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
284 assert_return(ra, -EINVAL);
285 assert_return(mtu >= 1280, -EINVAL);
286
287 if (ra->state != SD_RADV_STATE_IDLE)
288 return -EBUSY;
289
290 ra->mtu = mtu;
291
292 return 0;
293 }
294
295 _public_ int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) {
296 assert_return(ra, -EINVAL);
297
298 if (ra->state != SD_RADV_STATE_IDLE)
299 return -EBUSY;
300
301 ra->hop_limit = hop_limit;
302
303 return 0;
304 }
305
306 _public_ int sd_radv_set_router_lifetime(sd_radv *ra, uint32_t router_lifetime) {
307 assert_return(ra, -EINVAL);
308
309 if (ra->state != SD_RADV_STATE_IDLE)
310 return -EBUSY;
311
312 /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the
313 preference value MUST be set to (00) by the sender..." */
314 if (router_lifetime == 0 &&
315 (ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
316 return -ETIME;
317
318 ra->lifetime = router_lifetime;
319
320 return 0;
321 }
322
323 _public_ int sd_radv_set_managed_information(sd_radv *ra, int managed) {
324 assert_return(ra, -EINVAL);
325
326 if (ra->state != SD_RADV_STATE_IDLE)
327 return -EBUSY;
328
329 SET_FLAG(ra->flags, ND_RA_FLAG_MANAGED, managed);
330
331 return 0;
332 }
333
334 _public_ int sd_radv_set_other_information(sd_radv *ra, int other) {
335 assert_return(ra, -EINVAL);
336
337 if (ra->state != SD_RADV_STATE_IDLE)
338 return -EBUSY;
339
340 SET_FLAG(ra->flags, ND_RA_FLAG_OTHER, other);
341
342 return 0;
343 }
344
345 _public_ int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
346 int r = 0;
347
348 assert_return(ra, -EINVAL);
349 assert_return(IN_SET(preference,
350 SD_NDISC_PREFERENCE_LOW,
351 SD_NDISC_PREFERENCE_MEDIUM,
352 SD_NDISC_PREFERENCE_HIGH), -EINVAL);
353
354 ra->flags = (ra->flags & ~(0x3 << 3)) | (preference << 3);
355
356 return r;
357 }
358
359 _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
360 sd_radv_prefix *cur;
361 _cleanup_free_ char *addr_p = NULL;
362
363 assert_return(ra, -EINVAL);
364
365 if (!p)
366 return -EINVAL;
367
368 LIST_FOREACH(prefix, cur, ra->prefixes) {
369 int r;
370
371 r = in_addr_prefix_intersect(AF_INET6,
372 (union in_addr_union*) &cur->opt.in6_addr,
373 cur->opt.prefixlen,
374 (union in_addr_union*) &p->opt.in6_addr,
375 p->opt.prefixlen);
376 if (r > 0) {
377 _cleanup_free_ char *addr_cur = NULL;
378
379 (void) in_addr_to_string(AF_INET6,
380 (union in_addr_union*) &cur->opt.in6_addr,
381 &addr_cur);
382 (void) in_addr_to_string(AF_INET6,
383 (union in_addr_union*) &p->opt.in6_addr,
384 &addr_p);
385
386 log_radv("IPv6 prefix %s/%u already configured, ignoring %s/%u",
387 addr_cur, cur->opt.prefixlen,
388 addr_p, p->opt.prefixlen);
389
390 return -EEXIST;
391 }
392 }
393
394 p = sd_radv_prefix_ref(p);
395
396 LIST_APPEND(prefix, ra->prefixes, p);
397
398 ra->n_prefixes++;
399
400 (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &p->opt.in6_addr, &addr_p);
401 log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
402
403 return 0;
404 }
405
406 _public_ int sd_radv_prefix_new(sd_radv_prefix **ret) {
407 _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
408
409 assert_return(ret, -EINVAL);
410
411 p = new0(sd_radv_prefix, 1);
412 if (!p)
413 return -ENOMEM;
414
415 p->n_ref = 1;
416
417 p->opt.type = ND_OPT_PREFIX_INFORMATION;
418 p->opt.length = (sizeof(p->opt) - 1) /8 + 1;
419
420 p->opt.prefixlen = 64;
421
422 /* RFC 4861, Section 6.2.1 */
423 SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, true);
424 SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, true);
425 p->opt.preferred_lifetime = htobe32(604800);
426 p->opt.valid_lifetime = htobe32(2592000);
427
428 LIST_INIT(prefix, p);
429
430 *ret = p;
431 p = NULL;
432
433 return 0;
434 }
435
436 _public_ sd_radv_prefix *sd_radv_prefix_ref(sd_radv_prefix *p) {
437 if (!p)
438 return NULL;
439
440 assert(p->n_ref > 0);
441 p->n_ref++;
442
443 return p;
444 }
445
446 _public_ sd_radv_prefix *sd_radv_prefix_unref(sd_radv_prefix *p) {
447 if (!p)
448 return NULL;
449
450 assert(p->n_ref > 0);
451 p->n_ref--;
452
453 if (p->n_ref > 0)
454 return NULL;
455
456 return mfree(p);
457 }
458
459 _public_ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, struct in6_addr *in6_addr,
460 unsigned char prefixlen) {
461 assert_return(p, -EINVAL);
462 assert_return(in6_addr, -EINVAL);
463
464 if (prefixlen < 3 || prefixlen > 128)
465 return -EINVAL;
466
467 if (prefixlen > 64)
468 /* unusual but allowed, log it */
469 log_radv("Unusual prefix length %d greater than 64", prefixlen);
470
471 p->opt.in6_addr = *in6_addr;
472 p->opt.prefixlen = prefixlen;
473
474 return 0;
475 }
476
477 _public_ int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) {
478 assert_return(p, -EINVAL);
479
480 SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, onlink);
481
482 return 0;
483 }
484
485 _public_ int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p,
486 int address_autoconfiguration) {
487 assert_return(p, -EINVAL);
488
489 SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, address_autoconfiguration);
490
491 return 0;
492 }
493
494 _public_ int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix *p,
495 uint32_t valid_lifetime) {
496 assert_return(p, -EINVAL);
497
498 p->opt.valid_lifetime = htobe32(valid_lifetime);
499
500 return 0;
501 }
502
503 _public_ int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix *p,
504 uint32_t preferred_lifetime) {
505 assert_return(p, -EINVAL);
506
507 p->opt.preferred_lifetime = htobe32(preferred_lifetime);
508
509 return 0;
510 }