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