1*2d988276Sflorian /* $OpenBSD: unwind.c,v 1.26 2019/05/10 14:10:38 florian Exp $ */ 2018cebfbSflorian 3018cebfbSflorian /* 4018cebfbSflorian * Copyright (c) 2018 Florian Obser <florian@openbsd.org> 5018cebfbSflorian * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6018cebfbSflorian * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 7018cebfbSflorian * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 8018cebfbSflorian * 9018cebfbSflorian * Permission to use, copy, modify, and distribute this software for any 10018cebfbSflorian * purpose with or without fee is hereby granted, provided that the above 11018cebfbSflorian * copyright notice and this permission notice appear in all copies. 12018cebfbSflorian * 13018cebfbSflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14018cebfbSflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15018cebfbSflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16018cebfbSflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17018cebfbSflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18018cebfbSflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19018cebfbSflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20018cebfbSflorian */ 21018cebfbSflorian #include <sys/types.h> 22018cebfbSflorian #include <sys/queue.h> 23018cebfbSflorian #include <sys/socket.h> 24296cf316Sflorian #include <sys/stat.h> 25018cebfbSflorian #include <sys/syslog.h> 26018cebfbSflorian #include <sys/wait.h> 27018cebfbSflorian 28018cebfbSflorian #include <net/if.h> 29018cebfbSflorian #include <net/route.h> 30018cebfbSflorian 31018cebfbSflorian #include <err.h> 32018cebfbSflorian #include <errno.h> 33018cebfbSflorian #include <event.h> 34018cebfbSflorian #include <fcntl.h> 35018cebfbSflorian #include <imsg.h> 36018cebfbSflorian #include <netdb.h> 372f29e846Sflorian #include <asr.h> 38018cebfbSflorian #include <pwd.h> 39018cebfbSflorian #include <stdio.h> 40018cebfbSflorian #include <stdlib.h> 41018cebfbSflorian #include <string.h> 42018cebfbSflorian #include <signal.h> 43018cebfbSflorian #include <unistd.h> 44018cebfbSflorian 4558b5b9b8Sflorian #include "log.h" 46018cebfbSflorian #include "unwind.h" 47018cebfbSflorian #include "frontend.h" 48018cebfbSflorian #include "resolver.h" 49018cebfbSflorian #include "control.h" 50b2501eadSflorian #include "captiveportal.h" 51018cebfbSflorian 52296cf316Sflorian #define LEASE_DB_DIR "/var/db/" 53296cf316Sflorian #define _PATH_LEASE_DB "/var/db/dhclient.leases." 54296cf316Sflorian 5590d56d5fSflorian #define TRUST_ANCHOR_FILE "/var/db/unwind.key" 56296cf316Sflorian 57018cebfbSflorian __dead void usage(void); 58018cebfbSflorian __dead void main_shutdown(void); 59018cebfbSflorian 60018cebfbSflorian void main_sig_handler(int, short, void *); 61018cebfbSflorian 62018cebfbSflorian static pid_t start_child(int, char *, int, int, int); 63018cebfbSflorian 64018cebfbSflorian void main_dispatch_frontend(int, short, void *); 65018cebfbSflorian void main_dispatch_resolver(int, short, void *); 66b2501eadSflorian void main_dispatch_captiveportal(int, short, void *); 67018cebfbSflorian 68b2501eadSflorian static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *, 69b2501eadSflorian struct imsgbuf *); 70bb81f7e1Sflorian static int main_imsg_send_config(struct uw_conf *); 71018cebfbSflorian 72018cebfbSflorian int main_reload(void); 73b2501eadSflorian int main_sendall(enum imsg_type, void *, uint16_t); 74018cebfbSflorian void open_dhcp_lease(int); 75d265a5d3Sflorian void open_ports(void); 762f29e846Sflorian void resolve_captive_portal(void); 772f29e846Sflorian void resolve_captive_portal_done(struct asr_result *, void *); 78*2d988276Sflorian void send_blocklist_fd(void); 79018cebfbSflorian 80bb81f7e1Sflorian struct uw_conf *main_conf; 81018cebfbSflorian struct imsgev *iev_frontend; 82018cebfbSflorian struct imsgev *iev_resolver; 83b2501eadSflorian struct imsgev *iev_captiveportal; 84018cebfbSflorian char *conffile; 85018cebfbSflorian 86018cebfbSflorian pid_t frontend_pid; 87018cebfbSflorian pid_t resolver_pid; 88b2501eadSflorian pid_t captiveportal_pid; 89018cebfbSflorian 90018cebfbSflorian uint32_t cmd_opts; 91018cebfbSflorian 92018cebfbSflorian void 93018cebfbSflorian main_sig_handler(int sig, short event, void *arg) 94018cebfbSflorian { 95018cebfbSflorian /* 96018cebfbSflorian * Normal signal handler rules don't apply because libevent 97018cebfbSflorian * decouples for us. 98018cebfbSflorian */ 99018cebfbSflorian 100018cebfbSflorian switch (sig) { 101018cebfbSflorian case SIGTERM: 102018cebfbSflorian case SIGINT: 1035472663aSflorian main_shutdown(); 104018cebfbSflorian break; 105018cebfbSflorian case SIGHUP: 106018cebfbSflorian if (main_reload() == -1) 107018cebfbSflorian log_warnx("configuration reload failed"); 108018cebfbSflorian else 109018cebfbSflorian log_debug("configuration reloaded"); 110018cebfbSflorian break; 111018cebfbSflorian default: 112018cebfbSflorian fatalx("unexpected signal"); 113018cebfbSflorian } 114018cebfbSflorian } 115018cebfbSflorian 116018cebfbSflorian __dead void 117018cebfbSflorian usage(void) 118018cebfbSflorian { 119018cebfbSflorian extern char *__progname; 120018cebfbSflorian 121018cebfbSflorian fprintf(stderr, "usage: %s [-dnv] [-f file] [-s socket]\n", 122018cebfbSflorian __progname); 123018cebfbSflorian exit(1); 124018cebfbSflorian } 125018cebfbSflorian 126018cebfbSflorian int 127018cebfbSflorian main(int argc, char *argv[]) 128018cebfbSflorian { 129018cebfbSflorian struct event ev_sigint, ev_sigterm, ev_sighup; 130bb81f7e1Sflorian int ch, debug = 0, resolver_flag = 0, frontend_flag = 0; 131bb81f7e1Sflorian int captiveportal_flag = 0, frontend_routesock, rtfilter; 132bb81f7e1Sflorian int pipe_main2frontend[2], pipe_main2resolver[2]; 133b2501eadSflorian int pipe_main2captiveportal[2]; 134d1b04a40Sflorian int control_fd, ta_fd; 135bb81f7e1Sflorian char *csock, *saved_argv0; 136018cebfbSflorian 137018cebfbSflorian conffile = CONF_FILE; 138018cebfbSflorian csock = UNWIND_SOCKET; 139018cebfbSflorian 140018cebfbSflorian log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ 141018cebfbSflorian log_setverbose(1); 142018cebfbSflorian 143018cebfbSflorian saved_argv0 = argv[0]; 144018cebfbSflorian if (saved_argv0 == NULL) 145018cebfbSflorian saved_argv0 = "unwind"; 146018cebfbSflorian 147b2501eadSflorian while ((ch = getopt(argc, argv, "CdEFf:ns:v")) != -1) { 148018cebfbSflorian switch (ch) { 149b2501eadSflorian case 'C': 150b2501eadSflorian captiveportal_flag = 1; 151b2501eadSflorian break; 152018cebfbSflorian case 'd': 153018cebfbSflorian debug = 1; 154018cebfbSflorian break; 155018cebfbSflorian case 'E': 156018cebfbSflorian resolver_flag = 1; 157018cebfbSflorian break; 158018cebfbSflorian case 'F': 159018cebfbSflorian frontend_flag = 1; 160018cebfbSflorian break; 161018cebfbSflorian case 'f': 162018cebfbSflorian conffile = optarg; 163018cebfbSflorian break; 164018cebfbSflorian case 'n': 165018cebfbSflorian cmd_opts |= OPT_NOACTION; 166018cebfbSflorian break; 167018cebfbSflorian case 's': 168018cebfbSflorian csock = optarg; 169018cebfbSflorian break; 170018cebfbSflorian case 'v': 171018cebfbSflorian if (cmd_opts & OPT_VERBOSE) 172018cebfbSflorian cmd_opts |= OPT_VERBOSE2; 173018cebfbSflorian cmd_opts |= OPT_VERBOSE; 174018cebfbSflorian break; 175018cebfbSflorian default: 176018cebfbSflorian usage(); 177018cebfbSflorian } 178018cebfbSflorian } 179018cebfbSflorian 180018cebfbSflorian argc -= optind; 181018cebfbSflorian argv += optind; 182b2501eadSflorian if (argc > 0 || (resolver_flag && frontend_flag && captiveportal_flag)) 183018cebfbSflorian usage(); 184018cebfbSflorian 185018cebfbSflorian if (resolver_flag) 186018cebfbSflorian resolver(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2)); 187018cebfbSflorian else if (frontend_flag) 188018cebfbSflorian frontend(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2)); 189b2501eadSflorian else if (captiveportal_flag) 190b2501eadSflorian captiveportal(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2)); 191018cebfbSflorian 192588e8263Sflorian if ((main_conf = parse_config(conffile)) == NULL) 193018cebfbSflorian exit(1); 194018cebfbSflorian 195018cebfbSflorian if (cmd_opts & OPT_NOACTION) { 196018cebfbSflorian if (cmd_opts & OPT_VERBOSE) 197018cebfbSflorian print_config(main_conf); 198018cebfbSflorian else 199018cebfbSflorian fprintf(stderr, "configuration OK\n"); 200018cebfbSflorian exit(0); 201018cebfbSflorian } 202018cebfbSflorian 203018cebfbSflorian /* Check for root privileges. */ 204018cebfbSflorian if (geteuid()) 205018cebfbSflorian errx(1, "need root privileges"); 206018cebfbSflorian 207018cebfbSflorian /* Check for assigned daemon user */ 208018cebfbSflorian if (getpwnam(UNWIND_USER) == NULL) 209018cebfbSflorian errx(1, "unknown user %s", UNWIND_USER); 210018cebfbSflorian 211018cebfbSflorian log_init(debug, LOG_DAEMON); 212018cebfbSflorian log_setverbose(cmd_opts & OPT_VERBOSE); 213018cebfbSflorian 214018cebfbSflorian if (!debug) 215018cebfbSflorian daemon(1, 0); 216018cebfbSflorian 217018cebfbSflorian log_info("startup"); 218018cebfbSflorian 219018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 220018cebfbSflorian PF_UNSPEC, pipe_main2frontend) == -1) 221018cebfbSflorian fatal("main2frontend socketpair"); 222018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 223018cebfbSflorian PF_UNSPEC, pipe_main2resolver) == -1) 224018cebfbSflorian fatal("main2resolver socketpair"); 225b2501eadSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 226b2501eadSflorian PF_UNSPEC, pipe_main2captiveportal) == -1) 227b2501eadSflorian fatal("main2captiveportal socketpair"); 228018cebfbSflorian 229018cebfbSflorian /* Start children. */ 230018cebfbSflorian resolver_pid = start_child(PROC_RESOLVER, saved_argv0, 231018cebfbSflorian pipe_main2resolver[1], debug, cmd_opts & (OPT_VERBOSE | 232018cebfbSflorian OPT_VERBOSE2)); 233018cebfbSflorian frontend_pid = start_child(PROC_FRONTEND, saved_argv0, 234018cebfbSflorian pipe_main2frontend[1], debug, cmd_opts & (OPT_VERBOSE | 235018cebfbSflorian OPT_VERBOSE2)); 236b2501eadSflorian captiveportal_pid = start_child(PROC_CAPTIVEPORTAL, saved_argv0, 237b2501eadSflorian pipe_main2captiveportal[1], debug, cmd_opts & (OPT_VERBOSE | 238b2501eadSflorian OPT_VERBOSE2)); 239018cebfbSflorian 240bb81f7e1Sflorian uw_process = PROC_MAIN; 241bb81f7e1Sflorian log_procinit(log_procnames[uw_process]); 242018cebfbSflorian 243018cebfbSflorian event_init(); 244018cebfbSflorian 245018cebfbSflorian /* Setup signal handler. */ 246018cebfbSflorian signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 247018cebfbSflorian signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 248018cebfbSflorian signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); 249018cebfbSflorian signal_add(&ev_sigint, NULL); 250018cebfbSflorian signal_add(&ev_sigterm, NULL); 251018cebfbSflorian signal_add(&ev_sighup, NULL); 252018cebfbSflorian signal(SIGPIPE, SIG_IGN); 253018cebfbSflorian 254018cebfbSflorian /* Setup pipes to children. */ 255018cebfbSflorian 256018cebfbSflorian if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL || 257b2501eadSflorian (iev_captiveportal = malloc(sizeof(struct imsgev))) == NULL || 258018cebfbSflorian (iev_resolver = malloc(sizeof(struct imsgev))) == NULL) 259018cebfbSflorian fatal(NULL); 260018cebfbSflorian imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]); 261018cebfbSflorian iev_frontend->handler = main_dispatch_frontend; 262018cebfbSflorian imsg_init(&iev_resolver->ibuf, pipe_main2resolver[0]); 263018cebfbSflorian iev_resolver->handler = main_dispatch_resolver; 264b2501eadSflorian imsg_init(&iev_captiveportal->ibuf, pipe_main2captiveportal[0]); 265b2501eadSflorian iev_captiveportal->handler = main_dispatch_captiveportal; 266018cebfbSflorian 267b2501eadSflorian /* Setup event handlers for pipes. */ 268018cebfbSflorian iev_frontend->events = EV_READ; 269018cebfbSflorian event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 270018cebfbSflorian iev_frontend->events, iev_frontend->handler, iev_frontend); 271018cebfbSflorian event_add(&iev_frontend->ev, NULL); 272018cebfbSflorian 273018cebfbSflorian iev_resolver->events = EV_READ; 274bb81f7e1Sflorian event_set(&iev_resolver->ev, iev_resolver->ibuf.fd, 275bb81f7e1Sflorian iev_resolver->events, iev_resolver->handler, iev_resolver); 276018cebfbSflorian event_add(&iev_resolver->ev, NULL); 277018cebfbSflorian 278b2501eadSflorian iev_captiveportal->events = EV_READ; 279b2501eadSflorian event_set(&iev_captiveportal->ev, iev_captiveportal->ibuf.fd, 280b2501eadSflorian iev_captiveportal->events, iev_captiveportal->handler, 281b2501eadSflorian iev_captiveportal); 282b2501eadSflorian event_add(&iev_captiveportal->ev, NULL); 283b2501eadSflorian 284b2501eadSflorian if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, 285b2501eadSflorian &iev_resolver->ibuf, &iev_captiveportal->ibuf)) 286018cebfbSflorian fatal("could not establish imsg links"); 287018cebfbSflorian 288018cebfbSflorian if ((control_fd = control_init(csock)) == -1) 289018cebfbSflorian fatalx("control socket setup failed"); 290018cebfbSflorian 2919e627e00Sflorian if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 292018cebfbSflorian AF_INET)) < 0) 293018cebfbSflorian fatal("route socket"); 294018cebfbSflorian 295018cebfbSflorian rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_PROPOSAL) | 296018cebfbSflorian ROUTE_FILTER(RTM_GET); 2979e627e00Sflorian if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, 298018cebfbSflorian &rtfilter, sizeof(rtfilter)) < 0) 299018cebfbSflorian fatal("setsockopt(ROUTE_MSGFILTER)"); 300018cebfbSflorian 301d1b04a40Sflorian if ((ta_fd = open(TRUST_ANCHOR_FILE, O_RDWR | O_CREAT, 0644)) == -1) 302d1b04a40Sflorian log_warn("%s", TRUST_ANCHOR_FILE); 303d1b04a40Sflorian 304d1b04a40Sflorian /* receiver handles failed open correctly */ 305d1b04a40Sflorian main_imsg_compose_frontend_fd(IMSG_TAFD, 0, ta_fd); 306d1b04a40Sflorian 307018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_CONTROLFD, 0, control_fd); 308018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_ROUTESOCK, 0, frontend_routesock); 309018cebfbSflorian main_imsg_send_config(main_conf); 310018cebfbSflorian 311*2d988276Sflorian if (main_conf->blocklist_file != NULL) 312*2d988276Sflorian send_blocklist_fd(); 313*2d988276Sflorian 314d1b04a40Sflorian if (pledge("stdio inet dns rpath sendfd", NULL) == -1) 315018cebfbSflorian fatal("pledge"); 316018cebfbSflorian 317018cebfbSflorian main_imsg_compose_frontend(IMSG_STARTUP, 0, NULL, 0); 318296cf316Sflorian main_imsg_compose_resolver(IMSG_STARTUP, 0, NULL, 0); 319018cebfbSflorian 320018cebfbSflorian event_dispatch(); 321018cebfbSflorian 322018cebfbSflorian main_shutdown(); 323018cebfbSflorian return (0); 324018cebfbSflorian } 325018cebfbSflorian 326018cebfbSflorian __dead void 327018cebfbSflorian main_shutdown(void) 328018cebfbSflorian { 329018cebfbSflorian pid_t pid; 330018cebfbSflorian int status; 331018cebfbSflorian 332018cebfbSflorian /* Close pipes. */ 333018cebfbSflorian msgbuf_clear(&iev_frontend->ibuf.w); 334018cebfbSflorian close(iev_frontend->ibuf.fd); 335018cebfbSflorian msgbuf_clear(&iev_resolver->ibuf.w); 336018cebfbSflorian close(iev_resolver->ibuf.fd); 337b2501eadSflorian msgbuf_clear(&iev_captiveportal->ibuf.w); 338b2501eadSflorian close(iev_captiveportal->ibuf.fd); 339018cebfbSflorian 340018cebfbSflorian config_clear(main_conf); 341018cebfbSflorian 342018cebfbSflorian log_debug("waiting for children to terminate"); 343018cebfbSflorian do { 344018cebfbSflorian pid = wait(&status); 345018cebfbSflorian if (pid == -1) { 346018cebfbSflorian if (errno != EINTR && errno != ECHILD) 347018cebfbSflorian fatal("wait"); 348018cebfbSflorian } else if (WIFSIGNALED(status)) 349018cebfbSflorian log_warnx("%s terminated; signal %d", 350018cebfbSflorian (pid == resolver_pid) ? "resolver" : 351018cebfbSflorian "frontend", WTERMSIG(status)); 352018cebfbSflorian } while (pid != -1 || (pid == -1 && errno == EINTR)); 353018cebfbSflorian 354018cebfbSflorian free(iev_frontend); 355018cebfbSflorian free(iev_resolver); 356b2501eadSflorian free(iev_captiveportal); 357018cebfbSflorian 358018cebfbSflorian log_info("terminating"); 359018cebfbSflorian exit(0); 360018cebfbSflorian } 361018cebfbSflorian 362018cebfbSflorian static pid_t 363018cebfbSflorian start_child(int p, char *argv0, int fd, int debug, int verbose) 364018cebfbSflorian { 365018cebfbSflorian char *argv[7]; 366018cebfbSflorian int argc = 0; 367018cebfbSflorian pid_t pid; 368018cebfbSflorian 369018cebfbSflorian switch (pid = fork()) { 370018cebfbSflorian case -1: 371018cebfbSflorian fatal("cannot fork"); 372018cebfbSflorian case 0: 373018cebfbSflorian break; 374018cebfbSflorian default: 375018cebfbSflorian close(fd); 376018cebfbSflorian return (pid); 377018cebfbSflorian } 378018cebfbSflorian 379ef4f5895Syasuoka if (fd != 3) { 380018cebfbSflorian if (dup2(fd, 3) == -1) 381018cebfbSflorian fatal("cannot setup imsg fd"); 382ef4f5895Syasuoka } else if (fcntl(fd, F_SETFD, 0) == -1) 383ef4f5895Syasuoka fatal("cannot setup imsg fd"); 384018cebfbSflorian 385018cebfbSflorian argv[argc++] = argv0; 386018cebfbSflorian switch (p) { 387018cebfbSflorian case PROC_MAIN: 388018cebfbSflorian fatalx("Can not start main process"); 389018cebfbSflorian case PROC_RESOLVER: 390018cebfbSflorian argv[argc++] = "-E"; 391018cebfbSflorian break; 392018cebfbSflorian case PROC_FRONTEND: 393018cebfbSflorian argv[argc++] = "-F"; 394018cebfbSflorian break; 395b2501eadSflorian case PROC_CAPTIVEPORTAL: 396b2501eadSflorian argv[argc++] = "-C"; 397b2501eadSflorian break; 398018cebfbSflorian } 399018cebfbSflorian if (debug) 400018cebfbSflorian argv[argc++] = "-d"; 401018cebfbSflorian if (verbose & OPT_VERBOSE) 402018cebfbSflorian argv[argc++] = "-v"; 403018cebfbSflorian if (verbose & OPT_VERBOSE2) 404018cebfbSflorian argv[argc++] = "-v"; 405018cebfbSflorian argv[argc++] = NULL; 406018cebfbSflorian 407018cebfbSflorian execvp(argv0, argv); 408018cebfbSflorian fatal("execvp"); 409018cebfbSflorian } 410018cebfbSflorian 411018cebfbSflorian void 412018cebfbSflorian main_dispatch_frontend(int fd, short event, void *bula) 413018cebfbSflorian { 414018cebfbSflorian struct imsgev *iev = bula; 415018cebfbSflorian struct imsgbuf *ibuf; 416018cebfbSflorian struct imsg imsg; 417018cebfbSflorian ssize_t n; 418018cebfbSflorian int shut = 0, verbose; 419018cebfbSflorian u_short rtm_index; 420018cebfbSflorian 421018cebfbSflorian ibuf = &iev->ibuf; 422018cebfbSflorian 423018cebfbSflorian if (event & EV_READ) { 424018cebfbSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 425018cebfbSflorian fatal("imsg_read error"); 426018cebfbSflorian if (n == 0) /* Connection closed. */ 427018cebfbSflorian shut = 1; 428018cebfbSflorian } 429018cebfbSflorian if (event & EV_WRITE) { 430018cebfbSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 431018cebfbSflorian fatal("msgbuf_write"); 432018cebfbSflorian if (n == 0) /* Connection closed. */ 433018cebfbSflorian shut = 1; 434018cebfbSflorian } 435018cebfbSflorian 436018cebfbSflorian for (;;) { 437018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 438018cebfbSflorian fatal("imsg_get"); 439018cebfbSflorian if (n == 0) /* No more messages. */ 440018cebfbSflorian break; 441018cebfbSflorian 442018cebfbSflorian switch (imsg.hdr.type) { 443018cebfbSflorian case IMSG_STARTUP_DONE: 444018cebfbSflorian break; 445018cebfbSflorian case IMSG_CTL_RELOAD: 446018cebfbSflorian if (main_reload() == -1) 447018cebfbSflorian log_warnx("configuration reload failed"); 448018cebfbSflorian else 449018cebfbSflorian log_warnx("configuration reloaded"); 450018cebfbSflorian break; 451018cebfbSflorian case IMSG_CTL_LOG_VERBOSE: 452a9155f32Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 4532b821978Sflorian fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " 454a9155f32Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 455018cebfbSflorian memcpy(&verbose, imsg.data, sizeof(verbose)); 456018cebfbSflorian log_setverbose(verbose); 457018cebfbSflorian break; 458018cebfbSflorian case IMSG_OPEN_DHCP_LEASE: 459a9155f32Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(rtm_index)) 4602b821978Sflorian fatalx("%s: IMSG_OPEN_DHCP_LEASE wrong length: " 461a9155f32Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 462018cebfbSflorian memcpy(&rtm_index, imsg.data, sizeof(rtm_index)); 463018cebfbSflorian open_dhcp_lease(rtm_index); 464018cebfbSflorian break; 465d265a5d3Sflorian case IMSG_OPEN_PORTS: 466d265a5d3Sflorian open_ports(); 467d265a5d3Sflorian break; 468018cebfbSflorian default: 469018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 470018cebfbSflorian imsg.hdr.type); 471018cebfbSflorian break; 472018cebfbSflorian } 473018cebfbSflorian imsg_free(&imsg); 474018cebfbSflorian } 475018cebfbSflorian if (!shut) 476018cebfbSflorian imsg_event_add(iev); 477018cebfbSflorian else { 478018cebfbSflorian /* This pipe is dead. Remove its event handler */ 479018cebfbSflorian event_del(&iev->ev); 480018cebfbSflorian event_loopexit(NULL); 481018cebfbSflorian } 482018cebfbSflorian } 483018cebfbSflorian 484018cebfbSflorian void 485018cebfbSflorian main_dispatch_resolver(int fd, short event, void *bula) 486018cebfbSflorian { 487018cebfbSflorian struct imsgev *iev = bula; 488018cebfbSflorian struct imsgbuf *ibuf; 489018cebfbSflorian struct imsg imsg; 490b2501eadSflorian ssize_t n; 4912f29e846Sflorian int shut = 0; 492b2501eadSflorian 493b2501eadSflorian ibuf = &iev->ibuf; 494b2501eadSflorian 495b2501eadSflorian if (event & EV_READ) { 496b2501eadSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 497b2501eadSflorian fatal("imsg_read error"); 498b2501eadSflorian if (n == 0) /* Connection closed. */ 499b2501eadSflorian shut = 1; 500b2501eadSflorian } 501b2501eadSflorian if (event & EV_WRITE) { 502b2501eadSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 503b2501eadSflorian fatal("msgbuf_write"); 504b2501eadSflorian if (n == 0) /* Connection closed. */ 505b2501eadSflorian shut = 1; 506b2501eadSflorian } 507b2501eadSflorian 508b2501eadSflorian for (;;) { 509b2501eadSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 510b2501eadSflorian fatal("imsg_get"); 511b2501eadSflorian if (n == 0) /* No more messages. */ 512b2501eadSflorian break; 513b2501eadSflorian 514b2501eadSflorian switch (imsg.hdr.type) { 5152f29e846Sflorian case IMSG_RESOLVE_CAPTIVE_PORTAL: 5162f29e846Sflorian resolve_captive_portal(); 517b2501eadSflorian break; 518b2501eadSflorian default: 519b2501eadSflorian log_debug("%s: error handling imsg %d", __func__, 520b2501eadSflorian imsg.hdr.type); 521b2501eadSflorian break; 522b2501eadSflorian } 523b2501eadSflorian imsg_free(&imsg); 524b2501eadSflorian } 525b2501eadSflorian if (!shut) 526b2501eadSflorian imsg_event_add(iev); 527b2501eadSflorian else { 528b2501eadSflorian /* This pipe is dead. Remove its event handler. */ 529b2501eadSflorian event_del(&iev->ev); 530b2501eadSflorian event_loopexit(NULL); 531b2501eadSflorian } 532b2501eadSflorian } 533b2501eadSflorian 534b2501eadSflorian void 535b2501eadSflorian main_dispatch_captiveportal(int fd, short event, void *bula) 536b2501eadSflorian { 537b2501eadSflorian struct imsgev *iev = bula; 538b2501eadSflorian struct imsgbuf *ibuf; 539b2501eadSflorian struct imsg imsg; 540018cebfbSflorian ssize_t n; 541018cebfbSflorian int shut = 0; 542018cebfbSflorian 543018cebfbSflorian ibuf = &iev->ibuf; 544018cebfbSflorian 545018cebfbSflorian if (event & EV_READ) { 546018cebfbSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 547018cebfbSflorian fatal("imsg_read error"); 548018cebfbSflorian if (n == 0) /* Connection closed. */ 549018cebfbSflorian shut = 1; 550018cebfbSflorian } 551018cebfbSflorian if (event & EV_WRITE) { 552018cebfbSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 553018cebfbSflorian fatal("msgbuf_write"); 554018cebfbSflorian if (n == 0) /* Connection closed. */ 555018cebfbSflorian shut = 1; 556018cebfbSflorian } 557018cebfbSflorian 558018cebfbSflorian for (;;) { 559018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 560018cebfbSflorian fatal("imsg_get"); 561018cebfbSflorian if (n == 0) /* No more messages. */ 562018cebfbSflorian break; 563018cebfbSflorian 564018cebfbSflorian switch (imsg.hdr.type) { 565018cebfbSflorian default: 566018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 567018cebfbSflorian imsg.hdr.type); 568018cebfbSflorian break; 569018cebfbSflorian } 570018cebfbSflorian imsg_free(&imsg); 571018cebfbSflorian } 572018cebfbSflorian if (!shut) 573018cebfbSflorian imsg_event_add(iev); 574018cebfbSflorian else { 575018cebfbSflorian /* This pipe is dead. Remove its event handler. */ 576018cebfbSflorian event_del(&iev->ev); 577018cebfbSflorian event_loopexit(NULL); 578018cebfbSflorian } 579018cebfbSflorian } 580018cebfbSflorian 581018cebfbSflorian void 582018cebfbSflorian main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) 583018cebfbSflorian { 584018cebfbSflorian if (iev_frontend) 585018cebfbSflorian imsg_compose_event(iev_frontend, type, 0, pid, -1, data, 586018cebfbSflorian datalen); 587018cebfbSflorian } 588018cebfbSflorian 589018cebfbSflorian void 590018cebfbSflorian main_imsg_compose_frontend_fd(int type, pid_t pid, int fd) 591018cebfbSflorian { 592018cebfbSflorian if (iev_frontend) 593018cebfbSflorian imsg_compose_event(iev_frontend, type, 0, pid, fd, NULL, 0); 594018cebfbSflorian } 595018cebfbSflorian 596018cebfbSflorian void 597018cebfbSflorian main_imsg_compose_resolver(int type, pid_t pid, void *data, uint16_t datalen) 598018cebfbSflorian { 599018cebfbSflorian if (iev_resolver) 600018cebfbSflorian imsg_compose_event(iev_resolver, type, 0, pid, -1, data, 601018cebfbSflorian datalen); 602018cebfbSflorian } 603018cebfbSflorian 604018cebfbSflorian void 605b2501eadSflorian main_imsg_compose_captiveportal(int type, pid_t pid, void *data, 606b2501eadSflorian uint16_t datalen) 607b2501eadSflorian { 608b2501eadSflorian if (iev_captiveportal) 609b2501eadSflorian imsg_compose_event(iev_captiveportal, type, 0, pid, -1, data, 610b2501eadSflorian datalen); 611b2501eadSflorian } 612b2501eadSflorian 613b2501eadSflorian void 614b2501eadSflorian main_imsg_compose_captiveportal_fd(int type, pid_t pid, int fd) 615b2501eadSflorian { 616b2501eadSflorian if (iev_frontend) 617b2501eadSflorian imsg_compose_event(iev_captiveportal, type, 0, pid, fd, NULL, 618b2501eadSflorian 0); 619b2501eadSflorian } 620b2501eadSflorian 621b2501eadSflorian void 622018cebfbSflorian imsg_event_add(struct imsgev *iev) 623018cebfbSflorian { 624018cebfbSflorian iev->events = EV_READ; 625018cebfbSflorian if (iev->ibuf.w.queued) 626018cebfbSflorian iev->events |= EV_WRITE; 627018cebfbSflorian 628018cebfbSflorian event_del(&iev->ev); 629018cebfbSflorian event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 630018cebfbSflorian event_add(&iev->ev, NULL); 631018cebfbSflorian } 632018cebfbSflorian 633018cebfbSflorian int 634018cebfbSflorian imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 635018cebfbSflorian pid_t pid, int fd, void *data, uint16_t datalen) 636018cebfbSflorian { 637018cebfbSflorian int ret; 638018cebfbSflorian 639018cebfbSflorian if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 640018cebfbSflorian datalen)) != -1) 641018cebfbSflorian imsg_event_add(iev); 642018cebfbSflorian 643018cebfbSflorian return (ret); 644018cebfbSflorian } 645018cebfbSflorian 646018cebfbSflorian static int 647018cebfbSflorian main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, 648b2501eadSflorian struct imsgbuf *resolver_buf, struct imsgbuf *captiveportal_buf) 649018cebfbSflorian { 650018cebfbSflorian int pipe_frontend2resolver[2]; 651b2501eadSflorian int pipe_frontend2captiveportal[2]; 652b2501eadSflorian int pipe_resolver2captiveportal[2]; 653018cebfbSflorian 654018cebfbSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 655018cebfbSflorian PF_UNSPEC, pipe_frontend2resolver) == -1) 656018cebfbSflorian return (-1); 657018cebfbSflorian 658b2501eadSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 659b2501eadSflorian PF_UNSPEC, pipe_frontend2captiveportal) == -1) 660b2501eadSflorian return (-1); 661b2501eadSflorian 662b2501eadSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 663b2501eadSflorian PF_UNSPEC, pipe_resolver2captiveportal) == -1) 664b2501eadSflorian return (-1); 665b2501eadSflorian 666b2501eadSflorian if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC_RESOLVER, 0, 0, 667018cebfbSflorian pipe_frontend2resolver[0], NULL, 0) == -1) 668018cebfbSflorian return (-1); 669b2501eadSflorian if (imsg_compose(resolver_buf, IMSG_SOCKET_IPC_FRONTEND, 0, 0, 670018cebfbSflorian pipe_frontend2resolver[1], NULL, 0) == -1) 671018cebfbSflorian return (-1); 672018cebfbSflorian 673b2501eadSflorian if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC_CAPTIVEPORTAL, 0, 0, 674b2501eadSflorian pipe_frontend2captiveportal[0], NULL, 0) == -1) 675b2501eadSflorian return (-1); 676b2501eadSflorian if (imsg_compose(captiveportal_buf, IMSG_SOCKET_IPC_FRONTEND, 0, 0, 677b2501eadSflorian pipe_frontend2captiveportal[1], NULL, 0) == -1) 678b2501eadSflorian return (-1); 679b2501eadSflorian 680b2501eadSflorian if (imsg_compose(resolver_buf, IMSG_SOCKET_IPC_CAPTIVEPORTAL, 0, 0, 681b2501eadSflorian pipe_resolver2captiveportal[0], NULL, 0) == -1) 682b2501eadSflorian return (-1); 683b2501eadSflorian if (imsg_compose(captiveportal_buf, IMSG_SOCKET_IPC_RESOLVER, 0, 0, 684b2501eadSflorian pipe_resolver2captiveportal[1], NULL, 0) == -1) 685b2501eadSflorian return (-1); 686b2501eadSflorian 687018cebfbSflorian return (0); 688018cebfbSflorian } 689018cebfbSflorian 690018cebfbSflorian int 691018cebfbSflorian main_reload(void) 692018cebfbSflorian { 693bb81f7e1Sflorian struct uw_conf *xconf; 694018cebfbSflorian 695018cebfbSflorian if ((xconf = parse_config(conffile)) == NULL) 696018cebfbSflorian return (-1); 697018cebfbSflorian 698018cebfbSflorian if (main_imsg_send_config(xconf) == -1) 699018cebfbSflorian return (-1); 700018cebfbSflorian 701018cebfbSflorian merge_config(main_conf, xconf); 702018cebfbSflorian 703*2d988276Sflorian if (main_conf->blocklist_file != NULL) 704*2d988276Sflorian send_blocklist_fd(); 705*2d988276Sflorian 706018cebfbSflorian return (0); 707018cebfbSflorian } 708018cebfbSflorian 709018cebfbSflorian int 710bb81f7e1Sflorian main_imsg_send_config(struct uw_conf *xconf) 711018cebfbSflorian { 712bb81f7e1Sflorian struct uw_forwarder *uw_forwarder; 713018cebfbSflorian 714018cebfbSflorian /* Send fixed part of config to children. */ 715b2501eadSflorian if (main_sendall(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 716018cebfbSflorian return (-1); 717b2501eadSflorian if (xconf->captive_portal_host != NULL) { 718b2501eadSflorian if (main_sendall(IMSG_RECONF_CAPTIVE_PORTAL_HOST, 719b2501eadSflorian xconf->captive_portal_host, 720b2501eadSflorian strlen(xconf->captive_portal_host) + 1) == -1) 721b2501eadSflorian return (-1); 722b2501eadSflorian } 723b2501eadSflorian 724b2501eadSflorian if (xconf->captive_portal_path != NULL) { 725b2501eadSflorian if (main_sendall(IMSG_RECONF_CAPTIVE_PORTAL_PATH, 726b2501eadSflorian xconf->captive_portal_path, 727b2501eadSflorian strlen(xconf->captive_portal_path) + 1) == -1) 728b2501eadSflorian return (-1); 729b2501eadSflorian } 730b2501eadSflorian 731b2501eadSflorian if (xconf->captive_portal_expected_response != NULL) { 732b2501eadSflorian if (main_sendall(IMSG_RECONF_CAPTIVE_PORTAL_EXPECTED_RESPONSE, 733b2501eadSflorian xconf->captive_portal_expected_response, 734b2501eadSflorian strlen(xconf->captive_portal_expected_response) + 1) 735b2501eadSflorian == -1) 736b2501eadSflorian return (-1); 737b2501eadSflorian } 738018cebfbSflorian 739*2d988276Sflorian if (xconf->blocklist_file != NULL) { 740*2d988276Sflorian if (main_sendall(IMSG_RECONF_BLOCKLIST_FILE, 741*2d988276Sflorian xconf->blocklist_file, strlen(xconf->blocklist_file) + 1) 742*2d988276Sflorian == -1) 743*2d988276Sflorian return (-1); 744*2d988276Sflorian } 745*2d988276Sflorian 7463570995aSflorian /* send static forwarders to children */ 747bb81f7e1Sflorian SIMPLEQ_FOREACH(uw_forwarder, &xconf->uw_forwarder_list, entry) { 748bb81f7e1Sflorian if (main_sendall(IMSG_RECONF_FORWARDER, uw_forwarder, 749bb81f7e1Sflorian sizeof(*uw_forwarder)) == -1) 750018cebfbSflorian return (-1); 751018cebfbSflorian } 752018cebfbSflorian 7533570995aSflorian /* send static DoT forwarders to children */ 754bb81f7e1Sflorian SIMPLEQ_FOREACH(uw_forwarder, &xconf->uw_dot_forwarder_list, 7553570995aSflorian entry) { 756bb81f7e1Sflorian if (main_sendall(IMSG_RECONF_DOT_FORWARDER, uw_forwarder, 757bb81f7e1Sflorian sizeof(*uw_forwarder)) == -1) 7583570995aSflorian return (-1); 7593570995aSflorian } 7603570995aSflorian 761018cebfbSflorian /* Tell children the revised config is now complete. */ 762b2501eadSflorian if (main_sendall(IMSG_RECONF_END, NULL, 0) == -1) 763018cebfbSflorian return (-1); 764018cebfbSflorian 765018cebfbSflorian return (0); 766018cebfbSflorian } 767018cebfbSflorian 768018cebfbSflorian int 769b2501eadSflorian main_sendall(enum imsg_type type, void *buf, uint16_t len) 770018cebfbSflorian { 771018cebfbSflorian if (imsg_compose_event(iev_frontend, type, 0, 0, -1, buf, len) == -1) 772018cebfbSflorian return (-1); 773018cebfbSflorian if (imsg_compose_event(iev_resolver, type, 0, 0, -1, buf, len) == -1) 774018cebfbSflorian return (-1); 775b2501eadSflorian if (imsg_compose_event(iev_captiveportal, type, 0, 0, -1, buf, len) == 776b2501eadSflorian -1) 777b2501eadSflorian return (-1); 778018cebfbSflorian return (0); 779018cebfbSflorian } 780018cebfbSflorian 781018cebfbSflorian void 782bb81f7e1Sflorian merge_config(struct uw_conf *conf, struct uw_conf *xconf) 783018cebfbSflorian { 784bb81f7e1Sflorian struct uw_forwarder *uw_forwarder; 785018cebfbSflorian 786018cebfbSflorian /* Remove & discard existing forwarders. */ 787bb81f7e1Sflorian while ((uw_forwarder = SIMPLEQ_FIRST(&conf->uw_forwarder_list)) != 788bb81f7e1Sflorian NULL) { 789bb81f7e1Sflorian SIMPLEQ_REMOVE_HEAD(&conf->uw_forwarder_list, entry); 790bb81f7e1Sflorian free(uw_forwarder); 791018cebfbSflorian } 792bb81f7e1Sflorian while ((uw_forwarder = SIMPLEQ_FIRST(&conf->uw_dot_forwarder_list)) != 793bb81f7e1Sflorian NULL) { 794bb81f7e1Sflorian SIMPLEQ_REMOVE_HEAD(&conf->uw_dot_forwarder_list, entry); 795bb81f7e1Sflorian free(uw_forwarder); 7963570995aSflorian } 797018cebfbSflorian 798bb81f7e1Sflorian conf->uw_options = xconf->uw_options; 799fd873f7fSflorian conf->res_pref_len = xconf->res_pref_len; 800fd873f7fSflorian memcpy(&conf->res_pref, &xconf->res_pref, 801fd873f7fSflorian sizeof(conf->res_pref)); 802018cebfbSflorian 803b2501eadSflorian free(conf->captive_portal_host); 804b2501eadSflorian conf->captive_portal_host = xconf->captive_portal_host; 805b2501eadSflorian 806b2501eadSflorian free(conf->captive_portal_path); 807b2501eadSflorian conf->captive_portal_path = xconf->captive_portal_path; 808b2501eadSflorian 809b2501eadSflorian free(conf->captive_portal_expected_response); 810b2501eadSflorian conf->captive_portal_expected_response = 811b2501eadSflorian xconf->captive_portal_expected_response; 812b2501eadSflorian 813b2501eadSflorian conf->captive_portal_expected_status = 814b2501eadSflorian xconf->captive_portal_expected_status; 815b2501eadSflorian 816b2501eadSflorian conf->captive_portal_auto = xconf->captive_portal_auto; 817b2501eadSflorian 818*2d988276Sflorian free(conf->blocklist_file); 819*2d988276Sflorian conf->blocklist_file = xconf->blocklist_file; 820*2d988276Sflorian 821018cebfbSflorian /* Add new forwarders. */ 822bb81f7e1Sflorian while ((uw_forwarder = SIMPLEQ_FIRST(&xconf->uw_forwarder_list)) != 823bb81f7e1Sflorian NULL) { 824bb81f7e1Sflorian SIMPLEQ_REMOVE_HEAD(&xconf->uw_forwarder_list, entry); 825bb81f7e1Sflorian SIMPLEQ_INSERT_TAIL(&conf->uw_forwarder_list, 826bb81f7e1Sflorian uw_forwarder, entry); 827018cebfbSflorian } 828bb81f7e1Sflorian while ((uw_forwarder = SIMPLEQ_FIRST(&xconf->uw_dot_forwarder_list)) != 829bb81f7e1Sflorian NULL) { 830bb81f7e1Sflorian SIMPLEQ_REMOVE_HEAD(&xconf->uw_dot_forwarder_list, entry); 831bb81f7e1Sflorian SIMPLEQ_INSERT_TAIL(&conf->uw_dot_forwarder_list, 832bb81f7e1Sflorian uw_forwarder, entry); 8333570995aSflorian } 834018cebfbSflorian 835018cebfbSflorian free(xconf); 836018cebfbSflorian } 837018cebfbSflorian 838bb81f7e1Sflorian struct uw_conf * 839018cebfbSflorian config_new_empty(void) 840018cebfbSflorian { 841fd873f7fSflorian static enum uw_resolver_type default_res_pref[] = { 842fd873f7fSflorian UW_RES_DOT, 843fd873f7fSflorian UW_RES_FORWARDER, 844fd873f7fSflorian UW_RES_RECURSOR, 845fd873f7fSflorian UW_RES_DHCP}; 846bb81f7e1Sflorian struct uw_conf *xconf; 847018cebfbSflorian 848018cebfbSflorian xconf = calloc(1, sizeof(*xconf)); 849018cebfbSflorian if (xconf == NULL) 850018cebfbSflorian fatal(NULL); 851018cebfbSflorian 852fd873f7fSflorian memcpy(&xconf->res_pref, &default_res_pref, 853fd873f7fSflorian sizeof(default_res_pref)); 854fd873f7fSflorian xconf->res_pref_len = 4; 855fd873f7fSflorian 856bb81f7e1Sflorian SIMPLEQ_INIT(&xconf->uw_forwarder_list); 857bb81f7e1Sflorian SIMPLEQ_INIT(&xconf->uw_dot_forwarder_list); 858018cebfbSflorian 859b2501eadSflorian if ((xconf->captive_portal_expected_response = strdup("")) == NULL) 860b2501eadSflorian fatal(NULL); 861bb81f7e1Sflorian 862b2501eadSflorian xconf->captive_portal_expected_status = 200; 863b2501eadSflorian xconf->captive_portal_auto = 1; 864b2501eadSflorian 865018cebfbSflorian return (xconf); 866018cebfbSflorian } 867018cebfbSflorian 868018cebfbSflorian void 869bb81f7e1Sflorian config_clear(struct uw_conf *conf) 870018cebfbSflorian { 871bb81f7e1Sflorian struct uw_conf *xconf; 872018cebfbSflorian 873018cebfbSflorian /* Merge current config with an empty config. */ 874018cebfbSflorian xconf = config_new_empty(); 875018cebfbSflorian merge_config(conf, xconf); 876018cebfbSflorian 877018cebfbSflorian free(conf); 878018cebfbSflorian } 879018cebfbSflorian 880018cebfbSflorian void 881018cebfbSflorian open_dhcp_lease(int if_idx) 882018cebfbSflorian { 883018cebfbSflorian static char lease_filename[sizeof(_PATH_LEASE_DB) + IF_NAMESIZE] = 884018cebfbSflorian _PATH_LEASE_DB; 885018cebfbSflorian 886018cebfbSflorian int fd; 887018cebfbSflorian char *bufp; 888018cebfbSflorian 889018cebfbSflorian bufp = lease_filename + sizeof(_PATH_LEASE_DB) - 1; 890018cebfbSflorian bufp = if_indextoname(if_idx, bufp); 891018cebfbSflorian 892018cebfbSflorian if (bufp == NULL) { 893018cebfbSflorian log_debug("cannot find interface %d", if_idx); 894018cebfbSflorian return; 895018cebfbSflorian } 896018cebfbSflorian 897018cebfbSflorian log_debug("lease file name: %s", lease_filename); 898018cebfbSflorian 899018cebfbSflorian if ((fd = open(lease_filename, O_RDONLY)) == -1) { 9004a26c82dSjca if (errno != ENOENT) 9014a26c82dSjca log_warn("cannot open lease file %s", lease_filename); 902018cebfbSflorian return; 903018cebfbSflorian } 904018cebfbSflorian 905018cebfbSflorian main_imsg_compose_frontend_fd(IMSG_LEASEFD, 0, fd); 906018cebfbSflorian } 907d265a5d3Sflorian 908d265a5d3Sflorian void 909d265a5d3Sflorian open_ports(void) 910d265a5d3Sflorian { 911d265a5d3Sflorian struct addrinfo hints, *res0; 912d265a5d3Sflorian int udp4sock = -1, udp6sock = -1, error; 913d265a5d3Sflorian 914d265a5d3Sflorian memset(&hints, 0, sizeof(hints)); 915d265a5d3Sflorian hints.ai_family = AF_INET; 916d265a5d3Sflorian hints.ai_socktype = SOCK_DGRAM; 917cc4fd5c4Stedu hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; 918d265a5d3Sflorian 919d265a5d3Sflorian error = getaddrinfo("127.0.0.1", "domain", &hints, &res0); 920d265a5d3Sflorian if (!error && res0) { 921d265a5d3Sflorian if ((udp4sock = socket(res0->ai_family, res0->ai_socktype, 922d265a5d3Sflorian res0->ai_protocol)) != -1) { 923d265a5d3Sflorian if (bind(udp4sock, res0->ai_addr, res0->ai_addrlen) 924d265a5d3Sflorian == -1) { 925d265a5d3Sflorian close(udp4sock); 926d265a5d3Sflorian udp4sock = -1; 927d265a5d3Sflorian } 928d265a5d3Sflorian } 929d265a5d3Sflorian } 930296cf316Sflorian if (res0) 931d265a5d3Sflorian freeaddrinfo(res0); 932d265a5d3Sflorian 933d265a5d3Sflorian hints.ai_family = AF_INET6; 934d265a5d3Sflorian error = getaddrinfo("::1", "domain", &hints, &res0); 935d265a5d3Sflorian if (!error && res0) { 936d265a5d3Sflorian if ((udp6sock = socket(res0->ai_family, res0->ai_socktype, 937d265a5d3Sflorian res0->ai_protocol)) != -1) { 938d265a5d3Sflorian if (bind(udp6sock, res0->ai_addr, res0->ai_addrlen) 939d265a5d3Sflorian == -1) { 940d265a5d3Sflorian close(udp6sock); 941d265a5d3Sflorian udp6sock = -1; 942d265a5d3Sflorian } 943d265a5d3Sflorian } 944d265a5d3Sflorian } 945296cf316Sflorian if (res0) 946d265a5d3Sflorian freeaddrinfo(res0); 947d265a5d3Sflorian 948d265a5d3Sflorian if (udp4sock == -1 && udp6sock == -1) 949d265a5d3Sflorian fatal("could not bind to 127.0.0.1 or ::1 on port 53"); 950d265a5d3Sflorian 951b04dd19dSflorian if (udp4sock != -1) 952d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP4SOCK, 0, udp4sock); 953b04dd19dSflorian if (udp6sock != -1) 954d265a5d3Sflorian main_imsg_compose_frontend_fd(IMSG_UDP6SOCK, 0, udp6sock); 955d265a5d3Sflorian } 9562f29e846Sflorian 9572f29e846Sflorian void 9582f29e846Sflorian resolve_captive_portal(void) 9592f29e846Sflorian { 9602f29e846Sflorian struct addrinfo hints; 9612f29e846Sflorian void *as; 9622f29e846Sflorian 9632f29e846Sflorian if (main_conf->captive_portal_host == NULL) 9642f29e846Sflorian return; 9652f29e846Sflorian 9662f29e846Sflorian memset(&hints, 0, sizeof(hints)); 9672f29e846Sflorian hints.ai_family = PF_INET; 9682f29e846Sflorian hints.ai_socktype = SOCK_STREAM; 9692f29e846Sflorian 9702f29e846Sflorian log_debug("%s: %s", __func__, main_conf->captive_portal_host); 9712f29e846Sflorian 9722f29e846Sflorian if ((as = getaddrinfo_async(main_conf->captive_portal_host, "www", 9732f29e846Sflorian &hints, NULL)) != NULL) 9742f29e846Sflorian event_asr_run(as, resolve_captive_portal_done, NULL); 9752f29e846Sflorian else 9762f29e846Sflorian log_warn("%s: getaddrinfo_async", __func__); 9772f29e846Sflorian 9782f29e846Sflorian } 9792f29e846Sflorian 9802f29e846Sflorian void 9812f29e846Sflorian resolve_captive_portal_done(struct asr_result *ar, void *arg) 9822f29e846Sflorian { 9832f29e846Sflorian struct addrinfo *res; 9842f29e846Sflorian int httpsock; 9852f29e846Sflorian 9862f29e846Sflorian if (ar->ar_gai_errno) { 9872f29e846Sflorian log_warnx("%s: %s", __func__, gai_strerror(ar->ar_gai_errno)); 9882f29e846Sflorian return; 9892f29e846Sflorian } 9902f29e846Sflorian 9912f29e846Sflorian for (res = ar->ar_addrinfo; res; res = res->ai_next) { 9922f29e846Sflorian if (res->ai_family != PF_INET) 9932f29e846Sflorian continue; 9942f29e846Sflorian log_debug("%s: ip_port: %s", __func__, 9952f29e846Sflorian ip_port(res->ai_addr)); 9962f29e846Sflorian 9972f29e846Sflorian if ((httpsock = socket(AF_INET, SOCK_STREAM | 9982f29e846Sflorian SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) { 9992f29e846Sflorian log_warn("%s: socket", __func__); 10002f29e846Sflorian break; 10012f29e846Sflorian } 10022f29e846Sflorian if (connect(httpsock, res->ai_addr, res->ai_addrlen) == -1) { 10032f29e846Sflorian if (errno != EINPROGRESS) { 10042f29e846Sflorian log_warn("%s: connect", __func__); 10052f29e846Sflorian close(httpsock); 10062f29e846Sflorian break; 10072f29e846Sflorian } 10082f29e846Sflorian } 10092f29e846Sflorian main_imsg_compose_captiveportal_fd(IMSG_HTTPSOCK, 0, 10102f29e846Sflorian httpsock); 10112f29e846Sflorian } 10122f29e846Sflorian 10132f29e846Sflorian freeaddrinfo(ar->ar_addrinfo); 10142f29e846Sflorian } 1015*2d988276Sflorian 1016*2d988276Sflorian void 1017*2d988276Sflorian send_blocklist_fd(void) 1018*2d988276Sflorian { 1019*2d988276Sflorian int bl_fd; 1020*2d988276Sflorian 1021*2d988276Sflorian if ((bl_fd = open(main_conf->blocklist_file, O_RDONLY)) != -1) 1022*2d988276Sflorian main_imsg_compose_frontend_fd(IMSG_BLFD, 0, bl_fd); 1023*2d988276Sflorian else 1024*2d988276Sflorian log_warn("%s", main_conf->blocklist_file); 1025*2d988276Sflorian } 1026