1*f1b790a5Sclaudio /* $OpenBSD: control.c,v 1.38 2024/11/21 13:38:14 claudio Exp $ */ 2a1a4e97bSnorby 3a1a4e97bSnorby /* 4a1a4e97bSnorby * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5a1a4e97bSnorby * 6a1a4e97bSnorby * Permission to use, copy, modify, and distribute this software for any 7a1a4e97bSnorby * purpose with or without fee is hereby granted, provided that the above 8a1a4e97bSnorby * copyright notice and this permission notice appear in all copies. 9a1a4e97bSnorby * 10a1a4e97bSnorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11a1a4e97bSnorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12a1a4e97bSnorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13a1a4e97bSnorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14a1a4e97bSnorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15a1a4e97bSnorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16a1a4e97bSnorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17a1a4e97bSnorby */ 18a1a4e97bSnorby 19a1a4e97bSnorby #include <sys/types.h> 20a1a4e97bSnorby #include <sys/stat.h> 21a1a4e97bSnorby #include <sys/socket.h> 22a1a4e97bSnorby #include <sys/un.h> 23a1a4e97bSnorby #include <errno.h> 24a1a4e97bSnorby #include <fcntl.h> 25a1a4e97bSnorby #include <stdlib.h> 26a1a4e97bSnorby #include <string.h> 27a1a4e97bSnorby #include <unistd.h> 28a1a4e97bSnorby 29a1a4e97bSnorby #include "ospf6d.h" 30a1a4e97bSnorby #include "ospf6.h" 31a1a4e97bSnorby #include "ospfe.h" 32a1a4e97bSnorby #include "log.h" 33a1a4e97bSnorby #include "control.h" 34a1a4e97bSnorby 35bf1e0606Sclaudio TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns); 36bf1e0606Sclaudio 37a1a4e97bSnorby #define CONTROL_BACKLOG 5 38a1a4e97bSnorby 39a1a4e97bSnorby struct ctl_conn *control_connbyfd(int); 40a1a4e97bSnorby struct ctl_conn *control_connbypid(pid_t); 41a1a4e97bSnorby void control_close(int); 42a1a4e97bSnorby 43bf1e0606Sclaudio struct { 44bf1e0606Sclaudio struct event ev; 45bf1e0606Sclaudio struct event evt; 46bf1e0606Sclaudio int fd; 47bf1e0606Sclaudio } control_state; 48bf1e0606Sclaudio 49a1a4e97bSnorby int 50cb75d791Sremi control_check(char *path) 51cb75d791Sremi { 52cb75d791Sremi struct sockaddr_un sun; 53cb75d791Sremi int fd; 54cb75d791Sremi 55cb75d791Sremi bzero(&sun, sizeof(sun)); 56cb75d791Sremi sun.sun_family = AF_UNIX; 57cb75d791Sremi strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 58cb75d791Sremi 59cb75d791Sremi if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 60cb75d791Sremi log_warn("control_check: socket check"); 61cb75d791Sremi return (-1); 62cb75d791Sremi } 63cb75d791Sremi 64cb75d791Sremi if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == 0) { 65cb75d791Sremi log_warnx("control_check: socket in use"); 66cb75d791Sremi close(fd); 67cb75d791Sremi return (-1); 68cb75d791Sremi } 69cb75d791Sremi 70cb75d791Sremi close(fd); 71cb75d791Sremi 72cb75d791Sremi return (0); 73cb75d791Sremi } 74cb75d791Sremi 75cb75d791Sremi int 76c2ca8945Ssthen control_init(char *path) 77a1a4e97bSnorby { 78a1a4e97bSnorby struct sockaddr_un sun; 79a1a4e97bSnorby int fd; 80a1a4e97bSnorby mode_t old_umask; 81a1a4e97bSnorby 8235251ca5Sclaudio if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 8335251ca5Sclaudio 0)) == -1) { 84a1a4e97bSnorby log_warn("control_init: socket"); 85a1a4e97bSnorby return (-1); 86a1a4e97bSnorby } 87a1a4e97bSnorby 88a1a4e97bSnorby bzero(&sun, sizeof(sun)); 89a1a4e97bSnorby sun.sun_family = AF_UNIX; 90c2ca8945Ssthen strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 91a1a4e97bSnorby 92c2ca8945Ssthen if (unlink(path) == -1) 93a1a4e97bSnorby if (errno != ENOENT) { 94c2ca8945Ssthen log_warn("control_init: unlink %s", path); 95a1a4e97bSnorby close(fd); 96a1a4e97bSnorby return (-1); 97a1a4e97bSnorby } 98a1a4e97bSnorby 99a1a4e97bSnorby old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 100a1a4e97bSnorby if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 101c2ca8945Ssthen log_warn("control_init: bind: %s", path); 102a1a4e97bSnorby close(fd); 103a1a4e97bSnorby umask(old_umask); 104a1a4e97bSnorby return (-1); 105a1a4e97bSnorby } 106a1a4e97bSnorby umask(old_umask); 107a1a4e97bSnorby 108c2ca8945Ssthen if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { 109a1a4e97bSnorby log_warn("control_init: chmod"); 110a1a4e97bSnorby close(fd); 111c2ca8945Ssthen (void)unlink(path); 112a1a4e97bSnorby return (-1); 113a1a4e97bSnorby } 114a1a4e97bSnorby 115cb75d791Sremi return (fd); 116a1a4e97bSnorby } 117a1a4e97bSnorby 118a1a4e97bSnorby int 119bf1e0606Sclaudio control_listen(int fd) 120a1a4e97bSnorby { 121bf1e0606Sclaudio control_state.fd = fd; 122bf1e0606Sclaudio 123a1a4e97bSnorby if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { 124a1a4e97bSnorby log_warn("control_listen: listen"); 125a1a4e97bSnorby return (-1); 126a1a4e97bSnorby } 127a1a4e97bSnorby 128e215f40dSderaadt event_set(&control_state.ev, control_state.fd, EV_READ, 129a1a4e97bSnorby control_accept, NULL); 130a1a4e97bSnorby event_add(&control_state.ev, NULL); 131e215f40dSderaadt evtimer_set(&control_state.evt, control_accept, NULL); 132a1a4e97bSnorby 133a1a4e97bSnorby return (0); 134a1a4e97bSnorby } 135a1a4e97bSnorby 136a1a4e97bSnorby void 137faef135eSremi control_cleanup(void) 138a1a4e97bSnorby { 139e215f40dSderaadt event_del(&control_state.ev); 140e215f40dSderaadt event_del(&control_state.evt); 141a1a4e97bSnorby } 142a1a4e97bSnorby 143a1a4e97bSnorby void 144a1a4e97bSnorby control_accept(int listenfd, short event, void *bula) 145a1a4e97bSnorby { 146a1a4e97bSnorby int connfd; 147a1a4e97bSnorby socklen_t len; 148a1a4e97bSnorby struct sockaddr_un sun; 149a1a4e97bSnorby struct ctl_conn *c; 150a1a4e97bSnorby 151e215f40dSderaadt event_add(&control_state.ev, NULL); 152e215f40dSderaadt if ((event & EV_TIMEOUT)) 153e215f40dSderaadt return; 154e215f40dSderaadt 155a1a4e97bSnorby len = sizeof(sun); 15635251ca5Sclaudio if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len, 15735251ca5Sclaudio 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"); 170a1a4e97bSnorby return; 171a1a4e97bSnorby } 172a1a4e97bSnorby 17388d8283aSclaudio if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 174a1a4e97bSnorby log_warn("control_accept"); 175ac50b3daShenning close(connfd); 176a1a4e97bSnorby return; 177a1a4e97bSnorby } 178a1a4e97bSnorby 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 } 185f78850efSeric c->iev.handler = control_dispatch_imsg; 186f78850efSeric c->iev.events = EV_READ; 187f78850efSeric event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 188f78850efSeric c->iev.handler, &c->iev); 189f78850efSeric event_add(&c->iev.ev, NULL); 190a1a4e97bSnorby 191a1a4e97bSnorby TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 192a1a4e97bSnorby } 193a1a4e97bSnorby 194a1a4e97bSnorby struct ctl_conn * 195a1a4e97bSnorby control_connbyfd(int fd) 196a1a4e97bSnorby { 197a1a4e97bSnorby struct ctl_conn *c; 198a1a4e97bSnorby 199c39b7208Skrw TAILQ_FOREACH(c, &ctl_conns, entry) { 200c39b7208Skrw if (c->iev.ibuf.fd == fd) 201c39b7208Skrw break; 202c39b7208Skrw } 203a1a4e97bSnorby 204a1a4e97bSnorby return (c); 205a1a4e97bSnorby } 206a1a4e97bSnorby 207a1a4e97bSnorby struct ctl_conn * 208a1a4e97bSnorby control_connbypid(pid_t pid) 209a1a4e97bSnorby { 210a1a4e97bSnorby struct ctl_conn *c; 211a1a4e97bSnorby 212c39b7208Skrw TAILQ_FOREACH(c, &ctl_conns, entry) { 213c39b7208Skrw if (c->iev.ibuf.pid == pid) 214c39b7208Skrw break; 215c39b7208Skrw } 216a1a4e97bSnorby 217a1a4e97bSnorby return (c); 218a1a4e97bSnorby } 219a1a4e97bSnorby 220a1a4e97bSnorby void 221a1a4e97bSnorby control_close(int fd) 222a1a4e97bSnorby { 223a1a4e97bSnorby struct ctl_conn *c; 224a1a4e97bSnorby 225bca0e58eSclaudio if ((c = control_connbyfd(fd)) == NULL) { 226a1a4e97bSnorby log_warn("control_close: fd %d: not found", fd); 227bca0e58eSclaudio return; 228bca0e58eSclaudio } 229a1a4e97bSnorby 2309cbf9e90Sclaudio imsgbuf_clear(&c->iev.ibuf); 231a1a4e97bSnorby TAILQ_REMOVE(&ctl_conns, c, entry); 232a1a4e97bSnorby 233f78850efSeric event_del(&c->iev.ev); 234f78850efSeric 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 242a1a4e97bSnorby free(c); 243a1a4e97bSnorby } 244a1a4e97bSnorby 245a1a4e97bSnorby void 246a1a4e97bSnorby control_dispatch_imsg(int fd, short event, void *bula) 247a1a4e97bSnorby { 248a1a4e97bSnorby struct ctl_conn *c; 249a1a4e97bSnorby struct imsg imsg; 250b529fab9Sdenis ssize_t n; 251a1a4e97bSnorby unsigned int ifidx; 252a97e7964Sclaudio int verbose; 253a1a4e97bSnorby 254a1a4e97bSnorby if ((c = control_connbyfd(fd)) == NULL) { 255a1a4e97bSnorby log_warn("control_dispatch_imsg: fd %d: not found", fd); 256a1a4e97bSnorby return; 257a1a4e97bSnorby } 258a1a4e97bSnorby 25941e7b05eSclaudio if (event & EV_READ) { 260668e5ba9Sclaudio if (imsgbuf_read(&c->iev.ibuf) != 1) { 261a1a4e97bSnorby control_close(fd); 262a1a4e97bSnorby return; 263a1a4e97bSnorby } 26441e7b05eSclaudio } 26541e7b05eSclaudio if (event & EV_WRITE) { 266dd7efffeSclaudio if (imsgbuf_write(&c->iev.ibuf) == -1) { 267a1a4e97bSnorby control_close(fd); 268a1a4e97bSnorby return; 269a1a4e97bSnorby } 270a1a4e97bSnorby } 271a1a4e97bSnorby 272a1a4e97bSnorby for (;;) { 273f78850efSeric if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 274a1a4e97bSnorby control_close(fd); 275a1a4e97bSnorby return; 276a1a4e97bSnorby } 277a1a4e97bSnorby 278a1a4e97bSnorby if (n == 0) 279a1a4e97bSnorby break; 280a1a4e97bSnorby 281a1a4e97bSnorby switch (imsg.hdr.type) { 282a1a4e97bSnorby case IMSG_CTL_FIB_COUPLE: 283a1a4e97bSnorby case IMSG_CTL_FIB_DECOUPLE: 284d7a89a67Sclaudio ospfe_fib_update(imsg.hdr.type); 285a1a4e97bSnorby /* FALLTHROUGH */ 286dd3b9a80Ssthen case IMSG_CTL_FIB_RELOAD: 287a1a4e97bSnorby case IMSG_CTL_RELOAD: 288f78850efSeric c->iev.ibuf.pid = imsg.hdr.pid; 289a1a4e97bSnorby ospfe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0); 290a1a4e97bSnorby break; 291a1a4e97bSnorby case IMSG_CTL_KROUTE: 292a1a4e97bSnorby case IMSG_CTL_KROUTE_ADDR: 293f78850efSeric c->iev.ibuf.pid = imsg.hdr.pid; 294a97e7964Sclaudio ospfe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, 295a97e7964Sclaudio imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 296a1a4e97bSnorby break; 297a1a4e97bSnorby case IMSG_CTL_SHOW_INTERFACE: 298a1a4e97bSnorby if (imsg.hdr.len == IMSG_HEADER_SIZE + 299a1a4e97bSnorby sizeof(ifidx)) { 300a1a4e97bSnorby memcpy(&ifidx, imsg.data, sizeof(ifidx)); 301a1a4e97bSnorby ospfe_iface_ctl(c, ifidx); 302b529fab9Sdenis imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 303f78850efSeric 0, -1, NULL, 0); 304a1a4e97bSnorby } 305a1a4e97bSnorby break; 306a1a4e97bSnorby case IMSG_CTL_SHOW_DATABASE: 307a1a4e97bSnorby case IMSG_CTL_SHOW_DB_EXT: 308d913b22eSclaudio case IMSG_CTL_SHOW_DB_LINK: 309a1a4e97bSnorby case IMSG_CTL_SHOW_DB_NET: 310a1a4e97bSnorby case IMSG_CTL_SHOW_DB_RTR: 311d5dafa54Sstsp case IMSG_CTL_SHOW_DB_INTRA: 312a1a4e97bSnorby case IMSG_CTL_SHOW_DB_SELF: 313a1a4e97bSnorby case IMSG_CTL_SHOW_DB_SUM: 314a1a4e97bSnorby case IMSG_CTL_SHOW_DB_ASBR: 315a1a4e97bSnorby case IMSG_CTL_SHOW_RIB: 316a1a4e97bSnorby case IMSG_CTL_SHOW_SUM: 317f78850efSeric c->iev.ibuf.pid = imsg.hdr.pid; 318a1a4e97bSnorby ospfe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, 319a1a4e97bSnorby imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 320a1a4e97bSnorby break; 321a1a4e97bSnorby case IMSG_CTL_SHOW_NBR: 322a1a4e97bSnorby ospfe_nbr_ctl(c); 323a1a4e97bSnorby break; 324a97e7964Sclaudio case IMSG_CTL_LOG_VERBOSE: 325a97e7964Sclaudio if (imsg.hdr.len != IMSG_HEADER_SIZE + 326a97e7964Sclaudio sizeof(verbose)) 327a97e7964Sclaudio break; 328a97e7964Sclaudio 329307aca1bSjsg /* forward to other processes */ 330a97e7964Sclaudio ospfe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, 331a97e7964Sclaudio imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 332a97e7964Sclaudio ospfe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, 333a97e7964Sclaudio imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 334a97e7964Sclaudio 335a97e7964Sclaudio memcpy(&verbose, imsg.data, sizeof(verbose)); 336189fd1ceSbenno log_setverbose(verbose); 337a97e7964Sclaudio break; 338a1a4e97bSnorby default: 339a1a4e97bSnorby log_debug("control_dispatch_imsg: " 340a1a4e97bSnorby "error handling imsg %d", imsg.hdr.type); 341a1a4e97bSnorby break; 342a1a4e97bSnorby } 343a1a4e97bSnorby imsg_free(&imsg); 344a1a4e97bSnorby } 345a1a4e97bSnorby 346f78850efSeric imsg_event_add(&c->iev); 347a1a4e97bSnorby } 348a1a4e97bSnorby 349a1a4e97bSnorby int 350a1a4e97bSnorby control_imsg_relay(struct imsg *imsg) 351a1a4e97bSnorby { 352a1a4e97bSnorby struct ctl_conn *c; 353a1a4e97bSnorby 354a1a4e97bSnorby if ((c = control_connbypid(imsg->hdr.pid)) == NULL) 355a1a4e97bSnorby return (0); 356a1a4e97bSnorby 357f78850efSeric return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, 358f78850efSeric -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); 359a1a4e97bSnorby } 360