1*57419a7fSflorian /* $OpenBSD: dhcpleased.c,v 1.1 2021/02/26 16:16:37 florian Exp $ */ 2*57419a7fSflorian 3*57419a7fSflorian /* 4*57419a7fSflorian * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org> 5*57419a7fSflorian * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6*57419a7fSflorian * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 7*57419a7fSflorian * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 8*57419a7fSflorian * 9*57419a7fSflorian * Permission to use, copy, modify, and distribute this software for any 10*57419a7fSflorian * purpose with or without fee is hereby granted, provided that the above 11*57419a7fSflorian * copyright notice and this permission notice appear in all copies. 12*57419a7fSflorian * 13*57419a7fSflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14*57419a7fSflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15*57419a7fSflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16*57419a7fSflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17*57419a7fSflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18*57419a7fSflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19*57419a7fSflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20*57419a7fSflorian */ 21*57419a7fSflorian #include <sys/types.h> 22*57419a7fSflorian #include <sys/ioctl.h> 23*57419a7fSflorian #include <sys/queue.h> 24*57419a7fSflorian #include <sys/socket.h> 25*57419a7fSflorian #include <sys/stat.h> 26*57419a7fSflorian #include <sys/syslog.h> 27*57419a7fSflorian #include <sys/sysctl.h> 28*57419a7fSflorian #include <sys/uio.h> 29*57419a7fSflorian #include <sys/wait.h> 30*57419a7fSflorian 31*57419a7fSflorian #include <net/if.h> 32*57419a7fSflorian #include <net/route.h> 33*57419a7fSflorian #include <netinet/in.h> 34*57419a7fSflorian #include <netinet/if_ether.h> 35*57419a7fSflorian #include <netinet/in_var.h> 36*57419a7fSflorian 37*57419a7fSflorian #include <arpa/inet.h> 38*57419a7fSflorian 39*57419a7fSflorian #include <err.h> 40*57419a7fSflorian #include <errno.h> 41*57419a7fSflorian #include <fcntl.h> 42*57419a7fSflorian #include <event.h> 43*57419a7fSflorian #include <ifaddrs.h> 44*57419a7fSflorian #include <imsg.h> 45*57419a7fSflorian #include <netdb.h> 46*57419a7fSflorian #include <pwd.h> 47*57419a7fSflorian #include <stddef.h> 48*57419a7fSflorian #include <stdio.h> 49*57419a7fSflorian #include <stdlib.h> 50*57419a7fSflorian #include <string.h> 51*57419a7fSflorian #include <signal.h> 52*57419a7fSflorian #include <unistd.h> 53*57419a7fSflorian 54*57419a7fSflorian #include "bpf.h" 55*57419a7fSflorian #include "log.h" 56*57419a7fSflorian #include "dhcpleased.h" 57*57419a7fSflorian #include "frontend.h" 58*57419a7fSflorian #include "engine.h" 59*57419a7fSflorian #include "control.h" 60*57419a7fSflorian 61*57419a7fSflorian enum dhcpleased_process { 62*57419a7fSflorian PROC_MAIN, 63*57419a7fSflorian PROC_ENGINE, 64*57419a7fSflorian PROC_FRONTEND 65*57419a7fSflorian }; 66*57419a7fSflorian 67*57419a7fSflorian __dead void usage(void); 68*57419a7fSflorian __dead void main_shutdown(void); 69*57419a7fSflorian 70*57419a7fSflorian void main_sig_handler(int, short, void *); 71*57419a7fSflorian 72*57419a7fSflorian static pid_t start_child(enum dhcpleased_process, char *, int, int, int); 73*57419a7fSflorian 74*57419a7fSflorian void main_dispatch_frontend(int, short, void *); 75*57419a7fSflorian void main_dispatch_engine(int, short, void *); 76*57419a7fSflorian void open_bpfsock(uint32_t); 77*57419a7fSflorian void configure_interface(struct imsg_configure_interface *); 78*57419a7fSflorian void deconfigure_interface(struct imsg_configure_interface *); 79*57419a7fSflorian void propose_rdns(struct imsg_propose_rdns *); 80*57419a7fSflorian void configure_gateway(struct imsg_configure_interface *, uint8_t); 81*57419a7fSflorian int open_lease_file(int); 82*57419a7fSflorian 83*57419a7fSflorian static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); 84*57419a7fSflorian int main_imsg_compose_frontend(int, int, void *, uint16_t); 85*57419a7fSflorian int main_imsg_compose_engine(int, int, void *, uint16_t); 86*57419a7fSflorian 87*57419a7fSflorian static struct imsgev *iev_frontend; 88*57419a7fSflorian static struct imsgev *iev_engine; 89*57419a7fSflorian 90*57419a7fSflorian pid_t frontend_pid; 91*57419a7fSflorian pid_t engine_pid; 92*57419a7fSflorian 93*57419a7fSflorian int routesock, ioctl_sock, rtm_seq = 0; 94*57419a7fSflorian 95*57419a7fSflorian void 96*57419a7fSflorian main_sig_handler(int sig, short event, void *arg) 97*57419a7fSflorian { 98*57419a7fSflorian /* 99*57419a7fSflorian * Normal signal handler rules don't apply because libevent 100*57419a7fSflorian * decouples for us. 101*57419a7fSflorian */ 102*57419a7fSflorian 103*57419a7fSflorian switch (sig) { 104*57419a7fSflorian case SIGTERM: 105*57419a7fSflorian case SIGINT: 106*57419a7fSflorian main_shutdown(); 107*57419a7fSflorian default: 108*57419a7fSflorian fatalx("unexpected signal"); 109*57419a7fSflorian } 110*57419a7fSflorian } 111*57419a7fSflorian 112*57419a7fSflorian __dead void 113*57419a7fSflorian usage(void) 114*57419a7fSflorian { 115*57419a7fSflorian extern char *__progname; 116*57419a7fSflorian 117*57419a7fSflorian fprintf(stderr, "usage: %s [-dv] [-s socket]\n", 118*57419a7fSflorian __progname); 119*57419a7fSflorian exit(1); 120*57419a7fSflorian } 121*57419a7fSflorian 122*57419a7fSflorian int 123*57419a7fSflorian main(int argc, char *argv[]) 124*57419a7fSflorian { 125*57419a7fSflorian struct event ev_sigint, ev_sigterm; 126*57419a7fSflorian int ch; 127*57419a7fSflorian int debug = 0, engine_flag = 0, frontend_flag = 0; 128*57419a7fSflorian int verbose = 0; 129*57419a7fSflorian char *saved_argv0; 130*57419a7fSflorian int pipe_main2frontend[2]; 131*57419a7fSflorian int pipe_main2engine[2]; 132*57419a7fSflorian int frontend_routesock, rtfilter; 133*57419a7fSflorian int rtable_any = RTABLE_ANY; 134*57419a7fSflorian char *csock = DHCPLEASED_SOCKET; 135*57419a7fSflorian #ifndef SMALL 136*57419a7fSflorian int control_fd; 137*57419a7fSflorian #endif /* SMALL */ 138*57419a7fSflorian 139*57419a7fSflorian log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ 140*57419a7fSflorian log_setverbose(1); 141*57419a7fSflorian 142*57419a7fSflorian saved_argv0 = argv[0]; 143*57419a7fSflorian if (saved_argv0 == NULL) 144*57419a7fSflorian saved_argv0 = "dhcpleased"; 145*57419a7fSflorian 146*57419a7fSflorian while ((ch = getopt(argc, argv, "dEFs:v")) != -1) { 147*57419a7fSflorian switch (ch) { 148*57419a7fSflorian case 'd': 149*57419a7fSflorian debug = 1; 150*57419a7fSflorian break; 151*57419a7fSflorian case 'E': 152*57419a7fSflorian engine_flag = 1; 153*57419a7fSflorian break; 154*57419a7fSflorian case 'F': 155*57419a7fSflorian frontend_flag = 1; 156*57419a7fSflorian break; 157*57419a7fSflorian case 's': 158*57419a7fSflorian csock = optarg; 159*57419a7fSflorian break; 160*57419a7fSflorian case 'v': 161*57419a7fSflorian verbose++; 162*57419a7fSflorian break; 163*57419a7fSflorian default: 164*57419a7fSflorian usage(); 165*57419a7fSflorian } 166*57419a7fSflorian } 167*57419a7fSflorian 168*57419a7fSflorian argc -= optind; 169*57419a7fSflorian argv += optind; 170*57419a7fSflorian if (argc > 0 || (engine_flag && frontend_flag)) 171*57419a7fSflorian usage(); 172*57419a7fSflorian 173*57419a7fSflorian if (engine_flag) 174*57419a7fSflorian engine(debug, verbose); 175*57419a7fSflorian else if (frontend_flag) 176*57419a7fSflorian frontend(debug, verbose); 177*57419a7fSflorian 178*57419a7fSflorian /* Check for root privileges. */ 179*57419a7fSflorian if (geteuid()) 180*57419a7fSflorian errx(1, "need root privileges"); 181*57419a7fSflorian 182*57419a7fSflorian /* Check for assigned daemon user */ 183*57419a7fSflorian if (getpwnam(DHCPLEASED_USER) == NULL) 184*57419a7fSflorian errx(1, "unknown user %s", DHCPLEASED_USER); 185*57419a7fSflorian 186*57419a7fSflorian log_init(debug, LOG_DAEMON); 187*57419a7fSflorian log_setverbose(verbose); 188*57419a7fSflorian 189*57419a7fSflorian if (!debug) 190*57419a7fSflorian daemon(0, 0); 191*57419a7fSflorian 192*57419a7fSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 193*57419a7fSflorian PF_UNSPEC, pipe_main2frontend) == -1) 194*57419a7fSflorian fatal("main2frontend socketpair"); 195*57419a7fSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 196*57419a7fSflorian PF_UNSPEC, pipe_main2engine) == -1) 197*57419a7fSflorian fatal("main2engine socketpair"); 198*57419a7fSflorian 199*57419a7fSflorian /* Start children. */ 200*57419a7fSflorian engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1], 201*57419a7fSflorian debug, verbose); 202*57419a7fSflorian frontend_pid = start_child(PROC_FRONTEND, saved_argv0, 203*57419a7fSflorian pipe_main2frontend[1], debug, verbose); 204*57419a7fSflorian 205*57419a7fSflorian log_procinit("main"); 206*57419a7fSflorian 207*57419a7fSflorian if ((routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | 208*57419a7fSflorian SOCK_NONBLOCK, AF_INET)) == -1) 209*57419a7fSflorian fatal("route socket"); 210*57419a7fSflorian shutdown(SHUT_RD, routesock); 211*57419a7fSflorian 212*57419a7fSflorian event_init(); 213*57419a7fSflorian 214*57419a7fSflorian /* Setup signal handler. */ 215*57419a7fSflorian signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 216*57419a7fSflorian signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 217*57419a7fSflorian signal_add(&ev_sigint, NULL); 218*57419a7fSflorian signal_add(&ev_sigterm, NULL); 219*57419a7fSflorian signal(SIGPIPE, SIG_IGN); 220*57419a7fSflorian signal(SIGHUP, SIG_IGN); 221*57419a7fSflorian 222*57419a7fSflorian /* Setup pipes to children. */ 223*57419a7fSflorian 224*57419a7fSflorian if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL || 225*57419a7fSflorian (iev_engine = malloc(sizeof(struct imsgev))) == NULL) 226*57419a7fSflorian fatal(NULL); 227*57419a7fSflorian imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]); 228*57419a7fSflorian iev_frontend->handler = main_dispatch_frontend; 229*57419a7fSflorian imsg_init(&iev_engine->ibuf, pipe_main2engine[0]); 230*57419a7fSflorian iev_engine->handler = main_dispatch_engine; 231*57419a7fSflorian 232*57419a7fSflorian /* Setup event handlers for pipes to engine & frontend. */ 233*57419a7fSflorian iev_frontend->events = EV_READ; 234*57419a7fSflorian event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 235*57419a7fSflorian iev_frontend->events, iev_frontend->handler, iev_frontend); 236*57419a7fSflorian event_add(&iev_frontend->ev, NULL); 237*57419a7fSflorian 238*57419a7fSflorian iev_engine->events = EV_READ; 239*57419a7fSflorian event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events, 240*57419a7fSflorian iev_engine->handler, iev_engine); 241*57419a7fSflorian event_add(&iev_engine->ev, NULL); 242*57419a7fSflorian 243*57419a7fSflorian if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf)) 244*57419a7fSflorian fatal("could not establish imsg links"); 245*57419a7fSflorian 246*57419a7fSflorian if ((ioctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1) 247*57419a7fSflorian fatal("socket"); 248*57419a7fSflorian 249*57419a7fSflorian if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 250*57419a7fSflorian AF_INET)) == -1) 251*57419a7fSflorian fatal("route socket"); 252*57419a7fSflorian 253*57419a7fSflorian rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_NEWADDR) | 254*57419a7fSflorian ROUTE_FILTER(RTM_PROPOSAL); 255*57419a7fSflorian if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, 256*57419a7fSflorian &rtfilter, sizeof(rtfilter)) == -1) 257*57419a7fSflorian fatal("setsockopt(ROUTE_MSGFILTER)"); 258*57419a7fSflorian if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_TABLEFILTER, 259*57419a7fSflorian &rtable_any, sizeof(rtable_any)) == -1) 260*57419a7fSflorian fatal("setsockopt(ROUTE_TABLEFILTER)"); 261*57419a7fSflorian 262*57419a7fSflorian #ifndef SMALL 263*57419a7fSflorian if ((control_fd = control_init(csock)) == -1) 264*57419a7fSflorian fatalx("control socket setup failed"); 265*57419a7fSflorian #endif /* SMALL */ 266*57419a7fSflorian 267*57419a7fSflorian if (unveil("/dev/bpf", "rw") == -1) 268*57419a7fSflorian fatal("unveil"); 269*57419a7fSflorian 270*57419a7fSflorian if (unveil(LEASE_PATH, "rwc") == -1) 271*57419a7fSflorian fatal("unveil"); 272*57419a7fSflorian 273*57419a7fSflorian if (unveil(NULL, NULL) == -1) 274*57419a7fSflorian fatal("unveil"); 275*57419a7fSflorian #if notyet 276*57419a7fSflorian if (pledge("stdio inet rpath wpath sendfd wroute bpf", NULL) == -1) 277*57419a7fSflorian fatal("pledge"); 278*57419a7fSflorian #endif 279*57419a7fSflorian main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, NULL, 0); 280*57419a7fSflorian 281*57419a7fSflorian #ifndef SMALL 282*57419a7fSflorian main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL, 0); 283*57419a7fSflorian #endif /* SMALL */ 284*57419a7fSflorian 285*57419a7fSflorian main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL, 0); 286*57419a7fSflorian 287*57419a7fSflorian event_dispatch(); 288*57419a7fSflorian 289*57419a7fSflorian main_shutdown(); 290*57419a7fSflorian return (0); 291*57419a7fSflorian } 292*57419a7fSflorian 293*57419a7fSflorian __dead void 294*57419a7fSflorian main_shutdown(void) 295*57419a7fSflorian { 296*57419a7fSflorian pid_t pid; 297*57419a7fSflorian int status; 298*57419a7fSflorian 299*57419a7fSflorian /* Close pipes. */ 300*57419a7fSflorian msgbuf_clear(&iev_frontend->ibuf.w); 301*57419a7fSflorian close(iev_frontend->ibuf.fd); 302*57419a7fSflorian msgbuf_clear(&iev_engine->ibuf.w); 303*57419a7fSflorian close(iev_engine->ibuf.fd); 304*57419a7fSflorian 305*57419a7fSflorian log_debug("waiting for children to terminate"); 306*57419a7fSflorian do { 307*57419a7fSflorian pid = wait(&status); 308*57419a7fSflorian if (pid == -1) { 309*57419a7fSflorian if (errno != EINTR && errno != ECHILD) 310*57419a7fSflorian fatal("wait"); 311*57419a7fSflorian } else if (WIFSIGNALED(status)) 312*57419a7fSflorian log_warnx("%s terminated; signal %d", 313*57419a7fSflorian (pid == engine_pid) ? "engine" : 314*57419a7fSflorian "frontend", WTERMSIG(status)); 315*57419a7fSflorian } while (pid != -1 || (pid == -1 && errno == EINTR)); 316*57419a7fSflorian 317*57419a7fSflorian free(iev_frontend); 318*57419a7fSflorian free(iev_engine); 319*57419a7fSflorian 320*57419a7fSflorian log_info("terminating"); 321*57419a7fSflorian exit(0); 322*57419a7fSflorian } 323*57419a7fSflorian 324*57419a7fSflorian static pid_t 325*57419a7fSflorian start_child(enum dhcpleased_process p, char *argv0, int fd, int debug, int 326*57419a7fSflorian verbose) 327*57419a7fSflorian { 328*57419a7fSflorian char *argv[7]; 329*57419a7fSflorian int argc = 0; 330*57419a7fSflorian pid_t pid; 331*57419a7fSflorian 332*57419a7fSflorian switch (pid = fork()) { 333*57419a7fSflorian case -1: 334*57419a7fSflorian fatal("cannot fork"); 335*57419a7fSflorian case 0: 336*57419a7fSflorian break; 337*57419a7fSflorian default: 338*57419a7fSflorian close(fd); 339*57419a7fSflorian return (pid); 340*57419a7fSflorian } 341*57419a7fSflorian 342*57419a7fSflorian if (fd != 3) { 343*57419a7fSflorian if (dup2(fd, 3) == -1) 344*57419a7fSflorian fatal("cannot setup imsg fd"); 345*57419a7fSflorian } else if (fcntl(fd, F_SETFD, 0) == -1) 346*57419a7fSflorian fatal("cannot setup imsg fd"); 347*57419a7fSflorian 348*57419a7fSflorian argv[argc++] = argv0; 349*57419a7fSflorian switch (p) { 350*57419a7fSflorian case PROC_MAIN: 351*57419a7fSflorian fatalx("Can not start main process"); 352*57419a7fSflorian case PROC_ENGINE: 353*57419a7fSflorian argv[argc++] = "-E"; 354*57419a7fSflorian break; 355*57419a7fSflorian case PROC_FRONTEND: 356*57419a7fSflorian argv[argc++] = "-F"; 357*57419a7fSflorian break; 358*57419a7fSflorian } 359*57419a7fSflorian if (debug) 360*57419a7fSflorian argv[argc++] = "-d"; 361*57419a7fSflorian if (verbose) 362*57419a7fSflorian argv[argc++] = "-v"; 363*57419a7fSflorian if (verbose > 1) 364*57419a7fSflorian argv[argc++] = "-v"; 365*57419a7fSflorian argv[argc++] = NULL; 366*57419a7fSflorian 367*57419a7fSflorian execvp(argv0, argv); 368*57419a7fSflorian fatal("execvp"); 369*57419a7fSflorian } 370*57419a7fSflorian 371*57419a7fSflorian void 372*57419a7fSflorian main_dispatch_frontend(int fd, short event, void *bula) 373*57419a7fSflorian { 374*57419a7fSflorian struct imsgev *iev = bula; 375*57419a7fSflorian struct imsgbuf *ibuf; 376*57419a7fSflorian struct imsg imsg; 377*57419a7fSflorian struct imsg_ifinfo imsg_ifinfo; 378*57419a7fSflorian ssize_t n; 379*57419a7fSflorian int shut = 0; 380*57419a7fSflorian uint32_t if_index; 381*57419a7fSflorian #ifndef SMALL 382*57419a7fSflorian int verbose; 383*57419a7fSflorian #endif /* SMALL */ 384*57419a7fSflorian 385*57419a7fSflorian ibuf = &iev->ibuf; 386*57419a7fSflorian 387*57419a7fSflorian if (event & EV_READ) { 388*57419a7fSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 389*57419a7fSflorian fatal("imsg_read error"); 390*57419a7fSflorian if (n == 0) /* Connection closed. */ 391*57419a7fSflorian shut = 1; 392*57419a7fSflorian } 393*57419a7fSflorian if (event & EV_WRITE) { 394*57419a7fSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 395*57419a7fSflorian fatal("msgbuf_write"); 396*57419a7fSflorian if (n == 0) /* Connection closed. */ 397*57419a7fSflorian shut = 1; 398*57419a7fSflorian } 399*57419a7fSflorian 400*57419a7fSflorian for (;;) { 401*57419a7fSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 402*57419a7fSflorian fatal("imsg_get"); 403*57419a7fSflorian if (n == 0) /* No more messages. */ 404*57419a7fSflorian break; 405*57419a7fSflorian 406*57419a7fSflorian switch (imsg.hdr.type) { 407*57419a7fSflorian case IMSG_OPEN_BPFSOCK: 408*57419a7fSflorian log_debug("IMSG_OPEN_BPFSOCK"); 409*57419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 410*57419a7fSflorian fatalx("%s: IMSG_OPEN_BPFSOCK wrong length: " 411*57419a7fSflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 412*57419a7fSflorian memcpy(&if_index, imsg.data, sizeof(if_index)); 413*57419a7fSflorian open_bpfsock(if_index); 414*57419a7fSflorian break; 415*57419a7fSflorian #ifndef SMALL 416*57419a7fSflorian case IMSG_CTL_LOG_VERBOSE: 417*57419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 418*57419a7fSflorian fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " 419*57419a7fSflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 420*57419a7fSflorian memcpy(&verbose, imsg.data, sizeof(verbose)); 421*57419a7fSflorian log_setverbose(verbose); 422*57419a7fSflorian break; 423*57419a7fSflorian #endif /* SMALL */ 424*57419a7fSflorian case IMSG_UPDATE_IF: 425*57419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_ifinfo)) 426*57419a7fSflorian fatalx("%s: IMSG_UPDATE_IF wrong length: %lu", 427*57419a7fSflorian __func__, IMSG_DATA_SIZE(imsg)); 428*57419a7fSflorian memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo)); 429*57419a7fSflorian main_imsg_compose_engine(IMSG_UPDATE_IF, 430*57419a7fSflorian open_lease_file(imsg_ifinfo.if_index), &imsg_ifinfo, 431*57419a7fSflorian sizeof(imsg_ifinfo)); 432*57419a7fSflorian break; 433*57419a7fSflorian default: 434*57419a7fSflorian log_debug("%s: error handling imsg %d", __func__, 435*57419a7fSflorian imsg.hdr.type); 436*57419a7fSflorian break; 437*57419a7fSflorian } 438*57419a7fSflorian imsg_free(&imsg); 439*57419a7fSflorian } 440*57419a7fSflorian if (!shut) 441*57419a7fSflorian imsg_event_add(iev); 442*57419a7fSflorian else { 443*57419a7fSflorian /* This pipe is dead. Remove its event handler */ 444*57419a7fSflorian event_del(&iev->ev); 445*57419a7fSflorian event_loopexit(NULL); 446*57419a7fSflorian } 447*57419a7fSflorian } 448*57419a7fSflorian 449*57419a7fSflorian void 450*57419a7fSflorian main_dispatch_engine(int fd, short event, void *bula) 451*57419a7fSflorian { 452*57419a7fSflorian struct imsgev *iev = bula; 453*57419a7fSflorian struct imsgbuf *ibuf; 454*57419a7fSflorian struct imsg imsg; 455*57419a7fSflorian ssize_t n; 456*57419a7fSflorian int shut = 0; 457*57419a7fSflorian 458*57419a7fSflorian ibuf = &iev->ibuf; 459*57419a7fSflorian 460*57419a7fSflorian if (event & EV_READ) { 461*57419a7fSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 462*57419a7fSflorian fatal("imsg_read error"); 463*57419a7fSflorian if (n == 0) /* Connection closed. */ 464*57419a7fSflorian shut = 1; 465*57419a7fSflorian } 466*57419a7fSflorian if (event & EV_WRITE) { 467*57419a7fSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 468*57419a7fSflorian fatal("msgbuf_write"); 469*57419a7fSflorian if (n == 0) /* Connection closed. */ 470*57419a7fSflorian shut = 1; 471*57419a7fSflorian } 472*57419a7fSflorian 473*57419a7fSflorian for (;;) { 474*57419a7fSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 475*57419a7fSflorian fatal("imsg_get"); 476*57419a7fSflorian if (n == 0) /* No more messages. */ 477*57419a7fSflorian break; 478*57419a7fSflorian 479*57419a7fSflorian switch (imsg.hdr.type) { 480*57419a7fSflorian case IMSG_CONFIGURE_INTERFACE: { 481*57419a7fSflorian struct imsg_configure_interface imsg_interface; 482*57419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_interface)) 483*57419a7fSflorian fatalx("%s: IMSG_CONFIGURE_INTERFACE wrong " 484*57419a7fSflorian "length: %lu", __func__, 485*57419a7fSflorian IMSG_DATA_SIZE(imsg)); 486*57419a7fSflorian memcpy(&imsg_interface, imsg.data, 487*57419a7fSflorian sizeof(imsg_interface)); 488*57419a7fSflorian configure_interface(&imsg_interface); 489*57419a7fSflorian break; 490*57419a7fSflorian } 491*57419a7fSflorian case IMSG_DECONFIGURE_INTERFACE: { 492*57419a7fSflorian struct imsg_configure_interface imsg_interface; 493*57419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_interface)) 494*57419a7fSflorian fatalx("%s: IMSG_CONFIGURE_INTERFACE wrong " 495*57419a7fSflorian "length: %lu", __func__, 496*57419a7fSflorian IMSG_DATA_SIZE(imsg)); 497*57419a7fSflorian memcpy(&imsg_interface, imsg.data, 498*57419a7fSflorian sizeof(imsg_interface)); 499*57419a7fSflorian deconfigure_interface(&imsg_interface); 500*57419a7fSflorian main_imsg_compose_frontend(IMSG_CLOSE_UDPSOCK, -1, 501*57419a7fSflorian &imsg_interface.if_index, 502*57419a7fSflorian sizeof(imsg_interface.if_index)); 503*57419a7fSflorian break; 504*57419a7fSflorian } 505*57419a7fSflorian case IMSG_PROPOSE_RDNS: { 506*57419a7fSflorian struct imsg_propose_rdns rdns; 507*57419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(rdns)) 508*57419a7fSflorian fatalx("%s: IMSG_PROPOSE_RDNS wrong " 509*57419a7fSflorian "length: %lu", __func__, 510*57419a7fSflorian IMSG_DATA_SIZE(imsg)); 511*57419a7fSflorian memcpy(&rdns, imsg.data, sizeof(rdns)); 512*57419a7fSflorian if ((2 + rdns.rdns_count * sizeof(struct in_addr)) > 513*57419a7fSflorian sizeof(struct sockaddr_rtdns)) 514*57419a7fSflorian fatalx("%s: rdns_count too big: %d", __func__, 515*57419a7fSflorian rdns.rdns_count); 516*57419a7fSflorian propose_rdns(&rdns); 517*57419a7fSflorian break; 518*57419a7fSflorian } 519*57419a7fSflorian case IMSG_WITHDRAW_RDNS: { 520*57419a7fSflorian struct imsg_propose_rdns rdns; 521*57419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(rdns)) 522*57419a7fSflorian fatalx("%s: IMSG_PROPOSE_RDNS wrong " 523*57419a7fSflorian "length: %lu", __func__, 524*57419a7fSflorian IMSG_DATA_SIZE(imsg)); 525*57419a7fSflorian memcpy(&rdns, imsg.data, sizeof(rdns)); 526*57419a7fSflorian if (rdns.rdns_count != 0) 527*57419a7fSflorian fatalx("%s: expected rdns_count == 0: %d", 528*57419a7fSflorian __func__, rdns.rdns_count); 529*57419a7fSflorian propose_rdns(&rdns); 530*57419a7fSflorian break; 531*57419a7fSflorian } 532*57419a7fSflorian default: 533*57419a7fSflorian log_debug("%s: error handling imsg %d", __func__, 534*57419a7fSflorian imsg.hdr.type); 535*57419a7fSflorian break; 536*57419a7fSflorian } 537*57419a7fSflorian imsg_free(&imsg); 538*57419a7fSflorian } 539*57419a7fSflorian if (!shut) 540*57419a7fSflorian imsg_event_add(iev); 541*57419a7fSflorian else { 542*57419a7fSflorian /* This pipe is dead. Remove its event handler. */ 543*57419a7fSflorian event_del(&iev->ev); 544*57419a7fSflorian event_loopexit(NULL); 545*57419a7fSflorian } 546*57419a7fSflorian } 547*57419a7fSflorian 548*57419a7fSflorian int 549*57419a7fSflorian main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen) 550*57419a7fSflorian { 551*57419a7fSflorian if (iev_frontend) 552*57419a7fSflorian return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data, 553*57419a7fSflorian datalen)); 554*57419a7fSflorian else 555*57419a7fSflorian return (-1); 556*57419a7fSflorian } 557*57419a7fSflorian 558*57419a7fSflorian int 559*57419a7fSflorian main_imsg_compose_engine(int type, int fd, void *data, uint16_t datalen) 560*57419a7fSflorian { 561*57419a7fSflorian if (iev_engine) 562*57419a7fSflorian return(imsg_compose_event(iev_engine, type, 0, 0, fd, data, 563*57419a7fSflorian datalen)); 564*57419a7fSflorian else 565*57419a7fSflorian return (-1); 566*57419a7fSflorian } 567*57419a7fSflorian 568*57419a7fSflorian void 569*57419a7fSflorian imsg_event_add(struct imsgev *iev) 570*57419a7fSflorian { 571*57419a7fSflorian iev->events = EV_READ; 572*57419a7fSflorian if (iev->ibuf.w.queued) 573*57419a7fSflorian iev->events |= EV_WRITE; 574*57419a7fSflorian 575*57419a7fSflorian event_del(&iev->ev); 576*57419a7fSflorian event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 577*57419a7fSflorian event_add(&iev->ev, NULL); 578*57419a7fSflorian } 579*57419a7fSflorian 580*57419a7fSflorian int 581*57419a7fSflorian imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 582*57419a7fSflorian pid_t pid, int fd, void *data, uint16_t datalen) 583*57419a7fSflorian { 584*57419a7fSflorian int ret; 585*57419a7fSflorian 586*57419a7fSflorian if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 587*57419a7fSflorian datalen)) != -1) 588*57419a7fSflorian imsg_event_add(iev); 589*57419a7fSflorian 590*57419a7fSflorian return (ret); 591*57419a7fSflorian } 592*57419a7fSflorian 593*57419a7fSflorian static int 594*57419a7fSflorian main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, 595*57419a7fSflorian struct imsgbuf *engine_buf) 596*57419a7fSflorian { 597*57419a7fSflorian int pipe_frontend2engine[2]; 598*57419a7fSflorian 599*57419a7fSflorian if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 600*57419a7fSflorian PF_UNSPEC, pipe_frontend2engine) == -1) 601*57419a7fSflorian return (-1); 602*57419a7fSflorian 603*57419a7fSflorian if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0, 604*57419a7fSflorian pipe_frontend2engine[0], NULL, 0) == -1) 605*57419a7fSflorian return (-1); 606*57419a7fSflorian imsg_flush(frontend_buf); 607*57419a7fSflorian if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0, 608*57419a7fSflorian pipe_frontend2engine[1], NULL, 0) == -1) 609*57419a7fSflorian return (-1); 610*57419a7fSflorian imsg_flush(engine_buf); 611*57419a7fSflorian return (0); 612*57419a7fSflorian } 613*57419a7fSflorian 614*57419a7fSflorian void 615*57419a7fSflorian configure_interface(struct imsg_configure_interface *imsg) 616*57419a7fSflorian { 617*57419a7fSflorian struct ifaliasreq ifaliasreq; 618*57419a7fSflorian struct ifaddrs *ifap, *ifa; 619*57419a7fSflorian struct sockaddr_in *req_sin_addr, *req_sin_mask; 620*57419a7fSflorian int found = 0, udpsock, opt = 1, len, fd = -1; 621*57419a7fSflorian char *if_name; 622*57419a7fSflorian char ntop_buf[INET_ADDRSTRLEN]; 623*57419a7fSflorian char lease_buf[LEASE_SIZE]; 624*57419a7fSflorian char lease_file_buf[sizeof(LEASE_PATH) + 625*57419a7fSflorian IF_NAMESIZE]; 626*57419a7fSflorian char tmpl[] = LEASE_PATH"XXXXXXXXXX"; 627*57419a7fSflorian 628*57419a7fSflorian log_debug("%s", __func__); 629*57419a7fSflorian 630*57419a7fSflorian memset(&ifaliasreq, 0, sizeof(ifaliasreq)); 631*57419a7fSflorian 632*57419a7fSflorian if_name = if_indextoname(imsg->if_index, ifaliasreq.ifra_name); 633*57419a7fSflorian if (if_name == NULL) { 634*57419a7fSflorian log_warnx("%s: cannot find interface %d", __func__, 635*57419a7fSflorian imsg->if_index); 636*57419a7fSflorian return; 637*57419a7fSflorian } 638*57419a7fSflorian 639*57419a7fSflorian if (getifaddrs(&ifap) != 0) 640*57419a7fSflorian fatal("getifaddrs"); 641*57419a7fSflorian 642*57419a7fSflorian req_sin_addr = (struct sockaddr_in *)&ifaliasreq.ifra_addr; 643*57419a7fSflorian req_sin_addr->sin_family = AF_INET; 644*57419a7fSflorian req_sin_addr->sin_len = sizeof(*req_sin_addr); 645*57419a7fSflorian 646*57419a7fSflorian for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 647*57419a7fSflorian struct in_addr addr, mask; 648*57419a7fSflorian 649*57419a7fSflorian if (strcmp(if_name, ifa->ifa_name) != 0) 650*57419a7fSflorian continue; 651*57419a7fSflorian if (ifa->ifa_addr == NULL) 652*57419a7fSflorian continue; 653*57419a7fSflorian if (ifa->ifa_addr->sa_family != AF_INET) 654*57419a7fSflorian continue; 655*57419a7fSflorian 656*57419a7fSflorian addr.s_addr = ((struct sockaddr_in *)ifa->ifa_addr) 657*57419a7fSflorian ->sin_addr.s_addr; 658*57419a7fSflorian mask.s_addr = ((struct sockaddr_in *)ifa->ifa_netmask) 659*57419a7fSflorian ->sin_addr.s_addr; 660*57419a7fSflorian 661*57419a7fSflorian if (imsg->addr.s_addr == addr.s_addr) { 662*57419a7fSflorian if (imsg->mask.s_addr == mask.s_addr) 663*57419a7fSflorian found = 1; 664*57419a7fSflorian else { 665*57419a7fSflorian req_sin_addr->sin_addr.s_addr = addr.s_addr; 666*57419a7fSflorian if (ioctl(ioctl_sock, SIOCDIFADDR, &ifaliasreq) 667*57419a7fSflorian == -1) { 668*57419a7fSflorian if (errno != EADDRNOTAVAIL) 669*57419a7fSflorian log_warn("SIOCDIFADDR"); 670*57419a7fSflorian } 671*57419a7fSflorian } 672*57419a7fSflorian break; 673*57419a7fSflorian } 674*57419a7fSflorian } 675*57419a7fSflorian 676*57419a7fSflorian req_sin_addr->sin_addr.s_addr = imsg->addr.s_addr; 677*57419a7fSflorian if (!found) { 678*57419a7fSflorian req_sin_mask = (struct sockaddr_in *)&ifaliasreq.ifra_mask; 679*57419a7fSflorian req_sin_mask->sin_family = AF_INET; 680*57419a7fSflorian req_sin_mask->sin_len = sizeof(*req_sin_mask); 681*57419a7fSflorian req_sin_mask->sin_addr.s_addr = imsg->mask.s_addr; 682*57419a7fSflorian if (ioctl(ioctl_sock, SIOCAIFADDR, &ifaliasreq) == -1) 683*57419a7fSflorian fatal("SIOCAIFADDR"); 684*57419a7fSflorian 685*57419a7fSflorian /* XXX check weird shit in dhclient/kroute.c set_routes() */ 686*57419a7fSflorian if (imsg->router.s_addr != INADDR_ANY) 687*57419a7fSflorian configure_gateway(imsg, RTM_ADD); 688*57419a7fSflorian } 689*57419a7fSflorian req_sin_addr->sin_port = ntohs(CLIENT_PORT); 690*57419a7fSflorian if ((udpsock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 691*57419a7fSflorian log_warn("socket"); 692*57419a7fSflorian return; 693*57419a7fSflorian } 694*57419a7fSflorian if (setsockopt(udpsock, SOL_SOCKET, SO_REUSEADDR, &opt, 695*57419a7fSflorian sizeof(opt)) == -1) 696*57419a7fSflorian log_warn("setting SO_REUSEADDR on socket"); 697*57419a7fSflorian 698*57419a7fSflorian if (setsockopt(udpsock, SOL_SOCKET, SO_RTABLE, &imsg->rdomain, 699*57419a7fSflorian sizeof(imsg->rdomain)) == -1) { 700*57419a7fSflorian /* we might race against removal of the rdomain */ 701*57419a7fSflorian log_warn("setsockopt SO_RTABLE"); 702*57419a7fSflorian close(udpsock); 703*57419a7fSflorian return; 704*57419a7fSflorian } 705*57419a7fSflorian 706*57419a7fSflorian if (bind(udpsock, (struct sockaddr *)req_sin_addr, 707*57419a7fSflorian sizeof(*req_sin_addr)) == -1) { 708*57419a7fSflorian close(udpsock); 709*57419a7fSflorian return; 710*57419a7fSflorian } 711*57419a7fSflorian 712*57419a7fSflorian shutdown(udpsock, SHUT_RD); 713*57419a7fSflorian log_debug("%s: udpsock: %d", __func__, udpsock); 714*57419a7fSflorian main_imsg_compose_frontend(IMSG_UDPSOCK, udpsock, 715*57419a7fSflorian &imsg->if_index, sizeof(imsg->if_index)); 716*57419a7fSflorian 717*57419a7fSflorian if (inet_ntop(AF_INET, &imsg->addr, ntop_buf, sizeof(ntop_buf)) == 718*57419a7fSflorian NULL) { 719*57419a7fSflorian log_warn("%s: inet_ntop", __func__); 720*57419a7fSflorian return; 721*57419a7fSflorian } 722*57419a7fSflorian 723*57419a7fSflorian len = snprintf(lease_file_buf, sizeof(lease_file_buf), "%s%s", 724*57419a7fSflorian LEASE_PATH, if_name); 725*57419a7fSflorian if ( len == -1 || (size_t) len >= sizeof(lease_file_buf)) { 726*57419a7fSflorian log_warnx("%s: failed to encode lease path for %s", __func__, 727*57419a7fSflorian if_name); 728*57419a7fSflorian return; 729*57419a7fSflorian } 730*57419a7fSflorian 731*57419a7fSflorian len = snprintf(lease_buf, sizeof(lease_buf), "%s%s\n", LEASE_PREFIX, 732*57419a7fSflorian ntop_buf); 733*57419a7fSflorian if ( len == -1 || (size_t) len >= sizeof(lease_buf)) { 734*57419a7fSflorian log_warnx("%s: failed to encode lease for %s", __func__, 735*57419a7fSflorian ntop_buf); 736*57419a7fSflorian return; 737*57419a7fSflorian } 738*57419a7fSflorian 739*57419a7fSflorian if ((fd = mkstemp(tmpl)) == -1) { 740*57419a7fSflorian log_warn("%s: mkstemp", __func__); 741*57419a7fSflorian return; 742*57419a7fSflorian } 743*57419a7fSflorian 744*57419a7fSflorian if (write(fd, lease_buf, len) < len) 745*57419a7fSflorian goto err; 746*57419a7fSflorian 747*57419a7fSflorian if (fchmod(fd, 0644) == -1) 748*57419a7fSflorian goto err; 749*57419a7fSflorian 750*57419a7fSflorian if (close(fd) == -1) 751*57419a7fSflorian goto err; 752*57419a7fSflorian fd = -1; 753*57419a7fSflorian 754*57419a7fSflorian if (rename(tmpl, lease_file_buf) == -1) 755*57419a7fSflorian goto err; 756*57419a7fSflorian return; 757*57419a7fSflorian err: 758*57419a7fSflorian log_warn("%s", __func__); 759*57419a7fSflorian if (fd != -1) 760*57419a7fSflorian close(fd); 761*57419a7fSflorian unlink(tmpl); 762*57419a7fSflorian } 763*57419a7fSflorian 764*57419a7fSflorian void 765*57419a7fSflorian deconfigure_interface(struct imsg_configure_interface *imsg) 766*57419a7fSflorian { 767*57419a7fSflorian struct ifaliasreq ifaliasreq; 768*57419a7fSflorian struct sockaddr_in *req_sin_addr; 769*57419a7fSflorian 770*57419a7fSflorian log_debug("%s", __func__); 771*57419a7fSflorian 772*57419a7fSflorian memset(&ifaliasreq, 0, sizeof(ifaliasreq)); 773*57419a7fSflorian 774*57419a7fSflorian if (if_indextoname(imsg->if_index, ifaliasreq.ifra_name) == NULL) { 775*57419a7fSflorian log_warnx("%s: cannot find interface %d", __func__, 776*57419a7fSflorian imsg->if_index); 777*57419a7fSflorian return; 778*57419a7fSflorian } 779*57419a7fSflorian 780*57419a7fSflorian req_sin_addr = (struct sockaddr_in *)&ifaliasreq.ifra_addr; 781*57419a7fSflorian req_sin_addr->sin_family = AF_INET; 782*57419a7fSflorian req_sin_addr->sin_len = sizeof(*req_sin_addr); 783*57419a7fSflorian 784*57419a7fSflorian req_sin_addr->sin_addr.s_addr = imsg->addr.s_addr; 785*57419a7fSflorian if (ioctl(ioctl_sock, SIOCDIFADDR, &ifaliasreq) == -1) { 786*57419a7fSflorian if (errno != EADDRNOTAVAIL) 787*57419a7fSflorian log_warn("SIOCDIFADDR"); 788*57419a7fSflorian } 789*57419a7fSflorian } 790*57419a7fSflorian 791*57419a7fSflorian #define ROUNDUP(a) \ 792*57419a7fSflorian (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a)) 793*57419a7fSflorian void 794*57419a7fSflorian configure_gateway(struct imsg_configure_interface *imsg, uint8_t rtm_type) 795*57419a7fSflorian { 796*57419a7fSflorian struct rt_msghdr rtm; 797*57419a7fSflorian struct sockaddr_rtlabel rl; 798*57419a7fSflorian struct sockaddr_in dst, gw, mask; 799*57419a7fSflorian struct iovec iov[10]; 800*57419a7fSflorian long pad = 0; 801*57419a7fSflorian int iovcnt = 0, padlen; 802*57419a7fSflorian 803*57419a7fSflorian memset(&rtm, 0, sizeof(rtm)); 804*57419a7fSflorian 805*57419a7fSflorian rtm.rtm_version = RTM_VERSION; 806*57419a7fSflorian rtm.rtm_type = rtm_type; 807*57419a7fSflorian rtm.rtm_msglen = sizeof(rtm); 808*57419a7fSflorian rtm.rtm_tableid = imsg->rdomain; 809*57419a7fSflorian rtm.rtm_index = imsg->if_index; 810*57419a7fSflorian rtm.rtm_seq = ++rtm_seq; 811*57419a7fSflorian rtm.rtm_priority = RTP_NONE; 812*57419a7fSflorian rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_LABEL; 813*57419a7fSflorian rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 814*57419a7fSflorian 815*57419a7fSflorian iov[iovcnt].iov_base = &rtm; 816*57419a7fSflorian iov[iovcnt++].iov_len = sizeof(rtm); 817*57419a7fSflorian 818*57419a7fSflorian memset(&dst, 0, sizeof(dst)); 819*57419a7fSflorian dst.sin_family = AF_INET; 820*57419a7fSflorian dst.sin_len = sizeof(struct sockaddr_in); 821*57419a7fSflorian 822*57419a7fSflorian iov[iovcnt].iov_base = &dst; 823*57419a7fSflorian iov[iovcnt++].iov_len = sizeof(dst); 824*57419a7fSflorian rtm.rtm_msglen += sizeof(dst); 825*57419a7fSflorian padlen = ROUNDUP(sizeof(dst)) - sizeof(dst); 826*57419a7fSflorian if (padlen > 0) { 827*57419a7fSflorian iov[iovcnt].iov_base = &pad; 828*57419a7fSflorian iov[iovcnt++].iov_len = padlen; 829*57419a7fSflorian rtm.rtm_msglen += padlen; 830*57419a7fSflorian } 831*57419a7fSflorian 832*57419a7fSflorian memset(&gw, 0, sizeof(gw)); 833*57419a7fSflorian memcpy(&gw.sin_addr, &imsg->router, sizeof(gw.sin_addr)); 834*57419a7fSflorian gw.sin_family = AF_INET; 835*57419a7fSflorian gw.sin_len = sizeof(struct sockaddr_in); 836*57419a7fSflorian iov[iovcnt].iov_base = &gw; 837*57419a7fSflorian iov[iovcnt++].iov_len = sizeof(gw); 838*57419a7fSflorian rtm.rtm_msglen += sizeof(gw); 839*57419a7fSflorian padlen = ROUNDUP(sizeof(gw)) - sizeof(gw); 840*57419a7fSflorian if (padlen > 0) { 841*57419a7fSflorian iov[iovcnt].iov_base = &pad; 842*57419a7fSflorian iov[iovcnt++].iov_len = padlen; 843*57419a7fSflorian rtm.rtm_msglen += padlen; 844*57419a7fSflorian } 845*57419a7fSflorian 846*57419a7fSflorian memset(&mask, 0, sizeof(mask)); 847*57419a7fSflorian mask.sin_family = AF_INET; 848*57419a7fSflorian mask.sin_len = sizeof(struct sockaddr_in); 849*57419a7fSflorian iov[iovcnt].iov_base = &mask; 850*57419a7fSflorian iov[iovcnt++].iov_len = sizeof(mask); 851*57419a7fSflorian rtm.rtm_msglen += sizeof(mask); 852*57419a7fSflorian padlen = ROUNDUP(sizeof(mask)) - sizeof(mask); 853*57419a7fSflorian if (padlen > 0) { 854*57419a7fSflorian iov[iovcnt].iov_base = &pad; 855*57419a7fSflorian iov[iovcnt++].iov_len = padlen; 856*57419a7fSflorian rtm.rtm_msglen += padlen; 857*57419a7fSflorian } 858*57419a7fSflorian 859*57419a7fSflorian memset(&rl, 0, sizeof(rl)); 860*57419a7fSflorian rl.sr_len = sizeof(rl); 861*57419a7fSflorian rl.sr_family = AF_UNSPEC; 862*57419a7fSflorian (void)snprintf(rl.sr_label, sizeof(rl.sr_label), "%s", 863*57419a7fSflorian DHCPLEASED_RTA_LABEL); 864*57419a7fSflorian iov[iovcnt].iov_base = &rl; 865*57419a7fSflorian iov[iovcnt++].iov_len = sizeof(rl); 866*57419a7fSflorian rtm.rtm_msglen += sizeof(rl); 867*57419a7fSflorian padlen = ROUNDUP(sizeof(rl)) - sizeof(rl); 868*57419a7fSflorian if (padlen > 0) { 869*57419a7fSflorian iov[iovcnt].iov_base = &pad; 870*57419a7fSflorian iov[iovcnt++].iov_len = padlen; 871*57419a7fSflorian rtm.rtm_msglen += padlen; 872*57419a7fSflorian } 873*57419a7fSflorian 874*57419a7fSflorian if (writev(routesock, iov, iovcnt) == -1) 875*57419a7fSflorian log_warn("failed to send route message"); 876*57419a7fSflorian } 877*57419a7fSflorian 878*57419a7fSflorian #ifndef SMALL 879*57419a7fSflorian const char* 880*57419a7fSflorian sin_to_str(struct sockaddr_in *sin) 881*57419a7fSflorian { 882*57419a7fSflorian static char hbuf[NI_MAXHOST]; 883*57419a7fSflorian int error; 884*57419a7fSflorian 885*57419a7fSflorian error = getnameinfo((struct sockaddr *)sin, sin->sin_len, hbuf, 886*57419a7fSflorian sizeof(hbuf), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); 887*57419a7fSflorian if (error) { 888*57419a7fSflorian log_warnx("%s", gai_strerror(error)); 889*57419a7fSflorian strlcpy(hbuf, "unknown", sizeof(hbuf)); 890*57419a7fSflorian } 891*57419a7fSflorian return hbuf; 892*57419a7fSflorian } 893*57419a7fSflorian #endif /* SMALL */ 894*57419a7fSflorian 895*57419a7fSflorian void 896*57419a7fSflorian open_bpfsock(uint32_t if_index) 897*57419a7fSflorian { 898*57419a7fSflorian int bpfsock; 899*57419a7fSflorian char ifname[IF_NAMESIZE]; 900*57419a7fSflorian 901*57419a7fSflorian log_debug("%s: %d", __func__, if_index); 902*57419a7fSflorian 903*57419a7fSflorian if (if_indextoname(if_index, ifname) == 0) { 904*57419a7fSflorian log_warnx("%s: cannot find interface %d", __func__, if_index); 905*57419a7fSflorian return; 906*57419a7fSflorian } 907*57419a7fSflorian 908*57419a7fSflorian if ((bpfsock = get_bpf_sock(ifname)) == -1) 909*57419a7fSflorian return; 910*57419a7fSflorian 911*57419a7fSflorian main_imsg_compose_frontend(IMSG_BPFSOCK, bpfsock, &if_index, 912*57419a7fSflorian sizeof(if_index)); 913*57419a7fSflorian } 914*57419a7fSflorian 915*57419a7fSflorian void 916*57419a7fSflorian propose_rdns(struct imsg_propose_rdns *rdns) 917*57419a7fSflorian { 918*57419a7fSflorian struct rt_msghdr rtm; 919*57419a7fSflorian struct sockaddr_rtdns rtdns; 920*57419a7fSflorian struct iovec iov[3]; 921*57419a7fSflorian long pad = 0; 922*57419a7fSflorian int iovcnt = 0, padlen; 923*57419a7fSflorian 924*57419a7fSflorian memset(&rtm, 0, sizeof(rtm)); 925*57419a7fSflorian 926*57419a7fSflorian rtm.rtm_version = RTM_VERSION; 927*57419a7fSflorian rtm.rtm_type = RTM_PROPOSAL; 928*57419a7fSflorian rtm.rtm_msglen = sizeof(rtm); 929*57419a7fSflorian rtm.rtm_tableid = rdns->rdomain; 930*57419a7fSflorian rtm.rtm_index = rdns->if_index; 931*57419a7fSflorian rtm.rtm_seq = ++rtm_seq; 932*57419a7fSflorian rtm.rtm_priority = RTP_PROPOSAL_DHCLIENT; 933*57419a7fSflorian rtm.rtm_addrs = RTA_DNS; 934*57419a7fSflorian rtm.rtm_flags = RTF_UP; 935*57419a7fSflorian 936*57419a7fSflorian iov[iovcnt].iov_base = &rtm; 937*57419a7fSflorian iov[iovcnt++].iov_len = sizeof(rtm); 938*57419a7fSflorian 939*57419a7fSflorian memset(&rtdns, 0, sizeof(rtdns)); 940*57419a7fSflorian rtdns.sr_family = AF_INET; 941*57419a7fSflorian rtdns.sr_len = 2 + rdns->rdns_count * sizeof(struct in_addr); 942*57419a7fSflorian memcpy(rtdns.sr_dns, rdns->rdns, sizeof(rtdns.sr_dns)); 943*57419a7fSflorian 944*57419a7fSflorian iov[iovcnt].iov_base = &rtdns; 945*57419a7fSflorian iov[iovcnt++].iov_len = sizeof(rtdns); 946*57419a7fSflorian rtm.rtm_msglen += sizeof(rtdns); 947*57419a7fSflorian padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns); 948*57419a7fSflorian if (padlen > 0) { 949*57419a7fSflorian iov[iovcnt].iov_base = &pad; 950*57419a7fSflorian iov[iovcnt++].iov_len = padlen; 951*57419a7fSflorian rtm.rtm_msglen += padlen; 952*57419a7fSflorian } 953*57419a7fSflorian 954*57419a7fSflorian if (writev(routesock, iov, iovcnt) == -1) 955*57419a7fSflorian log_warn("failed to send route message"); 956*57419a7fSflorian } 957*57419a7fSflorian 958*57419a7fSflorian int 959*57419a7fSflorian open_lease_file(int if_index) 960*57419a7fSflorian { 961*57419a7fSflorian int len; 962*57419a7fSflorian char if_name[IF_NAMESIZE]; 963*57419a7fSflorian char lease_file_buf[sizeof(LEASE_PATH) + IF_NAMESIZE]; 964*57419a7fSflorian 965*57419a7fSflorian if (if_indextoname(if_index, if_name) == 0) { 966*57419a7fSflorian log_warnx("%s: cannot find interface %d", __func__, if_index); 967*57419a7fSflorian return -1; 968*57419a7fSflorian } 969*57419a7fSflorian 970*57419a7fSflorian len = snprintf(lease_file_buf, sizeof(lease_file_buf), "%s%s", 971*57419a7fSflorian LEASE_PATH, if_name); 972*57419a7fSflorian if ( len == -1 || (size_t) len >= sizeof(lease_file_buf)) { 973*57419a7fSflorian log_warnx("%s: failed to encode lease path for %s", __func__, 974*57419a7fSflorian if_name); 975*57419a7fSflorian return -1; 976*57419a7fSflorian } 977*57419a7fSflorian 978*57419a7fSflorian return (open(lease_file_buf, O_RDONLY)); 979*57419a7fSflorian } 980