Bug Summary

File:src/sbin/unwind/unwind.c
Warning:line 173, 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 unwind.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/unwind/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sbin/unwind -I /usr/src/sbin/unwind -I /usr/src/sbin/unwind/libunbound/libunbound -I /usr/src/sbin/unwind/libunbound -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/unwind/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/unwind/unwind.c
1/* $OpenBSD: unwind.c,v 1.67 2021/12/18 10:34:19 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/stat.h>
25#include <sys/syslog.h>
26#include <sys/wait.h>
27
28#include <net/if.h>
29#include <net/route.h>
30
31#include <err.h>
32#include <errno(*__errno()).h>
33#include <event.h>
34#include <fcntl.h>
35#include <imsg.h>
36#include <netdb.h>
37#include <asr.h>
38#include <pwd.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <signal.h>
43#include <unistd.h>
44
45#include "log.h"
46#include "unwind.h"
47#include "frontend.h"
48#include "resolver.h"
49#include "control.h"
50
51#define TRUST_ANCHOR_FILE"/var/db/unwind.key" "/var/db/unwind.key"
52
53enum uw_process {
54 PROC_MAIN,
55 PROC_RESOLVER,
56 PROC_FRONTEND,
57};
58
59__dead__attribute__((__noreturn__)) void usage(void);
60__dead__attribute__((__noreturn__)) void main_shutdown(void);
61
62void main_sig_handler(int, short, void *);
63
64static pid_t start_child(enum uw_process, char *, int, int, int);
65
66void main_dispatch_frontend(int, short, void *);
67void main_dispatch_resolver(int, short, void *);
68
69static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *);
70static int main_imsg_send_config(struct uw_conf *);
71
72int main_reload(void);
73int main_sendall(enum imsg_type, void *, uint16_t);
74void open_ports(void);
75void solicit_dns_proposals(void);
76void send_blocklist_fd(void);
77
78struct uw_conf *main_conf;
79static struct imsgev *iev_frontend;
80static struct imsgev *iev_resolver;
81char *conffile;
82pid_t frontend_pid;
83pid_t resolver_pid;
84uint32_t cmd_opts;
85int routesock;
86
87void
88main_sig_handler(int sig, short event, void *arg)
89{
90 /*
91 * Normal signal handler rules don't apply because libevent
92 * decouples for us.
93 */
94
95 switch (sig) {
96 case SIGTERM15:
97 case SIGINT2:
98 main_shutdown();
99 break;
100 case SIGHUP1:
101 if (main_reload() == -1)
102 log_warnx("configuration reload failed");
103 else
104 log_debug("configuration reloaded");
105 break;
106 default:
107 fatalx("unexpected signal");
108 }
109}
110
111__dead__attribute__((__noreturn__)) void
112usage(void)
113{
114 extern char *__progname;
115
116 fprintf(stderr(&__sF[2]), "usage: %s [-dnv] [-f file] [-s socket]\n",
117 __progname);
118 exit(1);
119}
120
121int
122main(int argc, char *argv[])
123{
124 struct event ev_sigint, ev_sigterm, ev_sighup;
125 int ch, debug = 0, resolver_flag = 0, frontend_flag = 0;
126 int frontend_routesock, rtfilter;
127 int pipe_main2frontend[2], pipe_main2resolver[2];
128 int control_fd, ta_fd;
129 char *csock, *saved_argv0;
130
131 csock = _PATH_UNWIND_SOCKET"/dev/unwind.sock";
132
133 log_init(1, LOG_DAEMON)uw_log_init(1, (3<<3)); /* Log to stderr until daemonized. */
134 log_setverbose(1);
135
136 saved_argv0 = argv[0];
137 if (saved_argv0 == NULL((void *)0))
138 saved_argv0 = "unwind";
139
140 while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) {
141 switch (ch) {
142 case 'd':
143 debug = 1;
144 break;
145 case 'E':
146 resolver_flag = 1;
147 break;
148 case 'F':
149 frontend_flag = 1;
150 break;
151 case 'f':
152 conffile = optarg;
153 break;
154 case 'n':
155 cmd_opts |= OPT_NOACTION0x00000008;
156 break;
157 case 's':
158 csock = optarg;
159 break;
160 case 'v':
161 if (cmd_opts & OPT_VERBOSE20x00000002)
162 cmd_opts |= OPT_VERBOSE30x00000004;
163 if (cmd_opts & OPT_VERBOSE0x00000001)
164 cmd_opts |= OPT_VERBOSE20x00000002;
165 cmd_opts |= OPT_VERBOSE0x00000001;
166 break;
167 default:
168 usage();
169 }
170 }
171
172 argc -= optind;
173 argv += optind;
Value stored to 'argv' is never read
174 if (argc > 0 || (resolver_flag && frontend_flag))
175 usage();
176
177 if (resolver_flag)
178 resolver(debug, cmd_opts & (OPT_VERBOSE0x00000001 | OPT_VERBOSE20x00000002 |
179 OPT_VERBOSE30x00000004));
180 else if (frontend_flag)
181 frontend(debug, cmd_opts & (OPT_VERBOSE0x00000001 | OPT_VERBOSE20x00000002 |
182 OPT_VERBOSE30x00000004));
183
184 if ((main_conf = parse_config(conffile)) == NULL((void *)0))
185 exit(1);
186
187 if (cmd_opts & OPT_NOACTION0x00000008) {
188 if (cmd_opts & OPT_VERBOSE0x00000001)
189 print_config(main_conf);
190 else
191 fprintf(stderr(&__sF[2]), "configuration OK\n");
192 exit(0);
193 }
194
195 /* Check for root privileges. */
196 if (geteuid())
197 errx(1, "need root privileges");
198
199 /* Check for assigned daemon user */
200 if (getpwnam(UNWIND_USER"_unwind") == NULL((void *)0))
201 errx(1, "unknown user %s", UNWIND_USER"_unwind");
202
203 log_init(debug, LOG_DAEMON)uw_log_init(debug, (3<<3));
204 log_setverbose(cmd_opts & (OPT_VERBOSE0x00000001 | OPT_VERBOSE20x00000002 | OPT_VERBOSE30x00000004));
205
206 if (!debug)
207 daemon(1, 0);
208
209 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
210 PF_UNSPEC0, pipe_main2frontend) == -1)
211 fatal("main2frontend socketpair");
212 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
213 PF_UNSPEC0, pipe_main2resolver) == -1)
214 fatal("main2resolver socketpair");
215
216 /* Start children. */
217 resolver_pid = start_child(PROC_RESOLVER, saved_argv0,
218 pipe_main2resolver[1], debug, cmd_opts & (OPT_VERBOSE0x00000001 |
219 OPT_VERBOSE20x00000002 | OPT_VERBOSE30x00000004));
220 frontend_pid = start_child(PROC_FRONTEND, saved_argv0,
221 pipe_main2frontend[1], debug, cmd_opts & (OPT_VERBOSE0x00000001 |
222 OPT_VERBOSE20x00000002 | OPT_VERBOSE30x00000004));
223
224 log_procinit("main");
225
226 event_init();
227
228 /* Setup signal handler. */
229 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, main_sig_handler, ((void
*)0))
;
230 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, main_sig_handler, (
(void *)0))
;
231 signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL)event_set(&ev_sighup, 1, 0x08|0x10, main_sig_handler, ((void
*)0))
;
232 signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0));
233 signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0));
234 signal_add(&ev_sighup, NULL)event_add(&ev_sighup, ((void *)0));
235 signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
236
237 /* Setup pipes to children. */
238
239 if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL((void *)0) ||
240 (iev_resolver = malloc(sizeof(struct imsgev))) == NULL((void *)0))
241 fatal(NULL((void *)0));
242 imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]);
243 iev_frontend->handler = main_dispatch_frontend;
244 imsg_init(&iev_resolver->ibuf, pipe_main2resolver[0]);
245 iev_resolver->handler = main_dispatch_resolver;
246
247 /* Setup event handlers for pipes. */
248 iev_frontend->events = EV_READ0x02;
249 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
250 iev_frontend->events, iev_frontend->handler, iev_frontend);
251 event_add(&iev_frontend->ev, NULL((void *)0));
252
253 iev_resolver->events = EV_READ0x02;
254 event_set(&iev_resolver->ev, iev_resolver->ibuf.fd,
255 iev_resolver->events, iev_resolver->handler, iev_resolver);
256 event_add(&iev_resolver->ev, NULL((void *)0));
257
258 if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf,
259 &iev_resolver->ibuf))
260 fatal("could not establish imsg links");
261
262 open_ports();
263
264 if ((control_fd = control_init(csock)) == -1)
265 fatalx("control socket setup failed");
266
267 if ((frontend_routesock = socket(AF_ROUTE17, SOCK_RAW3 | SOCK_CLOEXEC0x8000 |
268 SOCK_NONBLOCK0x4000, 0)) == -1)
269 fatal("route socket");
270
271 rtfilter = ROUTE_FILTER(RTM_IFINFO)(1 << (0xe)) | ROUTE_FILTER(RTM_PROPOSAL)(1 << (0x13))
272 | ROUTE_FILTER(RTM_IFANNOUNCE)(1 << (0xf)) | ROUTE_FILTER(RTM_NEWADDR)(1 << (0xc))
273 | ROUTE_FILTER(RTM_DELADDR)(1 << (0xd));
274 if (setsockopt(frontend_routesock, AF_ROUTE17, ROUTE_MSGFILTER1,
275 &rtfilter, sizeof(rtfilter)) == -1)
276 fatal("setsockopt(ROUTE_MSGFILTER)");
277
278 if ((routesock = socket(AF_ROUTE17, SOCK_RAW3 | SOCK_CLOEXEC0x8000 |
279 SOCK_NONBLOCK0x4000, 0)) == -1)
280 fatal("route socket");
281 shutdown(SHUT_RD0, routesock);
282
283 if ((ta_fd = open(TRUST_ANCHOR_FILE"/var/db/unwind.key", O_RDWR0x0002 | O_CREAT0x0200, 0644)) == -1)
284 log_warn("%s", TRUST_ANCHOR_FILE)uw_log_warn("%s", "/var/db/unwind.key");
285
286 /* receiver handles failed open correctly */
287 main_imsg_compose_frontend_fd(IMSG_TAFD, 0, ta_fd);
288
289 main_imsg_compose_frontend_fd(IMSG_CONTROLFD, 0, control_fd);
290 main_imsg_compose_frontend_fd(IMSG_ROUTESOCK, 0, frontend_routesock);
291 main_imsg_send_config(main_conf);
292
293 if (main_conf->blocklist_file != NULL((void *)0))
294 send_blocklist_fd();
295
296 if (pledge("stdio rpath sendfd", NULL((void *)0)) == -1)
297 fatal("pledge");
298
299 main_imsg_compose_frontend(IMSG_STARTUP, 0, NULL((void *)0), 0);
300 main_imsg_compose_resolver(IMSG_STARTUP, 0, NULL((void *)0), 0);
301
302 event_dispatch();
303
304 main_shutdown();
305 return (0);
306}
307
308__dead__attribute__((__noreturn__)) void
309main_shutdown(void)
310{
311 pid_t pid;
312 int status;
313
314 /* Close pipes. */
315 msgbuf_clear(&iev_frontend->ibuf.w);
316 close(iev_frontend->ibuf.fd);
317 msgbuf_clear(&iev_resolver->ibuf.w);
318 close(iev_resolver->ibuf.fd);
319
320 config_clear(main_conf);
321
322 log_debug("waiting for children to terminate");
323 do {
324 pid = wait(&status);
325 if (pid == -1) {
326 if (errno(*__errno()) != EINTR4 && errno(*__errno()) != ECHILD10)
327 fatal("wait");
328 } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177
) != 0)
)
329 log_warnx("%s terminated; signal %d",
330 (pid == resolver_pid) ? "resolver" :
331 "frontend", WTERMSIG(status)(((status) & 0177)));
332 } while (pid != -1 || (pid == -1 && errno(*__errno()) == EINTR4));
333
334 free(iev_frontend);
335 free(iev_resolver);
336
337 log_info("terminating")uw_log_info("terminating");
338 exit(0);
339}
340
341static pid_t
342start_child(enum uw_process p, char *argv0, int fd, int debug, int verbose)
343{
344 char *argv[7];
345 int argc = 0;
346 pid_t pid;
347
348 switch (pid = fork()) {
349 case -1:
350 fatal("cannot fork");
351 case 0:
352 break;
353 default:
354 close(fd);
355 return (pid);
356 }
357
358 if (fd != 3) {
359 if (dup2(fd, 3) == -1)
360 fatal("cannot setup imsg fd");
361 } else if (fcntl(fd, F_SETFD2, 0) == -1)
362 fatal("cannot setup imsg fd");
363
364 argv[argc++] = argv0;
365 switch (p) {
366 case PROC_MAIN:
367 fatalx("Can not start main process");
368 case PROC_RESOLVER:
369 argv[argc++] = "-E";
370 break;
371 case PROC_FRONTEND:
372 argv[argc++] = "-F";
373 break;
374 }
375 if (debug)
376 argv[argc++] = "-d";
377 if (verbose & OPT_VERBOSE0x00000001)
378 argv[argc++] = "-v";
379 if (verbose & OPT_VERBOSE20x00000002)
380 argv[argc++] = "-v";
381 if (verbose & OPT_VERBOSE30x00000004)
382 argv[argc++] = "-v";
383 argv[argc++] = NULL((void *)0);
384
385 execvp(argv0, argv);
386 fatal("execvp");
387}
388
389void
390main_dispatch_frontend(int fd, short event, void *bula)
391{
392 struct imsgev *iev = bula;
393 struct imsgbuf *ibuf;
394 struct imsg imsg;
395 ssize_t n;
396 int shut = 0, verbose;
397
398 ibuf = &iev->ibuf;
399
400 if (event & EV_READ0x02) {
401 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
402 fatal("imsg_read error");
403 if (n == 0) /* Connection closed. */
404 shut = 1;
405 }
406 if (event & EV_WRITE0x04) {
407 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
408 fatal("msgbuf_write");
409 if (n == 0) /* Connection closed. */
410 shut = 1;
411 }
412
413 for (;;) {
414 if ((n = imsg_get(ibuf, &imsg)) == -1)
415 fatal("imsg_get");
416 if (n == 0) /* No more messages. */
417 break;
418
419 switch (imsg.hdr.type) {
420 case IMSG_STARTUP_DONE:
421 solicit_dns_proposals();
422 break;
423 case IMSG_CTL_RELOAD:
424 if (main_reload() == -1)
425 log_warnx("configuration reload failed");
426 else
427 log_warnx("configuration reloaded");
428 break;
429 case IMSG_CTL_LOG_VERBOSE:
430 if (IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(verbose))
431 fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
432 "%lu", __func__, IMSG_DATA_SIZE(imsg)((imsg).hdr.len - sizeof(struct imsg_hdr)));
433 memcpy(&verbose, imsg.data, sizeof(verbose));
434 log_setverbose(verbose);
435 break;
436 default:
437 log_debug("%s: error handling imsg %d", __func__,
438 imsg.hdr.type);
439 break;
440 }
441 imsg_free(&imsg);
442 }
443 if (!shut)
444 imsg_event_add(iev);
445 else {
446 /* This pipe is dead. Remove its event handler */
447 event_del(&iev->ev);
448 event_loopexit(NULL((void *)0));
449 }
450}
451
452void
453main_dispatch_resolver(int fd, short event, void *bula)
454{
455 struct imsgev *iev = bula;
456 struct imsgbuf *ibuf;
457 struct imsg imsg;
458 ssize_t n;
459 int shut = 0;
460
461 ibuf = &iev->ibuf;
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("imsg_get");
479 if (n == 0) /* No more messages. */
480 break;
481
482 switch (imsg.hdr.type) {
483 default:
484 log_debug("%s: error handling imsg %d", __func__,
485 imsg.hdr.type);
486 break;
487 }
488 imsg_free(&imsg);
489 }
490 if (!shut)
491 imsg_event_add(iev);
492 else {
493 /* This pipe is dead. Remove its event handler. */
494 event_del(&iev->ev);
495 event_loopexit(NULL((void *)0));
496 }
497}
498
499void
500main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen)
501{
502 if (iev_frontend)
503 imsg_compose_event(iev_frontend, type, 0, pid, -1, data,
504 datalen);
505}
506
507void
508main_imsg_compose_frontend_fd(int type, pid_t pid, int fd)
509{
510 if (iev_frontend)
511 imsg_compose_event(iev_frontend, type, 0, pid, fd, NULL((void *)0), 0);
512}
513
514void
515main_imsg_compose_resolver(int type, pid_t pid, void *data, uint16_t datalen)
516{
517 if (iev_resolver)
518 imsg_compose_event(iev_resolver, type, 0, pid, -1, data,
519 datalen);
520}
521
522void
523imsg_event_add(struct imsgev *iev)
524{
525 iev->events = EV_READ0x02;
526 if (iev->ibuf.w.queued)
527 iev->events |= EV_WRITE0x04;
528
529 event_del(&iev->ev);
530 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
531 event_add(&iev->ev, NULL((void *)0));
532}
533
534int
535imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
536 pid_t pid, int fd, void *data, uint16_t datalen)
537{
538 int ret;
539
540 if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data,
541 datalen)) != -1)
542 imsg_event_add(iev);
543
544 return (ret);
545}
546
547static int
548main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf,
549 struct imsgbuf *resolver_buf)
550{
551 int pipe_frontend2resolver[2];
552
553 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
554 PF_UNSPEC0, pipe_frontend2resolver) == -1)
555 return (-1);
556
557 if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC_RESOLVER, 0, 0,
558 pipe_frontend2resolver[0], NULL((void *)0), 0) == -1)
559 return (-1);
560 if (imsg_compose(resolver_buf, IMSG_SOCKET_IPC_FRONTEND, 0, 0,
561 pipe_frontend2resolver[1], NULL((void *)0), 0) == -1)
562 return (-1);
563
564 return (0);
565}
566
567int
568main_reload(void)
569{
570 struct uw_conf *xconf;
571
572 if ((xconf = parse_config(conffile)) == NULL((void *)0))
573 return (-1);
574
575 if (main_imsg_send_config(xconf) == -1)
576 return (-1);
577
578 merge_config(main_conf, xconf);
579
580 if (main_conf->blocklist_file != NULL((void *)0))
581 send_blocklist_fd();
582
583 return (0);
584}
585
586int
587main_imsg_send_config(struct uw_conf *xconf)
588{
589 struct uw_forwarder *uw_forwarder;
590 struct force_tree_entry *force_entry;
591
592 /* Send fixed part of config to children. */
593 if (main_sendall(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1)
594 return (-1);
595
596 if (xconf->blocklist_file != NULL((void *)0)) {
597 if (main_sendall(IMSG_RECONF_BLOCKLIST_FILE,
598 xconf->blocklist_file, strlen(xconf->blocklist_file) + 1)
599 == -1)
600 return (-1);
601 }
602
603 /* send static forwarders to children */
604 TAILQ_FOREACH(uw_forwarder, &xconf->uw_forwarder_list, entry)for((uw_forwarder) = ((&xconf->uw_forwarder_list)->
tqh_first); (uw_forwarder) != ((void *)0); (uw_forwarder) = (
(uw_forwarder)->entry.tqe_next))
{
605 if (main_sendall(IMSG_RECONF_FORWARDER, uw_forwarder,
606 sizeof(*uw_forwarder)) == -1)
607 return (-1);
608 }
609
610 /* send static DoT forwarders to children */
611 TAILQ_FOREACH(uw_forwarder, &xconf->uw_dot_forwarder_list,for((uw_forwarder) = ((&xconf->uw_dot_forwarder_list)->
tqh_first); (uw_forwarder) != ((void *)0); (uw_forwarder) = (
(uw_forwarder)->entry.tqe_next))
612 entry)for((uw_forwarder) = ((&xconf->uw_dot_forwarder_list)->
tqh_first); (uw_forwarder) != ((void *)0); (uw_forwarder) = (
(uw_forwarder)->entry.tqe_next))
{
613 if (main_sendall(IMSG_RECONF_DOT_FORWARDER, uw_forwarder,
614 sizeof(*uw_forwarder)) == -1)
615 return (-1);
616 }
617 RB_FOREACH(force_entry, force_tree, &xconf->force)for ((force_entry) = force_tree_RB_MINMAX(&xconf->force
, -1); (force_entry) != ((void *)0); (force_entry) = force_tree_RB_NEXT
(force_entry))
{
618 if (main_sendall(IMSG_RECONF_FORCE, force_entry,
619 sizeof(*force_entry)) == -1)
620 return (-1);
621 }
622
623 /* Tell children the revised config is now complete. */
624 if (main_sendall(IMSG_RECONF_END, NULL((void *)0), 0) == -1)
625 return (-1);
626
627 return (0);
628}
629
630int
631main_sendall(enum imsg_type type, void *buf, uint16_t len)
632{
633 if (imsg_compose_event(iev_frontend, type, 0, 0, -1, buf, len) == -1)
634 return (-1);
635 if (imsg_compose_event(iev_resolver, type, 0, 0, -1, buf, len) == -1)
636 return (-1);
637 return (0);
638}
639
640void
641merge_config(struct uw_conf *conf, struct uw_conf *xconf)
642{
643 struct uw_forwarder *uw_forwarder;
644 struct force_tree_entry *n, *nxt;
645
646 /* Remove & discard existing forwarders. */
647 while ((uw_forwarder = TAILQ_FIRST(&conf->uw_forwarder_list)((&conf->uw_forwarder_list)->tqh_first)) !=
648 NULL((void *)0)) {
649 TAILQ_REMOVE(&conf->uw_forwarder_list, uw_forwarder, entry)do { if (((uw_forwarder)->entry.tqe_next) != ((void *)0)) (
uw_forwarder)->entry.tqe_next->entry.tqe_prev = (uw_forwarder
)->entry.tqe_prev; else (&conf->uw_forwarder_list)->
tqh_last = (uw_forwarder)->entry.tqe_prev; *(uw_forwarder)
->entry.tqe_prev = (uw_forwarder)->entry.tqe_next; ; ; }
while (0)
;
650 free(uw_forwarder);
651 }
652 while ((uw_forwarder = TAILQ_FIRST(&conf->uw_dot_forwarder_list)((&conf->uw_dot_forwarder_list)->tqh_first)) !=
653 NULL((void *)0)) {
654 TAILQ_REMOVE(&conf->uw_dot_forwarder_list, uw_forwarder, entry)do { if (((uw_forwarder)->entry.tqe_next) != ((void *)0)) (
uw_forwarder)->entry.tqe_next->entry.tqe_prev = (uw_forwarder
)->entry.tqe_prev; else (&conf->uw_dot_forwarder_list
)->tqh_last = (uw_forwarder)->entry.tqe_prev; *(uw_forwarder
)->entry.tqe_prev = (uw_forwarder)->entry.tqe_next; ; ;
} while (0)
;
655 free(uw_forwarder);
656 }
657
658 /* Remove & discard existing force tree. */
659 RB_FOREACH_SAFE(n, force_tree, &conf->force, nxt)for ((n) = force_tree_RB_MINMAX(&conf->force, -1); ((n
) != ((void *)0)) && ((nxt) = force_tree_RB_NEXT(n), 1
); (n) = (nxt))
{
660 RB_REMOVE(force_tree, &conf->force, n)force_tree_RB_REMOVE(&conf->force, n);
661 free(n);
662 }
663
664 memcpy(&conf->enabled_resolvers, &xconf->enabled_resolvers,
665 sizeof(conf->enabled_resolvers));
666
667 memcpy(&conf->res_pref, &xconf->res_pref,
668 sizeof(conf->res_pref));
669
670 free(conf->blocklist_file);
671 conf->blocklist_file = xconf->blocklist_file;
672 conf->blocklist_log = xconf->blocklist_log;
673
674 /* Add new forwarders. */
675 TAILQ_CONCAT(&conf->uw_forwarder_list, &xconf->uw_forwarder_list,do { if (!(((&xconf->uw_forwarder_list)->tqh_first)
== ((void *)0))) { *(&conf->uw_forwarder_list)->tqh_last
= (&xconf->uw_forwarder_list)->tqh_first; (&xconf
->uw_forwarder_list)->tqh_first->entry.tqe_prev = (&
conf->uw_forwarder_list)->tqh_last; (&conf->uw_forwarder_list
)->tqh_last = (&xconf->uw_forwarder_list)->tqh_last
; do { ((&xconf->uw_forwarder_list))->tqh_first = (
(void *)0); ((&xconf->uw_forwarder_list))->tqh_last
= &((&xconf->uw_forwarder_list))->tqh_first; }
while (0); } } while (0)
676 entry)do { if (!(((&xconf->uw_forwarder_list)->tqh_first)
== ((void *)0))) { *(&conf->uw_forwarder_list)->tqh_last
= (&xconf->uw_forwarder_list)->tqh_first; (&xconf
->uw_forwarder_list)->tqh_first->entry.tqe_prev = (&
conf->uw_forwarder_list)->tqh_last; (&conf->uw_forwarder_list
)->tqh_last = (&xconf->uw_forwarder_list)->tqh_last
; do { ((&xconf->uw_forwarder_list))->tqh_first = (
(void *)0); ((&xconf->uw_forwarder_list))->tqh_last
= &((&xconf->uw_forwarder_list))->tqh_first; }
while (0); } } while (0)
;
677 TAILQ_CONCAT(&conf->uw_dot_forwarder_list,do { if (!(((&xconf->uw_dot_forwarder_list)->tqh_first
) == ((void *)0))) { *(&conf->uw_dot_forwarder_list)->
tqh_last = (&xconf->uw_dot_forwarder_list)->tqh_first
; (&xconf->uw_dot_forwarder_list)->tqh_first->entry
.tqe_prev = (&conf->uw_dot_forwarder_list)->tqh_last
; (&conf->uw_dot_forwarder_list)->tqh_last = (&
xconf->uw_dot_forwarder_list)->tqh_last; do { ((&xconf
->uw_dot_forwarder_list))->tqh_first = ((void *)0); ((&
xconf->uw_dot_forwarder_list))->tqh_last = &((&
xconf->uw_dot_forwarder_list))->tqh_first; } while (0);
} } while (0)
678 &xconf->uw_dot_forwarder_list, entry)do { if (!(((&xconf->uw_dot_forwarder_list)->tqh_first
) == ((void *)0))) { *(&conf->uw_dot_forwarder_list)->
tqh_last = (&xconf->uw_dot_forwarder_list)->tqh_first
; (&xconf->uw_dot_forwarder_list)->tqh_first->entry
.tqe_prev = (&conf->uw_dot_forwarder_list)->tqh_last
; (&conf->uw_dot_forwarder_list)->tqh_last = (&
xconf->uw_dot_forwarder_list)->tqh_last; do { ((&xconf
->uw_dot_forwarder_list))->tqh_first = ((void *)0); ((&
xconf->uw_dot_forwarder_list))->tqh_last = &((&
xconf->uw_dot_forwarder_list))->tqh_first; } while (0);
} } while (0)
;
679
680 RB_FOREACH_SAFE(n, force_tree, &xconf->force, nxt)for ((n) = force_tree_RB_MINMAX(&xconf->force, -1); ((
n) != ((void *)0)) && ((nxt) = force_tree_RB_NEXT(n),
1); (n) = (nxt))
{
681 RB_REMOVE(force_tree, &xconf->force, n)force_tree_RB_REMOVE(&xconf->force, n);
682 RB_INSERT(force_tree, &conf->force, n)force_tree_RB_INSERT(&conf->force, n);
683 }
684
685 free(xconf);
686}
687
688struct uw_conf *
689config_new_empty(void)
690{
691 struct uw_conf *xconf;
692
693 xconf = calloc(1, sizeof(*xconf));
694 if (xconf == NULL((void *)0))
695 fatal(NULL((void *)0));
696
697 TAILQ_INIT(&xconf->uw_forwarder_list)do { (&xconf->uw_forwarder_list)->tqh_first = ((void
*)0); (&xconf->uw_forwarder_list)->tqh_last = &
(&xconf->uw_forwarder_list)->tqh_first; } while (0)
;
698 TAILQ_INIT(&xconf->uw_dot_forwarder_list)do { (&xconf->uw_dot_forwarder_list)->tqh_first = (
(void *)0); (&xconf->uw_dot_forwarder_list)->tqh_last
= &(&xconf->uw_dot_forwarder_list)->tqh_first;
} while (0)
;
699
700 RB_INIT(&xconf->force)do { (&xconf->force)->rbh_root = ((void *)0); } while
(0)
;
701
702 return (xconf);
703}
704
705void
706config_clear(struct uw_conf *conf)
707{
708 struct uw_conf *xconf;
709
710 /* Merge current config with an empty config. */
711 xconf = config_new_empty();
712 merge_config(conf, xconf);
713
714 free(conf);
715}
716
717void
718open_ports(void)
719{
720 struct addrinfo hints, *res0;
721 int udp4sock = -1, udp6sock = -1, error, bsize = 65535;
722 int tcp4sock = -1, tcp6sock = -1;
723 int opt = 1;
724
725 memset(&hints, 0, sizeof(hints));
726 hints.ai_family = AF_INET2;
727 hints.ai_socktype = SOCK_DGRAM2;
728 hints.ai_flags = AI_NUMERICHOST4 | AI_PASSIVE1;
729
730 error = getaddrinfo("127.0.0.1", "domain", &hints, &res0);
731 if (!error && res0) {
732 if ((udp4sock = socket(res0->ai_family, res0->ai_socktype,
733 res0->ai_protocol)) != -1) {
734 if (setsockopt(udp4sock, SOL_SOCKET0xffff, SO_REUSEADDR0x0004,
735 &opt, sizeof(opt)) == -1)
736 log_warn("setting SO_REUSEADDR on socket")uw_log_warn("setting SO_REUSEADDR on socket");
737 if (setsockopt(udp4sock, SOL_SOCKET0xffff, SO_SNDBUF0x1001, &bsize,
738 sizeof(bsize)) == -1)
739 log_warn("setting SO_SNDBUF on socket")uw_log_warn("setting SO_SNDBUF on socket");
740 if (bind(udp4sock, res0->ai_addr, res0->ai_addrlen)
741 == -1) {
742 close(udp4sock);
743 udp4sock = -1;
744 }
745 }
746 }
747 if (res0)
748 freeaddrinfo(res0);
749
750 hints.ai_family = AF_INET624;
751 error = getaddrinfo("::1", "domain", &hints, &res0);
752 if (!error && res0) {
753 if ((udp6sock = socket(res0->ai_family, res0->ai_socktype,
754 res0->ai_protocol)) != -1) {
755 if (setsockopt(udp6sock, SOL_SOCKET0xffff, SO_REUSEADDR0x0004,
756 &opt, sizeof(opt)) == -1)
757 log_warn("setting SO_REUSEADDR on socket")uw_log_warn("setting SO_REUSEADDR on socket");
758 if (setsockopt(udp6sock, SOL_SOCKET0xffff, SO_SNDBUF0x1001, &bsize,
759 sizeof(bsize)) == -1)
760 log_warn("setting SO_SNDBUF on socket")uw_log_warn("setting SO_SNDBUF on socket");
761 if (bind(udp6sock, res0->ai_addr, res0->ai_addrlen)
762 == -1) {
763 close(udp6sock);
764 udp6sock = -1;
765 }
766 }
767 }
768 if (res0)
769 freeaddrinfo(res0);
770
771 hints.ai_family = AF_INET2;
772 hints.ai_socktype = SOCK_STREAM1;
773
774 error = getaddrinfo("127.0.0.1", "domain", &hints, &res0);
775 if (!error && res0) {
776 if ((tcp4sock = socket(res0->ai_family,
777 res0->ai_socktype | SOCK_NONBLOCK0x4000,
778 res0->ai_protocol)) != -1) {
779 if (setsockopt(tcp4sock, SOL_SOCKET0xffff, SO_REUSEADDR0x0004,
780 &opt, sizeof(opt)) == -1)
781 log_warn("setting SO_REUSEADDR on socket")uw_log_warn("setting SO_REUSEADDR on socket");
782 if (setsockopt(tcp4sock, SOL_SOCKET0xffff, SO_SNDBUF0x1001, &bsize,
783 sizeof(bsize)) == -1)
784 log_warn("setting SO_SNDBUF on socket")uw_log_warn("setting SO_SNDBUF on socket");
785 if (bind(tcp4sock, res0->ai_addr, res0->ai_addrlen)
786 == -1) {
787 close(tcp4sock);
788 tcp4sock = -1;
789 }
790 if (listen(tcp4sock, 5) == -1) {
791 close(tcp4sock);
792 tcp4sock = -1;
793 }
794 }
795 }
796 if (res0)
797 freeaddrinfo(res0);
798
799 hints.ai_family = AF_INET624;
800 error = getaddrinfo("::1", "domain", &hints, &res0);
801 if (!error && res0) {
802 if ((tcp6sock = socket(res0->ai_family,
803 res0->ai_socktype | SOCK_NONBLOCK0x4000,
804 res0->ai_protocol)) != -1) {
805 if (setsockopt(tcp6sock, SOL_SOCKET0xffff, SO_REUSEADDR0x0004,
806 &opt, sizeof(opt)) == -1)
807 log_warn("setting SO_REUSEADDR on socket")uw_log_warn("setting SO_REUSEADDR on socket");
808 if (setsockopt(tcp6sock, SOL_SOCKET0xffff, SO_SNDBUF0x1001, &bsize,
809 sizeof(bsize)) == -1)
810 log_warn("setting SO_SNDBUF on socket")uw_log_warn("setting SO_SNDBUF on socket");
811 if (bind(tcp6sock, res0->ai_addr, res0->ai_addrlen)
812 == -1) {
813 close(tcp6sock);
814 tcp6sock = -1;
815 }
816 if (listen(tcp6sock, 5) == -1) {
817 close(tcp6sock);
818 tcp6sock = -1;
819 }
820 }
821 }
822 if (res0)
823 freeaddrinfo(res0);
824
825 if ((udp4sock == -1 || tcp4sock == -1) && (udp6sock == -1 ||
826 tcp6sock == -1))
827 fatalx("could not bind to 127.0.0.1 or ::1 on port 53");
828
829 if (udp4sock != -1)
830 main_imsg_compose_frontend_fd(IMSG_UDP4SOCK, 0, udp4sock);
831 if (udp6sock != -1)
832 main_imsg_compose_frontend_fd(IMSG_UDP6SOCK, 0, udp6sock);
833 if (tcp4sock != -1)
834 main_imsg_compose_frontend_fd(IMSG_TCP4SOCK, 0, tcp4sock);
835 if (tcp6sock != -1)
836 main_imsg_compose_frontend_fd(IMSG_TCP6SOCK, 0, tcp6sock);
837}
838
839void
840solicit_dns_proposals(void)
841{
842 struct rt_msghdr rtm;
843 struct iovec iov[1];
844 int iovcnt = 0;
845
846 memset(&rtm, 0, sizeof(rtm));
847
848 rtm.rtm_version = RTM_VERSION5;
849 rtm.rtm_type = RTM_PROPOSAL0x13;
850 rtm.rtm_msglen = sizeof(rtm);
851 rtm.rtm_tableid = 0;
852 rtm.rtm_index = 0;
853 rtm.rtm_seq = arc4random();
854 rtm.rtm_priority = RTP_PROPOSAL_SOLICIT62;
855
856 iov[iovcnt].iov_base = &rtm;
857 iov[iovcnt++].iov_len = sizeof(rtm);
858
859 if (writev(routesock, iov, iovcnt) == -1)
860 log_warn("failed to send solicitation")uw_log_warn("failed to send solicitation");
861}
862
863void
864send_blocklist_fd(void)
865{
866 int bl_fd;
867
868 if ((bl_fd = open(main_conf->blocklist_file, O_RDONLY0x0000)) != -1)
869 main_imsg_compose_frontend_fd(IMSG_BLFD, 0, bl_fd);
870 else
871 log_warn("%s", main_conf->blocklist_file)uw_log_warn("%s", main_conf->blocklist_file);
872}
873
874void
875imsg_receive_config(struct imsg *imsg, struct uw_conf **xconf)
876{
877 struct uw_conf *nconf;
878 struct uw_forwarder *uw_forwarder;
879 struct force_tree_entry *force_entry;
880
881 nconf = *xconf;
882
883 switch (imsg->hdr.type) {
884 case IMSG_RECONF_CONF:
885 if (nconf != NULL((void *)0))
886 fatalx("%s: IMSG_RECONF_CONF already in "
887 "progress", __func__);
888 if (IMSG_DATA_SIZE(*imsg)((*imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct uw_conf))
889 fatalx("%s: IMSG_RECONF_CONF wrong length: %lu",
890 __func__, IMSG_DATA_SIZE(*imsg)((*imsg).hdr.len - sizeof(struct imsg_hdr)));
891 if ((*xconf = malloc(sizeof(struct uw_conf))) == NULL((void *)0))
892 fatal(NULL((void *)0));
893 nconf = *xconf;
894 memcpy(nconf, imsg->data, sizeof(struct uw_conf));
895 TAILQ_INIT(&nconf->uw_forwarder_list)do { (&nconf->uw_forwarder_list)->tqh_first = ((void
*)0); (&nconf->uw_forwarder_list)->tqh_last = &
(&nconf->uw_forwarder_list)->tqh_first; } while (0)
;
896 TAILQ_INIT(&nconf->uw_dot_forwarder_list)do { (&nconf->uw_dot_forwarder_list)->tqh_first = (
(void *)0); (&nconf->uw_dot_forwarder_list)->tqh_last
= &(&nconf->uw_dot_forwarder_list)->tqh_first;
} while (0)
;
897 RB_INIT(&nconf->force)do { (&nconf->force)->rbh_root = ((void *)0); } while
(0)
;
898 break;
899 case IMSG_RECONF_BLOCKLIST_FILE:
900 if (((char *)imsg->data)[IMSG_DATA_SIZE(*imsg)((*imsg).hdr.len - sizeof(struct imsg_hdr)) - 1] != '\0')
901 fatalx("Invalid blocklist file");
902 if ((nconf->blocklist_file = strdup(imsg->data)) ==
903 NULL((void *)0))
904 fatal("%s: strdup", __func__);
905 break;
906 case IMSG_RECONF_FORWARDER:
907 if (IMSG_DATA_SIZE(*imsg)((*imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct uw_forwarder))
908 fatalx("%s: IMSG_RECONF_FORWARDER wrong length:"
909 " %lu", __func__, IMSG_DATA_SIZE(*imsg)((*imsg).hdr.len - sizeof(struct imsg_hdr)));
910 if ((uw_forwarder = malloc(sizeof(struct
911 uw_forwarder))) == NULL((void *)0))
912 fatal(NULL((void *)0));
913 memcpy(uw_forwarder, imsg->data, sizeof(struct
914 uw_forwarder));
915 TAILQ_INSERT_TAIL(&nconf->uw_forwarder_list,do { (uw_forwarder)->entry.tqe_next = ((void *)0); (uw_forwarder
)->entry.tqe_prev = (&nconf->uw_forwarder_list)->
tqh_last; *(&nconf->uw_forwarder_list)->tqh_last = (
uw_forwarder); (&nconf->uw_forwarder_list)->tqh_last
= &(uw_forwarder)->entry.tqe_next; } while (0)
916 uw_forwarder, entry)do { (uw_forwarder)->entry.tqe_next = ((void *)0); (uw_forwarder
)->entry.tqe_prev = (&nconf->uw_forwarder_list)->
tqh_last; *(&nconf->uw_forwarder_list)->tqh_last = (
uw_forwarder); (&nconf->uw_forwarder_list)->tqh_last
= &(uw_forwarder)->entry.tqe_next; } while (0)
;
917 break;
918 case IMSG_RECONF_DOT_FORWARDER:
919 if (IMSG_DATA_SIZE(*imsg)((*imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct uw_forwarder))
920 fatalx("%s: IMSG_RECONF_DOT_FORWARDER wrong "
921 "length: %lu", __func__,
922 IMSG_DATA_SIZE(*imsg)((*imsg).hdr.len - sizeof(struct imsg_hdr)));
923 if ((uw_forwarder = malloc(sizeof(struct
924 uw_forwarder))) == NULL((void *)0))
925 fatal(NULL((void *)0));
926 memcpy(uw_forwarder, imsg->data, sizeof(struct
927 uw_forwarder));
928 TAILQ_INSERT_TAIL(&nconf->uw_dot_forwarder_list,do { (uw_forwarder)->entry.tqe_next = ((void *)0); (uw_forwarder
)->entry.tqe_prev = (&nconf->uw_dot_forwarder_list)
->tqh_last; *(&nconf->uw_dot_forwarder_list)->tqh_last
= (uw_forwarder); (&nconf->uw_dot_forwarder_list)->
tqh_last = &(uw_forwarder)->entry.tqe_next; } while (0
)
929 uw_forwarder, entry)do { (uw_forwarder)->entry.tqe_next = ((void *)0); (uw_forwarder
)->entry.tqe_prev = (&nconf->uw_dot_forwarder_list)
->tqh_last; *(&nconf->uw_dot_forwarder_list)->tqh_last
= (uw_forwarder); (&nconf->uw_dot_forwarder_list)->
tqh_last = &(uw_forwarder)->entry.tqe_next; } while (0
)
;
930 break;
931 case IMSG_RECONF_FORCE:
932 if (IMSG_DATA_SIZE(*imsg)((*imsg).hdr.len - sizeof(struct imsg_hdr)) != sizeof(struct force_tree_entry))
933 fatalx("%s: IMSG_RECONF_FORCE wrong "
934 "length: %lu", __func__,
935 IMSG_DATA_SIZE(*imsg)((*imsg).hdr.len - sizeof(struct imsg_hdr)));
936 if ((force_entry = malloc(sizeof(struct
937 force_tree_entry))) == NULL((void *)0))
938 fatal(NULL((void *)0));
939 memcpy(force_entry, imsg->data, sizeof(struct
940 force_tree_entry));
941 if (RB_INSERT(force_tree, &nconf->force, force_entry)force_tree_RB_INSERT(&nconf->force, force_entry) != NULL((void *)0)) {
942 free(force_entry);
943 fatalx("%s: IMSG_RECONF_FORCE duplicate entry",
944 __func__);
945 }
946 break;
947 default:
948 log_debug("%s: error handling imsg %d", __func__,
949 imsg->hdr.type);
950 break;
951 }
952}