1*f1b790a5Sclaudio /* $OpenBSD: control.c,v 1.54 2024/11/21 13:38:14 claudio Exp $ */ 2204df0f8Sclaudio 3204df0f8Sclaudio /* 4204df0f8Sclaudio * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5204df0f8Sclaudio * 6204df0f8Sclaudio * Permission to use, copy, modify, and distribute this software for any 7204df0f8Sclaudio * purpose with or without fee is hereby granted, provided that the above 8204df0f8Sclaudio * copyright notice and this permission notice appear in all copies. 9204df0f8Sclaudio * 10204df0f8Sclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11204df0f8Sclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12204df0f8Sclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13204df0f8Sclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14204df0f8Sclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15204df0f8Sclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16204df0f8Sclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17204df0f8Sclaudio */ 18204df0f8Sclaudio 19204df0f8Sclaudio #include <sys/types.h> 20204df0f8Sclaudio #include <sys/stat.h> 21204df0f8Sclaudio #include <sys/socket.h> 22204df0f8Sclaudio #include <sys/un.h> 23204df0f8Sclaudio #include <errno.h> 24204df0f8Sclaudio #include <fcntl.h> 25204df0f8Sclaudio #include <stdlib.h> 26204df0f8Sclaudio #include <string.h> 27204df0f8Sclaudio #include <unistd.h> 28204df0f8Sclaudio 29204df0f8Sclaudio #include "ospfd.h" 30204df0f8Sclaudio #include "ospf.h" 31204df0f8Sclaudio #include "ospfe.h" 32204df0f8Sclaudio #include "log.h" 33204df0f8Sclaudio #include "control.h" 34204df0f8Sclaudio 3542082862Sclaudio TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns); 3642082862Sclaudio 37204df0f8Sclaudio #define CONTROL_BACKLOG 5 38204df0f8Sclaudio 39204df0f8Sclaudio struct ctl_conn *control_connbyfd(int); 40204df0f8Sclaudio struct ctl_conn *control_connbypid(pid_t); 41204df0f8Sclaudio void control_close(int); 42204df0f8Sclaudio 4342082862Sclaudio struct { 4442082862Sclaudio struct event ev; 4542082862Sclaudio struct event evt; 4642082862Sclaudio int fd; 4742082862Sclaudio } control_state; 4842082862Sclaudio 49204df0f8Sclaudio int 50617bb465Sremi control_check(char *path) 51617bb465Sremi { 52617bb465Sremi struct sockaddr_un sun; 53617bb465Sremi int fd; 54617bb465Sremi 55617bb465Sremi bzero(&sun, sizeof(sun)); 56617bb465Sremi sun.sun_family = AF_UNIX; 57617bb465Sremi strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 58617bb465Sremi 59617bb465Sremi if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 60617bb465Sremi log_warn("control_check: socket check"); 61617bb465Sremi return (-1); 62617bb465Sremi } 63617bb465Sremi 64617bb465Sremi if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == 0) { 65617bb465Sremi log_warnx("control_check: socket in use"); 66617bb465Sremi close(fd); 67617bb465Sremi return (-1); 68617bb465Sremi } 69617bb465Sremi 70617bb465Sremi close(fd); 71617bb465Sremi 72617bb465Sremi return (0); 73617bb465Sremi } 74617bb465Sremi 75617bb465Sremi int 76d1b94773Sreyk control_init(char *path) 77204df0f8Sclaudio { 78204df0f8Sclaudio struct sockaddr_un sun; 79204df0f8Sclaudio int fd; 80204df0f8Sclaudio mode_t old_umask; 81204df0f8Sclaudio 8258ef7452Sclaudio if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 8358ef7452Sclaudio 0)) == -1) { 84204df0f8Sclaudio log_warn("control_init: socket"); 85204df0f8Sclaudio return (-1); 86204df0f8Sclaudio } 87204df0f8Sclaudio 88204df0f8Sclaudio bzero(&sun, sizeof(sun)); 89204df0f8Sclaudio sun.sun_family = AF_UNIX; 90d1b94773Sreyk strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 91204df0f8Sclaudio 92d1b94773Sreyk if (unlink(path) == -1) 93204df0f8Sclaudio if (errno != ENOENT) { 94d1b94773Sreyk log_warn("control_init: unlink %s", path); 95204df0f8Sclaudio close(fd); 96204df0f8Sclaudio return (-1); 97204df0f8Sclaudio } 98204df0f8Sclaudio 99126a8a1bSderaadt old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 100204df0f8Sclaudio if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 101d1b94773Sreyk log_warn("control_init: bind: %s", path); 102204df0f8Sclaudio close(fd); 103126a8a1bSderaadt umask(old_umask); 104204df0f8Sclaudio return (-1); 105204df0f8Sclaudio } 106126a8a1bSderaadt umask(old_umask); 107204df0f8Sclaudio 108d1b94773Sreyk if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { 109204df0f8Sclaudio log_warn("control_init: chmod"); 110204df0f8Sclaudio close(fd); 111d1b94773Sreyk (void)unlink(path); 112204df0f8Sclaudio return (-1); 113204df0f8Sclaudio } 114204df0f8Sclaudio 115617bb465Sremi return (fd); 116204df0f8Sclaudio } 117204df0f8Sclaudio 118204df0f8Sclaudio int 11942082862Sclaudio control_listen(int fd) 120204df0f8Sclaudio { 12142082862Sclaudio control_state.fd = fd; 122204df0f8Sclaudio 123204df0f8Sclaudio if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { 124204df0f8Sclaudio log_warn("control_listen: listen"); 125204df0f8Sclaudio return (-1); 126204df0f8Sclaudio } 127204df0f8Sclaudio 128e215f40dSderaadt event_set(&control_state.ev, control_state.fd, EV_READ, 129204df0f8Sclaudio control_accept, NULL); 130204df0f8Sclaudio event_add(&control_state.ev, NULL); 131e215f40dSderaadt evtimer_set(&control_state.evt, control_accept, NULL); 132204df0f8Sclaudio 133204df0f8Sclaudio return (0); 134204df0f8Sclaudio } 135204df0f8Sclaudio 136204df0f8Sclaudio void 137faef135eSremi control_cleanup(void) 138204df0f8Sclaudio { 139e215f40dSderaadt event_del(&control_state.ev); 140e215f40dSderaadt event_del(&control_state.evt); 141204df0f8Sclaudio } 142204df0f8Sclaudio 143204df0f8Sclaudio void 144204df0f8Sclaudio control_accept(int listenfd, short event, void *bula) 145204df0f8Sclaudio { 146204df0f8Sclaudio int connfd; 147204df0f8Sclaudio socklen_t len; 148204df0f8Sclaudio struct sockaddr_un sun; 149204df0f8Sclaudio struct ctl_conn *c; 150204df0f8Sclaudio 151e215f40dSderaadt event_add(&control_state.ev, NULL); 152e215f40dSderaadt if ((event & EV_TIMEOUT)) 153e215f40dSderaadt return; 154e215f40dSderaadt 155204df0f8Sclaudio len = sizeof(sun); 15658ef7452Sclaudio if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len, 15758ef7452Sclaudio SOCK_CLOEXEC | SOCK_NONBLOCK)) == -1) { 158e215f40dSderaadt /* 159e215f40dSderaadt * Pause accept if we are out of file descriptors, or 160e215f40dSderaadt * libevent will haunt us here too. 161e215f40dSderaadt */ 162e215f40dSderaadt if (errno == ENFILE || errno == EMFILE) { 163e215f40dSderaadt struct timeval evtpause = { 1, 0 }; 164e215f40dSderaadt 165e215f40dSderaadt event_del(&control_state.ev); 166e215f40dSderaadt evtimer_add(&control_state.evt, &evtpause); 16762e3c252Sderaadt } else if (errno != EWOULDBLOCK && errno != EINTR && 16862e3c252Sderaadt errno != ECONNABORTED) 169e7464dffSmk log_warn("control_accept: accept"); 170204df0f8Sclaudio return; 171204df0f8Sclaudio } 172204df0f8Sclaudio 17388d8283aSclaudio if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 174204df0f8Sclaudio log_warn("control_accept"); 175ac50b3daShenning close(connfd); 176204df0f8Sclaudio return; 177204df0f8Sclaudio } 178204df0f8Sclaudio 179*f1b790a5Sclaudio if (imsgbuf_init(&c->iev.ibuf, connfd) == -1) { 180*f1b790a5Sclaudio log_warn("imsgbuf_init"); 181*f1b790a5Sclaudio close(connfd); 182*f1b790a5Sclaudio free(c); 183*f1b790a5Sclaudio return; 184*f1b790a5Sclaudio } 1857b4c0c10Seric c->iev.handler = control_dispatch_imsg; 1867b4c0c10Seric c->iev.events = EV_READ; 1877b4c0c10Seric event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 1887b4c0c10Seric c->iev.handler, &c->iev); 1897b4c0c10Seric event_add(&c->iev.ev, NULL); 190204df0f8Sclaudio 191204df0f8Sclaudio TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 192204df0f8Sclaudio } 193204df0f8Sclaudio 194204df0f8Sclaudio struct ctl_conn * 195204df0f8Sclaudio control_connbyfd(int fd) 196204df0f8Sclaudio { 197204df0f8Sclaudio struct ctl_conn *c; 198204df0f8Sclaudio 199c39b7208Skrw TAILQ_FOREACH(c, &ctl_conns, entry) { 200c39b7208Skrw if (c->iev.ibuf.fd == fd) 201c39b7208Skrw break; 202c39b7208Skrw } 203204df0f8Sclaudio 204204df0f8Sclaudio return (c); 205204df0f8Sclaudio } 206204df0f8Sclaudio 207204df0f8Sclaudio struct ctl_conn * 208204df0f8Sclaudio control_connbypid(pid_t pid) 209204df0f8Sclaudio { 210204df0f8Sclaudio struct ctl_conn *c; 211204df0f8Sclaudio 212c39b7208Skrw TAILQ_FOREACH(c, &ctl_conns, entry) { 213c39b7208Skrw if (c->iev.ibuf.pid == pid) 214c39b7208Skrw break; 215c39b7208Skrw } 216204df0f8Sclaudio 217204df0f8Sclaudio return (c); 218204df0f8Sclaudio } 219204df0f8Sclaudio 220204df0f8Sclaudio void 221204df0f8Sclaudio control_close(int fd) 222204df0f8Sclaudio { 223204df0f8Sclaudio struct ctl_conn *c; 224204df0f8Sclaudio 225bca0e58eSclaudio if ((c = control_connbyfd(fd)) == NULL) { 226204df0f8Sclaudio log_warn("control_close: fd %d: not found", fd); 227bca0e58eSclaudio return; 228bca0e58eSclaudio } 229204df0f8Sclaudio 2309cbf9e90Sclaudio imsgbuf_clear(&c->iev.ibuf); 231204df0f8Sclaudio TAILQ_REMOVE(&ctl_conns, c, entry); 232204df0f8Sclaudio 2337b4c0c10Seric event_del(&c->iev.ev); 2347b4c0c10Seric close(c->iev.ibuf.fd); 235e215f40dSderaadt 236e215f40dSderaadt /* Some file descriptors are available again. */ 237e215f40dSderaadt if (evtimer_pending(&control_state.evt, NULL)) { 238e215f40dSderaadt evtimer_del(&control_state.evt); 239e215f40dSderaadt event_add(&control_state.ev, NULL); 240e215f40dSderaadt } 241e215f40dSderaadt 242204df0f8Sclaudio free(c); 243204df0f8Sclaudio } 244204df0f8Sclaudio 245204df0f8Sclaudio void 246204df0f8Sclaudio control_dispatch_imsg(int fd, short event, void *bula) 247204df0f8Sclaudio { 248204df0f8Sclaudio struct ctl_conn *c; 249204df0f8Sclaudio struct imsg imsg; 250c57f8da1Sclaudio ssize_t n; 251204df0f8Sclaudio unsigned int ifidx; 252636d06c3Sclaudio int verbose; 253204df0f8Sclaudio 254204df0f8Sclaudio if ((c = control_connbyfd(fd)) == NULL) { 255204df0f8Sclaudio log_warn("control_dispatch_imsg: fd %d: not found", fd); 256204df0f8Sclaudio return; 257204df0f8Sclaudio } 258204df0f8Sclaudio 259b202c6d3Sclaudio if (event & EV_READ) { 260668e5ba9Sclaudio if (imsgbuf_read(&c->iev.ibuf) != 1) { 261204df0f8Sclaudio control_close(fd); 262204df0f8Sclaudio return; 263204df0f8Sclaudio } 264b202c6d3Sclaudio } 265b202c6d3Sclaudio if (event & EV_WRITE) { 266dd7efffeSclaudio if (imsgbuf_write(&c->iev.ibuf) == -1) { 267204df0f8Sclaudio control_close(fd); 268204df0f8Sclaudio return; 269204df0f8Sclaudio } 270204df0f8Sclaudio } 271204df0f8Sclaudio 272204df0f8Sclaudio for (;;) { 2737b4c0c10Seric if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 274204df0f8Sclaudio control_close(fd); 275204df0f8Sclaudio return; 276204df0f8Sclaudio } 277204df0f8Sclaudio 278204df0f8Sclaudio if (n == 0) 279204df0f8Sclaudio break; 280204df0f8Sclaudio 281204df0f8Sclaudio switch (imsg.hdr.type) { 282204df0f8Sclaudio case IMSG_CTL_FIB_COUPLE: 283204df0f8Sclaudio case IMSG_CTL_FIB_DECOUPLE: 284faec9e2bSclaudio ospfe_fib_update(imsg.hdr.type); 2851891964aSclaudio /* FALLTHROUGH */ 286119f0f1dSdlg case IMSG_CTL_FIB_RELOAD: 287204df0f8Sclaudio case IMSG_CTL_RELOAD: 2887b4c0c10Seric c->iev.ibuf.pid = imsg.hdr.pid; 289204df0f8Sclaudio ospfe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0); 290204df0f8Sclaudio break; 291b6b3a59aSclaudio case IMSG_CTL_KROUTE: 292b6b3a59aSclaudio case IMSG_CTL_KROUTE_ADDR: 29370955e50Sclaudio case IMSG_CTL_IFINFO: 2947b4c0c10Seric c->iev.ibuf.pid = imsg.hdr.pid; 295636d06c3Sclaudio ospfe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, 296636d06c3Sclaudio imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 297b6b3a59aSclaudio break; 298204df0f8Sclaudio case IMSG_CTL_SHOW_INTERFACE: 299204df0f8Sclaudio if (imsg.hdr.len == IMSG_HEADER_SIZE + 300204df0f8Sclaudio sizeof(ifidx)) { 301204df0f8Sclaudio memcpy(&ifidx, imsg.data, sizeof(ifidx)); 302204df0f8Sclaudio ospfe_iface_ctl(c, ifidx); 3037b4c0c10Seric imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 304d13e54e1Spyr 0, -1, NULL, 0); 305204df0f8Sclaudio } 306204df0f8Sclaudio break; 307204df0f8Sclaudio case IMSG_CTL_SHOW_DATABASE: 30832286112Snorby case IMSG_CTL_SHOW_DB_EXT: 30932286112Snorby case IMSG_CTL_SHOW_DB_NET: 31032286112Snorby case IMSG_CTL_SHOW_DB_RTR: 31132286112Snorby case IMSG_CTL_SHOW_DB_SELF: 31232286112Snorby case IMSG_CTL_SHOW_DB_SUM: 31332286112Snorby case IMSG_CTL_SHOW_DB_ASBR: 314097ed198Sclaudio case IMSG_CTL_SHOW_DB_OPAQ: 315e01828d0Sclaudio case IMSG_CTL_SHOW_RIB: 316e01828d0Sclaudio case IMSG_CTL_SHOW_SUM: 3177b4c0c10Seric c->iev.ibuf.pid = imsg.hdr.pid; 318204df0f8Sclaudio ospfe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, 319204df0f8Sclaudio imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 320204df0f8Sclaudio break; 321204df0f8Sclaudio case IMSG_CTL_SHOW_NBR: 322204df0f8Sclaudio ospfe_nbr_ctl(c); 323204df0f8Sclaudio break; 324636d06c3Sclaudio case IMSG_CTL_LOG_VERBOSE: 325636d06c3Sclaudio if (imsg.hdr.len != IMSG_HEADER_SIZE + 326636d06c3Sclaudio sizeof(verbose)) 327636d06c3Sclaudio break; 328636d06c3Sclaudio 329307aca1bSjsg /* forward to other processes */ 330636d06c3Sclaudio ospfe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, 331636d06c3Sclaudio imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 332636d06c3Sclaudio ospfe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, 333636d06c3Sclaudio imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 334636d06c3Sclaudio 335636d06c3Sclaudio memcpy(&verbose, imsg.data, sizeof(verbose)); 336f2e37bc3Sbenno log_setverbose(verbose); 337636d06c3Sclaudio break; 338204df0f8Sclaudio default: 339204df0f8Sclaudio log_debug("control_dispatch_imsg: " 340204df0f8Sclaudio "error handling imsg %d", imsg.hdr.type); 341204df0f8Sclaudio break; 342204df0f8Sclaudio } 343204df0f8Sclaudio imsg_free(&imsg); 344204df0f8Sclaudio } 345204df0f8Sclaudio 3467b4c0c10Seric imsg_event_add(&c->iev); 347204df0f8Sclaudio } 348204df0f8Sclaudio 349204df0f8Sclaudio int 350204df0f8Sclaudio control_imsg_relay(struct imsg *imsg) 351204df0f8Sclaudio { 352204df0f8Sclaudio struct ctl_conn *c; 353204df0f8Sclaudio 3545f5d6e64Sclaudio if ((c = control_connbypid(imsg->hdr.pid)) == NULL) 355204df0f8Sclaudio return (0); 356204df0f8Sclaudio 3577b4c0c10Seric return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, 358d13e54e1Spyr -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); 359204df0f8Sclaudio } 360