Bug Summary

File:src/usr.sbin/rad/rad.c
Warning:line 177, column 2
Value stored to 'argv' is never read

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 rad.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/usr.sbin/rad/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/rad -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/rad/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/usr.sbin/rad/rad.c
1/* $OpenBSD: rad.c,v 1.27 2021/02/27 10:35:20 florian Exp $ */
2
3/*
4 * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
5 * Copyright (c) 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#include <sys/types.h>
22#include <sys/queue.h>
23#include <sys/socket.h>
24#include <sys/syslog.h>
25#include <sys/uio.h>
26#include <sys/wait.h>
27
28#include <netinet/in.h>
29#include <net/if.h>
30#include <net/route.h>
31#include <netinet/in.h>
32#include <netinet/if_ether.h>
33#include <netinet6/in6_var.h>
34#include <netinet/icmp6.h>
35
36#include <err.h>
37#include <errno(*__errno()).h>
38#include <event.h>
39#include <fcntl.h>
40#include <imsg.h>
41#include <netdb.h>
42#include <pwd.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <signal.h>
47#include <unistd.h>
48
49#include "log.h"
50#include "rad.h"
51#include "frontend.h"
52#include "engine.h"
53#include "control.h"
54
55enum rad_process {
56 PROC_MAIN,
57 PROC_ENGINE,
58 PROC_FRONTEND
59};
60
61__dead__attribute__((__noreturn__)) void usage(void);
62__dead__attribute__((__noreturn__)) void main_shutdown(void);
63
64void main_sig_handler(int, short, void *);
65
66static pid_t start_child(enum rad_process, char *, int, int, int);
67
68void main_dispatch_frontend(int, short, void *);
69void main_dispatch_engine(int, short, void *);
70void open_icmp6sock(int);
71
72static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *);
73static int main_imsg_send_config(struct rad_conf *);
74
75int main_reload(void);
76int main_sendboth(enum imsg_type, void *, uint16_t);
77
78void in6_prefixlen2mask(struct in6_addr *, int len);
79
80struct rad_conf *main_conf;
81static struct imsgev *iev_frontend;
82static struct imsgev *iev_engine;
83char *conffile;
84pid_t frontend_pid;
85pid_t engine_pid;
86uint32_t cmd_opts;
87
88void
89main_sig_handler(int sig, short event, void *arg)
90{
91 /*
92 * Normal signal handler rules don't apply because libevent
93 * decouples for us.
94 */
95
96 switch (sig) {
97 case SIGTERM15:
98 case SIGINT2:
99 main_shutdown();
100 break;
101 case SIGHUP1:
102 if (main_reload() == -1)
103 log_warnx("configuration reload failed");
104 else
105 log_debug("configuration reloaded");
106 break;
107 default:
108 fatalx("unexpected signal");
109 }
110}
111
112__dead__attribute__((__noreturn__)) void
113usage(void)
114{
115 extern char *__progname;
116
117 fprintf(stderr(&__sF[2]), "usage: %s [-dnv] [-f file] [-s socket]\n",
118 __progname);
119 exit(1);
120}
121
122int
123main(int argc, char *argv[])
124{
125 struct event ev_sigint, ev_sigterm, ev_sighup;
126 int ch;
127 int debug = 0, engine_flag = 0, frontend_flag = 0;
128 char *saved_argv0;
129 int pipe_main2frontend[2];
130 int pipe_main2engine[2];
131 int frontend_routesock, rtfilter;
132 int rtable_any = RTABLE_ANY0xffffffff;
133 int control_fd;
134 char *csock;
135
136 conffile = _PATH_CONF_FILE"/etc/rad.conf";
137 csock = _PATH_RAD_SOCKET"/var/run/rad.sock";
138
139 log_init(1, LOG_DAEMON(3<<3)); /* Log to stderr until daemonized. */
140 log_setverbose(1);
141
142 saved_argv0 = argv[0];
143 if (saved_argv0 == NULL((void *)0))
144 saved_argv0 = "rad";
145
146 while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) {
147 switch (ch) {
148 case 'd':
149 debug = 1;
150 break;
151 case 'E':
152 engine_flag = 1;
153 break;
154 case 'F':
155 frontend_flag = 1;
156 break;
157 case 'f':
158 conffile = optarg;
159 break;
160 case 'n':
161 cmd_opts |= OPT_NOACTION0x00000004;
162 break;
163 case 's':
164 csock = optarg;
165 break;
166 case 'v':
167 if (cmd_opts & OPT_VERBOSE0x00000001)
168 cmd_opts |= OPT_VERBOSE20x00000002;
169 cmd_opts |= OPT_VERBOSE0x00000001;
170 break;
171 default:
172 usage();
173 }
174 }
175
176 argc -= optind;
177 argv += optind;
Value stored to 'argv' is never read
178 if (argc > 0 || (engine_flag && frontend_flag))
179 usage();
180
181 if (engine_flag)
182 engine(debug, cmd_opts & OPT_VERBOSE0x00000001);
183 else if (frontend_flag)
184 frontend(debug, cmd_opts & OPT_VERBOSE0x00000001);
185
186 /* parse config file */
187 if ((main_conf = parse_config(conffile)) == NULL((void *)0)) {
188 exit(1);
189 }
190
191 if (cmd_opts & OPT_NOACTION0x00000004) {
192 if (cmd_opts & OPT_VERBOSE0x00000001)
193 print_config(main_conf);
194 else
195 fprintf(stderr(&__sF[2]), "configuration OK\n");
196 exit(0);
197 }
198
199 /* Check for root privileges. */
200 if (geteuid())
201 errx(1, "need root privileges");
202
203 /* Check for assigned daemon user */
204 if (getpwnam(RAD_USER"_rad") == NULL((void *)0))
205 errx(1, "unknown user %s", RAD_USER"_rad");
206
207 log_init(debug, LOG_DAEMON(3<<3));
208 log_setverbose(cmd_opts & OPT_VERBOSE0x00000001);
209
210 if (!debug)
211 daemon(1, 0);
212
213 log_info("startup");
214
215 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
216 PF_UNSPEC0, pipe_main2frontend) == -1)
217 fatal("main2frontend socketpair");
218 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
219 PF_UNSPEC0, pipe_main2engine) == -1)
220 fatal("main2engine socketpair");
221
222 /* Start children. */
223 engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1],
224 debug, cmd_opts & OPT_VERBOSE0x00000001);
225 frontend_pid = start_child(PROC_FRONTEND, saved_argv0,
226 pipe_main2frontend[1], debug, cmd_opts & OPT_VERBOSE0x00000001);
227
228 log_procinit("main");
229
230 event_init();
231
232 /* Setup signal handler. */
233 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, main_sig_handler, ((void
*)0))
;
234 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, main_sig_handler, (
(void *)0))
;
235 signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL)event_set(&ev_sighup, 1, 0x08|0x10, main_sig_handler, ((void
*)0))
;
236 signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0));
237 signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0));
238 signal_add(&ev_sighup, NULL)event_add(&ev_sighup, ((void *)0));
239 signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
240
241 /* Setup pipes to children. */
242
243 if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL((void *)0) ||
244 (iev_engine = malloc(sizeof(struct imsgev))) == NULL((void *)0))
245 fatal(NULL((void *)0));
246 imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]);
247 iev_frontend->handler = main_dispatch_frontend;
248 imsg_init(&iev_engine->ibuf, pipe_main2engine[0]);
249 iev_engine->handler = main_dispatch_engine;
250
251 /* Setup event handlers for pipes to engine & frontend. */
252 iev_frontend->events = EV_READ0x02;
253 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
254 iev_frontend->events, iev_frontend->handler, iev_frontend);
255 event_add(&iev_frontend->ev, NULL((void *)0));
256
257 iev_engine->events = EV_READ0x02;
258 event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events,
259 iev_engine->handler, iev_engine);
260 event_add(&iev_engine->ev, NULL((void *)0));
261
262 if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf))
263 fatal("could not establish imsg links");
264
265 if ((frontend_routesock = socket(AF_ROUTE17, SOCK_RAW3 | SOCK_CLOEXEC0x8000,
266 AF_INET624)) == -1)
267 fatal("route socket");
268
269 rtfilter = ROUTE_FILTER(RTM_IFINFO)(1 << (0xe)) | ROUTE_FILTER(RTM_NEWADDR)(1 << (0xc)) |
270 ROUTE_FILTER(RTM_DELADDR)(1 << (0xd)) | ROUTE_FILTER(RTM_CHGADDRATTR)(1 << (0x14));
271 if (setsockopt(frontend_routesock, AF_ROUTE17, ROUTE_MSGFILTER1,
272 &rtfilter, sizeof(rtfilter)) == -1)
273 fatal("setsockopt(ROUTE_MSGFILTER)");
274 if (setsockopt(frontend_routesock, AF_ROUTE17, ROUTE_TABLEFILTER2,
275 &rtable_any, sizeof(rtable_any)) == -1)
276 fatal("setsockopt(ROUTE_TABLEFILTER)");
277
278 if ((control_fd = control_init(csock)) == -1)
279 fatalx("control socket setup failed");
280
281 main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock,
282 NULL((void *)0), 0);
283 main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL((void *)0), 0);
284 main_imsg_send_config(main_conf);
285
286 if (pledge("stdio inet rpath sendfd mcast wroute", NULL((void *)0)) == -1)
287 fatal("pledge");
288
289 main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL((void *)0), 0);
290
291 event_dispatch();
292
293 main_shutdown();
294 return (0);
295}
296
297__dead__attribute__((__noreturn__)) void
298main_shutdown(void)
299{
300 pid_t pid;
301 int status;
302
303 /* Close pipes. */
304 msgbuf_clear(&iev_frontend->ibuf.w);
305 close(iev_frontend->ibuf.fd);
306 msgbuf_clear(&iev_engine->ibuf.w);
307 close(iev_engine->ibuf.fd);
308
309 config_clear(main_conf);
310
311 log_debug("waiting for children to terminate");
312 do {
313 pid = wait(&status);
314 if (pid == -1) {
315 if (errno(*__errno()) != EINTR4 && errno(*__errno()) != ECHILD10)
316 fatal("wait");
317 } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177
) != 0)
)
318 log_warnx("%s terminated; signal %d",
319 (pid == engine_pid) ? "engine" :
320 "frontend", WTERMSIG(status)(((status) & 0177)));
321 } while (pid != -1 || (pid == -1 && errno(*__errno()) == EINTR4));
322
323 free(iev_frontend);
324 free(iev_engine);
325
326 log_info("terminating");
327 exit(0);
328}
329
330static pid_t
331start_child(enum rad_process p, char *argv0, int fd, int debug, int verbose)
332{
333 char *argv[6];
334 int argc = 0;
335 pid_t pid;
336
337 switch (pid = fork()) {
338 case -1:
339 fatal("cannot fork");
340 case 0:
341 break;
342 default:
343 close(fd);
344 return (pid);
345 }
346
347 if (fd != 3) {
348 if (dup2(fd, 3) == -1)
349 fatal("cannot setup imsg fd");
350 } else if (fcntl(fd, F_SETFD2, 0) == -1)
351 fatal("cannot setup imsg fd");
352
353 argv[argc++] = argv0;
354 switch (p) {
355 case PROC_MAIN:
356 fatalx("Can not start main process");
357 case PROC_ENGINE:
358 argv[argc++] = "-E";
359 break;
360 case PROC_FRONTEND:
361 argv[argc++] = "-F";
362 break;
363 }
364 if (debug)
365 argv[argc++] = "-d";
366 if (verbose)
367 argv[argc++] = "-v";
368 argv[argc++] = NULL((void *)0);
369
370 execvp(argv0, argv);
371 fatal("execvp");
372}
373
374void
375main_dispatch_frontend(int fd, short event, void *bula)
376{
377 struct imsgev *iev = bula;
378 struct imsgbuf *ibuf;
379 struct imsg imsg;
380 ssize_t n;
381 int shut = 0, verbose;
382 int rdomain;
383
384 ibuf = &iev->ibuf;
385
386 if (event & EV_READ0x02) {
387 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
388 fatal("imsg_read error");
389 if (n == 0) /* Connection closed. */
390 shut = 1;
391 }
392 if (event & EV_WRITE0x04) {
393 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
394 fatal("msgbuf_write");
395 if (n == 0) /* Connection closed. */
396 shut = 1;
397 }
398
399 for (;;) {
400 if ((n = imsg_get(ibuf, &imsg)) == -1)
401 fatal("imsg_get");
402 if (n == 0) /* No more messages. */
403 break;
404
405 switch (imsg.hdr.type) {
406 case IMSG_OPEN_ICMP6SOCK:
407 log_debug("IMSG_OPEN_ICMP6SOCK");
408 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(rdomain))
409 fatalx("%s: IMSG_OPEN_ICMP6SOCK wrong length: "
410 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
411 memcpy(&rdomain, imsg.data, sizeof(rdomain));
412 open_icmp6sock(rdomain);
413 break;
414 case IMSG_CTL_RELOAD:
415 if (main_reload() == -1)
416 log_warnx("configuration reload failed");
417 else
418 log_warnx("configuration reloaded");
419 break;
420 case IMSG_CTL_LOG_VERBOSE:
421 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(verbose))
422 fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
423 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
424 memcpy(&verbose, imsg.data, sizeof(verbose));
425 log_setverbose(verbose);
426 break;
427 default:
428 log_debug("%s: error handling imsg %d", __func__,
429 imsg.hdr.type);
430 break;
431 }
432 imsg_free(&imsg);
433 }
434 if (!shut)
435 imsg_event_add(iev);
436 else {
437 /* This pipe is dead. Remove its event handler */
438 event_del(&iev->ev);
439 event_loopexit(NULL((void *)0));
440 }
441}
442
443void
444main_dispatch_engine(int fd, short event, void *bula)
445{
446 struct imsgev *iev = bula;
447 struct imsgbuf *ibuf;
448 struct imsg imsg;
449 ssize_t n;
450 int shut = 0;
451
452 ibuf = &iev->ibuf;
453
454 if (event & EV_READ0x02) {
455 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
456 fatal("imsg_read error");
457 if (n == 0) /* Connection closed. */
458 shut = 1;
459 }
460 if (event & EV_WRITE0x04) {
461 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
462 fatal("msgbuf_write");
463 if (n == 0) /* Connection closed. */
464 shut = 1;
465 }
466
467 for (;;) {
468 if ((n = imsg_get(ibuf, &imsg)) == -1)
469 fatal("imsg_get");
470 if (n == 0) /* No more messages. */
471 break;
472
473 switch (imsg.hdr.type) {
474 default:
475 log_debug("%s: error handling imsg %d", __func__,
476 imsg.hdr.type);
477 break;
478 }
479 imsg_free(&imsg);
480 }
481 if (!shut)
482 imsg_event_add(iev);
483 else {
484 /* This pipe is dead. Remove its event handler. */
485 event_del(&iev->ev);
486 event_loopexit(NULL((void *)0));
487 }
488}
489
490int
491main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen)
492{
493 if (iev_frontend)
494 return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data,
495 datalen));
496 else
497 return (-1);
498}
499
500void
501main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen)
502{
503 if (iev_engine)
504 imsg_compose_event(iev_engine, type, 0, pid, -1, data,
505 datalen);
506}
507
508void
509imsg_event_add(struct imsgev *iev)
510{
511 iev->events = EV_READ0x02;
512 if (iev->ibuf.w.queued)
513 iev->events |= EV_WRITE0x04;
514
515 event_del(&iev->ev);
516 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
517 event_add(&iev->ev, NULL((void *)0));
518}
519
520int
521imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
522 pid_t pid, int fd, void *data, uint16_t datalen)
523{
524 int ret;
525
526 if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data,
527 datalen)) != -1)
528 imsg_event_add(iev);
529
530 return (ret);
531}
532
533static int
534main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf,
535 struct imsgbuf *engine_buf)
536{
537 int pipe_frontend2engine[2];
538
539 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
540 PF_UNSPEC0, pipe_frontend2engine) == -1)
541 return (-1);
542
543 if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0,
544 pipe_frontend2engine[0], NULL((void *)0), 0) == -1)
545 return (-1);
546 if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0,
547 pipe_frontend2engine[1], NULL((void *)0), 0) == -1)
548 return (-1);
549
550 return (0);
551}
552
553int
554main_reload(void)
555{
556 struct rad_conf *xconf;
557
558 if ((xconf = parse_config(conffile)) == NULL((void *)0))
559 return (-1);
560
561 if (main_imsg_send_config(xconf) == -1)
562 return (-1);
563
564 merge_config(main_conf, xconf);
565
566 return (0);
567}
568
569int
570main_imsg_send_config(struct rad_conf *xconf)
571{
572 struct ra_iface_conf *ra_iface_conf;
573 struct ra_prefix_conf *ra_prefix_conf;
574 struct ra_rdnss_conf *ra_rdnss_conf;
575 struct ra_dnssl_conf *ra_dnssl_conf;
576
577 /* Send fixed part of config to children. */
578 if (main_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1)
579 return (-1);
580
581 /* send global dns options to children */
582 SIMPLEQ_FOREACH(ra_rdnss_conf, &xconf->ra_options.ra_rdnss_list,for((ra_rdnss_conf) = ((&xconf->ra_options.ra_rdnss_list
)->sqh_first); (ra_rdnss_conf) != ((void *)0); (ra_rdnss_conf
) = ((ra_rdnss_conf)->entry.sqe_next))
583 entry)for((ra_rdnss_conf) = ((&xconf->ra_options.ra_rdnss_list
)->sqh_first); (ra_rdnss_conf) != ((void *)0); (ra_rdnss_conf
) = ((ra_rdnss_conf)->entry.sqe_next))
{
584 if (main_sendboth(IMSG_RECONF_RA_RDNSS, ra_rdnss_conf,
585 sizeof(*ra_rdnss_conf)) == -1)
586 return (-1);
587 }
588 SIMPLEQ_FOREACH(ra_dnssl_conf, &xconf->ra_options.ra_dnssl_list,for((ra_dnssl_conf) = ((&xconf->ra_options.ra_dnssl_list
)->sqh_first); (ra_dnssl_conf) != ((void *)0); (ra_dnssl_conf
) = ((ra_dnssl_conf)->entry.sqe_next))
589 entry)for((ra_dnssl_conf) = ((&xconf->ra_options.ra_dnssl_list
)->sqh_first); (ra_dnssl_conf) != ((void *)0); (ra_dnssl_conf
) = ((ra_dnssl_conf)->entry.sqe_next))
{
590 if (main_sendboth(IMSG_RECONF_RA_DNSSL, ra_dnssl_conf,
591 sizeof(*ra_dnssl_conf)) == -1)
592 return (-1);
593 }
594
595 /* Send the interface list to children. */
596 SIMPLEQ_FOREACH(ra_iface_conf, &xconf->ra_iface_list, entry)for((ra_iface_conf) = ((&xconf->ra_iface_list)->sqh_first
); (ra_iface_conf) != ((void *)0); (ra_iface_conf) = ((ra_iface_conf
)->entry.sqe_next))
{
597 if (main_sendboth(IMSG_RECONF_RA_IFACE, ra_iface_conf,
598 sizeof(*ra_iface_conf)) == -1)
599 return (-1);
600 if (ra_iface_conf->autoprefix) {
601 if (main_sendboth(IMSG_RECONF_RA_AUTOPREFIX,
602 ra_iface_conf->autoprefix,
603 sizeof(*ra_iface_conf->autoprefix)) == -1)
604 return (-1);
605 }
606 SIMPLEQ_FOREACH(ra_prefix_conf, &ra_iface_conf->ra_prefix_list,for((ra_prefix_conf) = ((&ra_iface_conf->ra_prefix_list
)->sqh_first); (ra_prefix_conf) != ((void *)0); (ra_prefix_conf
) = ((ra_prefix_conf)->entry.sqe_next))
607 entry)for((ra_prefix_conf) = ((&ra_iface_conf->ra_prefix_list
)->sqh_first); (ra_prefix_conf) != ((void *)0); (ra_prefix_conf
) = ((ra_prefix_conf)->entry.sqe_next))
{
608 if (main_sendboth(IMSG_RECONF_RA_PREFIX,
609 ra_prefix_conf, sizeof(*ra_prefix_conf)) == -1)
610 return (-1);
611 }
612 SIMPLEQ_FOREACH(ra_rdnss_conf,for((ra_rdnss_conf) = ((&ra_iface_conf->ra_options.ra_rdnss_list
)->sqh_first); (ra_rdnss_conf) != ((void *)0); (ra_rdnss_conf
) = ((ra_rdnss_conf)->entry.sqe_next))
613 &ra_iface_conf->ra_options.ra_rdnss_list, entry)for((ra_rdnss_conf) = ((&ra_iface_conf->ra_options.ra_rdnss_list
)->sqh_first); (ra_rdnss_conf) != ((void *)0); (ra_rdnss_conf
) = ((ra_rdnss_conf)->entry.sqe_next))
{
614 if (main_sendboth(IMSG_RECONF_RA_RDNSS, ra_rdnss_conf,
615 sizeof(*ra_rdnss_conf)) == -1)
616 return (-1);
617 }
618 SIMPLEQ_FOREACH(ra_dnssl_conf,for((ra_dnssl_conf) = ((&ra_iface_conf->ra_options.ra_dnssl_list
)->sqh_first); (ra_dnssl_conf) != ((void *)0); (ra_dnssl_conf
) = ((ra_dnssl_conf)->entry.sqe_next))
619 &ra_iface_conf->ra_options.ra_dnssl_list, entry)for((ra_dnssl_conf) = ((&ra_iface_conf->ra_options.ra_dnssl_list
)->sqh_first); (ra_dnssl_conf) != ((void *)0); (ra_dnssl_conf
) = ((ra_dnssl_conf)->entry.sqe_next))
{
620 if (main_sendboth(IMSG_RECONF_RA_DNSSL, ra_dnssl_conf,
621 sizeof(*ra_dnssl_conf)) == -1)
622 return (-1);
623 }
624 }
625
626 /* Tell children the revised config is now complete. */
627 if (main_sendboth(IMSG_RECONF_END, NULL((void *)0), 0) == -1)
628 return (-1);
629
630 return (0);
631}
632
633int
634main_sendboth(enum imsg_type type, void *buf, uint16_t len)
635{
636 if (imsg_compose_event(iev_frontend, type, 0, 0, -1, buf, len) == -1)
637 return (-1);
638 if (imsg_compose_event(iev_engine, type, 0, 0, -1, buf, len) == -1)
639 return (-1);
640 return (0);
641}
642
643void
644free_ra_iface_conf(struct ra_iface_conf *ra_iface_conf)
645{
646 struct ra_prefix_conf *prefix;
647
648 if (!ra_iface_conf)
649 return;
650
651 free(ra_iface_conf->autoprefix);
652
653 while ((prefix = SIMPLEQ_FIRST(&ra_iface_conf->ra_prefix_list)((&ra_iface_conf->ra_prefix_list)->sqh_first)) !=
654 NULL((void *)0)) {
655 SIMPLEQ_REMOVE_HEAD(&ra_iface_conf->ra_prefix_list, entry)do { if (((&ra_iface_conf->ra_prefix_list)->sqh_first
= (&ra_iface_conf->ra_prefix_list)->sqh_first->
entry.sqe_next) == ((void *)0)) (&ra_iface_conf->ra_prefix_list
)->sqh_last = &(&ra_iface_conf->ra_prefix_list)
->sqh_first; } while (0)
;
656 free(prefix);
657 }
658
659 free_dns_options(&ra_iface_conf->ra_options);
660
661 free(ra_iface_conf);
662}
663
664void
665free_dns_options(struct ra_options_conf *ra_options)
666{
667 struct ra_rdnss_conf *ra_rdnss;
668 struct ra_dnssl_conf *ra_dnssl;
669
670 while ((ra_rdnss = SIMPLEQ_FIRST(&ra_options->ra_rdnss_list)((&ra_options->ra_rdnss_list)->sqh_first)) != NULL((void *)0)) {
671 SIMPLEQ_REMOVE_HEAD(&ra_options->ra_rdnss_list, entry)do { if (((&ra_options->ra_rdnss_list)->sqh_first =
(&ra_options->ra_rdnss_list)->sqh_first->entry.
sqe_next) == ((void *)0)) (&ra_options->ra_rdnss_list)
->sqh_last = &(&ra_options->ra_rdnss_list)->
sqh_first; } while (0)
;
672 free(ra_rdnss);
673 }
674 ra_options->rdnss_count = 0;
675
676 while ((ra_dnssl = SIMPLEQ_FIRST(&ra_options->ra_dnssl_list)((&ra_options->ra_dnssl_list)->sqh_first)) != NULL((void *)0)) {
677 SIMPLEQ_REMOVE_HEAD(&ra_options->ra_dnssl_list, entry)do { if (((&ra_options->ra_dnssl_list)->sqh_first =
(&ra_options->ra_dnssl_list)->sqh_first->entry.
sqe_next) == ((void *)0)) (&ra_options->ra_dnssl_list)
->sqh_last = &(&ra_options->ra_dnssl_list)->
sqh_first; } while (0)
;
678 free(ra_dnssl);
679 }
680 ra_options->dnssl_len = 0;
681}
682
683void
684merge_config(struct rad_conf *conf, struct rad_conf *xconf)
685{
686 struct ra_iface_conf *ra_iface_conf;
687
688 /* Remove & discard existing interfaces. */
689 while ((ra_iface_conf = SIMPLEQ_FIRST(&conf->ra_iface_list)((&conf->ra_iface_list)->sqh_first)) != NULL((void *)0)) {
690 SIMPLEQ_REMOVE_HEAD(&conf->ra_iface_list, entry)do { if (((&conf->ra_iface_list)->sqh_first = (&
conf->ra_iface_list)->sqh_first->entry.sqe_next) == (
(void *)0)) (&conf->ra_iface_list)->sqh_last = &
(&conf->ra_iface_list)->sqh_first; } while (0)
;
691 free_ra_iface_conf(ra_iface_conf);
692 }
693 free_dns_options(&conf->ra_options);
694
695 conf->ra_options = xconf->ra_options;
696 SIMPLEQ_INIT(&conf->ra_options.ra_rdnss_list)do { (&conf->ra_options.ra_rdnss_list)->sqh_first =
((void *)0); (&conf->ra_options.ra_rdnss_list)->sqh_last
= &(&conf->ra_options.ra_rdnss_list)->sqh_first
; } while (0)
;
697 SIMPLEQ_INIT(&conf->ra_options.ra_dnssl_list)do { (&conf->ra_options.ra_dnssl_list)->sqh_first =
((void *)0); (&conf->ra_options.ra_dnssl_list)->sqh_last
= &(&conf->ra_options.ra_dnssl_list)->sqh_first
; } while (0)
;
698
699 /* Add new interfaces. */
700 SIMPLEQ_CONCAT(&conf->ra_iface_list, &xconf->ra_iface_list)do { if (!((((&xconf->ra_iface_list))->sqh_first) ==
((void *)0))) { *(&conf->ra_iface_list)->sqh_last =
(&xconf->ra_iface_list)->sqh_first; (&conf->
ra_iface_list)->sqh_last = (&xconf->ra_iface_list)->
sqh_last; do { ((&xconf->ra_iface_list))->sqh_first
= ((void *)0); ((&xconf->ra_iface_list))->sqh_last
= &((&xconf->ra_iface_list))->sqh_first; } while
(0); } } while (0)
;
701
702 /* Add dns options */
703 SIMPLEQ_CONCAT(&conf->ra_options.ra_rdnss_list,do { if (!((((&xconf->ra_options.ra_rdnss_list))->sqh_first
) == ((void *)0))) { *(&conf->ra_options.ra_rdnss_list
)->sqh_last = (&xconf->ra_options.ra_rdnss_list)->
sqh_first; (&conf->ra_options.ra_rdnss_list)->sqh_last
= (&xconf->ra_options.ra_rdnss_list)->sqh_last; do
{ ((&xconf->ra_options.ra_rdnss_list))->sqh_first =
((void *)0); ((&xconf->ra_options.ra_rdnss_list))->
sqh_last = &((&xconf->ra_options.ra_rdnss_list))->
sqh_first; } while (0); } } while (0)
704 &xconf->ra_options.ra_rdnss_list)do { if (!((((&xconf->ra_options.ra_rdnss_list))->sqh_first
) == ((void *)0))) { *(&conf->ra_options.ra_rdnss_list
)->sqh_last = (&xconf->ra_options.ra_rdnss_list)->
sqh_first; (&conf->ra_options.ra_rdnss_list)->sqh_last
= (&xconf->ra_options.ra_rdnss_list)->sqh_last; do
{ ((&xconf->ra_options.ra_rdnss_list))->sqh_first =
((void *)0); ((&xconf->ra_options.ra_rdnss_list))->
sqh_last = &((&xconf->ra_options.ra_rdnss_list))->
sqh_first; } while (0); } } while (0)
;
705 SIMPLEQ_CONCAT(&conf->ra_options.ra_dnssl_list,do { if (!((((&xconf->ra_options.ra_dnssl_list))->sqh_first
) == ((void *)0))) { *(&conf->ra_options.ra_dnssl_list
)->sqh_last = (&xconf->ra_options.ra_dnssl_list)->
sqh_first; (&conf->ra_options.ra_dnssl_list)->sqh_last
= (&xconf->ra_options.ra_dnssl_list)->sqh_last; do
{ ((&xconf->ra_options.ra_dnssl_list))->sqh_first =
((void *)0); ((&xconf->ra_options.ra_dnssl_list))->
sqh_last = &((&xconf->ra_options.ra_dnssl_list))->
sqh_first; } while (0); } } while (0)
706 &xconf->ra_options.ra_dnssl_list)do { if (!((((&xconf->ra_options.ra_dnssl_list))->sqh_first
) == ((void *)0))) { *(&conf->ra_options.ra_dnssl_list
)->sqh_last = (&xconf->ra_options.ra_dnssl_list)->
sqh_first; (&conf->ra_options.ra_dnssl_list)->sqh_last
= (&xconf->ra_options.ra_dnssl_list)->sqh_last; do
{ ((&xconf->ra_options.ra_dnssl_list))->sqh_first =
((void *)0); ((&xconf->ra_options.ra_dnssl_list))->
sqh_last = &((&xconf->ra_options.ra_dnssl_list))->
sqh_first; } while (0); } } while (0)
;
707 free(xconf);
708}
709
710struct rad_conf *
711config_new_empty(void)
712{
713 struct rad_conf *xconf;
714
715 xconf = calloc(1, sizeof(*xconf));
716 if (xconf == NULL((void *)0))
717 fatal(NULL((void *)0));
718
719 SIMPLEQ_INIT(&xconf->ra_iface_list)do { (&xconf->ra_iface_list)->sqh_first = ((void *)
0); (&xconf->ra_iface_list)->sqh_last = &(&
xconf->ra_iface_list)->sqh_first; } while (0)
;
720
721 xconf->ra_options.dfr = 1;
722 xconf->ra_options.cur_hl = 0;
723 xconf->ra_options.m_flag = 0;
724 xconf->ra_options.o_flag = 0;
725 xconf->ra_options.router_lifetime = ADV_DEFAULT_LIFETIME3 * 600;
726 xconf->ra_options.reachable_time = 0;
727 xconf->ra_options.retrans_timer = 0;
728 xconf->ra_options.mtu = 0;
729 xconf->ra_options.rdns_lifetime = DEFAULT_RDNS_LIFETIME600 * 1.5;
730 SIMPLEQ_INIT(&xconf->ra_options.ra_rdnss_list)do { (&xconf->ra_options.ra_rdnss_list)->sqh_first =
((void *)0); (&xconf->ra_options.ra_rdnss_list)->sqh_last
= &(&xconf->ra_options.ra_rdnss_list)->sqh_first
; } while (0)
;
731 SIMPLEQ_INIT(&xconf->ra_options.ra_dnssl_list)do { (&xconf->ra_options.ra_dnssl_list)->sqh_first =
((void *)0); (&xconf->ra_options.ra_dnssl_list)->sqh_last
= &(&xconf->ra_options.ra_dnssl_list)->sqh_first
; } while (0)
;
732
733 return (xconf);
734}
735
736void
737config_clear(struct rad_conf *conf)
738{
739 struct rad_conf *xconf;
740
741 /* Merge current config with an empty config. */
742 xconf = config_new_empty();
743 merge_config(conf, xconf);
744
745 free(conf);
746}
747
748void
749mask_prefix(struct in6_addr* in6, int len)
750{
751 uint8_t bitmask[8] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
752 int i, skip;
753
754 if (len < 0 || len > 128)
755 fatalx("invalid prefix length: %d", len);
756
757 skip = len / 8;
758
759 if (skip < 16)
760 in6->s6_addr__u6_addr.__u6_addr8[skip] &= bitmask[len % 8];
761
762 for (i = skip + 1; i < 16; i++)
763 in6->s6_addr__u6_addr.__u6_addr8[i] = 0;
764}
765
766const char*
767sin6_to_str(struct sockaddr_in6 *sin6)
768{
769 static char hbuf[NI_MAXHOST256];
770 int error;
771
772 error = getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, hbuf,
773 sizeof(hbuf), NULL((void *)0), 0, NI_NUMERICHOST1 | NI_NUMERICSERV2);
774 if (error) {
775 log_warnx("%s", gai_strerror(error));
776 strlcpy(hbuf, "unknown", sizeof(hbuf));
777 }
778 return hbuf;
779}
780
781const char*
782in6_to_str(struct in6_addr *in6)
783{
784
785 struct sockaddr_in6 sin6;
786
787 memset(&sin6, 0, sizeof(sin6));
788 sin6.sin6_len = sizeof(sin6);
789 sin6.sin6_family = AF_INET624;
790 sin6.sin6_addr = *in6;
791
792 return (sin6_to_str(&sin6));
793}
794
795void
796open_icmp6sock(int rdomain)
797{
798 int icmp6sock, on = 1, off = 0;
799
800 log_debug("%s: %d", __func__, rdomain);
801
802 if ((icmp6sock = socket(AF_INET624, SOCK_RAW3 | SOCK_CLOEXEC0x8000,
803 IPPROTO_ICMPV658)) == -1)
804 fatal("ICMPv6 socket");
805
806 if (setsockopt(icmp6sock, IPPROTO_IPV641, IPV6_RECVPKTINFO36, &on,
807 sizeof(on)) == -1)
808 fatal("IPV6_RECVPKTINFO");
809
810 if (setsockopt(icmp6sock, IPPROTO_IPV641, IPV6_RECVHOPLIMIT37, &on,
811 sizeof(on)) == -1)
812 fatal("IPV6_RECVHOPLIMIT");
813
814 if (setsockopt(icmp6sock, IPPROTO_IPV641, IPV6_MULTICAST_LOOP11, &off,
815 sizeof(off)) == -1)
816 fatal("IPV6_RECVHOPLIMIT");
817
818 if (setsockopt(icmp6sock, SOL_SOCKET0xffff, SO_RTABLE0x1021, &rdomain,
819 sizeof(rdomain)) == -1) {
820 /* we might race against removal of the rdomain */
821 log_warn("setsockopt SO_RTABLE");
822 close(icmp6sock);
823 return;
824 }
825
826 main_imsg_compose_frontend(IMSG_ICMP6SOCK, icmp6sock, &rdomain,
827 sizeof(rdomain));
828}