Bug Summary

File:src/sbin/slaacd/slaacd.c
Warning:line 168, 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 slaacd.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/slaacd.c
1/* $OpenBSD: slaacd.c,v 1.64 2021/08/24 14:56:06 florian Exp $ */
2
3/*
4 * Copyright (c) 2017 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/ioctl.h>
23#include <sys/queue.h>
24#include <sys/socket.h>
25#include <sys/syslog.h>
26#include <sys/sysctl.h>
27#include <sys/uio.h>
28#include <sys/wait.h>
29
30#include <net/if.h>
31#include <net/route.h>
32#include <netinet/in.h>
33#include <netinet/if_ether.h>
34#include <netinet6/in6_var.h>
35#include <netinet/icmp6.h>
36
37#include <err.h>
38#include <errno(*__errno()).h>
39#include <fcntl.h>
40#include <event.h>
41#include <imsg.h>
42#include <netdb.h>
43#include <pwd.h>
44#include <stddef.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <signal.h>
49#include <unistd.h>
50
51#include "log.h"
52#include "slaacd.h"
53#include "frontend.h"
54#include "engine.h"
55#include "control.h"
56
57enum slaacd_process {
58 PROC_MAIN,
59 PROC_ENGINE,
60 PROC_FRONTEND
61};
62
63__dead__attribute__((__noreturn__)) void usage(void);
64__dead__attribute__((__noreturn__)) void main_shutdown(void);
65
66void main_sig_handler(int, short, void *);
67
68static pid_t start_child(enum slaacd_process, char *, int, int, int);
69
70void main_dispatch_frontend(int, short, void *);
71void main_dispatch_engine(int, short, void *);
72void open_icmp6sock(int);
73void configure_interface(struct imsg_configure_address *);
74void delete_address(struct imsg_configure_address *);
75void configure_gateway(struct imsg_configure_dfr *, uint8_t);
76void add_gateway(struct imsg_configure_dfr *);
77void delete_gateway(struct imsg_configure_dfr *);
78void send_rdns_proposal(struct imsg_propose_rdns *);
79int get_soiikey(uint8_t *);
80
81static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *);
82int main_imsg_compose_frontend(int, int, void *, uint16_t);
83int main_imsg_compose_engine(int, pid_t, void *, uint16_t);
84
85static struct imsgev *iev_frontend;
86static struct imsgev *iev_engine;
87
88pid_t frontend_pid;
89pid_t engine_pid;
90
91int routesock, ioctl_sock, rtm_seq = 0;
92
93void
94main_sig_handler(int sig, short event, void *arg)
95{
96 /*
97 * Normal signal handler rules don't apply because libevent
98 * decouples for us.
99 */
100
101 switch (sig) {
102 case SIGTERM15:
103 case SIGINT2:
104 main_shutdown();
105 default:
106 fatalx("unexpected signal");
107 }
108}
109
110__dead__attribute__((__noreturn__)) void
111usage(void)
112{
113 extern char *__progname;
114
115 fprintf(stderr(&__sF[2]), "usage: %s [-dv] [-s socket]\n",
116 __progname);
117 exit(1);
118}
119
120int
121main(int argc, char *argv[])
122{
123 struct event ev_sigint, ev_sigterm;
124 int ch;
125 int debug = 0, engine_flag = 0, frontend_flag = 0;
126 int verbose = 0;
127 char *saved_argv0;
128 int pipe_main2frontend[2];
129 int pipe_main2engine[2];
130 int frontend_routesock, rtfilter, lockfd;
131 int rtable_any = RTABLE_ANY0xffffffff;
132 char *csock = _PATH_SLAACD_SOCKET"/dev/slaacd.sock";
133 struct imsg_propose_rdns rdns;
134#ifndef SMALL
135 int control_fd;
136#endif /* SMALL */
137
138 log_init(1, LOG_DAEMON(3<<3)); /* Log to stderr until daemonized. */
139 log_setverbose(1);
140
141 saved_argv0 = argv[0];
142 if (saved_argv0 == NULL((void*)0))
143 saved_argv0 = "slaacd";
144
145 while ((ch = getopt(argc, argv, "dEFs:v")) != -1) {
146 switch (ch) {
147 case 'd':
148 debug = 1;
149 break;
150 case 'E':
151 engine_flag = 1;
152 break;
153 case 'F':
154 frontend_flag = 1;
155 break;
156 case 's':
157 csock = optarg;
158 break;
159 case 'v':
160 verbose++;
161 break;
162 default:
163 usage();
164 }
165 }
166
167 argc -= optind;
168 argv += optind;
Value stored to 'argv' is never read
169 if (argc > 0 || (engine_flag && frontend_flag))
170 usage();
171
172 if (engine_flag)
173 engine(debug, verbose);
174 else if (frontend_flag)
175 frontend(debug, verbose);
176
177 /* Check for root privileges. */
178 if (geteuid())
179 errx(1, "need root privileges");
180
181 lockfd = open(_PATH_LOCKFILE"/dev/slaacd.lock", O_CREAT0x0200|O_RDWR0x0002|O_EXLOCK0x0020|O_NONBLOCK0x0004, 0600);
182 if (lockfd == -1)
183 errx(1, "already running");
184
185 /* Check for assigned daemon user */
186 if (getpwnam(SLAACD_USER"_slaacd") == NULL((void*)0))
187 errx(1, "unknown user %s", SLAACD_USER"_slaacd");
188
189 log_init(debug, LOG_DAEMON(3<<3));
190 log_setverbose(verbose);
191
192 if (!debug)
193 daemon(0, 0);
194
195 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
196 PF_UNSPEC0, pipe_main2frontend) == -1)
197 fatal("main2frontend socketpair");
198 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
199 PF_UNSPEC0, pipe_main2engine) == -1)
200 fatal("main2engine socketpair");
201
202 /* Start children. */
203 engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1],
204 debug, verbose);
205 frontend_pid = start_child(PROC_FRONTEND, saved_argv0,
206 pipe_main2frontend[1], debug, verbose);
207
208 log_procinit("main");
209
210 if ((routesock = socket(AF_ROUTE17, SOCK_RAW3 | SOCK_CLOEXEC0x8000 |
211 SOCK_NONBLOCK0x4000, AF_INET624)) == -1)
212 fatal("route socket");
213 shutdown(SHUT_RD0, routesock);
214
215 event_init();
216
217 /* Setup signal handler. */
218 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, main_sig_handler, ((void
*)0))
;
219 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, main_sig_handler, (
(void*)0))
;
220 signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void*)0));
221 signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void*)0));
222 signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
223 signal(SIGHUP1, SIG_IGN(void (*)(int))1);
224
225 /* Setup pipes to children. */
226
227 if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL((void*)0) ||
228 (iev_engine = malloc(sizeof(struct imsgev))) == NULL((void*)0))
229 fatal(NULL((void*)0));
230 imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]);
231 iev_frontend->handler = main_dispatch_frontend;
232 imsg_init(&iev_engine->ibuf, pipe_main2engine[0]);
233 iev_engine->handler = main_dispatch_engine;
234
235 /* Setup event handlers for pipes to engine & frontend. */
236 iev_frontend->events = EV_READ0x02;
237 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
238 iev_frontend->events, iev_frontend->handler, iev_frontend);
239 event_add(&iev_frontend->ev, NULL((void*)0));
240
241 iev_engine->events = EV_READ0x02;
242 event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events,
243 iev_engine->handler, iev_engine);
244 event_add(&iev_engine->ev, NULL((void*)0));
245
246 if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf))
247 fatal("could not establish imsg links");
248
249 if ((ioctl_sock = socket(AF_INET624, SOCK_DGRAM2 | SOCK_CLOEXEC0x8000, 0)) == -1)
250 fatal("socket");
251
252 if ((frontend_routesock = socket(AF_ROUTE17, SOCK_RAW3 | SOCK_CLOEXEC0x8000,
253 AF_INET624)) == -1)
254 fatal("route socket");
255
256 rtfilter = ROUTE_FILTER(RTM_IFINFO)(1 << (0xe)) | ROUTE_FILTER(RTM_NEWADDR)(1 << (0xc)) |
257 ROUTE_FILTER(RTM_DELADDR)(1 << (0xd)) | ROUTE_FILTER(RTM_DELETE)(1 << (0x2)) |
258 ROUTE_FILTER(RTM_CHGADDRATTR)(1 << (0x14)) | ROUTE_FILTER(RTM_PROPOSAL)(1 << (0x13)) |
259 ROUTE_FILTER(RTM_IFANNOUNCE)(1 << (0xf));
260 if (setsockopt(frontend_routesock, AF_ROUTE17, ROUTE_MSGFILTER1,
261 &rtfilter, sizeof(rtfilter)) == -1)
262 fatal("setsockopt(ROUTE_MSGFILTER)");
263 if (setsockopt(frontend_routesock, AF_ROUTE17, ROUTE_TABLEFILTER2,
264 &rtable_any, sizeof(rtable_any)) == -1)
265 fatal("setsockopt(ROUTE_TABLEFILTER)");
266
267#ifndef SMALL
268 if ((control_fd = control_init(csock)) == -1)
269 warnx("control socket setup failed");
270#endif /* SMALL */
271
272 if (pledge("stdio inet sendfd wroute", NULL((void*)0)) == -1)
273 fatal("pledge");
274
275 main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, NULL((void*)0), 0);
276
277#ifndef SMALL
278 if (control_fd != -1)
279 main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL((void*)0), 0);
280#endif /* SMALL */
281
282 main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL((void*)0), 0);
283
284 /* we are taking over, clear all previos slaac proposals */
285 memset(&rdns, 0, sizeof(rdns));
286 rdns.if_index = 0;
287 rdns.rdns_count = 0;
288 send_rdns_proposal(&rdns);
289
290 event_dispatch();
291
292 main_shutdown();
293 return (0);
294}
295
296__dead__attribute__((__noreturn__)) void
297main_shutdown(void)
298{
299 pid_t pid;
300 int status;
301
302 /* Close pipes. */
303 msgbuf_clear(&iev_frontend->ibuf.w);
304 close(iev_frontend->ibuf.fd);
305 msgbuf_clear(&iev_engine->ibuf.w);
306 close(iev_engine->ibuf.fd);
307
308 log_debug("waiting for children to terminate");
309 do {
310 pid = wait(&status);
311 if (pid == -1) {
312 if (errno(*__errno()) != EINTR4 && errno(*__errno()) != ECHILD10)
313 fatal("wait");
314 } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177
) != 0)
)
315 log_warnx("%s terminated; signal %d",
316 (pid == engine_pid) ? "engine" :
317 "frontend", WTERMSIG(status)(((status) & 0177)));
318 } while (pid != -1 || (pid == -1 && errno(*__errno()) == EINTR4));
319
320 free(iev_frontend);
321 free(iev_engine);
322
323 log_info("terminating");
324 exit(0);
325}
326
327static pid_t
328start_child(enum slaacd_process p, char *argv0, int fd, int debug, int verbose)
329{
330 char *argv[7];
331 int argc = 0;
332 pid_t pid;
333
334 switch (pid = fork()) {
335 case -1:
336 fatal("cannot fork");
337 case 0:
338 break;
339 default:
340 close(fd);
341 return (pid);
342 }
343
344 if (fd != 3) {
345 if (dup2(fd, 3) == -1)
346 fatal("cannot setup imsg fd");
347 } else if (fcntl(fd, F_SETFD2, 0) == -1)
348 fatal("cannot setup imsg fd");
349
350 argv[argc++] = argv0;
351 switch (p) {
352 case PROC_MAIN:
353 fatalx("Can not start main process");
354 case PROC_ENGINE:
355 argv[argc++] = "-E";
356 break;
357 case PROC_FRONTEND:
358 argv[argc++] = "-F";
359 break;
360 }
361 if (debug)
362 argv[argc++] = "-d";
363 if (verbose)
364 argv[argc++] = "-v";
365 if (verbose > 1)
366 argv[argc++] = "-v";
367 argv[argc++] = NULL((void*)0);
368
369 execvp(argv0, argv);
370 fatal("execvp");
371}
372
373void
374main_dispatch_frontend(int fd, short event, void *bula)
375{
376 struct imsgev *iev = bula;
377 struct imsgbuf *ibuf;
378 struct imsg imsg;
379 struct imsg_ifinfo imsg_ifinfo;
380 ssize_t n;
381 int shut = 0;
382 int rdomain;
383#ifndef SMALL
384 struct imsg_addrinfo imsg_addrinfo;
385 int verbose;
386#endif /* SMALL */
387
388 ibuf = &iev->ibuf;
389
390 if (event & EV_READ0x02) {
391 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
392 fatal("imsg_read error");
393 if (n == 0) /* Connection closed. */
394 shut = 1;
395 }
396 if (event & EV_WRITE0x04) {
397 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
398 fatal("msgbuf_write");
399 if (n == 0) /* Connection closed. */
400 shut = 1;
401 }
402
403 for (;;) {
404 if ((n = imsg_get(ibuf, &imsg)) == -1)
405 fatal("imsg_get");
406 if (n == 0) /* No more messages. */
407 break;
408
409 switch (imsg.hdr.type) {
410 case IMSG_OPEN_ICMP6SOCK:
411 log_debug("IMSG_OPEN_ICMP6SOCK");
412 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(rdomain))
413 fatalx("%s: IMSG_OPEN_ICMP6SOCK wrong length: "
414 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
415 memcpy(&rdomain, imsg.data, sizeof(rdomain));
416 open_icmp6sock(rdomain);
417 break;
418#ifndef SMALL
419 case IMSG_CTL_LOG_VERBOSE:
420 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(verbose))
421 fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
422 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
423 memcpy(&verbose, imsg.data, sizeof(verbose));
424 log_setverbose(verbose);
425 break;
426 case IMSG_UPDATE_ADDRESS:
427 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(imsg_addrinfo))
428 fatalx("%s: IMSG_UPDATE_ADDRESS wrong length: "
429 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
430 memcpy(&imsg_addrinfo, imsg.data,
431 sizeof(imsg_addrinfo));
432 main_imsg_compose_engine(IMSG_UPDATE_ADDRESS, 0,
433 &imsg_addrinfo, sizeof(imsg_addrinfo));
434 break;
435#endif /* SMALL */
436 case IMSG_UPDATE_IF:
437 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(imsg_ifinfo))
438 fatalx("%s: IMSG_UPDATE_IF wrong length: %lu",
439 __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
440 memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo));
441 if (get_soiikey(imsg_ifinfo.soiikey) == -1)
442 log_warn("get_soiikey");
443 else
444 main_imsg_compose_engine(IMSG_UPDATE_IF, 0,
445 &imsg_ifinfo, sizeof(imsg_ifinfo));
446 break;
447 default:
448 log_debug("%s: error handling imsg %d", __func__,
449 imsg.hdr.type);
450 break;
451 }
452 imsg_free(&imsg);
453 }
454 if (!shut)
455 imsg_event_add(iev);
456 else {
457 /* This pipe is dead. Remove its event handler */
458 event_del(&iev->ev);
459 event_loopexit(NULL((void*)0));
460 }
461}
462
463void
464main_dispatch_engine(int fd, short event, void *bula)
465{
466 struct imsgev *iev = bula;
467 struct imsgbuf *ibuf;
468 struct imsg imsg;
469 struct imsg_configure_address address;
470 struct imsg_configure_dfr dfr;
471 struct imsg_propose_rdns rdns;
472 ssize_t n;
473 int shut = 0;
474
475 ibuf = &iev->ibuf;
476
477 if (event & EV_READ0x02) {
478 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
479 fatal("imsg_read error");
480 if (n == 0) /* Connection closed. */
481 shut = 1;
482 }
483 if (event & EV_WRITE0x04) {
484 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
485 fatal("msgbuf_write");
486 if (n == 0) /* Connection closed. */
487 shut = 1;
488 }
489
490 for (;;) {
491 if ((n = imsg_get(ibuf, &imsg)) == -1)
492 fatal("imsg_get");
493 if (n == 0) /* No more messages. */
494 break;
495
496 switch (imsg.hdr.type) {
497 case IMSG_CONFIGURE_ADDRESS:
498 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(address))
499 fatalx("%s: IMSG_CONFIGURE_ADDRESS wrong "
500 "length: %lu", __func__,
501 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
502 memcpy(&address, imsg.data, sizeof(address));
503 configure_interface(&address);
504 break;
505 case IMSG_WITHDRAW_ADDRESS:
506 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(address))
507 fatalx("%s: IMSG_WITHDRAW_ADDRESS wrong "
508 "length: %lu", __func__,
509 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
510 memcpy(&address, imsg.data, sizeof(address));
511 delete_address(&address);
512 break;
513 case IMSG_CONFIGURE_DFR:
514 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(dfr))
515 fatalx("%s: IMSG_CONFIGURE_DFR wrong "
516 "length: %lu", __func__,
517 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
518 memcpy(&dfr, imsg.data, sizeof(dfr));
519 add_gateway(&dfr);
520 break;
521 case IMSG_WITHDRAW_DFR:
522 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(dfr))
523 fatalx("%s: IMSG_WITHDRAW_DFR wrong "
524 "length: %lu", __func__,
525 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
526 memcpy(&dfr, imsg.data, sizeof(dfr));
527 delete_gateway(&dfr);
528 break;
529 case IMSG_PROPOSE_RDNS:
530 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(rdns))
531 fatalx("%s: IMSG_PROPOSE_RDNS wrong "
532 "length: %lu", __func__,
533 IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
534 memcpy(&rdns, imsg.data, sizeof(rdns));
535 if ((2 + rdns.rdns_count * sizeof(struct in6_addr)) >
536 sizeof(struct sockaddr_rtdns))
537 fatalx("%s: rdns_count too big: %d", __func__,
538 rdns.rdns_count);
539 send_rdns_proposal(&rdns);
540 break;
541 default:
542 log_debug("%s: error handling imsg %d", __func__,
543 imsg.hdr.type);
544 break;
545 }
546 imsg_free(&imsg);
547 }
548 if (!shut)
549 imsg_event_add(iev);
550 else {
551 /* This pipe is dead. Remove its event handler. */
552 event_del(&iev->ev);
553 event_loopexit(NULL((void*)0));
554 }
555}
556
557int
558main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen)
559{
560 if (iev_frontend)
561 return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data,
562 datalen));
563 else
564 return (-1);
565}
566
567int
568main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen)
569{
570 if (iev_engine)
571 return(imsg_compose_event(iev_engine, type, 0, pid, -1, data,
572 datalen));
573 else
574 return (-1);
575}
576
577void
578imsg_event_add(struct imsgev *iev)
579{
580 iev->events = EV_READ0x02;
581 if (iev->ibuf.w.queued)
582 iev->events |= EV_WRITE0x04;
583
584 event_del(&iev->ev);
585 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
586 event_add(&iev->ev, NULL((void*)0));
587}
588
589int
590imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
591 pid_t pid, int fd, void *data, uint16_t datalen)
592{
593 int ret;
594
595 if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data,
596 datalen)) != -1)
597 imsg_event_add(iev);
598
599 return (ret);
600}
601
602static int
603main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf,
604 struct imsgbuf *engine_buf)
605{
606 int pipe_frontend2engine[2];
607
608 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
609 PF_UNSPEC0, pipe_frontend2engine) == -1)
610 return (-1);
611
612 if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0,
613 pipe_frontend2engine[0], NULL((void*)0), 0) == -1)
614 return (-1);
615 imsg_flush(frontend_buf);
616 if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0,
617 pipe_frontend2engine[1], NULL((void*)0), 0) == -1)
618 return (-1);
619 imsg_flush(engine_buf);
620 return (0);
621}
622
623void
624configure_interface(struct imsg_configure_address *address)
625{
626
627 struct in6_aliasreq in6_addreq;
628 time_t t;
629 char *if_name;
630
631 memset(&in6_addreq, 0, sizeof(in6_addreq));
632
633 if_name = if_indextoname(address->if_index, in6_addreq.ifra_name);
634 if (if_name == NULL((void*)0)) {
635 log_warnx("%s: cannot find interface %d", __func__,
636 address->if_index);
637 return;
638 }
639
640 memcpy(&in6_addreq.ifra_addrifra_ifrau.ifrau_addr, &address->addr,
641 sizeof(in6_addreq.ifra_addrifra_ifrau.ifrau_addr));
642 memcpy(&in6_addreq.ifra_prefixmask.sin6_addr, &address->mask,
643 sizeof(in6_addreq.ifra_prefixmask.sin6_addr));
644 in6_addreq.ifra_prefixmask.sin6_family = AF_INET624;
645 in6_addreq.ifra_prefixmask.sin6_len =
646 sizeof(in6_addreq.ifra_prefixmask);
647
648 t = time(NULL((void*)0));
649
650 in6_addreq.ifra_lifetime.ia6t_expire = t + address->vltime;
651 in6_addreq.ifra_lifetime.ia6t_vltime = address->vltime;
652
653 in6_addreq.ifra_lifetime.ia6t_preferred = t + address->pltime;
654 in6_addreq.ifra_lifetime.ia6t_pltime = address->pltime;
655
656 in6_addreq.ifra_flags |= IN6_IFF_AUTOCONF0x40;
657
658 if (address->temporary)
659 in6_addreq.ifra_flags |= IN6_IFF_TEMPORARY0x80;
660
661 log_debug("%s: %s", __func__, if_name);
662
663 if (ioctl(ioctl_sock, SIOCAIFADDR_IN6((unsigned long)0x80000000 | ((sizeof(struct in6_aliasreq) &
0x1fff) << 16) | ((('i')) << 8) | ((26)))
, &in6_addreq) == -1)
664 log_warn("SIOCAIFADDR_IN6");
665
666 if (address->mtu) {
667 struct ifreq ifr;
668
669 strlcpy(ifr.ifr_name, in6_addreq.ifra_name,
670 sizeof(ifr.ifr_name));
671 ifr.ifr_mtuifr_ifru.ifru_metric = address->mtu;
672 log_debug("Setting MTU to %d", ifr.ifr_mtuifr_ifru.ifru_metric);
673
674 if (ioctl(ioctl_sock, SIOCSIFMTU((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((127)))
, &ifr) == -1)
675 log_warn("failed to set MTU");
676 }
677}
678
679void
680delete_address(struct imsg_configure_address *address)
681{
682
683 struct in6_ifreq in6_ridreq;
684 char *if_name;
685
686 memset(&in6_ridreq, 0, sizeof(in6_ridreq));
687
688 if_name = if_indextoname(address->if_index, in6_ridreq.ifr_name);
689 if (if_name == NULL((void*)0)) {
690 log_warnx("%s: cannot find interface %d", __func__,
691 address->if_index);
692 return;
693 }
694
695 memcpy(&in6_ridreq.ifr_addrifr_ifru.ifru_addr, &address->addr,
696 sizeof(in6_ridreq.ifr_addrifr_ifru.ifru_addr));
697
698 log_debug("%s: %s", __func__, if_name);
699
700 if (ioctl(ioctl_sock, SIOCDIFADDR_IN6((unsigned long)0x80000000 | ((sizeof(struct in6_ifreq) &
0x1fff) << 16) | ((('i')) << 8) | ((25)))
, &in6_ridreq) == -1)
701 log_warn("%s: cannot remove address", __func__);
702
703}
704
705#define ROUNDUP(a)(((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) -
1))) : (a))
\
706 (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
707
708void
709configure_gateway(struct imsg_configure_dfr *dfr, uint8_t rtm_type)
710{
711 struct rt_msghdr rtm;
712 struct sockaddr_rtlabel rl;
713 struct sockaddr_in6 dst, gw, mask;
714 struct iovec iov[10];
715 long pad = 0;
716 int iovcnt = 0, padlen;
717
718 memset(&rtm, 0, sizeof(rtm));
719
720 rtm.rtm_version = RTM_VERSION5;
721 rtm.rtm_type = rtm_type;
722 rtm.rtm_msglen = sizeof(rtm);
723 rtm.rtm_tableid = dfr->rdomain;
724 rtm.rtm_index = dfr->if_index;
725 rtm.rtm_seq = ++rtm_seq;
726 rtm.rtm_priority = RTP_NONE0;
727 rtm.rtm_addrs = RTA_DST0x1 | RTA_GATEWAY0x2 | RTA_NETMASK0x4 | RTA_LABEL0x400;
728 rtm.rtm_flags = RTF_UP0x1 | RTF_GATEWAY0x2 | RTF_STATIC0x800 | RTF_MPATH0x40000;
729
730 iov[iovcnt].iov_base = &rtm;
731 iov[iovcnt++].iov_len = sizeof(rtm);
732
733 memset(&dst, 0, sizeof(mask));
734 dst.sin6_family = AF_INET624;
735 dst.sin6_len = sizeof(struct sockaddr_in6);
736
737 iov[iovcnt].iov_base = &dst;
738 iov[iovcnt++].iov_len = sizeof(dst);
739 rtm.rtm_msglen += sizeof(dst);
740 padlen = ROUNDUP(sizeof(dst))(((sizeof(dst)) & (sizeof(long) - 1)) ? (1 + ((sizeof(dst
)) | (sizeof(long) - 1))) : (sizeof(dst)))
- sizeof(dst);
741 if (padlen > 0) {
742 iov[iovcnt].iov_base = &pad;
743 iov[iovcnt++].iov_len = padlen;
744 rtm.rtm_msglen += padlen;
745 }
746
747 memcpy(&gw, &dfr->addr, sizeof(gw));
748#ifdef __KAME__
749 /* from route(8) getaddr()*/
750 *(u_int16_t *)& gw.sin6_addr.s6_addr__u6_addr.__u6_addr8[2] = htons(gw.sin6_scope_id)(__uint16_t)(__builtin_constant_p(gw.sin6_scope_id) ? (__uint16_t
)(((__uint16_t)(gw.sin6_scope_id) & 0xffU) << 8 | (
(__uint16_t)(gw.sin6_scope_id) & 0xff00U) >> 8) : __swap16md
(gw.sin6_scope_id))
;
751 gw.sin6_scope_id = 0;
752#endif
753 iov[iovcnt].iov_base = &gw;
754 iov[iovcnt++].iov_len = sizeof(gw);
755 rtm.rtm_msglen += sizeof(gw);
756 padlen = ROUNDUP(sizeof(gw))(((sizeof(gw)) & (sizeof(long) - 1)) ? (1 + ((sizeof(gw))
| (sizeof(long) - 1))) : (sizeof(gw)))
- sizeof(gw);
757 if (padlen > 0) {
758 iov[iovcnt].iov_base = &pad;
759 iov[iovcnt++].iov_len = padlen;
760 rtm.rtm_msglen += padlen;
761 }
762
763 memset(&mask, 0, sizeof(mask));
764 mask.sin6_family = AF_INET624;
765 mask.sin6_len = sizeof(struct sockaddr_in6);
766 iov[iovcnt].iov_base = &mask;
767 iov[iovcnt++].iov_len = sizeof(mask);
768 rtm.rtm_msglen += sizeof(mask);
769 padlen = ROUNDUP(sizeof(mask))(((sizeof(mask)) & (sizeof(long) - 1)) ? (1 + ((sizeof(mask
)) | (sizeof(long) - 1))) : (sizeof(mask)))
- sizeof(mask);
770 if (padlen > 0) {
771 iov[iovcnt].iov_base = &pad;
772 iov[iovcnt++].iov_len = padlen;
773 rtm.rtm_msglen += padlen;
774 }
775
776 memset(&rl, 0, sizeof(rl));
777 rl.sr_len = sizeof(rl);
778 rl.sr_family = AF_UNSPEC0;
779 (void)snprintf(rl.sr_label, sizeof(rl.sr_label), "%s",
780 SLAACD_RTA_LABEL"slaacd");
781 iov[iovcnt].iov_base = &rl;
782 iov[iovcnt++].iov_len = sizeof(rl);
783 rtm.rtm_msglen += sizeof(rl);
784 padlen = ROUNDUP(sizeof(rl))(((sizeof(rl)) & (sizeof(long) - 1)) ? (1 + ((sizeof(rl))
| (sizeof(long) - 1))) : (sizeof(rl)))
- sizeof(rl);
785 if (padlen > 0) {
786 iov[iovcnt].iov_base = &pad;
787 iov[iovcnt++].iov_len = padlen;
788 rtm.rtm_msglen += padlen;
789 }
790
791 if (writev(routesock, iov, iovcnt) == -1)
792 log_warn("failed to send route message");
793}
794
795void
796add_gateway(struct imsg_configure_dfr *dfr)
797{
798 configure_gateway(dfr, RTM_ADD0x1);
799}
800
801void
802delete_gateway(struct imsg_configure_dfr *dfr)
803{
804 configure_gateway(dfr, RTM_DELETE0x2);
805}
806
807void
808send_rdns_proposal(struct imsg_propose_rdns *rdns)
809{
810 struct rt_msghdr rtm;
811 struct sockaddr_rtdns rtdns;
812 struct iovec iov[3];
813 long pad = 0;
814 int iovcnt = 0, padlen;
815
816 memset(&rtm, 0, sizeof(rtm));
817
818 rtm.rtm_version = RTM_VERSION5;
819 rtm.rtm_type = RTM_PROPOSAL0x13;
820 rtm.rtm_msglen = sizeof(rtm);
821 rtm.rtm_tableid = rdns->rdomain;
822 rtm.rtm_index = rdns->if_index;
823 rtm.rtm_seq = ++rtm_seq;
824 rtm.rtm_priority = RTP_PROPOSAL_SLAAC59;
825 rtm.rtm_addrs = RTA_DNS0x1000;
826 rtm.rtm_flags = RTF_UP0x1;
827
828 iov[iovcnt].iov_base = &rtm;
829 iov[iovcnt++].iov_len = sizeof(rtm);
830
831 memset(&rtdns, 0, sizeof(rtdns));
832 rtdns.sr_family = AF_INET624;
833 rtdns.sr_len = 2 + rdns->rdns_count * sizeof(struct in6_addr);
834 memcpy(rtdns.sr_dns, rdns->rdns, sizeof(rtdns.sr_dns));
835
836 iov[iovcnt].iov_base = &rtdns;
837 iov[iovcnt++].iov_len = sizeof(rtdns);
838 rtm.rtm_msglen += sizeof(rtdns);
839 padlen = ROUNDUP(sizeof(rtdns))(((sizeof(rtdns)) & (sizeof(long) - 1)) ? (1 + ((sizeof(rtdns
)) | (sizeof(long) - 1))) : (sizeof(rtdns)))
- sizeof(rtdns);
840 if (padlen > 0) {
841 iov[iovcnt].iov_base = &pad;
842 iov[iovcnt++].iov_len = padlen;
843 rtm.rtm_msglen += padlen;
844 }
845
846 if (writev(routesock, iov, iovcnt) == -1)
847 log_warn("failed to send route message");
848}
849
850#ifndef SMALL
851const char*
852sin6_to_str(struct sockaddr_in6 *sin6)
853{
854 static char hbuf[NI_MAXHOST256];
855 int error;
856
857 error = getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, hbuf,
858 sizeof(hbuf), NULL((void*)0), 0, NI_NUMERICHOST1 | NI_NUMERICSERV2);
859 if (error) {
860 log_warnx("%s", gai_strerror(error));
861 strlcpy(hbuf, "unknown", sizeof(hbuf));
862 }
863 return hbuf;
864}
865#endif /* SMALL */
866
867int
868get_soiikey(uint8_t *key)
869{
870 int mib[4] = {CTL_NET4, PF_INET624, IPPROTO_IPV641, IPV6CTL_SOIIKEY54};
871 size_t size = SLAACD_SOIIKEY_LEN16;
872
873 return sysctl(mib, sizeof(mib) / sizeof(mib[0]), key, &size, NULL((void*)0), 0);
874}
875
876void
877open_icmp6sock(int rdomain)
878{
879 int icmp6sock, on = 1;
880
881 log_debug("%s: %d", __func__, rdomain);
882
883 if ((icmp6sock = socket(AF_INET624, SOCK_RAW3 | SOCK_CLOEXEC0x8000,
884 IPPROTO_ICMPV658)) == -1)
885 fatal("ICMPv6 socket");
886
887 if (setsockopt(icmp6sock, IPPROTO_IPV641, IPV6_RECVPKTINFO36, &on,
888 sizeof(on)) == -1)
889 fatal("IPV6_RECVPKTINFO");
890
891 if (setsockopt(icmp6sock, IPPROTO_IPV641, IPV6_RECVHOPLIMIT37, &on,
892 sizeof(on)) == -1)
893 fatal("IPV6_RECVHOPLIMIT");
894
895 if (setsockopt(icmp6sock, SOL_SOCKET0xffff, SO_RTABLE0x1021, &rdomain,
896 sizeof(rdomain)) == -1) {
897 /* we might race against removal of the rdomain */
898 log_warn("setsockopt SO_RTABLE");
899 close(icmp6sock);
900 return;
901 }
902
903 main_imsg_compose_frontend(IMSG_ICMP6SOCK, icmp6sock, &rdomain,
904 sizeof(rdomain));
905}