1 /* $OpenBSD: engine.c,v 1.99 2024/11/21 13:35:20 claudio Exp $ */
2
3 /*
4 * Copyright (c) 2017 Florian Obser <florian@openbsd.org>
5 * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22 /*
23 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
24 * All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. Neither the name of the project nor the names of its contributors
35 * may be used to endorse or promote products derived from this software
36 * without specific prior written permission.
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 */
50
51 #include <sys/types.h>
52 #include <sys/queue.h>
53 #include <sys/socket.h>
54 #include <sys/syslog.h>
55 #include <sys/uio.h>
56
57 #include <net/if.h>
58 #include <net/route.h>
59 #include <arpa/inet.h>
60 #include <netinet/in.h>
61 #include <netinet/if_ether.h>
62 #include <netinet/ip6.h>
63 #include <netinet6/nd6.h>
64 #include <netinet/icmp6.h>
65
66 #include <crypto/sha2.h>
67
68 #include <errno.h>
69 #include <event.h>
70 #include <imsg.h>
71 #include <pwd.h>
72 #include <signal.h>
73 #include <stddef.h>
74 #include <stdlib.h>
75 #include <string.h>
76 #include <time.h>
77 #include <unistd.h>
78
79 #include "log.h"
80 #include "slaacd.h"
81 #include "engine.h"
82
83 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
84
85 #define MAX_RTR_SOLICITATION_DELAY 1
86 #define MAX_RTR_SOLICITATION_DELAY_USEC MAX_RTR_SOLICITATION_DELAY * 1000000
87 #define RTR_SOLICITATION_INTERVAL 4
88 #define MAX_RTR_SOLICITATIONS 3
89
90 /*
91 * Constants for RFC 8981 temporary address extensions
92 *
93 * PRIV_PREFERRED_LIFETIME > (PRIV_MAX_DESYNC_FACTOR + PRIV_REGEN_ADVANCE)
94 */
95 #define PRIV_VALID_LIFETIME 172800 /* 2 days */
96 #define PRIV_PREFERRED_LIFETIME 86400 /* 1 day */
97 #define PRIV_MAX_DESYNC_FACTOR 34560 /* PRIV_PREFERRED_LIFETIME * 0.4 */
98 #define PRIV_REGEN_ADVANCE 5 /* 5 seconds */
99
100 enum if_state {
101 IF_DOWN,
102 IF_INIT,
103 IF_BOUND,
104 };
105
106 enum proposal_state {
107 PROPOSAL_IF_DOWN,
108 PROPOSAL_NOT_CONFIGURED,
109 PROPOSAL_CONFIGURED,
110 PROPOSAL_NEARLY_EXPIRED,
111 PROPOSAL_WITHDRAWN,
112 PROPOSAL_DUPLICATED,
113 PROPOSAL_STALE,
114 };
115
116 const char* rpref_name[] = {
117 "Low",
118 "Medium",
119 "High",
120 };
121
122 struct radv_prefix {
123 LIST_ENTRY(radv_prefix) entries;
124 struct in6_addr prefix;
125 uint8_t prefix_len; /*XXX int */
126 int onlink;
127 int autonomous;
128 uint32_t vltime;
129 uint32_t pltime;
130 int dad_counter;
131 };
132
133 struct radv_rdns {
134 LIST_ENTRY(radv_rdns) entries;
135 struct in6_addr rdns;
136 };
137
138 struct radv {
139 LIST_ENTRY(radv) entries;
140 struct sockaddr_in6 from;
141 struct timespec when;
142 struct timespec uptime;
143 struct event timer;
144 uint32_t min_lifetime;
145 uint8_t curhoplimit;
146 int managed;
147 int other;
148 enum rpref rpref;
149 uint16_t router_lifetime; /* in seconds */
150 uint32_t reachable_time; /* in milliseconds */
151 uint32_t retrans_time; /* in milliseconds */
152 LIST_HEAD(, radv_prefix) prefixes;
153 uint32_t rdns_lifetime;
154 LIST_HEAD(, radv_rdns) rdns_servers;
155 uint32_t mtu;
156 };
157
158 struct address_proposal {
159 LIST_ENTRY(address_proposal) entries;
160 struct event timer;
161 int64_t id;
162 enum proposal_state state;
163 struct timeval timo;
164 struct timespec created;
165 struct timespec when;
166 struct timespec uptime;
167 uint32_t if_index;
168 struct ether_addr hw_address;
169 struct sockaddr_in6 from;
170 struct sockaddr_in6 addr;
171 struct in6_addr mask;
172 struct in6_addr prefix;
173 int temporary;
174 uint8_t prefix_len;
175 uint32_t vltime;
176 uint32_t pltime;
177 uint32_t desync_factor;
178 uint8_t soiikey[SLAACD_SOIIKEY_LEN];
179 uint32_t mtu;
180 };
181
182 struct dfr_proposal {
183 LIST_ENTRY(dfr_proposal) entries;
184 struct event timer;
185 int64_t id;
186 enum proposal_state state;
187 struct timeval timo;
188 struct timespec when;
189 struct timespec uptime;
190 uint32_t if_index;
191 int rdomain;
192 struct sockaddr_in6 addr;
193 uint32_t router_lifetime;
194 enum rpref rpref;
195 };
196
197 struct rdns_proposal {
198 LIST_ENTRY(rdns_proposal) entries;
199 struct event timer;
200 int64_t id;
201 enum proposal_state state;
202 struct timeval timo;
203 struct timespec when;
204 struct timespec uptime;
205 uint32_t if_index;
206 int rdomain;
207 struct sockaddr_in6 from;
208 int rdns_count;
209 struct in6_addr rdns[MAX_RDNS_COUNT];
210 uint32_t rdns_lifetime;
211 };
212
213 struct slaacd_iface {
214 LIST_ENTRY(slaacd_iface) entries;
215 enum if_state state;
216 struct event timer;
217 struct timeval timo;
218 struct timespec last_sol;
219 int probes;
220 uint32_t if_index;
221 uint32_t rdomain;
222 int running;
223 int autoconf;
224 int temporary;
225 int soii;
226 struct ether_addr hw_address;
227 struct sockaddr_in6 ll_address;
228 uint8_t soiikey[SLAACD_SOIIKEY_LEN];
229 int link_state;
230 uint32_t cur_mtu;
231 LIST_HEAD(, radv) radvs;
232 LIST_HEAD(, address_proposal) addr_proposals;
233 LIST_HEAD(, dfr_proposal) dfr_proposals;
234 LIST_HEAD(, rdns_proposal) rdns_proposals;
235 };
236
237 LIST_HEAD(, slaacd_iface) slaacd_interfaces;
238
239 __dead void engine_shutdown(void);
240 void engine_sig_handler(int sig, short, void *);
241 void engine_dispatch_frontend(int, short, void *);
242 void engine_dispatch_main(int, short, void *);
243 #ifndef SMALL
244 void send_interface_info(struct slaacd_iface *, pid_t);
245 void engine_showinfo_ctl(pid_t, uint32_t);
246 void debug_log_ra(struct imsg_ra *);
247 int in6_mask2prefixlen(struct in6_addr *);
248 #endif /* SMALL */
249 struct slaacd_iface *get_slaacd_iface_by_id(uint32_t);
250 void remove_slaacd_iface(uint32_t);
251 void free_ra(struct radv *);
252 void iface_state_transition(struct slaacd_iface *, enum
253 if_state);
254 void addr_proposal_state_transition(struct
255 address_proposal *, enum proposal_state);
256 void dfr_proposal_state_transition(struct dfr_proposal *,
257 enum proposal_state);
258 void rdns_proposal_state_transition(struct rdns_proposal *,
259 enum proposal_state);
260 void engine_update_iface(struct imsg_ifinfo *);
261 void request_solicitation(struct slaacd_iface *);
262 void parse_ra(struct slaacd_iface *, struct imsg_ra *);
263 void gen_addr(struct slaacd_iface *, struct radv_prefix *,
264 struct address_proposal *, int);
265 void gen_address_proposal(struct slaacd_iface *, struct
266 radv *, struct radv_prefix *, int);
267 void free_address_proposal(struct address_proposal *);
268 void withdraw_addr(struct address_proposal *);
269 void configure_address(struct address_proposal *);
270 void in6_prefixlen2mask(struct in6_addr *, int len);
271 void gen_dfr_proposal(struct slaacd_iface *, struct
272 radv *);
273 void configure_dfr(struct dfr_proposal *);
274 void free_dfr_proposal(struct dfr_proposal *);
275 void withdraw_dfr(struct dfr_proposal *);
276 void update_iface_ra_rdns(struct slaacd_iface *,
277 struct radv *);
278 void gen_rdns_proposal(struct slaacd_iface *, struct
279 radv *);
280 void free_rdns_proposal(struct rdns_proposal *);
281 void withdraw_rdns(struct rdns_proposal *);
282 void compose_rdns_proposal(uint32_t, int);
283 void update_iface_ra(struct slaacd_iface *, struct radv *);
284 void update_iface_ra_dfr(struct slaacd_iface *,
285 struct radv *);
286 void update_iface_ra_prefix(struct slaacd_iface *,
287 struct radv *, struct radv_prefix *prefix);
288 void address_proposal_timeout(int, short, void *);
289 void dfr_proposal_timeout(int, short, void *);
290 void rdns_proposal_timeout(int, short, void *);
291 void iface_timeout(int, short, void *);
292 struct radv *find_ra(struct slaacd_iface *, struct sockaddr_in6 *);
293 struct address_proposal *find_address_proposal_by_addr(struct slaacd_iface *,
294 struct sockaddr_in6 *);
295 struct dfr_proposal *find_dfr_proposal_by_gw(struct slaacd_iface *,
296 struct sockaddr_in6 *);
297 struct rdns_proposal *find_rdns_proposal_by_gw(struct slaacd_iface *,
298 struct sockaddr_in6 *);
299 struct radv_prefix *find_prefix(struct radv *, struct in6_addr *, uint8_t);
300 int engine_imsg_compose_main(int, pid_t, void *, uint16_t);
301 uint32_t real_lifetime(struct timespec *, uint32_t);
302 void merge_dad_couters(struct radv *, struct radv *);
303
304 static struct imsgev *iev_frontend;
305 static struct imsgev *iev_main;
306 int64_t proposal_id;
307
308
309 #define CASE(x) case x : return #x
310
311 #ifndef SMALL
312 static const char*
if_state_name(enum if_state ifs)313 if_state_name(enum if_state ifs)
314 {
315 switch (ifs) {
316 CASE(IF_DOWN);
317 CASE(IF_INIT);
318 CASE(IF_BOUND);
319 }
320 }
321
322 static const char*
proposal_state_name(enum proposal_state ps)323 proposal_state_name(enum proposal_state ps)
324 {
325 switch (ps) {
326 CASE(PROPOSAL_IF_DOWN);
327 CASE(PROPOSAL_NOT_CONFIGURED);
328 CASE(PROPOSAL_CONFIGURED);
329 CASE(PROPOSAL_NEARLY_EXPIRED);
330 CASE(PROPOSAL_WITHDRAWN);
331 CASE(PROPOSAL_DUPLICATED);
332 CASE(PROPOSAL_STALE);
333 }
334 }
335 #endif
336
337 void
engine_sig_handler(int sig,short event,void * arg)338 engine_sig_handler(int sig, short event, void *arg)
339 {
340 /*
341 * Normal signal handler rules don't apply because libevent
342 * decouples for us.
343 */
344
345 switch (sig) {
346 case SIGINT:
347 case SIGTERM:
348 engine_shutdown();
349 default:
350 fatalx("unexpected signal");
351 }
352 }
353
354 void
engine(int debug,int verbose)355 engine(int debug, int verbose)
356 {
357 struct event ev_sigint, ev_sigterm;
358 struct passwd *pw;
359
360 log_init(debug, LOG_DAEMON);
361 log_setverbose(verbose);
362
363 if ((pw = getpwnam(SLAACD_USER)) == NULL)
364 fatal("getpwnam");
365
366 if (chdir("/") == -1)
367 fatal("chdir(\"/\")");
368
369 if (unveil("/", "") == -1)
370 fatal("unveil /");
371 if (unveil(NULL, NULL) == -1)
372 fatal("unveil");
373
374 setproctitle("%s", "engine");
375 log_procinit("engine");
376
377 if (setgroups(1, &pw->pw_gid) ||
378 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
379 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
380 fatal("can't drop privileges");
381
382 if (pledge("stdio recvfd", NULL) == -1)
383 fatal("pledge");
384
385 event_init();
386
387 /* Setup signal handler(s). */
388 signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL);
389 signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL);
390 signal_add(&ev_sigint, NULL);
391 signal_add(&ev_sigterm, NULL);
392 signal(SIGPIPE, SIG_IGN);
393 signal(SIGHUP, SIG_IGN);
394
395 /* Setup pipe and event handler to the main process. */
396 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
397 fatal(NULL);
398
399 if (imsgbuf_init(&iev_main->ibuf, 3) == -1)
400 fatal(NULL);
401 imsgbuf_allow_fdpass(&iev_main->ibuf);
402 iev_main->handler = engine_dispatch_main;
403
404 /* Setup event handlers. */
405 iev_main->events = EV_READ;
406 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
407 iev_main->handler, iev_main);
408 event_add(&iev_main->ev, NULL);
409
410 LIST_INIT(&slaacd_interfaces);
411
412 event_dispatch();
413
414 engine_shutdown();
415 }
416
417 __dead void
engine_shutdown(void)418 engine_shutdown(void)
419 {
420 /* Close pipes. */
421 imsgbuf_clear(&iev_frontend->ibuf);
422 close(iev_frontend->ibuf.fd);
423 imsgbuf_clear(&iev_main->ibuf);
424 close(iev_main->ibuf.fd);
425
426 free(iev_frontend);
427 free(iev_main);
428
429 log_info("engine exiting");
430 exit(0);
431 }
432
433 int
engine_imsg_compose_frontend(int type,pid_t pid,void * data,uint16_t datalen)434 engine_imsg_compose_frontend(int type, pid_t pid, void *data,
435 uint16_t datalen)
436 {
437 return (imsg_compose_event(iev_frontend, type, 0, pid, -1,
438 data, datalen));
439 }
440
441 int
engine_imsg_compose_main(int type,pid_t pid,void * data,uint16_t datalen)442 engine_imsg_compose_main(int type, pid_t pid, void *data,
443 uint16_t datalen)
444 {
445 return (imsg_compose_event(iev_main, type, 0, pid, -1,
446 data, datalen));
447 }
448
449 void
engine_dispatch_frontend(int fd,short event,void * bula)450 engine_dispatch_frontend(int fd, short event, void *bula)
451 {
452 struct imsgev *iev = bula;
453 struct imsgbuf *ibuf = &iev->ibuf;
454 struct imsg imsg;
455 struct slaacd_iface *iface;
456 struct imsg_ra ra;
457 struct address_proposal *addr_proposal = NULL;
458 struct dfr_proposal *dfr_proposal = NULL;
459 struct imsg_del_addr del_addr;
460 struct imsg_del_route del_route;
461 struct imsg_dup_addr dup_addr;
462 ssize_t n;
463 int shut = 0;
464 #ifndef SMALL
465 int verbose;
466 #endif /* SMALL */
467 uint32_t if_index, type;
468
469 if (event & EV_READ) {
470 if ((n = imsgbuf_read(ibuf)) == -1)
471 fatal("imsgbuf_read error");
472 if (n == 0) /* Connection closed. */
473 shut = 1;
474 }
475 if (event & EV_WRITE) {
476 if (imsgbuf_write(ibuf) == -1) {
477 if (errno == EPIPE) /* Connection closed. */
478 shut = 1;
479 else
480 fatal("imsgbuf_write");
481 }
482 }
483
484 for (;;) {
485 if ((n = imsg_get(ibuf, &imsg)) == -1)
486 fatal("%s: imsg_get error", __func__);
487 if (n == 0) /* No more messages. */
488 break;
489
490 type = imsg_get_type(&imsg);
491
492 switch (type) {
493 #ifndef SMALL
494 case IMSG_CTL_LOG_VERBOSE:
495 if (imsg_get_data(&imsg, &verbose,
496 sizeof(verbose)) == -1)
497 fatalx("%s: invalid %s", __func__, i2s(type));
498
499 log_setverbose(verbose);
500 break;
501 case IMSG_CTL_SHOW_INTERFACE_INFO:
502 if (imsg_get_data(&imsg, &if_index,
503 sizeof(if_index)) == -1)
504 fatalx("%s: invalid %s", __func__, i2s(type));
505
506 engine_showinfo_ctl(imsg_get_pid(&imsg), if_index);
507 break;
508 #endif /* SMALL */
509 case IMSG_REMOVE_IF:
510 if (imsg_get_data(&imsg, &if_index,
511 sizeof(if_index)) == -1)
512 fatalx("%s: invalid %s", __func__, i2s(type));
513
514 remove_slaacd_iface(if_index);
515 break;
516 case IMSG_RA:
517 if (imsg_get_data(&imsg, &ra, sizeof(ra)) == -1)
518 fatalx("%s: invalid %s", __func__, i2s(type));
519
520 iface = get_slaacd_iface_by_id(ra.if_index);
521
522 /*
523 * Ignore unsolicitated router advertisements
524 * if we think the interface is still down.
525 * Otherwise we confuse the state machine.
526 */
527 if (iface != NULL && iface->state != IF_DOWN)
528 parse_ra(iface, &ra);
529 break;
530 case IMSG_CTL_SEND_SOLICITATION:
531 if (imsg_get_data(&imsg, &if_index,
532 sizeof(if_index)) == -1)
533 fatalx("%s: invalid %s", __func__, i2s(type));
534
535 iface = get_slaacd_iface_by_id(if_index);
536 if (iface == NULL)
537 log_warnx("requested to send solicitation on "
538 "non-autoconf interface: %u", if_index);
539 else {
540 iface->last_sol.tv_sec = 0; /* no rate limit */
541 request_solicitation(iface);
542 }
543 break;
544 case IMSG_DEL_ADDRESS:
545 if (imsg_get_data(&imsg, &del_addr,
546 sizeof(del_addr)) == -1)
547 fatalx("%s: invalid %s", __func__, i2s(type));
548
549 iface = get_slaacd_iface_by_id(del_addr.if_index);
550 if (iface == NULL) {
551 log_debug("IMSG_DEL_ADDRESS: unknown interface"
552 ", ignoring");
553 break;
554 }
555
556 addr_proposal = find_address_proposal_by_addr(iface,
557 &del_addr.addr);
558 /*
559 * If it's in state PROPOSAL_WITHDRAWN we just
560 * deleted it ourself but want to keep it around
561 * so we can renew it
562 */
563 if (addr_proposal && addr_proposal->state !=
564 PROPOSAL_WITHDRAWN)
565 free_address_proposal(addr_proposal);
566 break;
567 case IMSG_DEL_ROUTE:
568 if (imsg_get_data(&imsg, &del_route,
569 sizeof(del_route)) == -1)
570 fatalx("%s: invalid %s", __func__, i2s(type));
571
572 iface = get_slaacd_iface_by_id(del_route.if_index);
573 if (iface == NULL) {
574 log_debug("IMSG_DEL_ROUTE: unknown interface"
575 ", ignoring");
576 break;
577 }
578
579 dfr_proposal = find_dfr_proposal_by_gw(iface,
580 &del_route.gw);
581
582 if (dfr_proposal) {
583 dfr_proposal->state = PROPOSAL_WITHDRAWN;
584 free_dfr_proposal(dfr_proposal);
585 }
586 break;
587 case IMSG_DUP_ADDRESS:
588 if (imsg_get_data(&imsg, &dup_addr,
589 sizeof(dup_addr)) == -1)
590 fatalx("%s: invalid %s", __func__, i2s(type));
591
592 iface = get_slaacd_iface_by_id(dup_addr.if_index);
593 if (iface == NULL) {
594 log_debug("IMSG_DUP_ADDRESS: unknown interface"
595 ", ignoring");
596 break;
597 }
598
599 addr_proposal = find_address_proposal_by_addr(iface,
600 &dup_addr.addr);
601
602 if (addr_proposal)
603 addr_proposal_state_transition(addr_proposal,
604 PROPOSAL_DUPLICATED);
605 break;
606 case IMSG_REPROPOSE_RDNS:
607 LIST_FOREACH (iface, &slaacd_interfaces, entries)
608 compose_rdns_proposal(iface->if_index,
609 iface->rdomain);
610 break;
611 default:
612 log_debug("%s: unexpected imsg %d", __func__, type);
613 break;
614 }
615 imsg_free(&imsg);
616 }
617 if (!shut)
618 imsg_event_add(iev);
619 else {
620 /* This pipe is dead. Remove its event handler. */
621 event_del(&iev->ev);
622 event_loopexit(NULL);
623 }
624 }
625
626 void
engine_dispatch_main(int fd,short event,void * bula)627 engine_dispatch_main(int fd, short event, void *bula)
628 {
629 struct imsg imsg;
630 struct imsgev *iev = bula;
631 struct imsgbuf *ibuf = &iev->ibuf;
632 struct imsg_ifinfo imsg_ifinfo;
633 ssize_t n;
634 uint32_t type;
635 int shut = 0;
636
637 if (event & EV_READ) {
638 if ((n = imsgbuf_read(ibuf)) == -1)
639 fatal("imsgbuf_read error");
640 if (n == 0) /* Connection closed. */
641 shut = 1;
642 }
643 if (event & EV_WRITE) {
644 if (imsgbuf_write(ibuf) == -1) {
645 if (errno == EPIPE) /* Connection closed. */
646 shut = 1;
647 else
648 fatal("imsgbuf_write");
649 }
650 }
651
652 for (;;) {
653 if ((n = imsg_get(ibuf, &imsg)) == -1)
654 fatal("%s: imsg_get error", __func__);
655 if (n == 0) /* No more messages. */
656 break;
657
658 type = imsg_get_type(&imsg);
659
660 switch (type) {
661 case IMSG_SOCKET_IPC:
662 /*
663 * Setup pipe and event handler to the frontend
664 * process.
665 */
666 if (iev_frontend)
667 fatalx("%s: received unexpected imsg fd "
668 "to engine", __func__);
669
670 if ((fd = imsg_get_fd(&imsg)) == -1)
671 fatalx("%s: expected to receive imsg fd to "
672 "engine but didn't receive any", __func__);
673
674 iev_frontend = malloc(sizeof(struct imsgev));
675 if (iev_frontend == NULL)
676 fatal(NULL);
677
678 if (imsgbuf_init(&iev_frontend->ibuf, fd) == -1)
679 fatal(NULL);
680 iev_frontend->handler = engine_dispatch_frontend;
681 iev_frontend->events = EV_READ;
682
683 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
684 iev_frontend->events, iev_frontend->handler,
685 iev_frontend);
686 event_add(&iev_frontend->ev, NULL);
687
688 if (pledge("stdio", NULL) == -1)
689 fatal("pledge");
690 break;
691 case IMSG_UPDATE_IF:
692 if (imsg_get_data(&imsg, &imsg_ifinfo,
693 sizeof(imsg_ifinfo)) == -1)
694 fatalx("%s: invalid %s", __func__, i2s(type));
695
696 engine_update_iface(&imsg_ifinfo);
697 break;
698 default:
699 log_debug("%s: unexpected imsg %d", __func__, type);
700 break;
701 }
702 imsg_free(&imsg);
703 }
704 if (!shut)
705 imsg_event_add(iev);
706 else {
707 /* This pipe is dead. Remove its event handler. */
708 event_del(&iev->ev);
709 event_loopexit(NULL);
710 }
711 }
712
713 #ifndef SMALL
714 void
send_interface_info(struct slaacd_iface * iface,pid_t pid)715 send_interface_info(struct slaacd_iface *iface, pid_t pid)
716 {
717 struct ctl_engine_info cei;
718 struct ctl_engine_info_ra cei_ra;
719 struct ctl_engine_info_ra_prefix cei_ra_prefix;
720 struct ctl_engine_info_ra_rdns cei_ra_rdns;
721 struct ctl_engine_info_address_proposal cei_addr_proposal;
722 struct ctl_engine_info_dfr_proposal cei_dfr_proposal;
723 struct ctl_engine_info_rdns_proposal cei_rdns_proposal;
724 struct radv *ra;
725 struct radv_prefix *prefix;
726 struct radv_rdns *rdns;
727 struct address_proposal *addr_proposal;
728 struct dfr_proposal *dfr_proposal;
729 struct rdns_proposal *rdns_proposal;
730
731 memset(&cei, 0, sizeof(cei));
732 cei.if_index = iface->if_index;
733 cei.running = iface->running;
734 cei.autoconf = iface->autoconf;
735 cei.temporary = iface->temporary;
736 cei.soii = iface->soii;
737 memcpy(&cei.hw_address, &iface->hw_address, sizeof(struct ether_addr));
738 memcpy(&cei.ll_address, &iface->ll_address,
739 sizeof(struct sockaddr_in6));
740 engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO, pid, &cei,
741 sizeof(cei));
742 LIST_FOREACH(ra, &iface->radvs, entries) {
743 memset(&cei_ra, 0, sizeof(cei_ra));
744 memcpy(&cei_ra.from, &ra->from, sizeof(cei_ra.from));
745 memcpy(&cei_ra.when, &ra->when, sizeof(cei_ra.when));
746 memcpy(&cei_ra.uptime, &ra->uptime, sizeof(cei_ra.uptime));
747 cei_ra.curhoplimit = ra->curhoplimit;
748 cei_ra.managed = ra->managed;
749 cei_ra.other = ra->other;
750 if (strlcpy(cei_ra.rpref, rpref_name[ra->rpref], sizeof(
751 cei_ra.rpref)) >= sizeof(cei_ra.rpref))
752 log_warnx("truncated router preference");
753 cei_ra.router_lifetime = ra->router_lifetime;
754 cei_ra.reachable_time = ra->reachable_time;
755 cei_ra.retrans_time = ra->retrans_time;
756 cei_ra.mtu = ra->mtu;
757 engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO_RA,
758 pid, &cei_ra, sizeof(cei_ra));
759
760 LIST_FOREACH(prefix, &ra->prefixes, entries) {
761 memset(&cei_ra_prefix, 0, sizeof(cei_ra_prefix));
762
763 cei_ra_prefix.prefix = prefix->prefix;
764 cei_ra_prefix.prefix_len = prefix->prefix_len;
765 cei_ra_prefix.onlink = prefix->onlink;
766 cei_ra_prefix.autonomous = prefix->autonomous;
767 cei_ra_prefix.vltime = prefix->vltime;
768 cei_ra_prefix.pltime = prefix->pltime;
769 engine_imsg_compose_frontend(
770 IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX, pid,
771 &cei_ra_prefix, sizeof(cei_ra_prefix));
772 }
773
774 LIST_FOREACH(rdns, &ra->rdns_servers, entries) {
775 memset(&cei_ra_rdns, 0, sizeof(cei_ra_rdns));
776 memcpy(&cei_ra_rdns.rdns, &rdns->rdns,
777 sizeof(cei_ra_rdns.rdns));
778 cei_ra_rdns.lifetime = ra->rdns_lifetime;
779 engine_imsg_compose_frontend(
780 IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS, pid,
781 &cei_ra_rdns, sizeof(cei_ra_rdns));
782 }
783 }
784
785 if (!LIST_EMPTY(&iface->addr_proposals))
786 engine_imsg_compose_frontend(
787 IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS, pid, NULL, 0);
788
789 LIST_FOREACH(addr_proposal, &iface->addr_proposals, entries) {
790 memset(&cei_addr_proposal, 0, sizeof(cei_addr_proposal));
791 cei_addr_proposal.id = addr_proposal->id;
792 if (strlcpy(cei_addr_proposal.state,
793 proposal_state_name(addr_proposal->state),
794 sizeof(cei_addr_proposal.state)) >=
795 sizeof(cei_addr_proposal.state))
796 log_warnx("truncated state name");
797 cei_addr_proposal.next_timeout = addr_proposal->timo.tv_sec;
798 cei_addr_proposal.when = addr_proposal->when;
799 cei_addr_proposal.uptime = addr_proposal->uptime;
800 memcpy(&cei_addr_proposal.addr, &addr_proposal->addr, sizeof(
801 cei_addr_proposal.addr));
802 memcpy(&cei_addr_proposal.prefix, &addr_proposal->prefix,
803 sizeof(cei_addr_proposal.prefix));
804 cei_addr_proposal.prefix_len = addr_proposal->prefix_len;
805 cei_addr_proposal.temporary = addr_proposal->temporary;
806 cei_addr_proposal.vltime = addr_proposal->vltime;
807 cei_addr_proposal.pltime = addr_proposal->pltime;
808
809 engine_imsg_compose_frontend(
810 IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL, pid,
811 &cei_addr_proposal, sizeof(cei_addr_proposal));
812 }
813
814 if (!LIST_EMPTY(&iface->dfr_proposals))
815 engine_imsg_compose_frontend(
816 IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS, pid, NULL, 0);
817
818 LIST_FOREACH(dfr_proposal, &iface->dfr_proposals, entries) {
819 memset(&cei_dfr_proposal, 0, sizeof(cei_dfr_proposal));
820 cei_dfr_proposal.id = dfr_proposal->id;
821 if (strlcpy(cei_dfr_proposal.state,
822 proposal_state_name(dfr_proposal->state),
823 sizeof(cei_dfr_proposal.state)) >=
824 sizeof(cei_dfr_proposal.state))
825 log_warnx("truncated state name");
826 cei_dfr_proposal.next_timeout = dfr_proposal->timo.tv_sec;
827 cei_dfr_proposal.when = dfr_proposal->when;
828 cei_dfr_proposal.uptime = dfr_proposal->uptime;
829 memcpy(&cei_dfr_proposal.addr, &dfr_proposal->addr, sizeof(
830 cei_dfr_proposal.addr));
831 cei_dfr_proposal.router_lifetime =
832 dfr_proposal->router_lifetime;
833 if (strlcpy(cei_dfr_proposal.rpref,
834 rpref_name[dfr_proposal->rpref],
835 sizeof(cei_dfr_proposal.rpref)) >=
836 sizeof(cei_dfr_proposal.rpref))
837 log_warnx("truncated router preference");
838 engine_imsg_compose_frontend(
839 IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL, pid,
840 &cei_dfr_proposal, sizeof(cei_dfr_proposal));
841 }
842
843 if (!LIST_EMPTY(&iface->rdns_proposals))
844 engine_imsg_compose_frontend(
845 IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSALS, pid, NULL, 0);
846
847 LIST_FOREACH(rdns_proposal, &iface->rdns_proposals, entries) {
848 memset(&cei_rdns_proposal, 0, sizeof(cei_rdns_proposal));
849 cei_rdns_proposal.id = rdns_proposal->id;
850 if (strlcpy(cei_rdns_proposal.state,
851 proposal_state_name(rdns_proposal->state),
852 sizeof(cei_rdns_proposal.state)) >=
853 sizeof(cei_rdns_proposal.state))
854 log_warnx("truncated state name");
855 cei_rdns_proposal.next_timeout = rdns_proposal->timo.tv_sec;
856 cei_rdns_proposal.when = rdns_proposal->when;
857 cei_rdns_proposal.uptime = rdns_proposal->uptime;
858 memcpy(&cei_rdns_proposal.from, &rdns_proposal->from, sizeof(
859 cei_rdns_proposal.from));
860 cei_rdns_proposal.rdns_count = rdns_proposal->rdns_count;
861 memcpy(&cei_rdns_proposal.rdns,
862 &rdns_proposal->rdns, sizeof(cei_rdns_proposal.rdns));
863 cei_rdns_proposal.rdns_lifetime =
864 rdns_proposal->rdns_lifetime;
865 engine_imsg_compose_frontend(
866 IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSAL, pid,
867 &cei_rdns_proposal, sizeof(cei_rdns_proposal));
868 }
869 }
870
871 void
engine_showinfo_ctl(pid_t pid,uint32_t if_index)872 engine_showinfo_ctl(pid_t pid, uint32_t if_index)
873 {
874 struct slaacd_iface *iface;
875
876 if (if_index == 0) {
877 LIST_FOREACH (iface, &slaacd_interfaces, entries)
878 send_interface_info(iface, pid);
879 } else {
880 if ((iface = get_slaacd_iface_by_id(if_index)) != NULL)
881 send_interface_info(iface, pid);
882 }
883 engine_imsg_compose_frontend(IMSG_CTL_END, pid, NULL, 0);
884 }
885
886 #endif /* SMALL */
887
888 struct slaacd_iface*
get_slaacd_iface_by_id(uint32_t if_index)889 get_slaacd_iface_by_id(uint32_t if_index)
890 {
891 struct slaacd_iface *iface;
892 LIST_FOREACH (iface, &slaacd_interfaces, entries) {
893 if (iface->if_index == if_index)
894 return (iface);
895 }
896
897 return (NULL);
898 }
899
900 void
remove_slaacd_iface(uint32_t if_index)901 remove_slaacd_iface(uint32_t if_index)
902 {
903 struct slaacd_iface *iface;
904 struct radv *ra;
905 struct address_proposal *addr_proposal;
906 struct dfr_proposal *dfr_proposal;
907 struct rdns_proposal *rdns_proposal;
908
909 iface = get_slaacd_iface_by_id(if_index);
910
911 if (iface == NULL)
912 return;
913
914 LIST_REMOVE(iface, entries);
915 while(!LIST_EMPTY(&iface->radvs)) {
916 ra = LIST_FIRST(&iface->radvs);
917 LIST_REMOVE(ra, entries);
918 free_ra(ra);
919 }
920 while(!LIST_EMPTY(&iface->addr_proposals)) {
921 addr_proposal = LIST_FIRST(&iface->addr_proposals);
922 free_address_proposal(addr_proposal);
923 }
924 while(!LIST_EMPTY(&iface->dfr_proposals)) {
925 dfr_proposal = LIST_FIRST(&iface->dfr_proposals);
926 free_dfr_proposal(dfr_proposal);
927 }
928 while(!LIST_EMPTY(&iface->rdns_proposals)) {
929 rdns_proposal = LIST_FIRST(&iface->rdns_proposals);
930 free_rdns_proposal(rdns_proposal);
931 }
932 compose_rdns_proposal(iface->if_index, iface->rdomain);
933 evtimer_del(&iface->timer);
934 free(iface);
935 }
936
937 void
free_ra(struct radv * ra)938 free_ra(struct radv *ra)
939 {
940 struct radv_prefix *prefix;
941 struct radv_rdns *rdns;
942
943 if (ra == NULL)
944 return;
945
946 evtimer_del(&ra->timer);
947
948 while (!LIST_EMPTY(&ra->prefixes)) {
949 prefix = LIST_FIRST(&ra->prefixes);
950 LIST_REMOVE(prefix, entries);
951 free(prefix);
952 }
953
954 while (!LIST_EMPTY(&ra->rdns_servers)) {
955 rdns = LIST_FIRST(&ra->rdns_servers);
956 LIST_REMOVE(rdns, entries);
957 free(rdns);
958 }
959
960 free(ra);
961 }
962
963 void
iface_state_transition(struct slaacd_iface * iface,enum if_state new_state)964 iface_state_transition(struct slaacd_iface *iface, enum if_state new_state)
965 {
966 enum if_state old_state = iface->state;
967 struct address_proposal *addr_proposal;
968 struct dfr_proposal *dfr_proposal;
969 struct rdns_proposal *rdns_proposal;
970
971 iface->state = new_state;
972
973 switch (new_state) {
974 case IF_DOWN:
975 if (old_state != IF_DOWN) {
976 LIST_FOREACH (addr_proposal, &iface->addr_proposals,
977 entries)
978 addr_proposal_state_transition(addr_proposal,
979 PROPOSAL_IF_DOWN);
980 LIST_FOREACH (dfr_proposal, &iface->dfr_proposals,
981 entries)
982 dfr_proposal_state_transition(dfr_proposal,
983 PROPOSAL_IF_DOWN);
984 LIST_FOREACH (rdns_proposal, &iface->rdns_proposals,
985 entries)
986 rdns_proposal_state_transition(rdns_proposal,
987 PROPOSAL_IF_DOWN);
988 }
989
990 /* nothing else to do until interface comes back up */
991 iface->timo.tv_sec = -1;
992 break;
993 case IF_INIT:
994 switch (old_state) {
995 case IF_INIT:
996 iface->probes++;
997 break;
998 case IF_DOWN:
999 LIST_FOREACH (addr_proposal, &iface->addr_proposals,
1000 entries)
1001 addr_proposal_state_transition(addr_proposal,
1002 PROPOSAL_WITHDRAWN);
1003 LIST_FOREACH (dfr_proposal, &iface->dfr_proposals,
1004 entries)
1005 dfr_proposal_state_transition(dfr_proposal,
1006 PROPOSAL_WITHDRAWN);
1007 LIST_FOREACH (rdns_proposal, &iface->rdns_proposals,
1008 entries)
1009 rdns_proposal_state_transition(rdns_proposal,
1010 PROPOSAL_WITHDRAWN);
1011 default:
1012 iface->probes = 0;
1013 }
1014 if (iface->probes < MAX_RTR_SOLICITATIONS) {
1015 iface->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1016 request_solicitation(iface);
1017 } else
1018 /* no router available, stop probing */
1019 iface->timo.tv_sec = -1;
1020 break;
1021 case IF_BOUND:
1022 iface->timo.tv_sec = -1;
1023 break;
1024 }
1025
1026 if (log_getverbose()) {
1027 char ifnamebuf[IF_NAMESIZE], *if_name;
1028 if_name = if_indextoname(iface->if_index, ifnamebuf);
1029 log_debug("%s[%s] %s -> %s, timo: %lld", __func__,
1030 if_name == NULL ? "?" : if_name, if_state_name(old_state),
1031 if_state_name(new_state), iface->timo.tv_sec);
1032 }
1033
1034 if (iface->timo.tv_sec == -1) {
1035 if (evtimer_pending(&iface->timer, NULL))
1036 evtimer_del(&iface->timer);
1037 } else
1038 evtimer_add(&iface->timer, &iface->timo);
1039 }
1040
addr_proposal_state_transition(struct address_proposal * addr_proposal,enum proposal_state new_state)1041 void addr_proposal_state_transition(struct address_proposal *addr_proposal,
1042 enum proposal_state new_state)
1043 {
1044 enum proposal_state old_state = addr_proposal->state;
1045 struct slaacd_iface *iface;
1046 uint32_t lifetime;
1047
1048 addr_proposal->state = new_state;
1049
1050 if ((iface = get_slaacd_iface_by_id(addr_proposal->if_index)) == NULL)
1051 return;
1052
1053 switch (addr_proposal->state) {
1054 case PROPOSAL_IF_DOWN:
1055 if (old_state == PROPOSAL_IF_DOWN) {
1056 withdraw_addr(addr_proposal);
1057 addr_proposal->timo.tv_sec = -1;
1058 } else {
1059 addr_proposal->timo.tv_sec =
1060 real_lifetime(&addr_proposal->uptime,
1061 addr_proposal->vltime);
1062 }
1063 break;
1064 case PROPOSAL_NOT_CONFIGURED:
1065 break;
1066 case PROPOSAL_CONFIGURED:
1067 lifetime = real_lifetime(&addr_proposal->uptime,
1068 addr_proposal->pltime);
1069 if (lifetime == 0)
1070 lifetime = real_lifetime(&addr_proposal->uptime,
1071 addr_proposal->vltime);
1072 if (lifetime > MAX_RTR_SOLICITATIONS *
1073 (RTR_SOLICITATION_INTERVAL + 1))
1074 addr_proposal->timo.tv_sec = lifetime -
1075 MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL;
1076 else
1077 addr_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1078 break;
1079 case PROPOSAL_NEARLY_EXPIRED:
1080 lifetime = real_lifetime(&addr_proposal->uptime,
1081 addr_proposal->pltime);
1082 if (lifetime == 0)
1083 lifetime = real_lifetime(&addr_proposal->uptime,
1084 addr_proposal->vltime);
1085 if (lifetime > MAX_RTR_SOLICITATIONS *
1086 (RTR_SOLICITATION_INTERVAL + 1))
1087 addr_proposal->timo.tv_sec = lifetime -
1088 MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL;
1089 else
1090 addr_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1091 request_solicitation(iface);
1092 break;
1093 case PROPOSAL_WITHDRAWN:
1094 withdraw_addr(addr_proposal);
1095 addr_proposal->timo.tv_sec = MAX_RTR_SOLICITATIONS *
1096 RTR_SOLICITATION_INTERVAL;
1097 break;
1098 case PROPOSAL_DUPLICATED:
1099 addr_proposal->timo.tv_sec = 0;
1100 break;
1101 case PROPOSAL_STALE:
1102 addr_proposal->timo.tv_sec = 0; /* remove immediately */
1103 break;
1104 }
1105
1106 if (log_getverbose()) {
1107 char ifnamebuf[IF_NAMESIZE], *if_name;
1108 if_name = if_indextoname(addr_proposal->if_index, ifnamebuf);
1109 log_debug("%s[%s] %s -> %s, timo: %lld", __func__,
1110 if_name == NULL ? "?" : if_name,
1111 proposal_state_name(old_state),
1112 proposal_state_name(new_state), addr_proposal->timo.tv_sec);
1113 }
1114
1115 if (addr_proposal->timo.tv_sec == -1) {
1116 if (evtimer_pending(&addr_proposal->timer, NULL))
1117 evtimer_del(&addr_proposal->timer);
1118 } else
1119 evtimer_add(&addr_proposal->timer, &addr_proposal->timo);
1120 }
1121
dfr_proposal_state_transition(struct dfr_proposal * dfr_proposal,enum proposal_state new_state)1122 void dfr_proposal_state_transition(struct dfr_proposal *dfr_proposal,
1123 enum proposal_state new_state)
1124 {
1125 enum proposal_state old_state = dfr_proposal->state;
1126 struct slaacd_iface *iface;
1127 uint32_t lifetime;
1128
1129 dfr_proposal->state = new_state;
1130
1131 if ((iface = get_slaacd_iface_by_id(dfr_proposal->if_index)) == NULL)
1132 return;
1133
1134 switch (dfr_proposal->state) {
1135 case PROPOSAL_IF_DOWN:
1136 if (old_state == PROPOSAL_IF_DOWN) {
1137 withdraw_dfr(dfr_proposal);
1138 dfr_proposal->timo.tv_sec = -1;
1139 } else {
1140 dfr_proposal->timo.tv_sec =
1141 real_lifetime(&dfr_proposal->uptime,
1142 dfr_proposal->router_lifetime);
1143 }
1144 break;
1145 case PROPOSAL_NOT_CONFIGURED:
1146 break;
1147 case PROPOSAL_CONFIGURED:
1148 lifetime = real_lifetime(&dfr_proposal->uptime,
1149 dfr_proposal->router_lifetime);
1150 if (lifetime > MAX_RTR_SOLICITATIONS *
1151 (RTR_SOLICITATION_INTERVAL + 1))
1152 dfr_proposal->timo.tv_sec = lifetime -
1153 MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL;
1154 else
1155 dfr_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1156 break;
1157 case PROPOSAL_NEARLY_EXPIRED:
1158 lifetime = real_lifetime(&dfr_proposal->uptime,
1159 dfr_proposal->router_lifetime);
1160 if (lifetime > MAX_RTR_SOLICITATIONS *
1161 (RTR_SOLICITATION_INTERVAL + 1))
1162 dfr_proposal->timo.tv_sec = lifetime -
1163 MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL;
1164 else
1165 dfr_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1166 request_solicitation(iface);
1167 break;
1168 case PROPOSAL_WITHDRAWN:
1169 withdraw_dfr(dfr_proposal);
1170 dfr_proposal->timo.tv_sec = MAX_RTR_SOLICITATIONS *
1171 RTR_SOLICITATION_INTERVAL;
1172 break;
1173 case PROPOSAL_STALE:
1174 dfr_proposal->timo.tv_sec = 0; /* remove immediately */
1175 break;
1176 case PROPOSAL_DUPLICATED:
1177 fatalx("invalid dfr state: PROPOSAL_DUPLICATED");
1178 break;
1179 }
1180
1181 if (log_getverbose()) {
1182 char ifnamebuf[IF_NAMESIZE], *if_name;
1183
1184 if_name = if_indextoname(dfr_proposal->if_index, ifnamebuf);
1185 log_debug("%s[%s] %s -> %s, timo: %lld", __func__,
1186 if_name == NULL ? "?" : if_name,
1187 proposal_state_name(old_state),
1188 proposal_state_name(new_state), dfr_proposal->timo.tv_sec);
1189 }
1190
1191 if (dfr_proposal->timo.tv_sec == -1) {
1192 if (evtimer_pending(&dfr_proposal->timer, NULL))
1193 evtimer_del(&dfr_proposal->timer);
1194 } else
1195 evtimer_add(&dfr_proposal->timer, &dfr_proposal->timo);
1196
1197 }
1198
rdns_proposal_state_transition(struct rdns_proposal * rdns_proposal,enum proposal_state new_state)1199 void rdns_proposal_state_transition(struct rdns_proposal *rdns_proposal,
1200 enum proposal_state new_state)
1201 {
1202 enum proposal_state old_state = rdns_proposal->state;
1203 struct slaacd_iface *iface;
1204 uint32_t lifetime;
1205
1206 rdns_proposal->state = new_state;
1207
1208 if ((iface = get_slaacd_iface_by_id(rdns_proposal->if_index)) == NULL)
1209 return;
1210
1211 switch (rdns_proposal->state) {
1212 case PROPOSAL_IF_DOWN:
1213 if (old_state == PROPOSAL_IF_DOWN) {
1214 withdraw_rdns(rdns_proposal);
1215 rdns_proposal->timo.tv_sec = -1;
1216 } else {
1217 rdns_proposal->timo.tv_sec =
1218 real_lifetime(&rdns_proposal->uptime,
1219 rdns_proposal->rdns_lifetime);
1220 }
1221 break;
1222 case PROPOSAL_NOT_CONFIGURED:
1223 break;
1224 case PROPOSAL_CONFIGURED:
1225 lifetime = real_lifetime(&rdns_proposal->uptime,
1226 rdns_proposal->rdns_lifetime);
1227 if (lifetime > MAX_RTR_SOLICITATIONS *
1228 (RTR_SOLICITATION_INTERVAL + 1))
1229 rdns_proposal->timo.tv_sec = lifetime -
1230 MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL;
1231 else
1232 rdns_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1233 break;
1234 case PROPOSAL_NEARLY_EXPIRED:
1235 lifetime = real_lifetime(&rdns_proposal->uptime,
1236 rdns_proposal->rdns_lifetime);
1237 if (lifetime > MAX_RTR_SOLICITATIONS *
1238 (RTR_SOLICITATION_INTERVAL + 1))
1239 rdns_proposal->timo.tv_sec = lifetime -
1240 MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL;
1241 else
1242 rdns_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL;
1243 request_solicitation(iface);
1244 break;
1245 case PROPOSAL_WITHDRAWN:
1246 withdraw_rdns(rdns_proposal);
1247 rdns_proposal->timo.tv_sec = MAX_RTR_SOLICITATIONS *
1248 RTR_SOLICITATION_INTERVAL;
1249 break;
1250 case PROPOSAL_STALE:
1251 rdns_proposal->timo.tv_sec = 0; /* remove immediately */
1252 break;
1253 case PROPOSAL_DUPLICATED:
1254 fatalx("invalid rdns state: PROPOSAL_DUPLICATED");
1255 break;
1256 }
1257
1258 if (log_getverbose()) {
1259 char ifnamebuf[IF_NAMESIZE], *if_name;
1260
1261 if_name = if_indextoname(rdns_proposal->if_index, ifnamebuf);
1262 log_debug("%s[%s] %s -> %s, timo: %lld", __func__,
1263 if_name == NULL ? "?" : if_name,
1264 proposal_state_name(old_state),
1265 proposal_state_name(new_state), rdns_proposal->timo.tv_sec);
1266 }
1267
1268 if (rdns_proposal->timo.tv_sec == -1) {
1269 if (evtimer_pending(&rdns_proposal->timer, NULL))
1270 evtimer_del(&rdns_proposal->timer);
1271 } else
1272 evtimer_add(&rdns_proposal->timer, &rdns_proposal->timo);
1273 }
1274
1275 void
request_solicitation(struct slaacd_iface * iface)1276 request_solicitation(struct slaacd_iface *iface)
1277 {
1278 struct timespec now, diff, sol_delay = {RTR_SOLICITATION_INTERVAL, 0};
1279
1280 clock_gettime(CLOCK_MONOTONIC, &now);
1281 timespecsub(&now, &iface->last_sol, &diff);
1282 if (timespeccmp(&diff, &sol_delay, <)) {
1283 log_debug("last solicitation less than %d seconds ago",
1284 RTR_SOLICITATION_INTERVAL);
1285 return;
1286 }
1287
1288 iface->last_sol = now;
1289 engine_imsg_compose_frontend(IMSG_CTL_SEND_SOLICITATION, 0,
1290 &iface->if_index, sizeof(iface->if_index));
1291 }
1292
1293 void
engine_update_iface(struct imsg_ifinfo * imsg_ifinfo)1294 engine_update_iface(struct imsg_ifinfo *imsg_ifinfo)
1295 {
1296 struct slaacd_iface *iface;
1297 int need_refresh = 0;
1298
1299 iface = get_slaacd_iface_by_id(imsg_ifinfo->if_index);
1300 if (iface == NULL) {
1301 if ((iface = calloc(1, sizeof(*iface))) == NULL)
1302 fatal("calloc");
1303 iface->state = IF_DOWN;
1304 iface->timo.tv_usec = arc4random_uniform(1000000);
1305 evtimer_set(&iface->timer, iface_timeout, iface);
1306 iface->if_index = imsg_ifinfo->if_index;
1307 iface->rdomain = imsg_ifinfo->rdomain;
1308 iface->running = imsg_ifinfo->running;
1309 iface->link_state = imsg_ifinfo->link_state;
1310 iface->autoconf = imsg_ifinfo->autoconf;
1311 iface->temporary = imsg_ifinfo->temporary;
1312 iface->soii = imsg_ifinfo->soii;
1313 memcpy(&iface->hw_address, &imsg_ifinfo->hw_address,
1314 sizeof(struct ether_addr));
1315 memcpy(&iface->ll_address, &imsg_ifinfo->ll_address,
1316 sizeof(struct sockaddr_in6));
1317 memcpy(iface->soiikey, imsg_ifinfo->soiikey,
1318 sizeof(iface->soiikey));
1319 LIST_INIT(&iface->radvs);
1320 LIST_INSERT_HEAD(&slaacd_interfaces, iface, entries);
1321 LIST_INIT(&iface->addr_proposals);
1322 LIST_INIT(&iface->dfr_proposals);
1323 LIST_INIT(&iface->rdns_proposals);
1324 need_refresh = 1;
1325 } else {
1326 memcpy(&iface->ll_address, &imsg_ifinfo->ll_address,
1327 sizeof(struct sockaddr_in6));
1328
1329 if (iface->autoconf != imsg_ifinfo->autoconf) {
1330 iface->autoconf = imsg_ifinfo->autoconf;
1331 need_refresh = 1;
1332 }
1333
1334 if (iface->temporary != imsg_ifinfo->temporary) {
1335 iface->temporary = imsg_ifinfo->temporary;
1336 need_refresh = 1;
1337 }
1338
1339 if (iface->soii != imsg_ifinfo->soii) {
1340 iface->soii = imsg_ifinfo->soii;
1341 need_refresh = 1;
1342 }
1343
1344 if (memcmp(&iface->hw_address, &imsg_ifinfo->hw_address,
1345 sizeof(struct ether_addr)) != 0) {
1346 memcpy(&iface->hw_address, &imsg_ifinfo->hw_address,
1347 sizeof(struct ether_addr));
1348 need_refresh = 1;
1349 }
1350
1351 if (memcmp(iface->soiikey, imsg_ifinfo->soiikey,
1352 sizeof(iface->soiikey)) != 0) {
1353 memcpy(iface->soiikey, imsg_ifinfo->soiikey,
1354 sizeof(iface->soiikey));
1355 need_refresh = 1;
1356 }
1357
1358 if (imsg_ifinfo->running != iface->running) {
1359 iface->running = imsg_ifinfo->running;
1360 need_refresh = 1;
1361 }
1362 if (imsg_ifinfo->link_state != iface->link_state) {
1363 iface->link_state = imsg_ifinfo->link_state;
1364 need_refresh = 1;
1365 }
1366 }
1367
1368 if (!need_refresh)
1369 return;
1370
1371 if (iface->running && LINK_STATE_IS_UP(iface->link_state))
1372 iface_state_transition(iface, IF_INIT);
1373
1374 else
1375 iface_state_transition(iface, IF_DOWN);
1376 }
1377
1378 void
parse_ra(struct slaacd_iface * iface,struct imsg_ra * ra)1379 parse_ra(struct slaacd_iface *iface, struct imsg_ra *ra)
1380 {
1381 struct icmp6_hdr *icmp6_hdr;
1382 struct nd_router_advert *nd_ra;
1383 struct radv *radv;
1384 struct radv_prefix *prefix;
1385 struct radv_rdns *rdns;
1386 ssize_t len = ra->len;
1387 const char *hbuf;
1388 uint8_t *p;
1389
1390 #ifndef SMALL
1391 if (log_getverbose() > 1)
1392 debug_log_ra(ra);
1393 #endif /* SMALL */
1394
1395 hbuf = sin6_to_str(&ra->from);
1396 if ((size_t)len < sizeof(struct icmp6_hdr)) {
1397 log_warnx("received too short message (%ld) from %s", len,
1398 hbuf);
1399 return;
1400 }
1401
1402 p = ra->packet;
1403 icmp6_hdr = (struct icmp6_hdr *)p;
1404 if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT)
1405 return;
1406
1407 if (!IN6_IS_ADDR_LINKLOCAL(&ra->from.sin6_addr)) {
1408 log_debug("RA from non link local address %s", hbuf);
1409 return;
1410 }
1411
1412 if ((size_t)len < sizeof(struct nd_router_advert)) {
1413 log_warnx("received too short message (%ld) from %s", len,
1414 hbuf);
1415 return;
1416 }
1417
1418 if ((radv = calloc(1, sizeof(*radv))) == NULL)
1419 fatal("calloc");
1420
1421 LIST_INIT(&radv->prefixes);
1422 LIST_INIT(&radv->rdns_servers);
1423
1424 radv->min_lifetime = UINT32_MAX;
1425
1426 nd_ra = (struct nd_router_advert *)p;
1427 len -= sizeof(struct nd_router_advert);
1428 p += sizeof(struct nd_router_advert);
1429
1430 log_debug("ICMPv6 type(%d), code(%d) from %s of length %ld",
1431 nd_ra->nd_ra_type, nd_ra->nd_ra_code, hbuf, len);
1432
1433 if (nd_ra->nd_ra_code != 0) {
1434 log_warnx("invalid ICMPv6 code (%d) from %s", nd_ra->nd_ra_code,
1435 hbuf);
1436 goto err;
1437 }
1438
1439 memcpy(&radv->from, &ra->from, sizeof(ra->from));
1440
1441 if (clock_gettime(CLOCK_REALTIME, &radv->when))
1442 fatal("clock_gettime");
1443 if (clock_gettime(CLOCK_MONOTONIC, &radv->uptime))
1444 fatal("clock_gettime");
1445
1446 radv->curhoplimit = nd_ra->nd_ra_curhoplimit;
1447 radv->managed = nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED;
1448 radv->other = nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER;
1449
1450 switch (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_RTPREF_MASK) {
1451 case ND_RA_FLAG_RTPREF_HIGH:
1452 radv->rpref=HIGH;
1453 break;
1454 case ND_RA_FLAG_RTPREF_LOW:
1455 radv->rpref=LOW;
1456 break;
1457 case ND_RA_FLAG_RTPREF_MEDIUM:
1458 /* fallthrough */
1459 default:
1460 radv->rpref=MEDIUM;
1461 break;
1462 }
1463 radv->router_lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
1464 if (radv->router_lifetime != 0)
1465 radv->min_lifetime = radv->router_lifetime;
1466 radv->reachable_time = ntohl(nd_ra->nd_ra_reachable);
1467 radv->retrans_time = ntohl(nd_ra->nd_ra_retransmit);
1468
1469 while ((size_t)len >= sizeof(struct nd_opt_hdr)) {
1470 struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p;
1471 struct nd_opt_prefix_info *prf;
1472 struct nd_opt_rdnss *rdnss;
1473 struct nd_opt_mtu *mtu;
1474 struct in6_addr *in6;
1475 int i;
1476
1477 len -= sizeof(struct nd_opt_hdr);
1478 p += sizeof(struct nd_opt_hdr);
1479
1480 if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) {
1481 log_warnx("invalid option len: %u > %ld",
1482 nd_opt_hdr->nd_opt_len, len);
1483 goto err;
1484 }
1485
1486 switch (nd_opt_hdr->nd_opt_type) {
1487 case ND_OPT_PREFIX_INFORMATION:
1488 if (nd_opt_hdr->nd_opt_len != 4) {
1489 log_warnx("invalid ND_OPT_PREFIX_INFORMATION: "
1490 "len != 4");
1491 goto err;
1492 }
1493
1494 if ((prefix = calloc(1, sizeof(*prefix))) == NULL)
1495 fatal("calloc");
1496
1497 prf = (struct nd_opt_prefix_info*) nd_opt_hdr;
1498 prefix->prefix = prf->nd_opt_pi_prefix;
1499 prefix->prefix_len = prf->nd_opt_pi_prefix_len;
1500 prefix->onlink = prf->nd_opt_pi_flags_reserved &
1501 ND_OPT_PI_FLAG_ONLINK;
1502 prefix->autonomous = prf->nd_opt_pi_flags_reserved &
1503 ND_OPT_PI_FLAG_AUTO;
1504 prefix->vltime = ntohl(prf->nd_opt_pi_valid_time);
1505 prefix->pltime = ntohl(prf->nd_opt_pi_preferred_time);
1506 if (radv->min_lifetime > prefix->pltime)
1507 radv->min_lifetime = prefix->pltime;
1508
1509 LIST_INSERT_HEAD(&radv->prefixes, prefix, entries);
1510
1511 break;
1512
1513 case ND_OPT_RDNSS:
1514 if (nd_opt_hdr->nd_opt_len < 3) {
1515 log_warnx("invalid ND_OPT_RDNSS: len < 24");
1516 goto err;
1517 }
1518
1519 if ((nd_opt_hdr->nd_opt_len - 1) % 2 != 0) {
1520 log_warnx("invalid ND_OPT_RDNSS: length with"
1521 "out header is not multiply of 16: %d",
1522 (nd_opt_hdr->nd_opt_len - 1) * 8);
1523 goto err;
1524 }
1525
1526 rdnss = (struct nd_opt_rdnss*) nd_opt_hdr;
1527
1528 radv->rdns_lifetime = ntohl(
1529 rdnss->nd_opt_rdnss_lifetime);
1530 if (radv->min_lifetime > radv->rdns_lifetime)
1531 radv->min_lifetime = radv->rdns_lifetime;
1532
1533 in6 = (struct in6_addr*) (p + 6);
1534 for (i=0; i < (nd_opt_hdr->nd_opt_len - 1)/2; i++,
1535 in6++) {
1536 if ((rdns = calloc(1, sizeof(*rdns))) == NULL)
1537 fatal("calloc");
1538 memcpy(&rdns->rdns, in6, sizeof(rdns->rdns));
1539 LIST_INSERT_HEAD(&radv->rdns_servers, rdns,
1540 entries);
1541 }
1542 break;
1543 case ND_OPT_MTU:
1544 if (nd_opt_hdr->nd_opt_len != 1) {
1545 log_warnx("invalid ND_OPT_MTU: len != 1");
1546 goto err;
1547 }
1548 mtu = (struct nd_opt_mtu*) nd_opt_hdr;
1549 radv->mtu = ntohl(mtu->nd_opt_mtu_mtu);
1550
1551 /* path MTU cannot be less than IPV6_MMTU */
1552 if (radv->mtu < IPV6_MMTU) {
1553 radv->mtu = 0;
1554 log_warnx("invalid advertised MTU");
1555 }
1556
1557 break;
1558 case ND_OPT_DNSSL:
1559 case ND_OPT_REDIRECTED_HEADER:
1560 case ND_OPT_SOURCE_LINKADDR:
1561 case ND_OPT_TARGET_LINKADDR:
1562 case ND_OPT_ROUTE_INFO:
1563 #if 0
1564 log_debug("\tOption: %u (len: %u) not implemented",
1565 nd_opt_hdr->nd_opt_type, nd_opt_hdr->nd_opt_len *
1566 8);
1567 #endif
1568 break;
1569 default:
1570 log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type);
1571 break;
1572
1573 }
1574 len -= nd_opt_hdr->nd_opt_len * 8 - 2;
1575 p += nd_opt_hdr->nd_opt_len * 8 - 2;
1576 }
1577 update_iface_ra(iface, radv);
1578 return;
1579
1580 err:
1581 free_ra(radv);
1582 }
1583
1584 void
gen_addr(struct slaacd_iface * iface,struct radv_prefix * prefix,struct address_proposal * addr_proposal,int temporary)1585 gen_addr(struct slaacd_iface *iface, struct radv_prefix *prefix, struct
1586 address_proposal *addr_proposal, int temporary)
1587 {
1588 SHA2_CTX ctx;
1589 struct in6_addr iid;
1590 int i;
1591 u_int8_t digest[SHA512_DIGEST_LENGTH];
1592
1593 memset(&iid, 0, sizeof(iid));
1594
1595 /* from in6_ifadd() in nd6_rtr.c */
1596 /* XXX from in6.h, guarded by #ifdef _KERNEL XXX nonstandard */
1597 #define s6_addr32 __u6_addr.__u6_addr32
1598
1599 in6_prefixlen2mask(&addr_proposal->mask, addr_proposal->prefix_len);
1600
1601 memset(&addr_proposal->addr, 0, sizeof(addr_proposal->addr));
1602
1603 addr_proposal->addr.sin6_family = AF_INET6;
1604 addr_proposal->addr.sin6_len = sizeof(addr_proposal->addr);
1605
1606 memcpy(&addr_proposal->addr.sin6_addr, &prefix->prefix,
1607 sizeof(addr_proposal->addr.sin6_addr));
1608
1609 for (i = 0; i < 4; i++)
1610 addr_proposal->addr.sin6_addr.s6_addr32[i] &=
1611 addr_proposal->mask.s6_addr32[i];
1612
1613 if (temporary) {
1614 arc4random_buf(&iid.s6_addr, sizeof(iid.s6_addr));
1615 } else if (iface->soii) {
1616 SHA512Init(&ctx);
1617 SHA512Update(&ctx, &prefix->prefix,
1618 sizeof(prefix->prefix));
1619 SHA512Update(&ctx, &iface->hw_address,
1620 sizeof(iface->hw_address));
1621 SHA512Update(&ctx, &prefix->dad_counter,
1622 sizeof(prefix->dad_counter));
1623 SHA512Update(&ctx, addr_proposal->soiikey,
1624 sizeof(addr_proposal->soiikey));
1625 SHA512Final(digest, &ctx);
1626
1627 memcpy(&iid.s6_addr, digest + (sizeof(digest) -
1628 sizeof(iid.s6_addr)), sizeof(iid.s6_addr));
1629 } else {
1630 /* This is safe, because we have a 64 prefix len */
1631 memcpy(&iid.s6_addr, &iface->ll_address.sin6_addr,
1632 sizeof(iid.s6_addr));
1633 }
1634
1635 for (i = 0; i < 4; i++)
1636 addr_proposal->addr.sin6_addr.s6_addr32[i] |=
1637 (iid.s6_addr32[i] & ~addr_proposal->mask.s6_addr32[i]);
1638 #undef s6_addr32
1639 }
1640
1641 /* from sys/netinet6/in6.c */
1642 void
in6_prefixlen2mask(struct in6_addr * maskp,int len)1643 in6_prefixlen2mask(struct in6_addr *maskp, int len)
1644 {
1645 u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
1646 int bytelen, bitlen, i;
1647
1648 if (0 > len || len > 128)
1649 fatalx("%s: invalid prefix length(%d)\n", __func__, len);
1650
1651 bzero(maskp, sizeof(*maskp));
1652 bytelen = len / 8;
1653 bitlen = len % 8;
1654 for (i = 0; i < bytelen; i++)
1655 maskp->s6_addr[i] = 0xff;
1656 /* len == 128 is ok because bitlen == 0 then */
1657 if (bitlen)
1658 maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
1659 }
1660
1661 #ifndef SMALL
1662 /* from kame via ifconfig, where it's called prefix() */
1663 int
in6_mask2prefixlen(struct in6_addr * in6)1664 in6_mask2prefixlen(struct in6_addr *in6)
1665 {
1666 u_char *nam = (u_char *)in6;
1667 int byte, bit, plen = 0, size = sizeof(struct in6_addr);
1668
1669 for (byte = 0; byte < size; byte++, plen += 8)
1670 if (nam[byte] != 0xff)
1671 break;
1672 if (byte == size)
1673 return (plen);
1674 for (bit = 7; bit != 0; bit--, plen++)
1675 if (!(nam[byte] & (1 << bit)))
1676 break;
1677 for (; bit != 0; bit--)
1678 if (nam[byte] & (1 << bit))
1679 return (0);
1680 byte++;
1681 for (; byte < size; byte++)
1682 if (nam[byte])
1683 return (0);
1684 return (plen);
1685 }
1686
1687 void
debug_log_ra(struct imsg_ra * ra)1688 debug_log_ra(struct imsg_ra *ra)
1689 {
1690 struct nd_router_advert *nd_ra;
1691 ssize_t len = ra->len;
1692 char ntopbuf[INET6_ADDRSTRLEN];
1693 const char *hbuf;
1694 uint8_t *p;
1695
1696 hbuf = sin6_to_str(&ra->from);
1697
1698 if (!IN6_IS_ADDR_LINKLOCAL(&ra->from.sin6_addr)) {
1699 log_warnx("RA from non link local address %s", hbuf);
1700 return;
1701 }
1702
1703 if ((size_t)len < sizeof(struct nd_router_advert)) {
1704 log_warnx("received too short message (%ld) from %s", len,
1705 hbuf);
1706 return;
1707 }
1708
1709 p = ra->packet;
1710 nd_ra = (struct nd_router_advert *)p;
1711 len -= sizeof(struct nd_router_advert);
1712 p += sizeof(struct nd_router_advert);
1713
1714 log_debug("ICMPv6 type(%d), code(%d) from %s of length %ld",
1715 nd_ra->nd_ra_type, nd_ra->nd_ra_code, hbuf, len);
1716
1717 if (nd_ra->nd_ra_type != ND_ROUTER_ADVERT) {
1718 log_warnx("invalid ICMPv6 type (%d) from %s", nd_ra->nd_ra_type,
1719 hbuf);
1720 return;
1721 }
1722
1723 if (nd_ra->nd_ra_code != 0) {
1724 log_warnx("invalid ICMPv6 code (%d) from %s", nd_ra->nd_ra_code,
1725 hbuf);
1726 return;
1727 }
1728
1729 log_debug("---");
1730 log_debug("RA from %s", hbuf);
1731 log_debug("\tCur Hop Limit: %u", nd_ra->nd_ra_curhoplimit);
1732 log_debug("\tManaged address configuration: %d",
1733 (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) ? 1 : 0);
1734 log_debug("\tOther configuration: %d",
1735 (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) ? 1 : 0);
1736 switch (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_RTPREF_MASK) {
1737 case ND_RA_FLAG_RTPREF_HIGH:
1738 log_debug("\tRouter Preference: high");
1739 break;
1740 case ND_RA_FLAG_RTPREF_MEDIUM:
1741 log_debug("\tRouter Preference: medium");
1742 break;
1743 case ND_RA_FLAG_RTPREF_LOW:
1744 log_debug("\tRouter Preference: low");
1745 break;
1746 case ND_RA_FLAG_RTPREF_RSV:
1747 log_debug("\tRouter Preference: reserved");
1748 break;
1749 }
1750 log_debug("\tRouter Lifetime: %hds",
1751 ntohs(nd_ra->nd_ra_router_lifetime));
1752 log_debug("\tReachable Time: %ums", ntohl(nd_ra->nd_ra_reachable));
1753 log_debug("\tRetrans Timer: %ums", ntohl(nd_ra->nd_ra_retransmit));
1754
1755 while ((size_t)len >= sizeof(struct nd_opt_hdr)) {
1756 struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p;
1757 struct nd_opt_mtu *mtu;
1758 struct nd_opt_prefix_info *prf;
1759 struct nd_opt_rdnss *rdnss;
1760 struct in6_addr *in6;
1761 int i;
1762
1763 len -= sizeof(struct nd_opt_hdr);
1764 p += sizeof(struct nd_opt_hdr);
1765 if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) {
1766 log_warnx("invalid option len: %u > %ld",
1767 nd_opt_hdr->nd_opt_len, len);
1768 return;
1769 }
1770 log_debug("\tOption: %u (len: %u)", nd_opt_hdr->nd_opt_type,
1771 nd_opt_hdr->nd_opt_len * 8);
1772 switch (nd_opt_hdr->nd_opt_type) {
1773 case ND_OPT_SOURCE_LINKADDR:
1774 if (nd_opt_hdr->nd_opt_len == 1)
1775 log_debug("\t\tND_OPT_SOURCE_LINKADDR: "
1776 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
1777 p[0], p[1], p[2], p[3], p[4], p[5], p[6],
1778 p[7]);
1779 else
1780 log_debug("\t\tND_OPT_SOURCE_LINKADDR");
1781 break;
1782 case ND_OPT_TARGET_LINKADDR:
1783 if (nd_opt_hdr->nd_opt_len == 1)
1784 log_debug("\t\tND_OPT_TARGET_LINKADDR: "
1785 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
1786 p[0], p[1], p[2], p[3], p[4], p[5], p[6],
1787 p[7]);
1788 else
1789 log_debug("\t\tND_OPT_TARGET_LINKADDR");
1790 break;
1791 case ND_OPT_PREFIX_INFORMATION:
1792 if (nd_opt_hdr->nd_opt_len != 4) {
1793 log_warnx("invalid ND_OPT_PREFIX_INFORMATION: "
1794 "len != 4");
1795 return;
1796 }
1797 prf = (struct nd_opt_prefix_info*) nd_opt_hdr;
1798
1799 log_debug("\t\tND_OPT_PREFIX_INFORMATION: %s/%u",
1800 inet_ntop(AF_INET6, &prf->nd_opt_pi_prefix,
1801 ntopbuf, INET6_ADDRSTRLEN),
1802 prf->nd_opt_pi_prefix_len);
1803 log_debug("\t\t\tOn-link: %d",
1804 prf->nd_opt_pi_flags_reserved &
1805 ND_OPT_PI_FLAG_ONLINK ? 1:0);
1806 log_debug("\t\t\tAutonomous address-configuration: %d",
1807 prf->nd_opt_pi_flags_reserved &
1808 ND_OPT_PI_FLAG_AUTO ? 1 : 0);
1809 log_debug("\t\t\tvltime: %u",
1810 ntohl(prf->nd_opt_pi_valid_time));
1811 log_debug("\t\t\tpltime: %u",
1812 ntohl(prf->nd_opt_pi_preferred_time));
1813 break;
1814 case ND_OPT_REDIRECTED_HEADER:
1815 log_debug("\t\tND_OPT_REDIRECTED_HEADER");
1816 break;
1817 case ND_OPT_MTU:
1818 if (nd_opt_hdr->nd_opt_len != 1) {
1819 log_warnx("invalid ND_OPT_MTU: len != 1");
1820 return;
1821 }
1822 mtu = (struct nd_opt_mtu*) nd_opt_hdr;
1823 log_debug("\t\tND_OPT_MTU: %u",
1824 ntohl(mtu->nd_opt_mtu_mtu));
1825 break;
1826 case ND_OPT_ROUTE_INFO:
1827 log_debug("\t\tND_OPT_ROUTE_INFO");
1828 break;
1829 case ND_OPT_RDNSS:
1830 if (nd_opt_hdr->nd_opt_len < 3) {
1831 log_warnx("invalid ND_OPT_RDNSS: len < 24");
1832 return;
1833 }
1834 if ((nd_opt_hdr->nd_opt_len - 1) % 2 != 0) {
1835 log_warnx("invalid ND_OPT_RDNSS: length with"
1836 "out header is not multiply of 16: %d",
1837 (nd_opt_hdr->nd_opt_len - 1) * 8);
1838 return;
1839 }
1840 rdnss = (struct nd_opt_rdnss*) nd_opt_hdr;
1841 log_debug("\t\tND_OPT_RDNSS: lifetime: %u", ntohl(
1842 rdnss->nd_opt_rdnss_lifetime));
1843 in6 = (struct in6_addr*) (p + 6);
1844 for (i=0; i < (nd_opt_hdr->nd_opt_len - 1)/2; i++,
1845 in6++) {
1846 log_debug("\t\t\t%s", inet_ntop(AF_INET6, in6,
1847 ntopbuf, INET6_ADDRSTRLEN));
1848 }
1849 break;
1850 default:
1851 log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type);
1852 break;
1853
1854 }
1855 len -= nd_opt_hdr->nd_opt_len * 8 - 2;
1856 p += nd_opt_hdr->nd_opt_len * 8 - 2;
1857 }
1858 }
1859 #endif /* SMALL */
1860
update_iface_ra(struct slaacd_iface * iface,struct radv * ra)1861 void update_iface_ra(struct slaacd_iface *iface, struct radv *ra)
1862 {
1863 struct radv *old_ra;
1864 struct radv_prefix *prefix;
1865
1866 if ((old_ra = find_ra(iface, &ra->from)) == NULL)
1867 LIST_INSERT_HEAD(&iface->radvs, ra, entries);
1868 else {
1869 LIST_REPLACE(old_ra, ra, entries);
1870 merge_dad_couters(old_ra, ra);
1871 free_ra(old_ra);
1872 }
1873
1874 update_iface_ra_dfr(iface, ra);
1875
1876 LIST_FOREACH(prefix, &ra->prefixes, entries) {
1877 if (!prefix->autonomous || prefix->vltime == 0 ||
1878 prefix->pltime > prefix->vltime ||
1879 IN6_IS_ADDR_LINKLOCAL(&prefix->prefix))
1880 continue;
1881 update_iface_ra_prefix(iface, ra, prefix);
1882 }
1883
1884 update_iface_ra_rdns(iface, ra);
1885 }
1886
1887 void
update_iface_ra_dfr(struct slaacd_iface * iface,struct radv * ra)1888 update_iface_ra_dfr(struct slaacd_iface *iface, struct radv *ra)
1889 {
1890 struct dfr_proposal *dfr_proposal;
1891
1892 dfr_proposal = find_dfr_proposal_by_gw(iface, &ra->from);
1893
1894 if (ra->router_lifetime == 0) {
1895 free_dfr_proposal(dfr_proposal);
1896 return;
1897 }
1898
1899 if (!dfr_proposal) {
1900 /* new proposal */
1901 gen_dfr_proposal(iface, ra);
1902 return;
1903 }
1904
1905 dfr_proposal->when = ra->when;
1906 dfr_proposal->uptime = ra->uptime;
1907 dfr_proposal->router_lifetime = ra->router_lifetime;
1908
1909 log_debug("%s, dfr state: %s, rl: %d", __func__,
1910 proposal_state_name(dfr_proposal->state),
1911 real_lifetime(&dfr_proposal->uptime,
1912 dfr_proposal->router_lifetime));
1913
1914 switch (dfr_proposal->state) {
1915 case PROPOSAL_CONFIGURED:
1916 case PROPOSAL_NEARLY_EXPIRED:
1917 /* routes do not expire in the kernel, update timeout */
1918 dfr_proposal_state_transition(dfr_proposal,
1919 PROPOSAL_CONFIGURED);
1920 break;
1921 case PROPOSAL_IF_DOWN:
1922 case PROPOSAL_WITHDRAWN:
1923 log_debug("updating dfr");
1924 configure_dfr(dfr_proposal);
1925 break;
1926 default:
1927 log_debug("%s: iface %d: %s", __func__, iface->if_index,
1928 sin6_to_str(&dfr_proposal->addr));
1929 break;
1930 }
1931 }
1932
1933 void
update_iface_ra_prefix(struct slaacd_iface * iface,struct radv * ra,struct radv_prefix * prefix)1934 update_iface_ra_prefix(struct slaacd_iface *iface, struct radv *ra,
1935 struct radv_prefix *prefix)
1936 {
1937 struct address_proposal *addr_proposal;
1938 uint32_t pltime, vltime;
1939 int found, found_temporary, duplicate_found;
1940
1941 found = found_temporary = duplicate_found = 0;
1942
1943 if (!!iface->autoconf != !!iface->temporary) {
1944 struct address_proposal *tmp;
1945 /*
1946 * If only the autoconf or temporary flag is set, check if we
1947 * have the "other kind" of address configured and delete it.
1948 */
1949 LIST_FOREACH_SAFE (addr_proposal, &iface->addr_proposals,
1950 entries, tmp) {
1951 if ((!addr_proposal->temporary && !iface->autoconf) ||
1952 (addr_proposal->temporary && !iface->temporary))
1953 free_address_proposal(addr_proposal);
1954 }
1955 }
1956
1957 LIST_FOREACH(addr_proposal, &iface->addr_proposals, entries) {
1958 if (prefix->prefix_len == addr_proposal-> prefix_len &&
1959 memcmp(&prefix->prefix, &addr_proposal->prefix,
1960 sizeof(struct in6_addr)) != 0)
1961 continue;
1962
1963 if (memcmp(&addr_proposal->hw_address,
1964 &iface->hw_address,
1965 sizeof(addr_proposal->hw_address)) != 0)
1966 continue;
1967
1968 if (memcmp(&addr_proposal->soiikey, &iface->soiikey,
1969 sizeof(addr_proposal->soiikey)) != 0)
1970 continue;
1971
1972 if (addr_proposal->state == PROPOSAL_DUPLICATED) {
1973 duplicate_found = 1;
1974 continue;
1975 }
1976
1977 vltime = prefix->vltime;
1978
1979 if (addr_proposal->temporary) {
1980 struct timespec now;
1981 int64_t ltime, mtime;
1982
1983 if (clock_gettime(CLOCK_MONOTONIC, &now))
1984 fatal("clock_gettime");
1985
1986 mtime = addr_proposal->created.tv_sec +
1987 PRIV_PREFERRED_LIFETIME -
1988 addr_proposal->desync_factor;
1989
1990 ltime = MINIMUM(mtime, now.tv_sec + prefix->pltime) -
1991 now.tv_sec;
1992
1993 pltime = ltime > 0 ? ltime : 0;
1994
1995 ltime = MINIMUM(addr_proposal->created.tv_sec +
1996 PRIV_VALID_LIFETIME, now.tv_sec + vltime) -
1997 now.tv_sec;
1998 vltime = ltime > 0 ? ltime : 0;
1999
2000 if ((mtime - now.tv_sec) > PRIV_REGEN_ADVANCE)
2001 found_temporary = 1;
2002 } else {
2003 pltime = prefix->pltime;
2004 found = 1;
2005 }
2006
2007 addr_proposal->from = ra->from;
2008 addr_proposal->when = ra->when;
2009 addr_proposal->uptime = ra->uptime;
2010
2011 addr_proposal->vltime = vltime;
2012 addr_proposal->pltime = pltime;
2013
2014 if (ra->mtu == iface->cur_mtu)
2015 addr_proposal->mtu = 0;
2016 else {
2017 addr_proposal->mtu = ra->mtu;
2018 iface->cur_mtu = ra->mtu;
2019 }
2020
2021 log_debug("%s, addr state: %s", __func__,
2022 proposal_state_name(addr_proposal->state));
2023
2024 switch (addr_proposal->state) {
2025 case PROPOSAL_CONFIGURED:
2026 case PROPOSAL_NEARLY_EXPIRED:
2027 case PROPOSAL_IF_DOWN:
2028 case PROPOSAL_WITHDRAWN:
2029 log_debug("updating address");
2030 configure_address(addr_proposal);
2031 break;
2032 default:
2033 log_debug("%s: iface %d: %s", __func__, iface->if_index,
2034 sin6_to_str(&addr_proposal->addr));
2035 break;
2036 }
2037 }
2038
2039 if (!found && iface->autoconf && duplicate_found && iface->soii) {
2040 prefix->dad_counter++;
2041 log_debug("%s dad_counter: %d", __func__, prefix->dad_counter);
2042 gen_address_proposal(iface, ra, prefix, 0);
2043 } else if (!found && iface->autoconf && (iface->soii ||
2044 prefix->prefix_len <= 64))
2045 /* new proposal */
2046 gen_address_proposal(iface, ra, prefix, 0);
2047
2048 /* temporary addresses do not depend on eui64 */
2049 if (!found_temporary && iface->temporary) {
2050 if (prefix->pltime >= PRIV_REGEN_ADVANCE) {
2051 /* new temporary proposal */
2052 gen_address_proposal(iface, ra, prefix, 1);
2053 } else if (prefix->pltime > 0) {
2054 log_warnx("%s: pltime from %s is too small: %d < %d; "
2055 "not generating temporary address", __func__,
2056 sin6_to_str(&ra->from), prefix->pltime,
2057 PRIV_REGEN_ADVANCE);
2058 }
2059 }
2060 }
2061
2062 void
update_iface_ra_rdns(struct slaacd_iface * iface,struct radv * ra)2063 update_iface_ra_rdns(struct slaacd_iface *iface, struct radv *ra)
2064 {
2065 struct rdns_proposal *rdns_proposal;
2066 struct radv_rdns *radv_rdns;
2067 struct in6_addr rdns[MAX_RDNS_COUNT];
2068 int rdns_count;
2069
2070 rdns_proposal = find_rdns_proposal_by_gw(iface, &ra->from);
2071
2072 if (!rdns_proposal) {
2073 /* new proposal */
2074 if (!LIST_EMPTY(&ra->rdns_servers))
2075 gen_rdns_proposal(iface, ra);
2076 return;
2077 }
2078
2079 rdns_count = 0;
2080 memset(&rdns, 0, sizeof(rdns));
2081 LIST_FOREACH(radv_rdns, &ra->rdns_servers, entries) {
2082 memcpy(&rdns[rdns_count++],
2083 &radv_rdns->rdns, sizeof(struct in6_addr));
2084 if (rdns_proposal->rdns_count == MAX_RDNS_COUNT)
2085 break;
2086 }
2087
2088 if (rdns_count == 0) {
2089 free_rdns_proposal(rdns_proposal);
2090 return;
2091 }
2092
2093 if (rdns_proposal->rdns_count != rdns_count ||
2094 memcmp(&rdns_proposal->rdns, &rdns, sizeof(rdns)) != 0) {
2095 memcpy(&rdns_proposal->rdns, &rdns, sizeof(rdns));
2096 rdns_proposal->rdns_count = rdns_count;
2097 rdns_proposal->state = PROPOSAL_NOT_CONFIGURED;
2098 }
2099 rdns_proposal->when = ra->when;
2100 rdns_proposal->uptime = ra->uptime;
2101 rdns_proposal->rdns_lifetime = ra->rdns_lifetime;
2102
2103 log_debug("%s, rdns state: %s, rl: %d", __func__,
2104 proposal_state_name(rdns_proposal->state),
2105 real_lifetime(&rdns_proposal->uptime,
2106 rdns_proposal->rdns_lifetime));
2107
2108 switch (rdns_proposal->state) {
2109 case PROPOSAL_CONFIGURED:
2110 case PROPOSAL_NEARLY_EXPIRED:
2111 /* rdns are not expired by the kernel, update timeout */
2112 rdns_proposal_state_transition(rdns_proposal,
2113 PROPOSAL_CONFIGURED);
2114 break;
2115 case PROPOSAL_IF_DOWN:
2116 case PROPOSAL_WITHDRAWN:
2117 case PROPOSAL_NOT_CONFIGURED:
2118 log_debug("updating rdns");
2119 rdns_proposal_state_transition(rdns_proposal,
2120 PROPOSAL_CONFIGURED);
2121 compose_rdns_proposal(rdns_proposal->if_index,
2122 rdns_proposal->rdomain);
2123 break;
2124 default:
2125 log_debug("%s: iface %d: %s", __func__, iface->if_index,
2126 sin6_to_str(&rdns_proposal->from));
2127 break;
2128 }
2129 }
2130
2131
2132 void
configure_address(struct address_proposal * addr_proposal)2133 configure_address(struct address_proposal *addr_proposal)
2134 {
2135 struct imsg_configure_address address;
2136 struct slaacd_iface *iface;
2137
2138 log_debug("%s: %d", __func__, addr_proposal->if_index);
2139
2140 address.if_index = addr_proposal->if_index;
2141 memcpy(&address.addr, &addr_proposal->addr, sizeof(address.addr));
2142 memcpy(&address.gw, &addr_proposal->from, sizeof(address.gw));
2143 memcpy(&address.mask, &addr_proposal->mask, sizeof(address.mask));
2144 address.vltime = addr_proposal->vltime;
2145 address.pltime = addr_proposal->pltime;
2146 address.temporary = addr_proposal->temporary;
2147 address.mtu = addr_proposal->mtu;
2148
2149 engine_imsg_compose_main(IMSG_CONFIGURE_ADDRESS, 0, &address,
2150 sizeof(address));
2151
2152 if ((iface = get_slaacd_iface_by_id(addr_proposal->if_index)) != NULL)
2153 iface_state_transition(iface, IF_BOUND);
2154 addr_proposal_state_transition(addr_proposal, PROPOSAL_CONFIGURED);
2155 }
2156
2157 void
gen_address_proposal(struct slaacd_iface * iface,struct radv * ra,struct radv_prefix * prefix,int temporary)2158 gen_address_proposal(struct slaacd_iface *iface, struct radv *ra, struct
2159 radv_prefix *prefix, int temporary)
2160 {
2161 struct address_proposal *addr_proposal;
2162 const char *hbuf;
2163
2164 if ((addr_proposal = calloc(1, sizeof(*addr_proposal))) == NULL)
2165 fatal("calloc");
2166 addr_proposal->id = ++proposal_id;
2167 evtimer_set(&addr_proposal->timer, address_proposal_timeout,
2168 addr_proposal);
2169 addr_proposal->timo.tv_sec = 1;
2170 addr_proposal->timo.tv_usec = arc4random_uniform(1000000);
2171 addr_proposal->state = PROPOSAL_NOT_CONFIGURED;
2172 if (clock_gettime(CLOCK_MONOTONIC, &addr_proposal->created))
2173 fatal("clock_gettime");
2174 addr_proposal->when = ra->when;
2175 addr_proposal->uptime = ra->uptime;
2176 addr_proposal->if_index = iface->if_index;
2177 memcpy(&addr_proposal->from, &ra->from,
2178 sizeof(addr_proposal->from));
2179 memcpy(&addr_proposal->hw_address, &iface->hw_address,
2180 sizeof(addr_proposal->hw_address));
2181 memcpy(&addr_proposal->soiikey, &iface->soiikey,
2182 sizeof(addr_proposal->soiikey));
2183 addr_proposal->temporary = temporary;
2184 memcpy(&addr_proposal->prefix, &prefix->prefix,
2185 sizeof(addr_proposal->prefix));
2186 addr_proposal->prefix_len = prefix->prefix_len;
2187
2188 if (temporary) {
2189 addr_proposal->vltime = MINIMUM(prefix->vltime,
2190 PRIV_VALID_LIFETIME);
2191 addr_proposal->desync_factor =
2192 arc4random_uniform(PRIV_MAX_DESYNC_FACTOR);
2193
2194 addr_proposal->pltime = MINIMUM(prefix->pltime,
2195 PRIV_PREFERRED_LIFETIME - addr_proposal->desync_factor);
2196 } else {
2197 addr_proposal->vltime = prefix->vltime;
2198 addr_proposal->pltime = prefix->pltime;
2199 }
2200
2201 if (ra->mtu == iface->cur_mtu)
2202 addr_proposal->mtu = 0;
2203 else {
2204 addr_proposal->mtu = ra->mtu;
2205 iface->cur_mtu = ra->mtu;
2206 }
2207
2208 gen_addr(iface, prefix, addr_proposal, temporary);
2209
2210 LIST_INSERT_HEAD(&iface->addr_proposals, addr_proposal, entries);
2211 configure_address(addr_proposal);
2212
2213 hbuf = sin6_to_str(&addr_proposal->addr);
2214 log_debug("%s: iface %d: %s", __func__, iface->if_index, hbuf);
2215 }
2216
2217 void
free_address_proposal(struct address_proposal * addr_proposal)2218 free_address_proposal(struct address_proposal *addr_proposal)
2219 {
2220 if (addr_proposal == NULL)
2221 return;
2222
2223 LIST_REMOVE(addr_proposal, entries);
2224 evtimer_del(&addr_proposal->timer);
2225 switch (addr_proposal->state) {
2226 case PROPOSAL_CONFIGURED:
2227 case PROPOSAL_NEARLY_EXPIRED:
2228 case PROPOSAL_STALE:
2229 withdraw_addr(addr_proposal);
2230 break;
2231 default:
2232 break;
2233 }
2234 free(addr_proposal);
2235 }
2236
2237 void
withdraw_addr(struct address_proposal * addr_proposal)2238 withdraw_addr(struct address_proposal *addr_proposal)
2239 {
2240 struct imsg_configure_address address;
2241
2242 log_debug("%s: %d", __func__, addr_proposal->if_index);
2243 memset(&address, 0, sizeof(address));
2244 address.if_index = addr_proposal->if_index;
2245 memcpy(&address.addr, &addr_proposal->addr, sizeof(address.addr));
2246
2247 engine_imsg_compose_main(IMSG_WITHDRAW_ADDRESS, 0, &address,
2248 sizeof(address));
2249 }
2250
2251 void
gen_dfr_proposal(struct slaacd_iface * iface,struct radv * ra)2252 gen_dfr_proposal(struct slaacd_iface *iface, struct radv *ra)
2253 {
2254 struct dfr_proposal *dfr_proposal;
2255 const char *hbuf;
2256
2257 if ((dfr_proposal = calloc(1, sizeof(*dfr_proposal))) == NULL)
2258 fatal("calloc");
2259 dfr_proposal->id = ++proposal_id;
2260 evtimer_set(&dfr_proposal->timer, dfr_proposal_timeout,
2261 dfr_proposal);
2262 dfr_proposal->timo.tv_sec = 1;
2263 dfr_proposal->timo.tv_usec = arc4random_uniform(1000000);
2264 dfr_proposal->state = PROPOSAL_NOT_CONFIGURED;
2265 dfr_proposal->when = ra->when;
2266 dfr_proposal->uptime = ra->uptime;
2267 dfr_proposal->if_index = iface->if_index;
2268 dfr_proposal->rdomain = iface->rdomain;
2269 memcpy(&dfr_proposal->addr, &ra->from,
2270 sizeof(dfr_proposal->addr));
2271 dfr_proposal->router_lifetime = ra->router_lifetime;
2272 dfr_proposal->rpref = ra->rpref;
2273
2274 LIST_INSERT_HEAD(&iface->dfr_proposals, dfr_proposal, entries);
2275 configure_dfr(dfr_proposal);
2276
2277 hbuf = sin6_to_str(&dfr_proposal->addr);
2278 log_debug("%s: iface %d: %s", __func__, iface->if_index, hbuf);
2279 }
2280
2281 void
configure_dfr(struct dfr_proposal * dfr_proposal)2282 configure_dfr(struct dfr_proposal *dfr_proposal)
2283 {
2284 struct imsg_configure_dfr dfr;
2285
2286 log_debug("%s: %d", __func__, dfr_proposal->if_index);
2287
2288 dfr.if_index = dfr_proposal->if_index;
2289 dfr.rdomain = dfr_proposal->rdomain;
2290 memcpy(&dfr.addr, &dfr_proposal->addr, sizeof(dfr.addr));
2291 dfr.router_lifetime = dfr_proposal->router_lifetime;
2292
2293 engine_imsg_compose_main(IMSG_CONFIGURE_DFR, 0, &dfr, sizeof(dfr));
2294
2295 dfr_proposal_state_transition(dfr_proposal, PROPOSAL_CONFIGURED);
2296 }
2297
2298 void
withdraw_dfr(struct dfr_proposal * dfr_proposal)2299 withdraw_dfr(struct dfr_proposal *dfr_proposal)
2300 {
2301 struct imsg_configure_dfr dfr;
2302
2303 log_debug("%s: %d", __func__, dfr_proposal->if_index);
2304
2305 dfr.if_index = dfr_proposal->if_index;
2306 dfr.rdomain = dfr_proposal->rdomain;
2307 memcpy(&dfr.addr, &dfr_proposal->addr, sizeof(dfr.addr));
2308 dfr.router_lifetime = dfr_proposal->router_lifetime;
2309
2310 engine_imsg_compose_main(IMSG_WITHDRAW_DFR, 0, &dfr, sizeof(dfr));
2311 }
2312
2313 void
free_dfr_proposal(struct dfr_proposal * dfr_proposal)2314 free_dfr_proposal(struct dfr_proposal *dfr_proposal)
2315 {
2316 if (dfr_proposal == NULL)
2317 return;
2318
2319 LIST_REMOVE(dfr_proposal, entries);
2320 evtimer_del(&dfr_proposal->timer);
2321 switch (dfr_proposal->state) {
2322 case PROPOSAL_CONFIGURED:
2323 case PROPOSAL_NEARLY_EXPIRED:
2324 case PROPOSAL_STALE:
2325 withdraw_dfr(dfr_proposal);
2326 break;
2327 default:
2328 break;
2329 }
2330 free(dfr_proposal);
2331 }
2332
2333 void
gen_rdns_proposal(struct slaacd_iface * iface,struct radv * ra)2334 gen_rdns_proposal(struct slaacd_iface *iface, struct radv *ra)
2335 {
2336 struct rdns_proposal *rdns_proposal;
2337 struct radv_rdns *rdns;
2338 const char *hbuf;
2339
2340 if ((rdns_proposal = calloc(1, sizeof(*rdns_proposal))) == NULL)
2341 fatal("calloc");
2342 rdns_proposal->id = ++proposal_id;
2343 evtimer_set(&rdns_proposal->timer, rdns_proposal_timeout,
2344 rdns_proposal);
2345 rdns_proposal->timo.tv_sec = 1;
2346 rdns_proposal->timo.tv_usec = arc4random_uniform(1000000);
2347 rdns_proposal->state = PROPOSAL_NOT_CONFIGURED;
2348 rdns_proposal->when = ra->when;
2349 rdns_proposal->uptime = ra->uptime;
2350 rdns_proposal->if_index = iface->if_index;
2351 rdns_proposal->rdomain = iface->rdomain;
2352 memcpy(&rdns_proposal->from, &ra->from,
2353 sizeof(rdns_proposal->from));
2354 rdns_proposal->rdns_lifetime = ra->rdns_lifetime;
2355 LIST_FOREACH(rdns, &ra->rdns_servers, entries) {
2356 memcpy(&rdns_proposal->rdns[rdns_proposal->rdns_count++],
2357 &rdns->rdns, sizeof(struct in6_addr));
2358 if (rdns_proposal->rdns_count == MAX_RDNS_COUNT)
2359 break;
2360 }
2361
2362 LIST_INSERT_HEAD(&iface->rdns_proposals, rdns_proposal, entries);
2363 compose_rdns_proposal(iface->if_index, iface->rdomain);
2364
2365 hbuf = sin6_to_str(&rdns_proposal->from);
2366 log_debug("%s: iface %d: %s", __func__, iface->if_index, hbuf);
2367 }
2368
2369 void
compose_rdns_proposal(uint32_t if_index,int rdomain)2370 compose_rdns_proposal(uint32_t if_index, int rdomain)
2371 {
2372 struct imsg_propose_rdns rdns;
2373 struct slaacd_iface *iface;
2374 struct rdns_proposal *rdns_proposal;
2375 int i;
2376
2377 memset(&rdns, 0, sizeof(rdns));
2378 rdns.if_index = if_index;
2379 rdns.rdomain = rdomain;
2380
2381 if ((iface = get_slaacd_iface_by_id(if_index)) != NULL) {
2382 LIST_FOREACH(rdns_proposal, &iface->rdns_proposals, entries) {
2383 if (rdns_proposal->state == PROPOSAL_WITHDRAWN ||
2384 rdns_proposal->state == PROPOSAL_STALE)
2385 continue;
2386 rdns_proposal_state_transition(rdns_proposal,
2387 PROPOSAL_CONFIGURED);
2388 for (i = 0; i < rdns_proposal->rdns_count &&
2389 rdns.rdns_count < MAX_RDNS_COUNT; i++) {
2390 rdns.rdns[rdns.rdns_count++] =
2391 rdns_proposal->rdns[i];
2392 }
2393 }
2394 }
2395
2396 engine_imsg_compose_main(IMSG_PROPOSE_RDNS, 0, &rdns, sizeof(rdns));
2397 }
2398
2399 void
free_rdns_proposal(struct rdns_proposal * rdns_proposal)2400 free_rdns_proposal(struct rdns_proposal *rdns_proposal)
2401 {
2402 if (rdns_proposal == NULL)
2403 return;
2404
2405 LIST_REMOVE(rdns_proposal, entries);
2406 evtimer_del(&rdns_proposal->timer);
2407 switch (rdns_proposal->state) {
2408 case PROPOSAL_CONFIGURED:
2409 case PROPOSAL_NEARLY_EXPIRED:
2410 case PROPOSAL_STALE:
2411 withdraw_rdns(rdns_proposal);
2412 break;
2413 default:
2414 break;
2415 }
2416 free(rdns_proposal);
2417 }
2418
2419 void
withdraw_rdns(struct rdns_proposal * rdns_proposal)2420 withdraw_rdns(struct rdns_proposal *rdns_proposal)
2421 {
2422 log_debug("%s: %d", __func__, rdns_proposal->if_index);
2423
2424 rdns_proposal->state = PROPOSAL_WITHDRAWN;
2425
2426 /* we have to re-propose all rdns servers, minus one */
2427 compose_rdns_proposal(rdns_proposal->if_index, rdns_proposal->rdomain);
2428 }
2429
2430 void
address_proposal_timeout(int fd,short events,void * arg)2431 address_proposal_timeout(int fd, short events, void *arg)
2432 {
2433 struct address_proposal *addr_proposal;
2434 struct slaacd_iface *iface = NULL;
2435 struct radv *ra = NULL;
2436 struct radv_prefix *prefix = NULL;
2437 const char *hbuf;
2438
2439 addr_proposal = (struct address_proposal *)arg;
2440
2441 hbuf = sin6_to_str(&addr_proposal->addr);
2442 log_debug("%s: iface %d: %s [%s], priv: %s", __func__,
2443 addr_proposal->if_index, hbuf,
2444 proposal_state_name(addr_proposal->state),
2445 addr_proposal->temporary ? "y" : "n");
2446
2447 switch (addr_proposal->state) {
2448 case PROPOSAL_IF_DOWN:
2449 addr_proposal_state_transition(addr_proposal, PROPOSAL_STALE);
2450 break;
2451 case PROPOSAL_CONFIGURED:
2452 addr_proposal_state_transition(addr_proposal,
2453 PROPOSAL_NEARLY_EXPIRED);
2454 break;
2455 case PROPOSAL_NEARLY_EXPIRED:
2456 if (real_lifetime(&addr_proposal->uptime,
2457 addr_proposal->vltime) > 0)
2458 addr_proposal_state_transition(addr_proposal,
2459 PROPOSAL_NEARLY_EXPIRED);
2460 else
2461 addr_proposal_state_transition(addr_proposal,
2462 PROPOSAL_STALE);
2463 break;
2464 case PROPOSAL_DUPLICATED:
2465 iface = get_slaacd_iface_by_id(addr_proposal->if_index);
2466 if (iface != NULL)
2467 ra = find_ra(iface, &addr_proposal->from);
2468 if (ra != NULL)
2469 prefix = find_prefix(ra, &addr_proposal->prefix,
2470 addr_proposal->prefix_len);
2471 if (prefix != NULL) {
2472 if (!addr_proposal->temporary) {
2473 prefix->dad_counter++;
2474 gen_address_proposal(iface, ra, prefix, 0);
2475 } else
2476 gen_address_proposal(iface, ra, prefix, 1);
2477 }
2478 addr_proposal_state_transition(addr_proposal, PROPOSAL_STALE);
2479 break;
2480 case PROPOSAL_STALE:
2481 free_address_proposal(addr_proposal);
2482 addr_proposal = NULL;
2483 break;
2484 case PROPOSAL_WITHDRAWN:
2485 free_address_proposal(addr_proposal);
2486 addr_proposal = NULL;
2487 break;
2488 default:
2489 log_debug("%s: unhandled state: %s", __func__,
2490 proposal_state_name(addr_proposal->state));
2491 }
2492 }
2493
2494 void
dfr_proposal_timeout(int fd,short events,void * arg)2495 dfr_proposal_timeout(int fd, short events, void *arg)
2496 {
2497 struct dfr_proposal *dfr_proposal;
2498 const char *hbuf;
2499
2500 dfr_proposal = (struct dfr_proposal *)arg;
2501
2502 hbuf = sin6_to_str(&dfr_proposal->addr);
2503 log_debug("%s: iface %d: %s [%s]", __func__, dfr_proposal->if_index,
2504 hbuf, proposal_state_name(dfr_proposal->state));
2505
2506 switch (dfr_proposal->state) {
2507 case PROPOSAL_IF_DOWN:
2508 dfr_proposal_state_transition(dfr_proposal, PROPOSAL_STALE);
2509 break;
2510 case PROPOSAL_CONFIGURED:
2511 dfr_proposal_state_transition(dfr_proposal,
2512 PROPOSAL_NEARLY_EXPIRED);
2513 break;
2514 case PROPOSAL_NEARLY_EXPIRED:
2515 if (real_lifetime(&dfr_proposal->uptime,
2516 dfr_proposal->router_lifetime) > 0)
2517 dfr_proposal_state_transition(dfr_proposal,
2518 PROPOSAL_NEARLY_EXPIRED);
2519 else
2520 dfr_proposal_state_transition(dfr_proposal,
2521 PROPOSAL_STALE);
2522 break;
2523 case PROPOSAL_STALE:
2524 free_dfr_proposal(dfr_proposal);
2525 dfr_proposal = NULL;
2526 break;
2527 case PROPOSAL_WITHDRAWN:
2528 free_dfr_proposal(dfr_proposal);
2529 dfr_proposal = NULL;
2530 break;
2531
2532 default:
2533 log_debug("%s: unhandled state: %s", __func__,
2534 proposal_state_name(dfr_proposal->state));
2535 }
2536 }
2537
2538 void
rdns_proposal_timeout(int fd,short events,void * arg)2539 rdns_proposal_timeout(int fd, short events, void *arg)
2540 {
2541 struct rdns_proposal *rdns_proposal;
2542 const char *hbuf;
2543
2544 rdns_proposal = (struct rdns_proposal *)arg;
2545
2546 hbuf = sin6_to_str(&rdns_proposal->from);
2547 log_debug("%s: iface %d: %s [%s]", __func__, rdns_proposal->if_index,
2548 hbuf, proposal_state_name(rdns_proposal->state));
2549
2550 switch (rdns_proposal->state) {
2551 case PROPOSAL_IF_DOWN:
2552 rdns_proposal_state_transition(rdns_proposal, PROPOSAL_STALE);
2553 break;
2554 case PROPOSAL_CONFIGURED:
2555 rdns_proposal_state_transition(rdns_proposal,
2556 PROPOSAL_NEARLY_EXPIRED);
2557 break;
2558 case PROPOSAL_NEARLY_EXPIRED:
2559 if (real_lifetime(&rdns_proposal->uptime,
2560 rdns_proposal->rdns_lifetime) > 0)
2561 rdns_proposal_state_transition(rdns_proposal,
2562 PROPOSAL_NEARLY_EXPIRED);
2563 else
2564 rdns_proposal_state_transition(rdns_proposal,
2565 PROPOSAL_STALE);
2566 break;
2567 case PROPOSAL_STALE:
2568 free_rdns_proposal(rdns_proposal);
2569 rdns_proposal = NULL;
2570 break;
2571 case PROPOSAL_WITHDRAWN:
2572 free_rdns_proposal(rdns_proposal);
2573 rdns_proposal = NULL;
2574 break;
2575
2576 default:
2577 log_debug("%s: unhandled state: %s", __func__,
2578 proposal_state_name(rdns_proposal->state));
2579 }
2580 }
2581
2582 void
iface_timeout(int fd,short events,void * arg)2583 iface_timeout(int fd, short events, void *arg)
2584 {
2585 struct slaacd_iface *iface = (struct slaacd_iface *)arg;
2586
2587 log_debug("%s[%d]: %s", __func__, iface->if_index,
2588 if_state_name(iface->state));
2589
2590 switch (iface->state) {
2591 case IF_DOWN:
2592 fatalx("%s: timeout in wrong state IF_DOWN", __func__);
2593 break;
2594 case IF_INIT:
2595 iface_state_transition(iface, IF_INIT);
2596 break;
2597 default:
2598 break;
2599 }
2600 }
2601
2602 struct radv*
find_ra(struct slaacd_iface * iface,struct sockaddr_in6 * from)2603 find_ra(struct slaacd_iface *iface, struct sockaddr_in6 *from)
2604 {
2605 struct radv *ra;
2606
2607 LIST_FOREACH (ra, &iface->radvs, entries) {
2608 if (memcmp(&ra->from.sin6_addr, &from->sin6_addr,
2609 sizeof(from->sin6_addr)) == 0)
2610 return (ra);
2611 }
2612
2613 return (NULL);
2614 }
2615
2616 struct address_proposal*
find_address_proposal_by_addr(struct slaacd_iface * iface,struct sockaddr_in6 * addr)2617 find_address_proposal_by_addr(struct slaacd_iface *iface, struct sockaddr_in6
2618 *addr)
2619 {
2620 struct address_proposal *addr_proposal;
2621
2622 LIST_FOREACH (addr_proposal, &iface->addr_proposals, entries) {
2623 if (memcmp(&addr_proposal->addr, addr, sizeof(*addr)) == 0)
2624 return (addr_proposal);
2625 }
2626
2627 return (NULL);
2628 }
2629
2630 struct dfr_proposal*
find_dfr_proposal_by_gw(struct slaacd_iface * iface,struct sockaddr_in6 * addr)2631 find_dfr_proposal_by_gw(struct slaacd_iface *iface, struct sockaddr_in6
2632 *addr)
2633 {
2634 struct dfr_proposal *dfr_proposal;
2635
2636 LIST_FOREACH (dfr_proposal, &iface->dfr_proposals, entries) {
2637 if (memcmp(&dfr_proposal->addr, addr, sizeof(*addr)) == 0)
2638 return (dfr_proposal);
2639 }
2640
2641 return (NULL);
2642 }
2643
2644 struct rdns_proposal*
find_rdns_proposal_by_gw(struct slaacd_iface * iface,struct sockaddr_in6 * from)2645 find_rdns_proposal_by_gw(struct slaacd_iface *iface, struct sockaddr_in6
2646 *from)
2647 {
2648 struct rdns_proposal *rdns_proposal;
2649
2650 LIST_FOREACH (rdns_proposal, &iface->rdns_proposals, entries) {
2651 if (memcmp(&rdns_proposal->from, from, sizeof(*from)) == 0)
2652 return (rdns_proposal);
2653 }
2654
2655 return (NULL);
2656 }
2657
2658 struct radv_prefix *
find_prefix(struct radv * ra,struct in6_addr * prefix,uint8_t prefix_len)2659 find_prefix(struct radv *ra, struct in6_addr *prefix, uint8_t prefix_len)
2660 {
2661 struct radv_prefix *result;
2662
2663
2664 LIST_FOREACH(result, &ra->prefixes, entries) {
2665 if (memcmp(&result->prefix, prefix,
2666 sizeof(result->prefix)) == 0 && result->prefix_len ==
2667 prefix_len)
2668 return (result);
2669 }
2670 return (NULL);
2671 }
2672
2673 uint32_t
real_lifetime(struct timespec * received_uptime,uint32_t ltime)2674 real_lifetime(struct timespec *received_uptime, uint32_t ltime)
2675 {
2676 struct timespec now, diff;
2677 int64_t remaining;
2678
2679 if (clock_gettime(CLOCK_MONOTONIC, &now))
2680 fatal("clock_gettime");
2681
2682 timespecsub(&now, received_uptime, &diff);
2683
2684 remaining = ((int64_t)ltime) - diff.tv_sec;
2685
2686 if (remaining < 0)
2687 remaining = 0;
2688
2689 return (remaining);
2690 }
2691
2692 void
merge_dad_couters(struct radv * old_ra,struct radv * new_ra)2693 merge_dad_couters(struct radv *old_ra, struct radv *new_ra)
2694 {
2695
2696 struct radv_prefix *old_prefix, *new_prefix;
2697
2698 LIST_FOREACH(old_prefix, &old_ra->prefixes, entries) {
2699 if (!old_prefix->dad_counter)
2700 continue;
2701 if ((new_prefix = find_prefix(new_ra, &old_prefix->prefix,
2702 old_prefix->prefix_len)) != NULL)
2703 new_prefix->dad_counter = old_prefix->dad_counter;
2704 }
2705 }
2706