1*f1b790a5Sclaudio /* $OpenBSD: control.c,v 1.34 2024/11/21 13:38:15 claudio Exp $ */ 2ddeeec14Snorby 3ddeeec14Snorby /* 4ddeeec14Snorby * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5ddeeec14Snorby * 6ddeeec14Snorby * Permission to use, copy, modify, and distribute this software for any 7ddeeec14Snorby * purpose with or without fee is hereby granted, provided that the above 8ddeeec14Snorby * copyright notice and this permission notice appear in all copies. 9ddeeec14Snorby * 10ddeeec14Snorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11ddeeec14Snorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12ddeeec14Snorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13ddeeec14Snorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14ddeeec14Snorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15ddeeec14Snorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16ddeeec14Snorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17ddeeec14Snorby */ 18ddeeec14Snorby 19ddeeec14Snorby #include <sys/types.h> 20ddeeec14Snorby #include <sys/stat.h> 21ddeeec14Snorby #include <sys/socket.h> 22ddeeec14Snorby #include <sys/un.h> 23ddeeec14Snorby #include <errno.h> 24ddeeec14Snorby #include <fcntl.h> 25ddeeec14Snorby #include <stdlib.h> 26ddeeec14Snorby #include <string.h> 27ddeeec14Snorby #include <unistd.h> 28ddeeec14Snorby 29ddeeec14Snorby #include "ripd.h" 30ddeeec14Snorby #include "rip.h" 31ddeeec14Snorby #include "ripe.h" 32ddeeec14Snorby #include "log.h" 33ddeeec14Snorby #include "control.h" 34ddeeec14Snorby 357b5b21dbSclaudio TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns); 367b5b21dbSclaudio 37ddeeec14Snorby #define CONTROL_BACKLOG 5 38ddeeec14Snorby 39ddeeec14Snorby struct ctl_conn *control_connbyfd(int); 40ddeeec14Snorby struct ctl_conn *control_connbypid(pid_t); 41ddeeec14Snorby void control_close(int); 42ddeeec14Snorby 437b5b21dbSclaudio struct { 447b5b21dbSclaudio struct event ev; 457b5b21dbSclaudio struct event evt; 467b5b21dbSclaudio int fd; 477b5b21dbSclaudio } control_state; 487b5b21dbSclaudio 49ddeeec14Snorby int 503dabc796Sjca control_init(char *path) 51ddeeec14Snorby { 52ddeeec14Snorby struct sockaddr_un sun; 53ddeeec14Snorby int fd; 54ddeeec14Snorby mode_t old_umask; 55ddeeec14Snorby 5633229c10Sclaudio if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 5733229c10Sclaudio 0)) == -1) { 58ddeeec14Snorby log_warn("control_init: socket"); 59ddeeec14Snorby return (-1); 60ddeeec14Snorby } 61ddeeec14Snorby 62ddeeec14Snorby bzero(&sun, sizeof(sun)); 63ddeeec14Snorby sun.sun_family = AF_UNIX; 643dabc796Sjca strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 65ddeeec14Snorby 663dabc796Sjca if (unlink(path) == -1) 67ddeeec14Snorby if (errno != ENOENT) { 683dabc796Sjca log_warn("control_init: unlink %s", path); 69ddeeec14Snorby close(fd); 70ddeeec14Snorby return (-1); 71ddeeec14Snorby } 72ddeeec14Snorby 73ddeeec14Snorby old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 74ddeeec14Snorby if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 753dabc796Sjca log_warn("control_init: bind: %s", path); 76ddeeec14Snorby close(fd); 77ddeeec14Snorby umask(old_umask); 78ddeeec14Snorby return (-1); 79ddeeec14Snorby } 80ddeeec14Snorby umask(old_umask); 81ddeeec14Snorby 823dabc796Sjca if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { 83ddeeec14Snorby log_warn("control_init: chmod"); 84ddeeec14Snorby close(fd); 853dabc796Sjca (void)unlink(path); 86ddeeec14Snorby return (-1); 87ddeeec14Snorby } 88ddeeec14Snorby 89ddeeec14Snorby control_state.fd = fd; 90ddeeec14Snorby 91ddeeec14Snorby return (0); 92ddeeec14Snorby } 93ddeeec14Snorby 94ddeeec14Snorby int 95ddeeec14Snorby control_listen(void) 96ddeeec14Snorby { 97ddeeec14Snorby if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { 98ddeeec14Snorby log_warn("control_listen: listen"); 99ddeeec14Snorby return (-1); 100ddeeec14Snorby } 101ddeeec14Snorby 102e215f40dSderaadt event_set(&control_state.ev, control_state.fd, EV_READ, 103ddeeec14Snorby control_accept, NULL); 104ddeeec14Snorby event_add(&control_state.ev, NULL); 105e215f40dSderaadt evtimer_set(&control_state.evt, control_accept, NULL); 106ddeeec14Snorby 107ddeeec14Snorby return (0); 108ddeeec14Snorby } 109ddeeec14Snorby 110ddeeec14Snorby void 111ddeeec14Snorby control_accept(int listenfd, short event, void *bula) 112ddeeec14Snorby { 113ddeeec14Snorby int connfd; 114ddeeec14Snorby socklen_t len; 115ddeeec14Snorby struct sockaddr_un sun; 116ddeeec14Snorby struct ctl_conn *c; 117ddeeec14Snorby 118e215f40dSderaadt event_add(&control_state.ev, NULL); 119e215f40dSderaadt if ((event & EV_TIMEOUT)) 120e215f40dSderaadt return; 121e215f40dSderaadt 122ddeeec14Snorby len = sizeof(sun); 12333229c10Sclaudio if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len, 12433229c10Sclaudio SOCK_CLOEXEC | SOCK_NONBLOCK)) == -1) { 125e215f40dSderaadt /* 126e215f40dSderaadt * Pause accept if we are out of file descriptors, or 127e215f40dSderaadt * libevent will haunt us here too. 128e215f40dSderaadt */ 129e215f40dSderaadt if (errno == ENFILE || errno == EMFILE) { 130e215f40dSderaadt struct timeval evtpause = { 1, 0 }; 131e215f40dSderaadt 132e215f40dSderaadt event_del(&control_state.ev); 133e215f40dSderaadt evtimer_add(&control_state.evt, &evtpause); 13462e3c252Sderaadt } else if (errno != EWOULDBLOCK && errno != EINTR && 13562e3c252Sderaadt errno != ECONNABORTED) 136e7464dffSmk log_warn("control_accept: accept"); 137ddeeec14Snorby return; 138ddeeec14Snorby } 139ddeeec14Snorby 14088d8283aSclaudio if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 141ddeeec14Snorby log_warn("control_accept"); 142ac50b3daShenning close(connfd); 143ddeeec14Snorby return; 144ddeeec14Snorby } 145ddeeec14Snorby 146*f1b790a5Sclaudio if (imsgbuf_init(&c->iev.ibuf, connfd) == -1) { 147*f1b790a5Sclaudio log_warn("control_accept"); 148*f1b790a5Sclaudio close(connfd); 149*f1b790a5Sclaudio free(c); 150*f1b790a5Sclaudio return; 151*f1b790a5Sclaudio } 152f7ce36daSeric c->iev.handler = control_dispatch_imsg; 153f7ce36daSeric c->iev.events = EV_READ; 154f7ce36daSeric event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 155f7ce36daSeric c->iev.handler, &c->iev); 156f7ce36daSeric event_add(&c->iev.ev, NULL); 157ddeeec14Snorby 158ddeeec14Snorby TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 159ddeeec14Snorby } 160ddeeec14Snorby 161ddeeec14Snorby struct ctl_conn * 162ddeeec14Snorby control_connbyfd(int fd) 163ddeeec14Snorby { 164ddeeec14Snorby struct ctl_conn *c; 165ddeeec14Snorby 166c39b7208Skrw TAILQ_FOREACH(c, &ctl_conns, entry) { 167c39b7208Skrw if (c->iev.ibuf.fd == fd) 168c39b7208Skrw break; 169c39b7208Skrw } 170ddeeec14Snorby 171ddeeec14Snorby return (c); 172ddeeec14Snorby } 173ddeeec14Snorby 174ddeeec14Snorby struct ctl_conn * 175ddeeec14Snorby control_connbypid(pid_t pid) 176ddeeec14Snorby { 177ddeeec14Snorby struct ctl_conn *c; 178ddeeec14Snorby 179c39b7208Skrw TAILQ_FOREACH(c, &ctl_conns, entry) { 180c39b7208Skrw if (c->iev.ibuf.pid == pid) 181c39b7208Skrw break; 182c39b7208Skrw } 183ddeeec14Snorby 184ddeeec14Snorby return (c); 185ddeeec14Snorby } 186ddeeec14Snorby 187ddeeec14Snorby void 188ddeeec14Snorby control_close(int fd) 189ddeeec14Snorby { 190ddeeec14Snorby struct ctl_conn *c; 191ddeeec14Snorby 192bca0e58eSclaudio if ((c = control_connbyfd(fd)) == NULL) { 193ddeeec14Snorby log_warn("control_close: fd %d: not found", fd); 194bca0e58eSclaudio return; 195bca0e58eSclaudio } 196ddeeec14Snorby 1979cbf9e90Sclaudio imsgbuf_clear(&c->iev.ibuf); 198ddeeec14Snorby TAILQ_REMOVE(&ctl_conns, c, entry); 199ddeeec14Snorby 200f7ce36daSeric event_del(&c->iev.ev); 201f7ce36daSeric close(c->iev.ibuf.fd); 202e215f40dSderaadt 203e215f40dSderaadt /* Some file descriptors are available again. */ 204e215f40dSderaadt if (evtimer_pending(&control_state.evt, NULL)) { 205e215f40dSderaadt evtimer_del(&control_state.evt); 206e215f40dSderaadt event_add(&control_state.ev, NULL); 207e215f40dSderaadt } 208e215f40dSderaadt 209ddeeec14Snorby free(c); 210ddeeec14Snorby } 211ddeeec14Snorby 212ddeeec14Snorby void 213ddeeec14Snorby control_dispatch_imsg(int fd, short event, void *bula) 214ddeeec14Snorby { 215ddeeec14Snorby struct ctl_conn *c; 216ddeeec14Snorby struct imsg imsg; 2174acb39a0Sclaudio ssize_t n; 218ddeeec14Snorby unsigned int ifidx; 219dce97bddSclaudio int verbose; 220ddeeec14Snorby 221ddeeec14Snorby if ((c = control_connbyfd(fd)) == NULL) { 222ddeeec14Snorby log_warn("control_dispatch_imsg: fd %d: not found", fd); 223ddeeec14Snorby return; 224ddeeec14Snorby } 225ddeeec14Snorby 226bd6053efSclaudio if (event & EV_READ) { 227668e5ba9Sclaudio if (imsgbuf_read(&c->iev.ibuf) != 1) { 228ddeeec14Snorby control_close(fd); 229ddeeec14Snorby return; 230ddeeec14Snorby } 231bd6053efSclaudio } 232bd6053efSclaudio if (event & EV_WRITE) { 233dd7efffeSclaudio if (imsgbuf_write(&c->iev.ibuf) == -1) { 234ddeeec14Snorby control_close(fd); 235ddeeec14Snorby return; 236ddeeec14Snorby } 237ddeeec14Snorby } 238ddeeec14Snorby 239ddeeec14Snorby for (;;) { 240f7ce36daSeric if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 241ddeeec14Snorby control_close(fd); 242ddeeec14Snorby return; 243ddeeec14Snorby } 244ddeeec14Snorby 245ddeeec14Snorby if (n == 0) 246ddeeec14Snorby break; 247ddeeec14Snorby 248ddeeec14Snorby switch (imsg.hdr.type) { 249ddeeec14Snorby case IMSG_CTL_SHOW_INTERFACE: 250ddeeec14Snorby if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(ifidx)) 251ddeeec14Snorby return; 252ddeeec14Snorby 253ddeeec14Snorby memcpy(&ifidx, imsg.data, sizeof(ifidx)); 254ddeeec14Snorby ripe_iface_ctl(c, ifidx); 255f7ce36daSeric imsg_compose(&c->iev.ibuf, IMSG_CTL_END, 0, 0, 256f7ce36daSeric -1, NULL, 0); 257ddeeec14Snorby 258ddeeec14Snorby break; 259ddeeec14Snorby case IMSG_CTL_SHOW_RIB: 260f7ce36daSeric c->iev.ibuf.pid = imsg.hdr.pid; 261ddeeec14Snorby ripe_imsg_compose_rde(imsg.hdr.type, 0, 262ddeeec14Snorby imsg.hdr.pid, imsg.data, imsg.hdr.len - 263ddeeec14Snorby IMSG_HEADER_SIZE); 264ddeeec14Snorby break; 265ddeeec14Snorby case IMSG_CTL_SHOW_NBR: 266ddeeec14Snorby ripe_nbr_ctl(c); 267ddeeec14Snorby break; 268ddeeec14Snorby case IMSG_CTL_KROUTE_ADDR: 269ddeeec14Snorby case IMSG_CTL_KROUTE: 270ddeeec14Snorby case IMSG_CTL_IFINFO: 271f7ce36daSeric c->iev.ibuf.pid = imsg.hdr.pid; 272ddeeec14Snorby ripe_imsg_compose_parent(imsg.hdr.type, 273ddeeec14Snorby imsg.hdr.pid, imsg.data, 274ddeeec14Snorby imsg.hdr.len - IMSG_HEADER_SIZE); 275ddeeec14Snorby break; 276ddeeec14Snorby case IMSG_CTL_FIB_COUPLE: 277ddeeec14Snorby case IMSG_CTL_FIB_DECOUPLE: 278ddeeec14Snorby case IMSG_CTL_RELOAD: 279f7ce36daSeric c->iev.ibuf.pid = imsg.hdr.pid; 280ddeeec14Snorby ripe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0); 281ddeeec14Snorby break; 282dce97bddSclaudio case IMSG_CTL_LOG_VERBOSE: 283dce97bddSclaudio if (imsg.hdr.len != IMSG_HEADER_SIZE + 284dce97bddSclaudio sizeof(verbose)) 285dce97bddSclaudio break; 286dce97bddSclaudio 287307aca1bSjsg /* forward to other processes */ 288dce97bddSclaudio ripe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, 289dce97bddSclaudio imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 290dce97bddSclaudio ripe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, 291dce97bddSclaudio imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 292dce97bddSclaudio 293dce97bddSclaudio memcpy(&verbose, imsg.data, sizeof(verbose)); 294dce97bddSclaudio log_verbose(verbose); 295dce97bddSclaudio break; 296ddeeec14Snorby default: 297ddeeec14Snorby log_debug("control_dispatch_imsg: " 298ddeeec14Snorby "error handling imsg %d", imsg.hdr.type); 299ddeeec14Snorby break; 300ddeeec14Snorby } 301ddeeec14Snorby imsg_free(&imsg); 302ddeeec14Snorby } 303ddeeec14Snorby 304f7ce36daSeric imsg_event_add(&c->iev); 305ddeeec14Snorby } 306ddeeec14Snorby 307ddeeec14Snorby int 308ddeeec14Snorby control_imsg_relay(struct imsg *imsg) 309ddeeec14Snorby { 310ddeeec14Snorby struct ctl_conn *c; 311ddeeec14Snorby 312ddeeec14Snorby if ((c = control_connbypid(imsg->hdr.pid)) == NULL) 313ddeeec14Snorby return (0); 314ddeeec14Snorby 315f7ce36daSeric return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, 316f7ce36daSeric -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); 317ddeeec14Snorby } 318