1*57419a7fSflorian /* $OpenBSD: frontend.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/syslog.h> 26*57419a7fSflorian #include <sys/uio.h> 27*57419a7fSflorian 28*57419a7fSflorian #include <net/bpf.h> 29*57419a7fSflorian #include <net/if.h> 30*57419a7fSflorian #include <net/if_dl.h> 31*57419a7fSflorian #include <net/if_types.h> 32*57419a7fSflorian #include <net/route.h> 33*57419a7fSflorian 34*57419a7fSflorian #include <netinet/ip.h> 35*57419a7fSflorian #include <netinet/udp.h> 36*57419a7fSflorian 37*57419a7fSflorian #include <arpa/inet.h> 38*57419a7fSflorian 39*57419a7fSflorian #include <netinet/in.h> 40*57419a7fSflorian #include <netinet/if_ether.h> 41*57419a7fSflorian 42*57419a7fSflorian #include <errno.h> 43*57419a7fSflorian #include <event.h> 44*57419a7fSflorian #include <ifaddrs.h> 45*57419a7fSflorian #include <imsg.h> 46*57419a7fSflorian #include <pwd.h> 47*57419a7fSflorian #include <signal.h> 48*57419a7fSflorian #include <stdio.h> 49*57419a7fSflorian #include <stdlib.h> 50*57419a7fSflorian #include <string.h> 51*57419a7fSflorian #include <unistd.h> 52*57419a7fSflorian 53*57419a7fSflorian #include "bpf.h" 54*57419a7fSflorian #include "log.h" 55*57419a7fSflorian #include "dhcpleased.h" 56*57419a7fSflorian #include "frontend.h" 57*57419a7fSflorian #include "control.h" 58*57419a7fSflorian #include "checksum.h" 59*57419a7fSflorian 60*57419a7fSflorian #define ROUTE_SOCKET_BUF_SIZE 16384 61*57419a7fSflorian 62*57419a7fSflorian struct bpf_ev { 63*57419a7fSflorian struct event ev; 64*57419a7fSflorian uint8_t buf[BPFLEN]; 65*57419a7fSflorian }; 66*57419a7fSflorian 67*57419a7fSflorian struct iface { 68*57419a7fSflorian LIST_ENTRY(iface) entries; 69*57419a7fSflorian struct bpf_ev bpfev; 70*57419a7fSflorian struct ether_addr hw_address; 71*57419a7fSflorian uint32_t if_index; 72*57419a7fSflorian int rdomain; 73*57419a7fSflorian int send_discover; 74*57419a7fSflorian uint32_t xid; 75*57419a7fSflorian struct in_addr requested_ip; 76*57419a7fSflorian struct in_addr server_identifier; 77*57419a7fSflorian struct in_addr dhcp_server; 78*57419a7fSflorian int udpsock; 79*57419a7fSflorian }; 80*57419a7fSflorian 81*57419a7fSflorian __dead void frontend_shutdown(void); 82*57419a7fSflorian void frontend_sig_handler(int, short, void *); 83*57419a7fSflorian void update_iface(uint32_t, char*); 84*57419a7fSflorian void frontend_startup(void); 85*57419a7fSflorian void route_receive(int, short, void *); 86*57419a7fSflorian void handle_route_message(struct rt_msghdr *, struct sockaddr **); 87*57419a7fSflorian void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 88*57419a7fSflorian void bpf_receive(int, short, void *); 89*57419a7fSflorian int get_flags(char *); 90*57419a7fSflorian int get_xflags(char *); 91*57419a7fSflorian int get_ifrdomain(char *); 92*57419a7fSflorian struct iface *get_iface_by_id(uint32_t); 93*57419a7fSflorian void remove_iface(uint32_t); 94*57419a7fSflorian void set_bpfsock(int, uint32_t); 95*57419a7fSflorian ssize_t build_packet(uint8_t, uint32_t, struct ether_addr *, struct 96*57419a7fSflorian in_addr *, struct in_addr *); 97*57419a7fSflorian void send_discover(struct iface *); 98*57419a7fSflorian void send_request(struct iface *); 99*57419a7fSflorian void bpf_send_packet(struct iface *, uint8_t *, ssize_t); 100*57419a7fSflorian void udp_send_packet(struct iface *, uint8_t *, ssize_t); 101*57419a7fSflorian 102*57419a7fSflorian LIST_HEAD(, iface) interfaces; 103*57419a7fSflorian static struct imsgev *iev_main; 104*57419a7fSflorian static struct imsgev *iev_engine; 105*57419a7fSflorian struct event ev_route; 106*57419a7fSflorian int ioctlsock; 107*57419a7fSflorian 108*57419a7fSflorian uint8_t dhcp_packet[1500]; 109*57419a7fSflorian 110*57419a7fSflorian void 111*57419a7fSflorian frontend_sig_handler(int sig, short event, void *bula) 112*57419a7fSflorian { 113*57419a7fSflorian /* 114*57419a7fSflorian * Normal signal handler rules don't apply because libevent 115*57419a7fSflorian * decouples for us. 116*57419a7fSflorian */ 117*57419a7fSflorian 118*57419a7fSflorian switch (sig) { 119*57419a7fSflorian case SIGINT: 120*57419a7fSflorian case SIGTERM: 121*57419a7fSflorian frontend_shutdown(); 122*57419a7fSflorian default: 123*57419a7fSflorian fatalx("unexpected signal"); 124*57419a7fSflorian } 125*57419a7fSflorian } 126*57419a7fSflorian 127*57419a7fSflorian void 128*57419a7fSflorian frontend(int debug, int verbose) 129*57419a7fSflorian { 130*57419a7fSflorian struct event ev_sigint, ev_sigterm; 131*57419a7fSflorian struct passwd *pw; 132*57419a7fSflorian 133*57419a7fSflorian log_init(debug, LOG_DAEMON); 134*57419a7fSflorian log_setverbose(verbose); 135*57419a7fSflorian 136*57419a7fSflorian if ((pw = getpwnam(DHCPLEASED_USER)) == NULL) 137*57419a7fSflorian fatal("getpwnam"); 138*57419a7fSflorian 139*57419a7fSflorian if (chroot(pw->pw_dir) == -1) 140*57419a7fSflorian fatal("chroot"); 141*57419a7fSflorian if (chdir("/") == -1) 142*57419a7fSflorian fatal("chdir(\"/\")"); 143*57419a7fSflorian 144*57419a7fSflorian setproctitle("%s", "frontend"); 145*57419a7fSflorian log_procinit("frontend"); 146*57419a7fSflorian 147*57419a7fSflorian if ((ioctlsock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1) 148*57419a7fSflorian fatal("socket"); 149*57419a7fSflorian 150*57419a7fSflorian if (setgroups(1, &pw->pw_gid) || 151*57419a7fSflorian setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 152*57419a7fSflorian setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 153*57419a7fSflorian fatal("can't drop privileges"); 154*57419a7fSflorian 155*57419a7fSflorian if (pledge("stdio unix recvfd route", NULL) == -1) 156*57419a7fSflorian fatal("pledge"); 157*57419a7fSflorian event_init(); 158*57419a7fSflorian 159*57419a7fSflorian /* Setup signal handler. */ 160*57419a7fSflorian signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL); 161*57419a7fSflorian signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL); 162*57419a7fSflorian signal_add(&ev_sigint, NULL); 163*57419a7fSflorian signal_add(&ev_sigterm, NULL); 164*57419a7fSflorian signal(SIGPIPE, SIG_IGN); 165*57419a7fSflorian signal(SIGHUP, SIG_IGN); 166*57419a7fSflorian 167*57419a7fSflorian /* Setup pipe and event handler to the parent process. */ 168*57419a7fSflorian if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 169*57419a7fSflorian fatal(NULL); 170*57419a7fSflorian imsg_init(&iev_main->ibuf, 3); 171*57419a7fSflorian iev_main->handler = frontend_dispatch_main; 172*57419a7fSflorian iev_main->events = EV_READ; 173*57419a7fSflorian event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 174*57419a7fSflorian iev_main->handler, iev_main); 175*57419a7fSflorian event_add(&iev_main->ev, NULL); 176*57419a7fSflorian 177*57419a7fSflorian LIST_INIT(&interfaces); 178*57419a7fSflorian event_dispatch(); 179*57419a7fSflorian 180*57419a7fSflorian frontend_shutdown(); 181*57419a7fSflorian } 182*57419a7fSflorian 183*57419a7fSflorian __dead void 184*57419a7fSflorian frontend_shutdown(void) 185*57419a7fSflorian { 186*57419a7fSflorian /* Close pipes. */ 187*57419a7fSflorian msgbuf_write(&iev_engine->ibuf.w); 188*57419a7fSflorian msgbuf_clear(&iev_engine->ibuf.w); 189*57419a7fSflorian close(iev_engine->ibuf.fd); 190*57419a7fSflorian msgbuf_write(&iev_main->ibuf.w); 191*57419a7fSflorian msgbuf_clear(&iev_main->ibuf.w); 192*57419a7fSflorian close(iev_main->ibuf.fd); 193*57419a7fSflorian 194*57419a7fSflorian free(iev_engine); 195*57419a7fSflorian free(iev_main); 196*57419a7fSflorian 197*57419a7fSflorian log_info("frontend exiting"); 198*57419a7fSflorian exit(0); 199*57419a7fSflorian } 200*57419a7fSflorian 201*57419a7fSflorian int 202*57419a7fSflorian frontend_imsg_compose_main(int type, pid_t pid, void *data, 203*57419a7fSflorian uint16_t datalen) 204*57419a7fSflorian { 205*57419a7fSflorian return (imsg_compose_event(iev_main, type, 0, pid, -1, data, 206*57419a7fSflorian datalen)); 207*57419a7fSflorian } 208*57419a7fSflorian 209*57419a7fSflorian int 210*57419a7fSflorian frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid, 211*57419a7fSflorian void *data, uint16_t datalen) 212*57419a7fSflorian { 213*57419a7fSflorian return (imsg_compose_event(iev_engine, type, peerid, pid, -1, 214*57419a7fSflorian data, datalen)); 215*57419a7fSflorian } 216*57419a7fSflorian 217*57419a7fSflorian void 218*57419a7fSflorian frontend_dispatch_main(int fd, short event, void *bula) 219*57419a7fSflorian { 220*57419a7fSflorian struct imsg imsg; 221*57419a7fSflorian struct imsgev *iev = bula; 222*57419a7fSflorian struct imsgbuf *ibuf = &iev->ibuf; 223*57419a7fSflorian struct iface *iface; 224*57419a7fSflorian ssize_t n; 225*57419a7fSflorian int shut = 0, bpfsock, if_index, udpsock; 226*57419a7fSflorian 227*57419a7fSflorian if (event & EV_READ) { 228*57419a7fSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 229*57419a7fSflorian fatal("imsg_read error"); 230*57419a7fSflorian if (n == 0) /* Connection closed. */ 231*57419a7fSflorian shut = 1; 232*57419a7fSflorian } 233*57419a7fSflorian if (event & EV_WRITE) { 234*57419a7fSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 235*57419a7fSflorian fatal("msgbuf_write"); 236*57419a7fSflorian if (n == 0) /* Connection closed. */ 237*57419a7fSflorian shut = 1; 238*57419a7fSflorian } 239*57419a7fSflorian 240*57419a7fSflorian for (;;) { 241*57419a7fSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 242*57419a7fSflorian fatal("%s: imsg_get error", __func__); 243*57419a7fSflorian if (n == 0) /* No more messages. */ 244*57419a7fSflorian break; 245*57419a7fSflorian 246*57419a7fSflorian switch (imsg.hdr.type) { 247*57419a7fSflorian case IMSG_SOCKET_IPC: 248*57419a7fSflorian /* 249*57419a7fSflorian * Setup pipe and event handler to the engine 250*57419a7fSflorian * process. 251*57419a7fSflorian */ 252*57419a7fSflorian if (iev_engine) 253*57419a7fSflorian fatalx("%s: received unexpected imsg fd " 254*57419a7fSflorian "to frontend", __func__); 255*57419a7fSflorian 256*57419a7fSflorian if ((fd = imsg.fd) == -1) 257*57419a7fSflorian fatalx("%s: expected to receive imsg fd to " 258*57419a7fSflorian "frontend but didn't receive any", 259*57419a7fSflorian __func__); 260*57419a7fSflorian 261*57419a7fSflorian iev_engine = malloc(sizeof(struct imsgev)); 262*57419a7fSflorian if (iev_engine == NULL) 263*57419a7fSflorian fatal(NULL); 264*57419a7fSflorian 265*57419a7fSflorian imsg_init(&iev_engine->ibuf, fd); 266*57419a7fSflorian iev_engine->handler = frontend_dispatch_engine; 267*57419a7fSflorian iev_engine->events = EV_READ; 268*57419a7fSflorian 269*57419a7fSflorian event_set(&iev_engine->ev, iev_engine->ibuf.fd, 270*57419a7fSflorian iev_engine->events, iev_engine->handler, iev_engine); 271*57419a7fSflorian event_add(&iev_engine->ev, NULL); 272*57419a7fSflorian break; 273*57419a7fSflorian case IMSG_BPFSOCK: 274*57419a7fSflorian if ((bpfsock = imsg.fd) == -1) 275*57419a7fSflorian fatalx("%s: expected to receive imsg " 276*57419a7fSflorian "bpf fd but didn't receive any", 277*57419a7fSflorian __func__); 278*57419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 279*57419a7fSflorian fatalx("%s: IMSG_BPFSOCK wrong length: " 280*57419a7fSflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 281*57419a7fSflorian memcpy(&if_index, imsg.data, sizeof(if_index)); 282*57419a7fSflorian set_bpfsock(bpfsock, if_index); 283*57419a7fSflorian break; 284*57419a7fSflorian case IMSG_UDPSOCK: 285*57419a7fSflorian if ((udpsock = imsg.fd) == -1) 286*57419a7fSflorian fatalx("%s: expected to receive imsg " 287*57419a7fSflorian "udpsocket fd but didn't receive any", 288*57419a7fSflorian __func__); 289*57419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 290*57419a7fSflorian fatalx("%s: IMSG_UDPSOCK wrong length: " 291*57419a7fSflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 292*57419a7fSflorian memcpy(&if_index, imsg.data, sizeof(if_index)); 293*57419a7fSflorian if ((iface = get_iface_by_id(if_index)) == NULL) { 294*57419a7fSflorian close(fd); 295*57419a7fSflorian break; 296*57419a7fSflorian } 297*57419a7fSflorian if (iface->udpsock != -1) 298*57419a7fSflorian fatalx("%s: received unexpected udpsocket", 299*57419a7fSflorian __func__); 300*57419a7fSflorian iface->udpsock = udpsock; 301*57419a7fSflorian break; 302*57419a7fSflorian case IMSG_CLOSE_UDPSOCK: 303*57419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 304*57419a7fSflorian fatalx("%s: IMSG_UDPSOCK wrong length: " 305*57419a7fSflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 306*57419a7fSflorian memcpy(&if_index, imsg.data, sizeof(if_index)); 307*57419a7fSflorian if ((iface = get_iface_by_id(if_index)) != NULL && 308*57419a7fSflorian iface->udpsock != -1) { 309*57419a7fSflorian close(iface->udpsock); 310*57419a7fSflorian iface->udpsock = -1; 311*57419a7fSflorian } 312*57419a7fSflorian break; 313*57419a7fSflorian case IMSG_ROUTESOCK: 314*57419a7fSflorian if ((fd = imsg.fd) == -1) 315*57419a7fSflorian fatalx("%s: expected to receive imsg " 316*57419a7fSflorian "routesocket fd but didn't receive any", 317*57419a7fSflorian __func__); 318*57419a7fSflorian event_set(&ev_route, fd, EV_READ | EV_PERSIST, 319*57419a7fSflorian route_receive, NULL); 320*57419a7fSflorian break; 321*57419a7fSflorian case IMSG_STARTUP: 322*57419a7fSflorian frontend_startup(); 323*57419a7fSflorian break; 324*57419a7fSflorian #ifndef SMALL 325*57419a7fSflorian case IMSG_CONTROLFD: 326*57419a7fSflorian if ((fd = imsg.fd) == -1) 327*57419a7fSflorian fatalx("%s: expected to receive imsg " 328*57419a7fSflorian "control fd but didn't receive any", 329*57419a7fSflorian __func__); 330*57419a7fSflorian /* Listen on control socket. */ 331*57419a7fSflorian control_listen(fd); 332*57419a7fSflorian break; 333*57419a7fSflorian case IMSG_CTL_END: 334*57419a7fSflorian control_imsg_relay(&imsg); 335*57419a7fSflorian break; 336*57419a7fSflorian #endif /* SMALL */ 337*57419a7fSflorian default: 338*57419a7fSflorian log_debug("%s: error handling imsg %d", __func__, 339*57419a7fSflorian imsg.hdr.type); 340*57419a7fSflorian break; 341*57419a7fSflorian } 342*57419a7fSflorian imsg_free(&imsg); 343*57419a7fSflorian } 344*57419a7fSflorian if (!shut) 345*57419a7fSflorian imsg_event_add(iev); 346*57419a7fSflorian else { 347*57419a7fSflorian /* This pipe is dead. Remove its event handler. */ 348*57419a7fSflorian event_del(&iev->ev); 349*57419a7fSflorian event_loopexit(NULL); 350*57419a7fSflorian } 351*57419a7fSflorian } 352*57419a7fSflorian 353*57419a7fSflorian void 354*57419a7fSflorian frontend_dispatch_engine(int fd, short event, void *bula) 355*57419a7fSflorian { 356*57419a7fSflorian struct imsgev *iev = bula; 357*57419a7fSflorian struct imsgbuf *ibuf = &iev->ibuf; 358*57419a7fSflorian struct imsg imsg; 359*57419a7fSflorian struct iface *iface; 360*57419a7fSflorian ssize_t n; 361*57419a7fSflorian int shut = 0; 362*57419a7fSflorian 363*57419a7fSflorian if (event & EV_READ) { 364*57419a7fSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 365*57419a7fSflorian fatal("imsg_read error"); 366*57419a7fSflorian if (n == 0) /* Connection closed. */ 367*57419a7fSflorian shut = 1; 368*57419a7fSflorian } 369*57419a7fSflorian if (event & EV_WRITE) { 370*57419a7fSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 371*57419a7fSflorian fatal("msgbuf_write"); 372*57419a7fSflorian if (n == 0) /* Connection closed. */ 373*57419a7fSflorian shut = 1; 374*57419a7fSflorian } 375*57419a7fSflorian 376*57419a7fSflorian for (;;) { 377*57419a7fSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 378*57419a7fSflorian fatal("%s: imsg_get error", __func__); 379*57419a7fSflorian if (n == 0) /* No more messages. */ 380*57419a7fSflorian break; 381*57419a7fSflorian 382*57419a7fSflorian switch (imsg.hdr.type) { 383*57419a7fSflorian #ifndef SMALL 384*57419a7fSflorian case IMSG_CTL_END: 385*57419a7fSflorian case IMSG_CTL_SHOW_INTERFACE_INFO: 386*57419a7fSflorian control_imsg_relay(&imsg); 387*57419a7fSflorian break; 388*57419a7fSflorian #endif /* SMALL */ 389*57419a7fSflorian case IMSG_SEND_DISCOVER: { 390*57419a7fSflorian struct imsg_req_discover imsg_req_discover; 391*57419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_discover)) 392*57419a7fSflorian fatalx("%s: IMSG_SEND_DISCOVER wrong " 393*57419a7fSflorian "length: %lu", __func__, 394*57419a7fSflorian IMSG_DATA_SIZE(imsg)); 395*57419a7fSflorian memcpy(&imsg_req_discover, imsg.data, 396*57419a7fSflorian sizeof(imsg_req_discover)); 397*57419a7fSflorian iface = get_iface_by_id(imsg_req_discover.if_index); 398*57419a7fSflorian if (iface != NULL) { 399*57419a7fSflorian iface->xid = imsg_req_discover.xid; 400*57419a7fSflorian send_discover(iface); 401*57419a7fSflorian } 402*57419a7fSflorian break; 403*57419a7fSflorian } 404*57419a7fSflorian case IMSG_SEND_REQUEST: { 405*57419a7fSflorian struct imsg_req_request imsg_req_request; 406*57419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_request)) 407*57419a7fSflorian fatalx("%s: IMSG_SEND_REQUEST wrong " 408*57419a7fSflorian "length: %lu", __func__, 409*57419a7fSflorian IMSG_DATA_SIZE(imsg)); 410*57419a7fSflorian memcpy(&imsg_req_request, imsg.data, 411*57419a7fSflorian sizeof(imsg_req_request)); 412*57419a7fSflorian iface = get_iface_by_id(imsg_req_request.if_index); 413*57419a7fSflorian if (iface != NULL) { 414*57419a7fSflorian iface->xid = imsg_req_request.xid; 415*57419a7fSflorian iface->requested_ip.s_addr = 416*57419a7fSflorian imsg_req_request.requested_ip.s_addr; 417*57419a7fSflorian iface->server_identifier.s_addr = 418*57419a7fSflorian imsg_req_request.server_identifier.s_addr; 419*57419a7fSflorian iface->dhcp_server.s_addr = 420*57419a7fSflorian imsg_req_request.dhcp_server.s_addr; 421*57419a7fSflorian send_request(iface); 422*57419a7fSflorian } 423*57419a7fSflorian break; 424*57419a7fSflorian } 425*57419a7fSflorian default: 426*57419a7fSflorian log_debug("%s: error handling imsg %d", __func__, 427*57419a7fSflorian imsg.hdr.type); 428*57419a7fSflorian break; 429*57419a7fSflorian } 430*57419a7fSflorian imsg_free(&imsg); 431*57419a7fSflorian } 432*57419a7fSflorian if (!shut) 433*57419a7fSflorian imsg_event_add(iev); 434*57419a7fSflorian else { 435*57419a7fSflorian /* This pipe is dead. Remove its event handler. */ 436*57419a7fSflorian event_del(&iev->ev); 437*57419a7fSflorian event_loopexit(NULL); 438*57419a7fSflorian } 439*57419a7fSflorian } 440*57419a7fSflorian 441*57419a7fSflorian int 442*57419a7fSflorian get_flags(char *if_name) 443*57419a7fSflorian { 444*57419a7fSflorian struct ifreq ifr; 445*57419a7fSflorian 446*57419a7fSflorian strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 447*57419a7fSflorian if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) { 448*57419a7fSflorian log_warn("SIOCGIFFLAGS"); 449*57419a7fSflorian return -1; 450*57419a7fSflorian } 451*57419a7fSflorian return ifr.ifr_flags; 452*57419a7fSflorian } 453*57419a7fSflorian 454*57419a7fSflorian int 455*57419a7fSflorian get_xflags(char *if_name) 456*57419a7fSflorian { 457*57419a7fSflorian struct ifreq ifr; 458*57419a7fSflorian 459*57419a7fSflorian strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 460*57419a7fSflorian if (ioctl(ioctlsock, SIOCGIFXFLAGS, (caddr_t)&ifr) == -1) { 461*57419a7fSflorian log_warn("SIOCGIFXFLAGS"); 462*57419a7fSflorian return -1; 463*57419a7fSflorian } 464*57419a7fSflorian return ifr.ifr_flags; 465*57419a7fSflorian } 466*57419a7fSflorian 467*57419a7fSflorian int 468*57419a7fSflorian get_ifrdomain(char *if_name) 469*57419a7fSflorian { 470*57419a7fSflorian struct ifreq ifr; 471*57419a7fSflorian 472*57419a7fSflorian strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 473*57419a7fSflorian if (ioctl(ioctlsock, SIOCGIFRDOMAIN, (caddr_t)&ifr) == -1) { 474*57419a7fSflorian log_warn("SIOCGIFRDOMAIN"); 475*57419a7fSflorian return -1; 476*57419a7fSflorian } 477*57419a7fSflorian return ifr.ifr_rdomainid; 478*57419a7fSflorian } 479*57419a7fSflorian 480*57419a7fSflorian void 481*57419a7fSflorian update_iface(uint32_t if_index, char* if_name) 482*57419a7fSflorian { 483*57419a7fSflorian struct iface *iface; 484*57419a7fSflorian struct imsg_ifinfo imsg_ifinfo; 485*57419a7fSflorian struct ifaddrs *ifap, *ifa; 486*57419a7fSflorian struct sockaddr_dl *sdl; 487*57419a7fSflorian int flags, xflags, ifrdomain; 488*57419a7fSflorian 489*57419a7fSflorian if ((flags = get_flags(if_name)) == -1 || (xflags = 490*57419a7fSflorian get_xflags(if_name)) == -1) 491*57419a7fSflorian return; 492*57419a7fSflorian 493*57419a7fSflorian if (!(xflags & IFXF_AUTOCONF4)) 494*57419a7fSflorian return; 495*57419a7fSflorian 496*57419a7fSflorian if((ifrdomain = get_ifrdomain(if_name)) == -1) 497*57419a7fSflorian return; 498*57419a7fSflorian 499*57419a7fSflorian iface = get_iface_by_id(if_index); 500*57419a7fSflorian 501*57419a7fSflorian if (iface != NULL) { 502*57419a7fSflorian if (iface->rdomain != ifrdomain) { 503*57419a7fSflorian iface->rdomain = ifrdomain; 504*57419a7fSflorian if (iface->udpsock != -1) { 505*57419a7fSflorian close(iface->udpsock); 506*57419a7fSflorian iface->udpsock = -1; 507*57419a7fSflorian } 508*57419a7fSflorian } 509*57419a7fSflorian } else { 510*57419a7fSflorian if ((iface = calloc(1, sizeof(*iface))) == NULL) 511*57419a7fSflorian fatal("calloc"); 512*57419a7fSflorian iface->if_index = if_index; 513*57419a7fSflorian iface->rdomain = ifrdomain; 514*57419a7fSflorian iface->udpsock = -1; 515*57419a7fSflorian LIST_INSERT_HEAD(&interfaces, iface, entries); 516*57419a7fSflorian frontend_imsg_compose_main(IMSG_OPEN_BPFSOCK, 0, 517*57419a7fSflorian &if_index, sizeof(if_index)); 518*57419a7fSflorian } 519*57419a7fSflorian 520*57419a7fSflorian memset(&imsg_ifinfo, 0, sizeof(imsg_ifinfo)); 521*57419a7fSflorian 522*57419a7fSflorian imsg_ifinfo.if_index = if_index; 523*57419a7fSflorian imsg_ifinfo.rdomain = ifrdomain; 524*57419a7fSflorian 525*57419a7fSflorian imsg_ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | 526*57419a7fSflorian IFF_RUNNING); 527*57419a7fSflorian 528*57419a7fSflorian 529*57419a7fSflorian if (getifaddrs(&ifap) != 0) 530*57419a7fSflorian fatal("getifaddrs"); 531*57419a7fSflorian 532*57419a7fSflorian for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 533*57419a7fSflorian if (strcmp(if_name, ifa->ifa_name) != 0) 534*57419a7fSflorian continue; 535*57419a7fSflorian if (ifa->ifa_addr == NULL) 536*57419a7fSflorian continue; 537*57419a7fSflorian 538*57419a7fSflorian switch(ifa->ifa_addr->sa_family) { 539*57419a7fSflorian case AF_LINK: 540*57419a7fSflorian imsg_ifinfo.link_state = 541*57419a7fSflorian ((struct if_data *)ifa->ifa_data)->ifi_link_state; 542*57419a7fSflorian sdl = (struct sockaddr_dl *)ifa->ifa_addr; 543*57419a7fSflorian if (sdl->sdl_type != IFT_ETHER || 544*57419a7fSflorian sdl->sdl_alen != ETHER_ADDR_LEN) 545*57419a7fSflorian continue; 546*57419a7fSflorian memcpy(iface->hw_address.ether_addr_octet, 547*57419a7fSflorian LLADDR(sdl), ETHER_ADDR_LEN); 548*57419a7fSflorian goto out; 549*57419a7fSflorian default: 550*57419a7fSflorian break; 551*57419a7fSflorian } 552*57419a7fSflorian } 553*57419a7fSflorian out: 554*57419a7fSflorian freeifaddrs(ifap); 555*57419a7fSflorian 556*57419a7fSflorian memcpy(&imsg_ifinfo.hw_address, &iface->hw_address, 557*57419a7fSflorian sizeof(imsg_ifinfo.hw_address)); 558*57419a7fSflorian 559*57419a7fSflorian frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &imsg_ifinfo, 560*57419a7fSflorian sizeof(imsg_ifinfo)); 561*57419a7fSflorian } 562*57419a7fSflorian 563*57419a7fSflorian void 564*57419a7fSflorian frontend_startup(void) 565*57419a7fSflorian { 566*57419a7fSflorian struct if_nameindex *ifnidxp, *ifnidx; 567*57419a7fSflorian 568*57419a7fSflorian if (!event_initialized(&ev_route)) 569*57419a7fSflorian fatalx("%s: did not receive a route socket from the main " 570*57419a7fSflorian "process", __func__); 571*57419a7fSflorian 572*57419a7fSflorian event_add(&ev_route, NULL); 573*57419a7fSflorian 574*57419a7fSflorian if ((ifnidxp = if_nameindex()) == NULL) 575*57419a7fSflorian fatalx("if_nameindex"); 576*57419a7fSflorian 577*57419a7fSflorian for(ifnidx = ifnidxp; ifnidx->if_index !=0 && ifnidx->if_name != NULL; 578*57419a7fSflorian ifnidx++) 579*57419a7fSflorian update_iface(ifnidx->if_index, ifnidx->if_name); 580*57419a7fSflorian 581*57419a7fSflorian if_freenameindex(ifnidxp); 582*57419a7fSflorian } 583*57419a7fSflorian 584*57419a7fSflorian void 585*57419a7fSflorian route_receive(int fd, short events, void *arg) 586*57419a7fSflorian { 587*57419a7fSflorian static uint8_t *buf; 588*57419a7fSflorian 589*57419a7fSflorian struct rt_msghdr *rtm; 590*57419a7fSflorian struct sockaddr *sa, *rti_info[RTAX_MAX]; 591*57419a7fSflorian ssize_t n; 592*57419a7fSflorian 593*57419a7fSflorian if (buf == NULL) { 594*57419a7fSflorian buf = malloc(ROUTE_SOCKET_BUF_SIZE); 595*57419a7fSflorian if (buf == NULL) 596*57419a7fSflorian fatal("malloc"); 597*57419a7fSflorian } 598*57419a7fSflorian rtm = (struct rt_msghdr *)buf; 599*57419a7fSflorian if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) { 600*57419a7fSflorian if (errno == EAGAIN || errno == EINTR) 601*57419a7fSflorian return; 602*57419a7fSflorian log_warn("dispatch_rtmsg: read error"); 603*57419a7fSflorian return; 604*57419a7fSflorian } 605*57419a7fSflorian 606*57419a7fSflorian if (n == 0) 607*57419a7fSflorian fatal("routing socket closed"); 608*57419a7fSflorian 609*57419a7fSflorian if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) { 610*57419a7fSflorian log_warnx("partial rtm of %zd in buffer", n); 611*57419a7fSflorian return; 612*57419a7fSflorian } 613*57419a7fSflorian 614*57419a7fSflorian if (rtm->rtm_version != RTM_VERSION) 615*57419a7fSflorian return; 616*57419a7fSflorian 617*57419a7fSflorian sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen); 618*57419a7fSflorian get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 619*57419a7fSflorian 620*57419a7fSflorian handle_route_message(rtm, rti_info); 621*57419a7fSflorian } 622*57419a7fSflorian 623*57419a7fSflorian void 624*57419a7fSflorian handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) 625*57419a7fSflorian { 626*57419a7fSflorian struct if_msghdr *ifm; 627*57419a7fSflorian int xflags, if_index; 628*57419a7fSflorian char ifnamebuf[IFNAMSIZ]; 629*57419a7fSflorian char *if_name; 630*57419a7fSflorian 631*57419a7fSflorian switch (rtm->rtm_type) { 632*57419a7fSflorian case RTM_IFINFO: 633*57419a7fSflorian ifm = (struct if_msghdr *)rtm; 634*57419a7fSflorian if_name = if_indextoname(ifm->ifm_index, ifnamebuf); 635*57419a7fSflorian if (if_name == NULL) { 636*57419a7fSflorian log_debug("RTM_IFINFO: lost if %d", ifm->ifm_index); 637*57419a7fSflorian if_index = ifm->ifm_index; 638*57419a7fSflorian frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 639*57419a7fSflorian &if_index, sizeof(if_index)); 640*57419a7fSflorian remove_iface(if_index); 641*57419a7fSflorian } else { 642*57419a7fSflorian xflags = get_xflags(if_name); 643*57419a7fSflorian if (xflags == -1 || !(xflags & IFXF_AUTOCONF4)) { 644*57419a7fSflorian log_debug("RTM_IFINFO: %s(%d) no(longer) " 645*57419a7fSflorian "autoconf4", if_name, ifm->ifm_index); 646*57419a7fSflorian if_index = ifm->ifm_index; 647*57419a7fSflorian frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 648*57419a7fSflorian 0, &if_index, sizeof(if_index)); 649*57419a7fSflorian } else { 650*57419a7fSflorian update_iface(ifm->ifm_index, if_name); 651*57419a7fSflorian } 652*57419a7fSflorian } 653*57419a7fSflorian break; 654*57419a7fSflorian case RTM_NEWADDR: 655*57419a7fSflorian ifm = (struct if_msghdr *)rtm; 656*57419a7fSflorian if_name = if_indextoname(ifm->ifm_index, ifnamebuf); 657*57419a7fSflorian log_debug("RTM_NEWADDR: %s[%u]", if_name, ifm->ifm_index); 658*57419a7fSflorian update_iface(ifm->ifm_index, if_name); 659*57419a7fSflorian break; 660*57419a7fSflorian case RTM_PROPOSAL: 661*57419a7fSflorian if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) { 662*57419a7fSflorian log_debug("RTP_PROPOSAL_SOLICIT"); 663*57419a7fSflorian frontend_imsg_compose_engine(IMSG_REPROPOSE_RDNS, 664*57419a7fSflorian 0, 0, NULL, 0); 665*57419a7fSflorian } 666*57419a7fSflorian break; 667*57419a7fSflorian default: 668*57419a7fSflorian log_debug("unexpected RTM: %d", rtm->rtm_type); 669*57419a7fSflorian break; 670*57419a7fSflorian } 671*57419a7fSflorian 672*57419a7fSflorian } 673*57419a7fSflorian 674*57419a7fSflorian #define ROUNDUP(a) \ 675*57419a7fSflorian ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 676*57419a7fSflorian 677*57419a7fSflorian void 678*57419a7fSflorian get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 679*57419a7fSflorian { 680*57419a7fSflorian int i; 681*57419a7fSflorian 682*57419a7fSflorian for (i = 0; i < RTAX_MAX; i++) { 683*57419a7fSflorian if (addrs & (1 << i)) { 684*57419a7fSflorian rti_info[i] = sa; 685*57419a7fSflorian sa = (struct sockaddr *)((char *)(sa) + 686*57419a7fSflorian ROUNDUP(sa->sa_len)); 687*57419a7fSflorian } else 688*57419a7fSflorian rti_info[i] = NULL; 689*57419a7fSflorian } 690*57419a7fSflorian } 691*57419a7fSflorian 692*57419a7fSflorian void 693*57419a7fSflorian bpf_receive(int fd, short events, void *arg) 694*57419a7fSflorian { 695*57419a7fSflorian struct bpf_hdr *hdr; 696*57419a7fSflorian struct imsg_dhcp imsg_dhcp; 697*57419a7fSflorian struct iface *iface; 698*57419a7fSflorian ssize_t len, rem; 699*57419a7fSflorian uint8_t *p; 700*57419a7fSflorian 701*57419a7fSflorian iface = (struct iface *)arg; 702*57419a7fSflorian 703*57419a7fSflorian log_debug("%s: fd: %d", __func__, fd); 704*57419a7fSflorian if ((len = read(fd, iface->bpfev.buf, BPFLEN)) == -1) { 705*57419a7fSflorian log_warn("read"); 706*57419a7fSflorian return; 707*57419a7fSflorian } 708*57419a7fSflorian /* XXX len = 0 */ 709*57419a7fSflorian log_debug("%s: %ld", __func__, len); 710*57419a7fSflorian 711*57419a7fSflorian memset(&imsg_dhcp, 0, sizeof(imsg_dhcp)); 712*57419a7fSflorian imsg_dhcp.if_index = iface->if_index; 713*57419a7fSflorian 714*57419a7fSflorian rem = len; 715*57419a7fSflorian p = iface->bpfev.buf; 716*57419a7fSflorian 717*57419a7fSflorian while (rem > 0) { 718*57419a7fSflorian if ((size_t)rem < sizeof(*hdr)) { 719*57419a7fSflorian log_warnx("packet too short"); 720*57419a7fSflorian return; 721*57419a7fSflorian } 722*57419a7fSflorian hdr = (struct bpf_hdr *)p; 723*57419a7fSflorian if (hdr->bh_caplen != hdr->bh_datalen) { 724*57419a7fSflorian log_warnx("skipping truncated packet"); 725*57419a7fSflorian goto cont; 726*57419a7fSflorian } 727*57419a7fSflorian if (rem < hdr->bh_hdrlen + hdr->bh_caplen) 728*57419a7fSflorian /* we are done */ 729*57419a7fSflorian break; 730*57419a7fSflorian if (hdr->bh_caplen > sizeof(imsg_dhcp.packet)) { 731*57419a7fSflorian log_warn("packet too big"); 732*57419a7fSflorian goto cont; 733*57419a7fSflorian } 734*57419a7fSflorian memcpy(&imsg_dhcp.packet, p + hdr->bh_hdrlen, hdr->bh_caplen); 735*57419a7fSflorian imsg_dhcp.len = hdr->bh_caplen; 736*57419a7fSflorian frontend_imsg_compose_engine(IMSG_DHCP, 0, 0, &imsg_dhcp, 737*57419a7fSflorian sizeof(imsg_dhcp)); 738*57419a7fSflorian cont: 739*57419a7fSflorian p += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen); 740*57419a7fSflorian rem -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen); 741*57419a7fSflorian 742*57419a7fSflorian } 743*57419a7fSflorian } 744*57419a7fSflorian 745*57419a7fSflorian ssize_t 746*57419a7fSflorian build_packet(uint8_t message_type, uint32_t xid, struct ether_addr *hw_address, 747*57419a7fSflorian struct in_addr *requested_ip, struct in_addr *server_identifier) 748*57419a7fSflorian { 749*57419a7fSflorian static uint8_t dhcp_cookie[] = DHCP_COOKIE; 750*57419a7fSflorian static uint8_t dhcp_message_type[] = {DHO_DHCP_MESSAGE_TYPE, 1, 751*57419a7fSflorian DHCPDISCOVER}; 752*57419a7fSflorian static uint8_t dhcp_hostname[255] = {DHO_HOST_NAME, 0 /*, ... */}; 753*57419a7fSflorian static uint8_t dhcp_client_id[] = {DHO_DHCP_CLIENT_IDENTIFIER, 7, 754*57419a7fSflorian HTYPE_ETHER, 0, 0, 0, 0, 0, 0}; 755*57419a7fSflorian static uint8_t dhcp_req_list[] = {DHO_DHCP_PARAMETER_REQUEST_LIST, 756*57419a7fSflorian 8, DHO_SUBNET_MASK, DHO_ROUTERS, DHO_DOMAIN_NAME_SERVERS, 757*57419a7fSflorian DHO_HOST_NAME, DHO_DOMAIN_NAME, DHO_BROADCAST_ADDRESS, 758*57419a7fSflorian DHO_DOMAIN_SEARCH, DHO_CLASSLESS_STATIC_ROUTES}; 759*57419a7fSflorian static uint8_t dhcp_requested_address[] = {DHO_DHCP_REQUESTED_ADDRESS, 760*57419a7fSflorian 4, 0, 0, 0, 0}; 761*57419a7fSflorian static uint8_t dhcp_server_identifier[] = {DHO_DHCP_SERVER_IDENTIFIER, 762*57419a7fSflorian 4, 0, 0, 0, 0}; 763*57419a7fSflorian struct dhcp_hdr *hdr; 764*57419a7fSflorian uint8_t *p; 765*57419a7fSflorian char *c; 766*57419a7fSflorian 767*57419a7fSflorian memset(dhcp_packet, 0, sizeof(dhcp_packet)); 768*57419a7fSflorian dhcp_message_type[2] = message_type; 769*57419a7fSflorian p = dhcp_packet; 770*57419a7fSflorian hdr = (struct dhcp_hdr *)p; 771*57419a7fSflorian hdr->op = DHCP_BOOTREQUEST; 772*57419a7fSflorian hdr->htype = HTYPE_ETHER; 773*57419a7fSflorian hdr->hlen = 6; 774*57419a7fSflorian hdr->hops = 0; 775*57419a7fSflorian hdr->xid = xid; 776*57419a7fSflorian hdr->secs = 0; 777*57419a7fSflorian memcpy(hdr->chaddr, hw_address, sizeof(*hw_address)); 778*57419a7fSflorian p += sizeof(struct dhcp_hdr); 779*57419a7fSflorian memcpy(p, dhcp_cookie, sizeof(dhcp_cookie)); 780*57419a7fSflorian p += sizeof(dhcp_cookie); 781*57419a7fSflorian memcpy(p, dhcp_message_type, sizeof(dhcp_message_type)); 782*57419a7fSflorian p += sizeof(dhcp_message_type); 783*57419a7fSflorian if (gethostname(dhcp_hostname + 2, sizeof(dhcp_hostname) - 2) == 0) { 784*57419a7fSflorian if ((c = strchr(dhcp_hostname + 2, '.')) != NULL) 785*57419a7fSflorian *c = '\0'; 786*57419a7fSflorian dhcp_hostname[1] = strlen(dhcp_hostname + 2); 787*57419a7fSflorian memcpy(p, dhcp_hostname, dhcp_hostname[1] + 2); 788*57419a7fSflorian p += dhcp_hostname[1] + 2; 789*57419a7fSflorian } 790*57419a7fSflorian memcpy(dhcp_client_id + 3, hw_address, sizeof(*hw_address)); 791*57419a7fSflorian memcpy(p, dhcp_client_id, sizeof(dhcp_client_id)); 792*57419a7fSflorian p += sizeof(dhcp_client_id); 793*57419a7fSflorian memcpy(p, dhcp_req_list, sizeof(dhcp_req_list)); 794*57419a7fSflorian p += sizeof(dhcp_req_list); 795*57419a7fSflorian 796*57419a7fSflorian if (message_type == DHCPREQUEST) { 797*57419a7fSflorian memcpy(dhcp_requested_address + 2, requested_ip, 798*57419a7fSflorian sizeof(*requested_ip)); 799*57419a7fSflorian memcpy(p, dhcp_requested_address, 800*57419a7fSflorian sizeof(dhcp_requested_address)); 801*57419a7fSflorian p += sizeof(dhcp_requested_address); 802*57419a7fSflorian 803*57419a7fSflorian if (server_identifier->s_addr != INADDR_ANY) { 804*57419a7fSflorian memcpy(dhcp_server_identifier + 2, server_identifier, 805*57419a7fSflorian sizeof(*server_identifier)); 806*57419a7fSflorian memcpy(p, dhcp_server_identifier, 807*57419a7fSflorian sizeof(dhcp_server_identifier)); 808*57419a7fSflorian p += sizeof(dhcp_server_identifier); 809*57419a7fSflorian } 810*57419a7fSflorian } 811*57419a7fSflorian 812*57419a7fSflorian *p = DHO_END; 813*57419a7fSflorian p += 1; 814*57419a7fSflorian 815*57419a7fSflorian return (p - dhcp_packet); 816*57419a7fSflorian } 817*57419a7fSflorian 818*57419a7fSflorian void 819*57419a7fSflorian send_discover(struct iface *iface) 820*57419a7fSflorian { 821*57419a7fSflorian ssize_t pkt_len; 822*57419a7fSflorian 823*57419a7fSflorian if (!event_initialized(&iface->bpfev.ev)) { 824*57419a7fSflorian iface->send_discover = 1; 825*57419a7fSflorian return; 826*57419a7fSflorian } 827*57419a7fSflorian iface->send_discover = 0; 828*57419a7fSflorian log_debug("%s", __func__); 829*57419a7fSflorian pkt_len = build_packet(DHCPDISCOVER, iface->xid, &iface->hw_address, 830*57419a7fSflorian &iface->requested_ip, NULL); 831*57419a7fSflorian log_debug("%s, pkt_len: %ld", __func__, pkt_len); 832*57419a7fSflorian bpf_send_packet(iface, dhcp_packet, pkt_len); 833*57419a7fSflorian } 834*57419a7fSflorian 835*57419a7fSflorian void 836*57419a7fSflorian send_request(struct iface *iface) 837*57419a7fSflorian { 838*57419a7fSflorian ssize_t pkt_len; 839*57419a7fSflorian 840*57419a7fSflorian pkt_len = build_packet(DHCPREQUEST, iface->xid, &iface->hw_address, 841*57419a7fSflorian &iface->requested_ip, &iface->server_identifier); 842*57419a7fSflorian log_debug("%s, pkt_len: %ld", __func__, pkt_len); 843*57419a7fSflorian if (iface->dhcp_server.s_addr != INADDR_ANY) 844*57419a7fSflorian udp_send_packet(iface, dhcp_packet, pkt_len); 845*57419a7fSflorian else 846*57419a7fSflorian bpf_send_packet(iface, dhcp_packet, pkt_len); 847*57419a7fSflorian } 848*57419a7fSflorian 849*57419a7fSflorian void 850*57419a7fSflorian udp_send_packet(struct iface *iface, uint8_t *packet, ssize_t len) 851*57419a7fSflorian { 852*57419a7fSflorian struct sockaddr_in to; 853*57419a7fSflorian 854*57419a7fSflorian log_debug("%s", __func__); 855*57419a7fSflorian memset(&to, 0, sizeof(to)); 856*57419a7fSflorian to.sin_family = AF_INET; 857*57419a7fSflorian to.sin_len = sizeof(to); 858*57419a7fSflorian to.sin_addr.s_addr = iface->dhcp_server.s_addr; 859*57419a7fSflorian to.sin_port = ntohs(SERVER_PORT); 860*57419a7fSflorian 861*57419a7fSflorian if (sendto(iface->udpsock, packet, len, 0, (struct sockaddr *)&to, 862*57419a7fSflorian sizeof(to)) == -1) 863*57419a7fSflorian log_warn("sendto"); 864*57419a7fSflorian } 865*57419a7fSflorian void 866*57419a7fSflorian bpf_send_packet(struct iface *iface, uint8_t *packet, ssize_t len) 867*57419a7fSflorian { 868*57419a7fSflorian struct iovec iov[4]; 869*57419a7fSflorian struct ether_header eh; 870*57419a7fSflorian struct ip ip; 871*57419a7fSflorian struct udphdr udp; 872*57419a7fSflorian ssize_t total, result; 873*57419a7fSflorian int iovcnt = 0, i; 874*57419a7fSflorian 875*57419a7fSflorian memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); 876*57419a7fSflorian memcpy(eh.ether_shost, &iface->hw_address, sizeof(eh.ether_dhost)); 877*57419a7fSflorian eh.ether_type = htons(ETHERTYPE_IP); 878*57419a7fSflorian iov[0].iov_base = &eh; 879*57419a7fSflorian iov[0].iov_len = sizeof(eh); 880*57419a7fSflorian iovcnt++; 881*57419a7fSflorian 882*57419a7fSflorian ip.ip_v = 4; 883*57419a7fSflorian ip.ip_hl = 5; 884*57419a7fSflorian ip.ip_tos = IPTOS_LOWDELAY; 885*57419a7fSflorian ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len); 886*57419a7fSflorian ip.ip_id = 0; 887*57419a7fSflorian ip.ip_off = 0; 888*57419a7fSflorian ip.ip_ttl = 128; 889*57419a7fSflorian ip.ip_p = IPPROTO_UDP; 890*57419a7fSflorian ip.ip_sum = 0; 891*57419a7fSflorian ip.ip_src.s_addr = 0; 892*57419a7fSflorian ip.ip_dst.s_addr = INADDR_BROADCAST; 893*57419a7fSflorian ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0)); 894*57419a7fSflorian iov[iovcnt].iov_base = &ip; 895*57419a7fSflorian iov[iovcnt].iov_len = sizeof(ip); 896*57419a7fSflorian iovcnt++; 897*57419a7fSflorian 898*57419a7fSflorian udp.uh_sport = htons(CLIENT_PORT); 899*57419a7fSflorian udp.uh_dport = htons(SERVER_PORT); 900*57419a7fSflorian udp.uh_ulen = htons(sizeof(udp) + len); 901*57419a7fSflorian udp.uh_sum = 0; 902*57419a7fSflorian udp.uh_sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp), 903*57419a7fSflorian checksum((unsigned char *)packet, len, 904*57419a7fSflorian checksum((unsigned char *)&ip.ip_src, 905*57419a7fSflorian 2 * sizeof(ip.ip_src), 906*57419a7fSflorian IPPROTO_UDP + (uint32_t)ntohs(udp.uh_ulen))))); 907*57419a7fSflorian iov[iovcnt].iov_base = &udp; 908*57419a7fSflorian iov[iovcnt].iov_len = sizeof(udp); 909*57419a7fSflorian iovcnt++; 910*57419a7fSflorian 911*57419a7fSflorian iov[iovcnt].iov_base = packet; 912*57419a7fSflorian iov[iovcnt].iov_len = len; 913*57419a7fSflorian iovcnt++; 914*57419a7fSflorian 915*57419a7fSflorian total = 0; 916*57419a7fSflorian for (i = 0; i < iovcnt; i++) 917*57419a7fSflorian total += iov[i].iov_len; 918*57419a7fSflorian 919*57419a7fSflorian result = writev(EVENT_FD(&iface->bpfev.ev), iov, iovcnt); 920*57419a7fSflorian if (result == -1) 921*57419a7fSflorian log_warn("%s: writev", __func__); 922*57419a7fSflorian else if (result < total) { 923*57419a7fSflorian log_warnx("%s, writev: %zd of %zd bytes", __func__, result, 924*57419a7fSflorian total); 925*57419a7fSflorian } 926*57419a7fSflorian } 927*57419a7fSflorian 928*57419a7fSflorian struct iface* 929*57419a7fSflorian get_iface_by_id(uint32_t if_index) 930*57419a7fSflorian { 931*57419a7fSflorian struct iface *iface; 932*57419a7fSflorian 933*57419a7fSflorian LIST_FOREACH (iface, &interfaces, entries) { 934*57419a7fSflorian if (iface->if_index == if_index) 935*57419a7fSflorian return (iface); 936*57419a7fSflorian } 937*57419a7fSflorian 938*57419a7fSflorian return (NULL); 939*57419a7fSflorian } 940*57419a7fSflorian 941*57419a7fSflorian void 942*57419a7fSflorian remove_iface(uint32_t if_index) 943*57419a7fSflorian { 944*57419a7fSflorian struct iface *iface; 945*57419a7fSflorian 946*57419a7fSflorian iface = get_iface_by_id(if_index); 947*57419a7fSflorian 948*57419a7fSflorian if (iface == NULL) 949*57419a7fSflorian return; 950*57419a7fSflorian 951*57419a7fSflorian LIST_REMOVE(iface, entries); 952*57419a7fSflorian event_del(&iface->bpfev.ev); 953*57419a7fSflorian close(EVENT_FD(&iface->bpfev.ev)); 954*57419a7fSflorian if (iface->udpsock != -1) 955*57419a7fSflorian close(iface->udpsock); 956*57419a7fSflorian free(iface); 957*57419a7fSflorian } 958*57419a7fSflorian 959*57419a7fSflorian void 960*57419a7fSflorian set_bpfsock(int bpfsock, uint32_t if_index) 961*57419a7fSflorian { 962*57419a7fSflorian struct iface *iface; 963*57419a7fSflorian 964*57419a7fSflorian log_debug("%s: %d fd: %d", __func__, if_index, bpfsock); 965*57419a7fSflorian 966*57419a7fSflorian if ((iface = get_iface_by_id(if_index)) == NULL) { 967*57419a7fSflorian /* 968*57419a7fSflorian * The interface disappeared while we were waiting for the 969*57419a7fSflorian * parent process to open the raw socket. 970*57419a7fSflorian */ 971*57419a7fSflorian close(bpfsock); 972*57419a7fSflorian } else { 973*57419a7fSflorian event_set(&iface->bpfev.ev, bpfsock, EV_READ | 974*57419a7fSflorian EV_PERSIST, bpf_receive, iface); 975*57419a7fSflorian event_add(&iface->bpfev.ev, NULL); 976*57419a7fSflorian if (iface->send_discover) 977*57419a7fSflorian send_discover(iface); 978*57419a7fSflorian } 979*57419a7fSflorian } 980