1 /* $OpenBSD: frontend.c,v 1.20 2024/11/21 13:35:20 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2017, 2021, 2024 Florian Obser <florian@openbsd.org> 5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 #include <sys/types.h> 22 #include <sys/ioctl.h> 23 #include <sys/queue.h> 24 #include <sys/socket.h> 25 #include <sys/syslog.h> 26 #include <sys/uio.h> 27 #include <sys/utsname.h> 28 29 #include <net/if.h> 30 #include <net/if_dl.h> 31 #include <net/if_types.h> 32 #include <net/route.h> 33 34 #include <netinet/in.h> 35 #include <netinet/ip.h> 36 37 #include <arpa/inet.h> 38 39 #include <errno.h> 40 #include <event.h> 41 #include <ifaddrs.h> 42 #include <imsg.h> 43 #include <pwd.h> 44 #include <signal.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 #include "log.h" 51 #include "dhcp6leased.h" 52 #include "frontend.h" 53 #include "control.h" 54 55 #define ALL_DHCP_RELAY_AGENTS_AND_SERVERS "ff02::1:2" 56 #define ROUTE_SOCKET_BUF_SIZE 16384 57 58 struct iface { 59 LIST_ENTRY(iface) entries; 60 struct event udpev; 61 struct imsg_ifinfo ifinfo; 62 int send_solicit; 63 int elapsed_time; 64 uint8_t xid[XID_SIZE]; 65 int serverid_len; 66 uint8_t serverid[SERVERID_SIZE]; 67 struct prefix pds[MAX_IA]; 68 }; 69 70 __dead void frontend_shutdown(void); 71 void frontend_sig_handler(int, short, void *); 72 void frontend_startup(void); 73 void update_iface(uint32_t); 74 void route_receive(int, short, void *); 75 void handle_route_message(struct rt_msghdr *, struct sockaddr **); 76 void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 77 void udp_receive(int, short, void *); 78 int get_flags(char *); 79 struct iface *get_iface_by_id(uint32_t); 80 struct iface *get_iface_by_name(const char *); 81 void remove_iface(uint32_t); 82 void set_udpsock(int, uint32_t); 83 void iface_data_from_imsg(struct iface*, struct imsg_req_dhcp *); 84 ssize_t build_packet(uint8_t, struct iface *, char *); 85 void send_packet(uint8_t, struct iface *); 86 int iface_conf_cmp(struct iface_conf *, struct iface_conf *); 87 88 LIST_HEAD(, iface) interfaces; 89 struct dhcp6leased_conf *frontend_conf; 90 static struct imsgev *iev_main; 91 static struct imsgev *iev_engine; 92 struct event ev_route; 93 struct sockaddr_in6 dst; 94 int ioctlsock; 95 96 uint8_t dhcp_packet[1500]; 97 static struct dhcp_duid duid; 98 char *vendor_class_data; 99 int vendor_class_len; 100 101 void 102 frontend_sig_handler(int sig, short event, void *bula) 103 { 104 /* 105 * Normal signal handler rules don't apply because libevent 106 * decouples for us. 107 */ 108 109 switch (sig) { 110 case SIGINT: 111 case SIGTERM: 112 frontend_shutdown(); 113 default: 114 fatalx("unexpected signal"); 115 } 116 } 117 118 void 119 frontend(int debug, int verbose) 120 { 121 struct event ev_sigint, ev_sigterm; 122 struct passwd *pw; 123 struct utsname utsname; 124 125 frontend_conf = config_new_empty(); 126 127 log_init(debug, LOG_DAEMON); 128 log_setverbose(verbose); 129 130 if ((pw = getpwnam(DHCP6LEASED_USER)) == NULL) 131 fatal("getpwnam"); 132 133 if (chdir("/") == -1) 134 fatal("chdir(\"/\")"); 135 136 if (unveil("/", "") == -1) 137 fatal("unveil /"); 138 if (unveil(NULL, NULL) == -1) 139 fatal("unveil"); 140 141 setproctitle("%s", "frontend"); 142 log_procinit("frontend"); 143 144 if ((ioctlsock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1) 145 fatal("socket"); 146 147 if (setgroups(1, &pw->pw_gid) || 148 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 149 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 150 fatal("can't drop privileges"); 151 152 if (pledge("stdio unix recvfd route", NULL) == -1) 153 fatal("pledge"); 154 155 if (uname(&utsname) == -1) 156 fatal("uname"); 157 vendor_class_len = asprintf(&vendor_class_data, "%s %s %s", 158 utsname.sysname, utsname.release, utsname.machine); 159 if (vendor_class_len == -1) 160 fatal("Cannot generate vendor-class-data"); 161 162 memset(&dst, 0, sizeof(dst)); 163 dst.sin6_family = AF_INET6; 164 if (inet_pton(AF_INET6, ALL_DHCP_RELAY_AGENTS_AND_SERVERS, 165 &dst.sin6_addr.s6_addr) != 1) 166 fatal("inet_pton"); 167 168 dst.sin6_port = ntohs(SERVER_PORT); 169 170 event_init(); 171 172 /* Setup signal handler. */ 173 signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL); 174 signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL); 175 signal_add(&ev_sigint, NULL); 176 signal_add(&ev_sigterm, NULL); 177 signal(SIGPIPE, SIG_IGN); 178 signal(SIGHUP, SIG_IGN); 179 180 /* Setup pipe and event handler to the parent process. */ 181 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 182 fatal(NULL); 183 if (imsgbuf_init(&iev_main->ibuf, 3) == -1) 184 fatal(NULL); 185 imsgbuf_allow_fdpass(&iev_main->ibuf); 186 iev_main->handler = frontend_dispatch_main; 187 iev_main->events = EV_READ; 188 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 189 iev_main->handler, iev_main); 190 event_add(&iev_main->ev, NULL); 191 192 LIST_INIT(&interfaces); 193 event_dispatch(); 194 195 frontend_shutdown(); 196 } 197 198 __dead void 199 frontend_shutdown(void) 200 { 201 /* Close pipes. */ 202 imsgbuf_write(&iev_engine->ibuf); 203 imsgbuf_clear(&iev_engine->ibuf); 204 close(iev_engine->ibuf.fd); 205 imsgbuf_write(&iev_main->ibuf); 206 imsgbuf_clear(&iev_main->ibuf); 207 close(iev_main->ibuf.fd); 208 209 config_clear(frontend_conf); 210 211 free(iev_engine); 212 free(iev_main); 213 214 log_info("frontend exiting"); 215 exit(0); 216 } 217 218 int 219 frontend_imsg_compose_main(int type, pid_t pid, void *data, 220 uint16_t datalen) 221 { 222 return (imsg_compose_event(iev_main, type, 0, pid, -1, data, 223 datalen)); 224 } 225 226 int 227 frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid, 228 void *data, uint16_t datalen) 229 { 230 return (imsg_compose_event(iev_engine, type, peerid, pid, -1, 231 data, datalen)); 232 } 233 234 void 235 frontend_dispatch_main(int fd, short event, void *bula) 236 { 237 static struct dhcp6leased_conf *nconf; 238 static struct iface_conf *iface_conf; 239 static struct iface_ia_conf *iface_ia_conf; 240 struct iface_pd_conf *iface_pd_conf; 241 struct imsg imsg; 242 struct imsgev *iev = bula; 243 struct imsgbuf *ibuf = &iev->ibuf; 244 ssize_t n; 245 int shut = 0, udpsock, if_index; 246 247 if (event & EV_READ) { 248 if ((n = imsgbuf_read(ibuf)) == -1) 249 fatal("imsgbuf_read error"); 250 if (n == 0) /* Connection closed. */ 251 shut = 1; 252 } 253 if (event & EV_WRITE) { 254 if (imsgbuf_write(ibuf) == -1) { 255 if (errno == EPIPE) /* Connection closed. */ 256 shut = 1; 257 else 258 fatal("imsgbuf_write"); 259 } 260 } 261 262 for (;;) { 263 if ((n = imsg_get(ibuf, &imsg)) == -1) 264 fatal("%s: imsg_get error", __func__); 265 if (n == 0) /* No more messages. */ 266 break; 267 268 switch (imsg.hdr.type) { 269 case IMSG_SOCKET_IPC: 270 /* 271 * Setup pipe and event handler to the engine 272 * process. 273 */ 274 if (iev_engine) 275 fatalx("%s: received unexpected imsg fd " 276 "to frontend", __func__); 277 278 if ((fd = imsg_get_fd(&imsg)) == -1) 279 fatalx("%s: expected to receive imsg fd to " 280 "frontend but didn't receive any", 281 __func__); 282 283 iev_engine = malloc(sizeof(struct imsgev)); 284 if (iev_engine == NULL) 285 fatal(NULL); 286 287 if (imsgbuf_init(&iev_engine->ibuf, fd) == -1) 288 fatal(NULL); 289 iev_engine->handler = frontend_dispatch_engine; 290 iev_engine->events = EV_READ; 291 292 event_set(&iev_engine->ev, iev_engine->ibuf.fd, 293 iev_engine->events, iev_engine->handler, iev_engine); 294 event_add(&iev_engine->ev, NULL); 295 break; 296 case IMSG_UDPSOCK: 297 if ((udpsock = imsg_get_fd(&imsg)) == -1) 298 fatalx("%s: expected to receive imsg " 299 "udp fd but didn't receive any", 300 __func__); 301 if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 302 fatalx("%s: IMSG_UDPSOCK wrong length: " 303 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 304 memcpy(&if_index, imsg.data, sizeof(if_index)); 305 set_udpsock(udpsock, if_index); 306 break; 307 case IMSG_ROUTESOCK: 308 if ((fd = imsg_get_fd(&imsg)) == -1) 309 fatalx("%s: expected to receive imsg " 310 "routesocket fd but didn't receive any", 311 __func__); 312 event_set(&ev_route, fd, EV_READ | EV_PERSIST, 313 route_receive, NULL); 314 break; 315 case IMSG_UUID: 316 if (IMSG_DATA_SIZE(imsg) != sizeof(duid.uuid)) 317 fatalx("%s: IMSG_UUID wrong length: " 318 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 319 duid.type = htons(DUID_UUID_TYPE); 320 memcpy(duid.uuid, imsg.data, sizeof(duid.uuid)); 321 break; 322 case IMSG_STARTUP: 323 frontend_startup(); 324 break; 325 case IMSG_RECONF_CONF: 326 if (nconf != NULL) 327 fatalx("%s: IMSG_RECONF_CONF already in " 328 "progress", __func__); 329 if (IMSG_DATA_SIZE(imsg) != 330 sizeof(struct dhcp6leased_conf)) 331 fatalx("%s: IMSG_RECONF_CONF wrong length: %lu", 332 __func__, IMSG_DATA_SIZE(imsg)); 333 if ((nconf = malloc(sizeof(struct dhcp6leased_conf))) == 334 NULL) 335 fatal(NULL); 336 memcpy(nconf, imsg.data, 337 sizeof(struct dhcp6leased_conf)); 338 SIMPLEQ_INIT(&nconf->iface_list); 339 break; 340 case IMSG_RECONF_IFACE: 341 if (IMSG_DATA_SIZE(imsg) != sizeof(struct 342 iface_conf)) 343 fatalx("%s: IMSG_RECONF_IFACE wrong length: " 344 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 345 if ((iface_conf = malloc(sizeof(struct iface_conf))) 346 == NULL) 347 fatal(NULL); 348 memcpy(iface_conf, imsg.data, sizeof(struct 349 iface_conf)); 350 SIMPLEQ_INIT(&iface_conf->iface_ia_list); 351 SIMPLEQ_INSERT_TAIL(&nconf->iface_list, 352 iface_conf, entry); 353 iface_conf->ia_count = 0; 354 break; 355 case IMSG_RECONF_IFACE_IA: 356 if (IMSG_DATA_SIZE(imsg) != sizeof(struct 357 iface_ia_conf)) 358 fatalx("%s: IMSG_RECONF_IFACE_IA wrong " 359 "length: %lu", __func__, 360 IMSG_DATA_SIZE(imsg)); 361 if ((iface_ia_conf = 362 malloc(sizeof(struct iface_ia_conf))) == NULL) 363 fatal(NULL); 364 memcpy(iface_ia_conf, imsg.data, sizeof(struct 365 iface_ia_conf)); 366 SIMPLEQ_INIT(&iface_ia_conf->iface_pd_list); 367 SIMPLEQ_INSERT_TAIL(&iface_conf->iface_ia_list, 368 iface_ia_conf, entry); 369 iface_ia_conf->id = iface_conf->ia_count++; 370 if (iface_conf->ia_count > MAX_IA) 371 fatalx("Too many prefix delegation requests."); 372 break; 373 case IMSG_RECONF_IFACE_PD: 374 if (IMSG_DATA_SIZE(imsg) != sizeof(struct 375 iface_pd_conf)) 376 fatalx("%s: IMSG_RECONF_IFACE_PD wrong length: " 377 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 378 if ((iface_pd_conf = 379 malloc(sizeof(struct iface_pd_conf))) == NULL) 380 fatal(NULL); 381 memcpy(iface_pd_conf, imsg.data, sizeof(struct 382 iface_pd_conf)); 383 SIMPLEQ_INSERT_TAIL(&iface_ia_conf->iface_pd_list, 384 iface_pd_conf, entry); 385 break; 386 case IMSG_RECONF_IFACE_IA_END: 387 iface_ia_conf = NULL; 388 break; 389 case IMSG_RECONF_IFACE_END: 390 iface_conf = NULL; 391 break; 392 case IMSG_RECONF_END: { 393 int i; 394 int *ifaces; 395 char ifnamebuf[IF_NAMESIZE], *if_name; 396 397 if (nconf == NULL) 398 fatalx("%s: IMSG_RECONF_END without " 399 "IMSG_RECONF_CONF", __func__); 400 401 ifaces = changed_ifaces(frontend_conf, nconf); 402 merge_config(frontend_conf, nconf); 403 nconf = NULL; 404 for (i = 0; ifaces[i] != 0; i++) { 405 if_index = ifaces[i]; 406 if_name = if_indextoname(if_index, ifnamebuf); 407 log_debug("changed iface: %s[%d]", if_name != 408 NULL ? if_name : "<unknown>", if_index); 409 update_iface(if_index); 410 frontend_imsg_compose_engine( 411 IMSG_REQUEST_REBOOT, 0, 0, &if_index, 412 sizeof(if_index)); 413 } 414 free(ifaces); 415 break; 416 } 417 case IMSG_CONTROLFD: 418 if ((fd = imsg_get_fd(&imsg)) == -1) 419 fatalx("%s: expected to receive imsg " 420 "control fd but didn't receive any", 421 __func__); 422 /* Listen on control socket. */ 423 control_listen(fd); 424 break; 425 case IMSG_CTL_END: 426 control_imsg_relay(&imsg); 427 break; 428 default: 429 log_debug("%s: error handling imsg %d", __func__, 430 imsg.hdr.type); 431 break; 432 } 433 imsg_free(&imsg); 434 } 435 if (!shut) 436 imsg_event_add(iev); 437 else { 438 /* This pipe is dead. Remove its event handler. */ 439 event_del(&iev->ev); 440 event_loopexit(NULL); 441 } 442 } 443 444 void 445 frontend_dispatch_engine(int fd, short event, void *bula) 446 { 447 struct imsgev *iev = bula; 448 struct imsgbuf *ibuf = &iev->ibuf; 449 struct imsg imsg; 450 struct iface *iface; 451 ssize_t n; 452 int shut = 0; 453 454 if (event & EV_READ) { 455 if ((n = imsgbuf_read(ibuf)) == -1) 456 fatal("imsgbuf_read error"); 457 if (n == 0) /* Connection closed. */ 458 shut = 1; 459 } 460 if (event & EV_WRITE) { 461 if (imsgbuf_write(ibuf) == -1) { 462 if (errno == EPIPE) /* Connection closed. */ 463 shut = 1; 464 else 465 fatal("imsgbuf_write"); 466 } 467 } 468 469 for (;;) { 470 if ((n = imsg_get(ibuf, &imsg)) == -1) 471 fatal("%s: imsg_get error", __func__); 472 if (n == 0) /* No more messages. */ 473 break; 474 475 switch (imsg.hdr.type) { 476 case IMSG_CTL_END: 477 case IMSG_CTL_SHOW_INTERFACE_INFO: 478 control_imsg_relay(&imsg); 479 break; 480 case IMSG_SEND_SOLICIT: 481 case IMSG_SEND_REQUEST: 482 case IMSG_SEND_RENEW: 483 case IMSG_SEND_REBIND: { 484 struct imsg_req_dhcp imsg_req_dhcp; 485 if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_dhcp)) 486 fatalx("%s: IMSG_SEND_DISCOVER wrong " 487 "length: %lu", __func__, 488 IMSG_DATA_SIZE(imsg)); 489 memcpy(&imsg_req_dhcp, imsg.data, 490 sizeof(imsg_req_dhcp)); 491 492 iface = get_iface_by_id(imsg_req_dhcp.if_index); 493 494 if (iface == NULL) 495 break; 496 497 iface_data_from_imsg(iface, &imsg_req_dhcp); 498 switch (imsg.hdr.type) { 499 case IMSG_SEND_SOLICIT: 500 send_packet(DHCPSOLICIT, iface); 501 break; 502 case IMSG_SEND_REQUEST: 503 send_packet(DHCPREQUEST, iface); 504 break; 505 case IMSG_SEND_RENEW: 506 send_packet(DHCPRENEW, iface); 507 break; 508 case IMSG_SEND_REBIND: 509 send_packet(DHCPREBIND, iface); 510 break; 511 } 512 break; 513 } 514 default: 515 log_debug("%s: error handling imsg %d", __func__, 516 imsg.hdr.type); 517 break; 518 } 519 imsg_free(&imsg); 520 } 521 if (!shut) 522 imsg_event_add(iev); 523 else { 524 /* This pipe is dead. Remove its event handler. */ 525 event_del(&iev->ev); 526 event_loopexit(NULL); 527 } 528 } 529 530 int 531 get_flags(char *if_name) 532 { 533 struct ifreq ifr; 534 535 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 536 if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) { 537 log_warn("SIOCGIFFLAGS"); 538 return -1; 539 } 540 return ifr.ifr_flags; 541 } 542 543 void 544 update_iface(uint32_t if_index) 545 { 546 struct ifaddrs *ifap, *ifa; 547 struct iface *iface; 548 struct imsg_ifinfo ifinfo; 549 int flags; 550 char ifnamebuf[IF_NAMESIZE], *if_name; 551 552 if (getifaddrs(&ifap) != 0) 553 fatal("getifaddrs"); 554 555 if ((if_name = if_indextoname(if_index, ifnamebuf)) == NULL) 556 return; 557 558 if ((flags = get_flags(if_name)) == -1) 559 return; 560 561 if (find_iface_conf(&frontend_conf->iface_list, if_name) == NULL) 562 return; 563 564 memset(&ifinfo, 0, sizeof(ifinfo)); 565 ifinfo.if_index = if_index; 566 ifinfo.link_state = -1; 567 ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == 568 (IFF_UP | IFF_RUNNING); 569 570 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 571 if (strcmp(if_name, ifa->ifa_name) != 0) 572 continue; 573 if (ifa->ifa_addr == NULL) 574 continue; 575 576 switch (ifa->ifa_addr->sa_family) { 577 case AF_LINK: { 578 struct if_data *if_data; 579 580 if_data = (struct if_data *)ifa->ifa_data; 581 ifinfo.link_state = if_data->ifi_link_state; 582 ifinfo.rdomain = if_data->ifi_rdomain; 583 goto out; 584 } 585 default: 586 break; 587 } 588 } 589 out: 590 freeifaddrs(ifap); 591 iface = get_iface_by_id(if_index); 592 if (iface == NULL) { 593 if ((iface = calloc(1, sizeof(*iface))) == NULL) 594 fatal("calloc"); 595 memcpy(&iface->ifinfo, &ifinfo, sizeof(iface->ifinfo)); 596 LIST_INSERT_HEAD(&interfaces, iface, entries); 597 frontend_imsg_compose_main(IMSG_OPEN_UDPSOCK, 0, 598 &if_index, sizeof(if_index)); 599 } else 600 /* XXX check rdomain changed ?*/ 601 memcpy(&iface->ifinfo, &ifinfo, sizeof(iface->ifinfo)); 602 603 frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &iface->ifinfo, 604 sizeof(iface->ifinfo)); 605 } 606 607 void 608 frontend_startup(void) 609 { 610 if (!event_initialized(&ev_route)) 611 fatalx("%s: did not receive a route socket from the main " 612 "process", __func__); 613 614 event_add(&ev_route, NULL); 615 } 616 617 void 618 route_receive(int fd, short events, void *arg) 619 { 620 static uint8_t *buf; 621 622 struct rt_msghdr *rtm; 623 struct sockaddr *sa, *rti_info[RTAX_MAX]; 624 ssize_t n; 625 626 if (buf == NULL) { 627 buf = malloc(ROUTE_SOCKET_BUF_SIZE); 628 if (buf == NULL) 629 fatal("malloc"); 630 } 631 rtm = (struct rt_msghdr *)buf; 632 if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) { 633 if (errno == EAGAIN || errno == EINTR) 634 return; 635 log_warn("dispatch_rtmsg: read error"); 636 return; 637 } 638 639 if (n == 0) 640 fatal("routing socket closed"); 641 642 if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) { 643 log_warnx("partial rtm of %zd in buffer", n); 644 return; 645 } 646 647 if (rtm->rtm_version != RTM_VERSION) 648 return; 649 650 sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen); 651 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 652 653 handle_route_message(rtm, rti_info); 654 } 655 656 void 657 handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) 658 { 659 struct if_announcemsghdr *ifan; 660 uint32_t if_index; 661 662 switch (rtm->rtm_type) { 663 case RTM_IFINFO: 664 if_index = ((struct if_msghdr *)rtm)->ifm_index; 665 update_iface(if_index); 666 break; 667 case RTM_IFANNOUNCE: 668 ifan = (struct if_announcemsghdr *)rtm; 669 if_index = ifan->ifan_index; 670 if (ifan->ifan_what == IFAN_DEPARTURE) { 671 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 672 &if_index, sizeof(if_index)); 673 remove_iface(if_index); 674 } 675 break; 676 default: 677 log_debug("unexpected RTM: %d", rtm->rtm_type); 678 break; 679 } 680 } 681 682 #define ROUNDUP(a) \ 683 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 684 685 void 686 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 687 { 688 int i; 689 690 for (i = 0; i < RTAX_MAX; i++) { 691 if (addrs & (1 << i)) { 692 rti_info[i] = sa; 693 sa = (struct sockaddr *)((char *)(sa) + 694 ROUNDUP(sa->sa_len)); 695 } else 696 rti_info[i] = NULL; 697 } 698 } 699 700 void 701 udp_receive(int fd, short events, void *arg) 702 { 703 struct imsg_dhcp imsg_dhcp; 704 struct iface *iface; 705 ssize_t len; 706 707 iface = (struct iface *)arg; 708 memset(&imsg_dhcp, 0, sizeof(imsg_dhcp)); 709 710 if ((len = read(fd, imsg_dhcp.packet, 1500)) == -1) { 711 log_warn("%s: read", __func__); 712 return; 713 } 714 715 if (len == 0) 716 fatal("%s len == 0", __func__); 717 718 imsg_dhcp.if_index = iface->ifinfo.if_index; 719 imsg_dhcp.len = len; 720 frontend_imsg_compose_engine(IMSG_DHCP, 0, 0, &imsg_dhcp, 721 sizeof(imsg_dhcp)); 722 } 723 724 void 725 iface_data_from_imsg(struct iface* iface, struct imsg_req_dhcp *imsg) 726 { 727 memcpy(iface->xid, imsg->xid, sizeof(iface->xid)); 728 iface->elapsed_time = imsg->elapsed_time; 729 iface->serverid_len = imsg->serverid_len; 730 memcpy(iface->serverid, imsg->serverid, SERVERID_SIZE); 731 memcpy(iface->pds, imsg->pds, sizeof(iface->pds)); 732 } 733 734 ssize_t 735 build_packet(uint8_t message_type, struct iface *iface, char *if_name) 736 { 737 struct iface_conf *iface_conf; 738 struct iface_ia_conf *ia_conf; 739 struct dhcp_hdr hdr; 740 struct dhcp_option_hdr opt_hdr; 741 struct dhcp_iapd iapd; 742 struct dhcp_iaprefix iaprefix; 743 struct dhcp_vendor_class vendor_class; 744 size_t i; 745 ssize_t len; 746 uint16_t request_option_code, elapsed_time; 747 const uint16_t options[] = {DHO_SOL_MAX_RT, 748 DHO_INF_MAX_RT}; 749 uint8_t *p; 750 751 switch (message_type) { 752 case DHCPSOLICIT: 753 case DHCPREQUEST: 754 case DHCPRENEW: 755 case DHCPREBIND: 756 break; 757 default: 758 fatalx("%s: %s not implemented", __func__, 759 dhcp_message_type2str(message_type)); 760 } 761 762 iface_conf = find_iface_conf(&frontend_conf->iface_list, if_name); 763 764 memset(dhcp_packet, 0, sizeof(dhcp_packet)); 765 766 p = dhcp_packet; 767 hdr.msg_type = message_type; 768 memcpy(hdr.xid, iface->xid, sizeof(hdr.xid)); 769 memcpy(p, &hdr, sizeof(struct dhcp_hdr)); 770 p += sizeof(struct dhcp_hdr); 771 772 opt_hdr.code = htons(DHO_CLIENTID); 773 opt_hdr.len = htons(sizeof(struct dhcp_duid)); 774 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr)); 775 p += sizeof(struct dhcp_option_hdr); 776 memcpy(p, &duid, sizeof(struct dhcp_duid)); 777 p += sizeof(struct dhcp_duid); 778 779 switch (message_type) { 780 case DHCPSOLICIT: 781 case DHCPREBIND: 782 break; 783 case DHCPREQUEST: 784 case DHCPRENEW: 785 opt_hdr.code = htons(DHO_SERVERID); 786 opt_hdr.len = htons(iface->serverid_len); 787 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr)); 788 p += sizeof(struct dhcp_option_hdr); 789 memcpy(p, iface->serverid, iface->serverid_len); 790 p += iface->serverid_len; 791 break; 792 default: 793 fatalx("%s: %s not implemented", __func__, 794 dhcp_message_type2str(message_type)); 795 } 796 SIMPLEQ_FOREACH(ia_conf, &iface_conf->iface_ia_list, entry) { 797 struct prefix *pd; 798 799 opt_hdr.code = htons(DHO_IA_PD); 800 opt_hdr.len = htons(sizeof(struct dhcp_iapd) + 801 sizeof(struct dhcp_option_hdr) + 802 sizeof(struct dhcp_iaprefix)); 803 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr)); 804 p += sizeof(struct dhcp_option_hdr); 805 iapd.iaid = htonl(ia_conf->id); 806 iapd.t1 = 0; 807 iapd.t2 = 0; 808 memcpy(p, &iapd, sizeof(struct dhcp_iapd)); 809 p += sizeof(struct dhcp_iapd); 810 811 opt_hdr.code = htons(DHO_IA_PREFIX); 812 opt_hdr.len = htons(sizeof(struct dhcp_iaprefix)); 813 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr)); 814 p += sizeof(struct dhcp_option_hdr); 815 816 memset(&iaprefix, 0, sizeof(struct dhcp_iaprefix)); 817 818 switch (message_type) { 819 case DHCPSOLICIT: 820 iaprefix.prefix_len = ia_conf->prefix_len; 821 break; 822 case DHCPREQUEST: 823 case DHCPRENEW: 824 case DHCPREBIND: 825 pd = &iface->pds[ia_conf->id]; 826 if (pd->prefix_len > 0) { 827 iaprefix.prefix_len = pd->prefix_len; 828 memcpy(&iaprefix.prefix, &pd->prefix, 829 sizeof(struct in6_addr)); 830 } else 831 iaprefix.prefix_len = ia_conf->prefix_len; 832 break; 833 default: 834 fatalx("%s: %s not implemented", __func__, 835 dhcp_message_type2str(message_type)); 836 } 837 memcpy(p, &iaprefix, sizeof(struct dhcp_iaprefix)); 838 p += sizeof(struct dhcp_iaprefix); 839 } 840 841 opt_hdr.code = htons(DHO_ORO); 842 opt_hdr.len = htons(sizeof(request_option_code) * nitems(options)); 843 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr)); 844 p += sizeof(struct dhcp_option_hdr); 845 for (i = 0; i < nitems(options); i++) { 846 request_option_code = htons(options[i]); 847 memcpy(p, &request_option_code, sizeof(uint16_t)); 848 p += sizeof(uint16_t); 849 } 850 851 opt_hdr.code = htons(DHO_ELAPSED_TIME); 852 opt_hdr.len = htons(2); 853 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr)); 854 p += sizeof(struct dhcp_option_hdr); 855 elapsed_time = htons(iface->elapsed_time); 856 memcpy(p, &elapsed_time, sizeof(uint16_t)); 857 p += sizeof(uint16_t); 858 859 if (message_type == DHCPSOLICIT && frontend_conf->rapid_commit) { 860 opt_hdr.code = htons(DHO_RAPID_COMMIT); 861 opt_hdr.len = htons(0); 862 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr)); 863 p += sizeof(struct dhcp_option_hdr); 864 } 865 866 opt_hdr.code = htons(DHO_VENDOR_CLASS); 867 opt_hdr.len = htons(sizeof(struct dhcp_vendor_class) + 868 vendor_class_len); 869 memcpy(p, &opt_hdr, sizeof(struct dhcp_option_hdr)); 870 p += sizeof(struct dhcp_option_hdr); 871 vendor_class.enterprise_number = htonl(OPENBSD_ENTERPRISENO); 872 vendor_class.vendor_class_len = htons(vendor_class_len); 873 memcpy(p, &vendor_class, sizeof(struct dhcp_vendor_class)); 874 p += sizeof(struct dhcp_vendor_class); 875 /* Not a C-string, leave out \0 */ 876 memcpy(p, vendor_class_data, vendor_class_len); 877 p += vendor_class_len; 878 879 len = p - dhcp_packet; 880 return (len); 881 } 882 883 void 884 send_packet(uint8_t message_type, struct iface *iface) 885 { 886 ssize_t pkt_len; 887 char ifnamebuf[IF_NAMESIZE], *if_name, *message_name; 888 889 if (!event_initialized(&iface->udpev)) { 890 iface->send_solicit = 1; 891 return; 892 } 893 894 iface->send_solicit = 0; 895 896 if ((if_name = if_indextoname(iface->ifinfo.if_index, ifnamebuf)) 897 == NULL) 898 return; /* iface went away, nothing to do */ 899 900 switch (message_type) { 901 case DHCPSOLICIT: 902 message_name = "Soliciting"; 903 break; 904 case DHCPREQUEST: 905 message_name = "Requesting"; 906 break; 907 case DHCPRENEW: 908 message_name = "Renewing"; 909 break; 910 case DHCPREBIND: 911 message_name = "Rebinding"; 912 break; 913 default: 914 message_name = NULL; 915 break; 916 } 917 918 if (message_name) 919 log_info("%s lease on %s", message_name, if_name); 920 921 pkt_len = build_packet(message_type, iface, if_name); 922 923 dst.sin6_scope_id = iface->ifinfo.if_index; 924 925 if (sendto(EVENT_FD(&iface->udpev), dhcp_packet, pkt_len, 0, 926 (struct sockaddr *)&dst, sizeof(dst)) == -1) 927 log_warn("sendto"); 928 } 929 930 struct iface* 931 get_iface_by_id(uint32_t if_index) 932 { 933 struct iface *iface; 934 935 LIST_FOREACH (iface, &interfaces, entries) { 936 if (iface->ifinfo.if_index == if_index) 937 return (iface); 938 } 939 940 return (NULL); 941 } 942 943 struct iface* 944 get_iface_by_name(const char *if_name) 945 { 946 uint32_t ifidx = if_nametoindex(if_name); 947 948 if (ifidx == 0) 949 return (NULL); 950 return get_iface_by_id(ifidx); 951 } 952 953 void 954 remove_iface(uint32_t if_index) 955 { 956 struct iface *iface; 957 958 iface = get_iface_by_id(if_index); 959 960 if (iface == NULL) 961 return; 962 963 LIST_REMOVE(iface, entries); 964 if (event_initialized(&iface->udpev)) { 965 event_del(&iface->udpev); 966 close(EVENT_FD(&iface->udpev)); 967 } 968 free(iface); 969 } 970 971 void 972 set_udpsock(int udpsock, uint32_t if_index) 973 { 974 struct iface *iface; 975 976 iface = get_iface_by_id(if_index); 977 978 if (iface == NULL) { 979 /* 980 * The interface disappeared while we were waiting for the 981 * parent process to open the udp socket. 982 */ 983 close(udpsock); 984 } else if (event_initialized(&iface->udpev)) { 985 /* 986 * XXX 987 * The autoconf flag is flapping and we have multiple udp 988 * sockets in flight. We don't need this one because we already 989 * got one. 990 */ 991 close(udpsock); 992 } else { 993 event_set(&iface->udpev, udpsock, EV_READ | 994 EV_PERSIST, udp_receive, iface); 995 event_add(&iface->udpev, NULL); 996 if (iface->send_solicit) 997 send_packet(DHCPSOLICIT, iface); 998 } 999 } 1000 1001 struct iface_conf* 1002 find_iface_conf(struct iface_conf_head *head, char *if_name) 1003 { 1004 struct iface_conf *iface_conf; 1005 1006 if (if_name == NULL) 1007 return (NULL); 1008 1009 SIMPLEQ_FOREACH(iface_conf, head, entry) { 1010 if (strcmp(iface_conf->name, if_name) == 0) 1011 return iface_conf; 1012 } 1013 return (NULL); 1014 } 1015 1016 int* 1017 changed_ifaces(struct dhcp6leased_conf *oconf, struct dhcp6leased_conf *nconf) 1018 { 1019 struct iface_conf *iface_conf, *oiface_conf; 1020 int *ret, if_index, count = 0, i = 0; 1021 1022 /* 1023 * Worst case: All old interfaces replaced with new interfaces. 1024 * This should still be a small number 1025 */ 1026 SIMPLEQ_FOREACH(iface_conf, &oconf->iface_list, entry) 1027 count++; 1028 SIMPLEQ_FOREACH(iface_conf, &nconf->iface_list, entry) 1029 count++; 1030 1031 ret = calloc(count + 1, sizeof(int)); 1032 1033 SIMPLEQ_FOREACH(iface_conf, &nconf->iface_list, entry) { 1034 if ((if_index = if_nametoindex(iface_conf->name)) == 0) 1035 continue; 1036 oiface_conf = find_iface_conf(&oconf->iface_list, 1037 iface_conf->name); 1038 if (oiface_conf == NULL) { 1039 /* new interface added to config */ 1040 ret[i++] = if_index; 1041 } else if (iface_conf_cmp(iface_conf, oiface_conf) != 0) { 1042 /* interface conf changed */ 1043 ret[i++] = if_index; 1044 } 1045 } 1046 SIMPLEQ_FOREACH(oiface_conf, &oconf->iface_list, entry) { 1047 if ((if_index = if_nametoindex(oiface_conf->name)) == 0) 1048 continue; 1049 if (find_iface_conf(&nconf->iface_list, oiface_conf->name) == 1050 NULL) { 1051 /* interface removed from config */ 1052 ret[i++] = if_index; 1053 } 1054 } 1055 return ret; 1056 } 1057 1058 int 1059 iface_conf_cmp(struct iface_conf *a, struct iface_conf *b) 1060 { 1061 return 0; 1062 } 1063