Bug Summary

File:src/sbin/slaacd/engine.c
Warning:line 2550, column 24
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

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