1 /* $OpenBSD: engine.c,v 1.9 2018/08/03 13:14:46 florian Exp $ */ 2 3 /* 4 * Copyright (c) 2018 Florian Obser <florian@openbsd.org> 5 * Copyright (c) 2004, 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 22 #include <sys/types.h> 23 #include <sys/queue.h> 24 #include <sys/socket.h> 25 #include <sys/syslog.h> 26 #include <sys/uio.h> 27 28 #include <netinet/in.h> 29 #include <net/if.h> 30 #include <arpa/inet.h> 31 #include <netinet/icmp6.h> 32 33 #include <errno.h> 34 #include <event.h> 35 #include <imsg.h> 36 #include <signal.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <pwd.h> 40 #include <unistd.h> 41 42 #include "log.h" 43 #include "rad.h" 44 #include "engine.h" 45 46 struct engine_iface { 47 TAILQ_ENTRY(engine_iface) entry; 48 struct event timer; 49 uint32_t if_index; 50 }; 51 52 TAILQ_HEAD(, engine_iface) engine_interfaces; 53 54 55 __dead void engine_shutdown(void); 56 void engine_sig_handler(int sig, short, void *); 57 void engine_dispatch_frontend(int, short, void *); 58 void engine_dispatch_main(int, short, void *); 59 void parse_ra_rs(struct imsg_ra_rs *); 60 void parse_ra(struct imsg_ra_rs *); 61 void parse_rs(struct imsg_ra_rs *); 62 void update_iface(uint32_t); 63 void remove_iface(uint32_t); 64 struct engine_iface *find_engine_iface_by_id(uint32_t); 65 void iface_timeout(int, short, void *); 66 67 struct rad_conf *engine_conf; 68 struct imsgev *iev_frontend; 69 struct imsgev *iev_main; 70 struct sockaddr_in6 all_nodes; 71 72 void 73 engine_sig_handler(int sig, short event, void *arg) 74 { 75 /* 76 * Normal signal handler rules don't apply because libevent 77 * decouples for us. 78 */ 79 80 switch (sig) { 81 case SIGINT: 82 case SIGTERM: 83 engine_shutdown(); 84 default: 85 fatalx("unexpected signal"); 86 } 87 } 88 89 void 90 engine(int debug, int verbose) 91 { 92 struct event ev_sigint, ev_sigterm; 93 struct passwd *pw; 94 95 engine_conf = config_new_empty(); 96 97 log_init(debug, LOG_DAEMON); 98 log_setverbose(verbose); 99 100 if ((pw = getpwnam(RAD_USER)) == NULL) 101 fatal("getpwnam"); 102 103 if (chroot(pw->pw_dir) == -1) 104 fatal("chroot"); 105 if (chdir("/") == -1) 106 fatal("chdir(\"/\")"); 107 108 rad_process = PROC_ENGINE; 109 setproctitle("%s", log_procnames[rad_process]); 110 log_procinit(log_procnames[rad_process]); 111 112 if (setgroups(1, &pw->pw_gid) || 113 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 114 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 115 fatal("can't drop privileges"); 116 117 if (pledge("stdio recvfd", NULL) == -1) 118 fatal("pledge"); 119 120 event_init(); 121 122 /* Setup signal handler(s). */ 123 signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL); 124 signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL); 125 signal_add(&ev_sigint, NULL); 126 signal_add(&ev_sigterm, NULL); 127 signal(SIGPIPE, SIG_IGN); 128 signal(SIGHUP, SIG_IGN); 129 130 /* Setup pipe and event handler to the main process. */ 131 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 132 fatal(NULL); 133 134 imsg_init(&iev_main->ibuf, 3); 135 iev_main->handler = engine_dispatch_main; 136 137 /* Setup event handlers. */ 138 iev_main->events = EV_READ; 139 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 140 iev_main->handler, iev_main); 141 event_add(&iev_main->ev, NULL); 142 143 all_nodes.sin6_len = sizeof(all_nodes); 144 all_nodes.sin6_family = AF_INET6; 145 if (inet_pton(AF_INET6, "ff02::1", &all_nodes.sin6_addr) != 1) 146 fatal("inet_pton"); 147 148 TAILQ_INIT(&engine_interfaces); 149 150 event_dispatch(); 151 152 engine_shutdown(); 153 } 154 155 __dead void 156 engine_shutdown(void) 157 { 158 /* Close pipes. */ 159 msgbuf_clear(&iev_frontend->ibuf.w); 160 close(iev_frontend->ibuf.fd); 161 msgbuf_clear(&iev_main->ibuf.w); 162 close(iev_main->ibuf.fd); 163 164 config_clear(engine_conf); 165 166 free(iev_frontend); 167 free(iev_main); 168 169 log_info("engine exiting"); 170 exit(0); 171 } 172 173 int 174 engine_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) 175 { 176 return (imsg_compose_event(iev_frontend, type, 0, pid, -1, 177 data, datalen)); 178 } 179 180 void 181 engine_dispatch_frontend(int fd, short event, void *bula) 182 { 183 struct imsgev *iev = bula; 184 struct imsgbuf *ibuf; 185 struct imsg imsg; 186 struct imsg_ra_rs ra_rs; 187 ssize_t n; 188 uint32_t if_index; 189 int shut = 0, verbose; 190 191 ibuf = &iev->ibuf; 192 193 if (event & EV_READ) { 194 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 195 fatal("imsg_read error"); 196 if (n == 0) /* Connection closed. */ 197 shut = 1; 198 } 199 if (event & EV_WRITE) { 200 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 201 fatal("msgbuf_write"); 202 if (n == 0) /* Connection closed. */ 203 shut = 1; 204 } 205 206 for (;;) { 207 if ((n = imsg_get(ibuf, &imsg)) == -1) 208 fatal("%s: imsg_get error", __func__); 209 if (n == 0) /* No more messages. */ 210 break; 211 212 switch (imsg.hdr.type) { 213 case IMSG_RA_RS: 214 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(ra_rs)) 215 fatal("%s: IMSG_RA_RS wrong length: %d", 216 __func__, imsg.hdr.len); 217 memcpy(&ra_rs, imsg.data, sizeof(ra_rs)); 218 parse_ra_rs(&ra_rs); 219 break; 220 case IMSG_UPDATE_IF: 221 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(if_index)) 222 fatal("%s: IMSG_UPDATE_IF wrong length: %d", 223 __func__, imsg.hdr.len); 224 memcpy(&if_index, imsg.data, sizeof(if_index)); 225 update_iface(if_index); 226 break; 227 case IMSG_REMOVE_IF: 228 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(if_index)) 229 fatal("%s: IMSG_REMOVE_IF wrong length: %d", 230 __func__, imsg.hdr.len); 231 memcpy(&if_index, imsg.data, sizeof(if_index)); 232 remove_iface(if_index); 233 break; 234 case IMSG_CTL_LOG_VERBOSE: 235 /* Already checked by frontend. */ 236 memcpy(&verbose, imsg.data, sizeof(verbose)); 237 log_setverbose(verbose); 238 break; 239 case IMSG_SHUTDOWN: 240 engine_imsg_compose_frontend(IMSG_SHUTDOWN, 0, NULL, 0); 241 break; 242 default: 243 log_debug("%s: unexpected imsg %d", __func__, 244 imsg.hdr.type); 245 break; 246 } 247 imsg_free(&imsg); 248 } 249 if (!shut) 250 imsg_event_add(iev); 251 else { 252 /* This pipe is dead. Remove its event handler. */ 253 event_del(&iev->ev); 254 event_loopexit(NULL); 255 } 256 } 257 258 void 259 engine_dispatch_main(int fd, short event, void *bula) 260 { 261 static struct rad_conf *nconf; 262 static struct ra_iface_conf *ra_iface_conf; 263 static struct ra_options_conf *ra_options; 264 struct imsg imsg; 265 struct imsgev *iev = bula; 266 struct imsgbuf *ibuf; 267 struct ra_prefix_conf *ra_prefix_conf; 268 struct ra_rdnss_conf *ra_rdnss_conf; 269 struct ra_dnssl_conf *ra_dnssl_conf; 270 ssize_t n; 271 int shut = 0; 272 273 ibuf = &iev->ibuf; 274 275 if (event & EV_READ) { 276 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 277 fatal("imsg_read error"); 278 if (n == 0) /* Connection closed. */ 279 shut = 1; 280 } 281 if (event & EV_WRITE) { 282 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 283 fatal("msgbuf_write"); 284 if (n == 0) /* Connection closed. */ 285 shut = 1; 286 } 287 288 for (;;) { 289 if ((n = imsg_get(ibuf, &imsg)) == -1) 290 fatal("%s: imsg_get error", __func__); 291 if (n == 0) /* No more messages. */ 292 break; 293 294 switch (imsg.hdr.type) { 295 case IMSG_SOCKET_IPC: 296 /* 297 * Setup pipe and event handler to the frontend 298 * process. 299 */ 300 if (iev_frontend) { 301 log_warnx("%s: received unexpected imsg fd " 302 "to engine", __func__); 303 break; 304 } 305 if ((fd = imsg.fd) == -1) { 306 log_warnx("%s: expected to receive imsg fd to " 307 "engine but didn't receive any", __func__); 308 break; 309 } 310 311 iev_frontend = malloc(sizeof(struct imsgev)); 312 if (iev_frontend == NULL) 313 fatal(NULL); 314 315 imsg_init(&iev_frontend->ibuf, fd); 316 iev_frontend->handler = engine_dispatch_frontend; 317 iev_frontend->events = EV_READ; 318 319 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 320 iev_frontend->events, iev_frontend->handler, 321 iev_frontend); 322 event_add(&iev_frontend->ev, NULL); 323 break; 324 case IMSG_RECONF_CONF: 325 if ((nconf = malloc(sizeof(struct rad_conf))) == NULL) 326 fatal(NULL); 327 memcpy(nconf, imsg.data, sizeof(struct rad_conf)); 328 SIMPLEQ_INIT(&nconf->ra_iface_list); 329 SIMPLEQ_INIT(&nconf->ra_options.ra_rdnss_list); 330 SIMPLEQ_INIT(&nconf->ra_options.ra_dnssl_list); 331 ra_options = &nconf->ra_options; 332 break; 333 case IMSG_RECONF_RA_IFACE: 334 if ((ra_iface_conf = malloc(sizeof(struct 335 ra_iface_conf))) == NULL) 336 fatal(NULL); 337 memcpy(ra_iface_conf, imsg.data, 338 sizeof(struct ra_iface_conf)); 339 ra_iface_conf->autoprefix = NULL; 340 SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list); 341 SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_rdnss_list); 342 SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_dnssl_list); 343 SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list, 344 ra_iface_conf, entry); 345 ra_options = &ra_iface_conf->ra_options; 346 break; 347 case IMSG_RECONF_RA_AUTOPREFIX: 348 if ((ra_iface_conf->autoprefix = malloc(sizeof(struct 349 ra_prefix_conf))) == NULL) 350 fatal(NULL); 351 memcpy(ra_iface_conf->autoprefix, imsg.data, 352 sizeof(struct ra_prefix_conf)); 353 break; 354 case IMSG_RECONF_RA_PREFIX: 355 if ((ra_prefix_conf = malloc(sizeof(struct 356 ra_prefix_conf))) == NULL) 357 fatal(NULL); 358 memcpy(ra_prefix_conf, imsg.data, sizeof(struct 359 ra_prefix_conf)); 360 SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, 361 ra_prefix_conf, entry); 362 break; 363 case IMSG_RECONF_RA_RDNSS: 364 if ((ra_rdnss_conf = malloc(sizeof(struct 365 ra_rdnss_conf))) == NULL) 366 fatal(NULL); 367 memcpy(ra_rdnss_conf, imsg.data, sizeof(struct 368 ra_rdnss_conf)); 369 SIMPLEQ_INSERT_TAIL(&ra_options->ra_rdnss_list, 370 ra_rdnss_conf, entry); 371 break; 372 case IMSG_RECONF_RA_DNSSL: 373 if ((ra_dnssl_conf = malloc(sizeof(struct 374 ra_dnssl_conf))) == NULL) 375 fatal(NULL); 376 memcpy(ra_dnssl_conf, imsg.data, sizeof(struct 377 ra_dnssl_conf)); 378 SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list, 379 ra_dnssl_conf, entry); 380 break; 381 case IMSG_RECONF_END: 382 merge_config(engine_conf, nconf); 383 nconf = NULL; 384 break; 385 default: 386 log_debug("%s: unexpected imsg %d", __func__, 387 imsg.hdr.type); 388 break; 389 } 390 imsg_free(&imsg); 391 } 392 if (!shut) 393 imsg_event_add(iev); 394 else { 395 /* This pipe is dead. Remove its event handler. */ 396 event_del(&iev->ev); 397 event_loopexit(NULL); 398 } 399 } 400 401 402 void 403 parse_ra_rs(struct imsg_ra_rs *ra_rs) 404 { 405 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 406 struct icmp6_hdr *hdr; 407 408 hdr = (struct icmp6_hdr *) ra_rs->packet; 409 410 switch (hdr->icmp6_type) { 411 case ND_ROUTER_ADVERT: 412 parse_ra(ra_rs); 413 break; 414 case ND_ROUTER_SOLICIT: 415 parse_rs(ra_rs); 416 break; 417 default: 418 log_warnx("unexpected icmp6_type: %d from %s on %s", 419 hdr->icmp6_type, inet_ntop(AF_INET6, &ra_rs->from.sin6_addr, 420 ntopbuf, INET6_ADDRSTRLEN), if_indextoname(ra_rs->if_index, 421 ifnamebuf)); 422 break; 423 } 424 } 425 426 void 427 parse_ra(struct imsg_ra_rs *ra) 428 { 429 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 430 log_debug("got RA from %s on %s", 431 inet_ntop(AF_INET6, &ra->from.sin6_addr, ntopbuf, 432 INET6_ADDRSTRLEN), if_indextoname(ra->if_index, 433 ifnamebuf)); 434 /* XXX not yet */ 435 } 436 437 void 438 parse_rs(struct imsg_ra_rs *rs) 439 { 440 struct nd_router_solicit *nd_rs; 441 struct imsg_send_ra send_ra; 442 ssize_t len; 443 const char *hbuf; 444 char ifnamebuf[IFNAMSIZ]; 445 uint8_t *p; 446 447 hbuf = sin6_to_str(&rs->from); 448 449 send_ra.if_index = rs->if_index; 450 memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); 451 452 log_debug("got RS from %s on %s", hbuf, if_indextoname(rs->if_index, 453 ifnamebuf)); 454 455 len = rs->len; 456 457 if (!IN6_IS_ADDR_LINKLOCAL(&rs->from.sin6_addr)) { 458 log_warnx("RA from non link local address %s", hbuf); 459 return; 460 } 461 462 if ((size_t)len < sizeof(struct nd_router_solicit)) { 463 log_warnx("received too short message (%ld) from %s", len, 464 hbuf); 465 return; 466 } 467 468 p = rs->packet; 469 nd_rs = (struct nd_router_solicit *)p; 470 len -= sizeof(struct nd_router_solicit); 471 p += sizeof(struct nd_router_solicit); 472 473 if (nd_rs->nd_rs_code != 0) { 474 log_warnx("invalid ICMPv6 code (%d) from %s", nd_rs->nd_rs_code, 475 hbuf); 476 return; 477 } 478 while ((size_t)len >= sizeof(struct nd_opt_hdr)) { 479 struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p; 480 481 len -= sizeof(struct nd_opt_hdr); 482 p += sizeof(struct nd_opt_hdr); 483 484 if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) { 485 log_warnx("invalid option len: %u > %ld", 486 nd_opt_hdr->nd_opt_len, len); 487 return; 488 } 489 switch (nd_opt_hdr->nd_opt_type) { 490 case ND_OPT_SOURCE_LINKADDR: 491 log_debug("got RS with source linkaddr option"); 492 memcpy(&send_ra.to, &rs->from, sizeof(send_ra.to)); 493 break; 494 default: 495 log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type); 496 break; 497 } 498 len -= nd_opt_hdr->nd_opt_len * 8 - 2; 499 p += nd_opt_hdr->nd_opt_len * 8 - 2; 500 } 501 engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, 502 sizeof(send_ra)); 503 } 504 505 struct engine_iface* 506 find_engine_iface_by_id(uint32_t if_index) 507 { 508 struct engine_iface *engine_iface; 509 510 TAILQ_FOREACH(engine_iface, &engine_interfaces, entry) { 511 if (engine_iface->if_index == if_index) 512 return engine_iface; 513 } 514 return (NULL); 515 } 516 517 void 518 update_iface(uint32_t if_index) 519 { 520 struct engine_iface *engine_iface; 521 struct timeval tv; 522 523 if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL) { 524 engine_iface = calloc(1, sizeof(*engine_iface)); 525 engine_iface->if_index = if_index; 526 evtimer_set(&engine_iface->timer, iface_timeout, engine_iface); 527 TAILQ_INSERT_TAIL(&engine_interfaces, engine_iface, entry); 528 } 529 530 tv.tv_sec = 0; 531 tv.tv_usec = arc4random_uniform(1000000); 532 evtimer_add(&engine_iface->timer, &tv); 533 } 534 535 void 536 remove_iface(uint32_t if_index) 537 { 538 struct engine_iface *engine_iface; 539 struct imsg_send_ra send_ra; 540 char if_name[IF_NAMESIZE]; 541 542 if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL) { 543 /* we don't know this interface, frontend can delete it */ 544 engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0, 545 &if_index, sizeof(if_index)); 546 return; 547 } 548 549 send_ra.if_index = engine_iface->if_index; 550 memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); 551 552 TAILQ_REMOVE(&engine_interfaces, engine_iface, entry); 553 evtimer_del(&engine_iface->timer); 554 555 if (if_indextoname(if_index, if_name) != NULL) 556 engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, 557 sizeof(send_ra)); 558 engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0, 559 &engine_iface->if_index, sizeof(engine_iface->if_index)); 560 free(engine_iface); 561 } 562 563 void 564 iface_timeout(int fd, short events, void *arg) 565 { 566 struct engine_iface *engine_iface = (struct engine_iface *)arg; 567 struct imsg_send_ra send_ra; 568 struct timeval tv; 569 570 tv.tv_sec = MIN_RTR_ADV_INTERVAL + 571 arc4random_uniform(MAX_RTR_ADV_INTERVAL - MIN_RTR_ADV_INTERVAL); 572 tv.tv_usec = arc4random_uniform(1000000); 573 574 log_debug("%s new timeout in %lld", __func__, tv.tv_sec); 575 576 evtimer_add(&engine_iface->timer, &tv); 577 578 send_ra.if_index = engine_iface->if_index; 579 memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); 580 engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, 581 sizeof(send_ra)); 582 } 583