1*f1b790a5Sclaudio /* $OpenBSD: control.c,v 1.38 2024/11/21 13:38:14 claudio Exp $ */ 2ab0c2486Smichele 3ab0c2486Smichele /* 4ab0c2486Smichele * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5ab0c2486Smichele * 6ab0c2486Smichele * Permission to use, copy, modify, and distribute this software for any 7ab0c2486Smichele * purpose with or without fee is hereby granted, provided that the above 8ab0c2486Smichele * copyright notice and this permission notice appear in all copies. 9ab0c2486Smichele * 10ab0c2486Smichele * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11ab0c2486Smichele * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12ab0c2486Smichele * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13ab0c2486Smichele * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14ab0c2486Smichele * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15ab0c2486Smichele * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16ab0c2486Smichele * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17ab0c2486Smichele */ 18ab0c2486Smichele 19ab0c2486Smichele #include <sys/types.h> 20ab0c2486Smichele #include <sys/stat.h> 21ab0c2486Smichele #include <sys/un.h> 22ab0c2486Smichele #include <errno.h> 23ab0c2486Smichele #include <stdlib.h> 24ab0c2486Smichele #include <string.h> 25ab0c2486Smichele #include <unistd.h> 26ab0c2486Smichele 27ab0c2486Smichele #include "ldpd.h" 28ab0c2486Smichele #include "ldpe.h" 29ab0c2486Smichele #include "log.h" 30ab0c2486Smichele #include "control.h" 31ab0c2486Smichele 32d93ca237Sclaudio TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns); 33d93ca237Sclaudio 34ab0c2486Smichele #define CONTROL_BACKLOG 5 35ab0c2486Smichele 36c28a25a1Srenato static void control_accept(int, short, void *); 37c28a25a1Srenato static struct ctl_conn *control_connbyfd(int); 38c28a25a1Srenato static struct ctl_conn *control_connbypid(pid_t); 39c28a25a1Srenato static void control_close(int); 40c28a25a1Srenato static void control_dispatch_imsg(int, short, void *); 41ab0c2486Smichele 42c28a25a1Srenato static int control_fd; 434dda87d0Sclaudio 44ab0c2486Smichele int 45dcaf1165Srenato control_init(char *path) 46ab0c2486Smichele { 47ab0c2486Smichele struct sockaddr_un sun; 48ab0c2486Smichele int fd; 49ab0c2486Smichele mode_t old_umask; 50ab0c2486Smichele 515f3d6e22Sclaudio if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 525f3d6e22Sclaudio 0)) == -1) { 53b7b4db73Srenato log_warn("%s: socket", __func__); 54ab0c2486Smichele return (-1); 55ab0c2486Smichele } 56ab0c2486Smichele 573de94509Srenato memset(&sun, 0, sizeof(sun)); 58ab0c2486Smichele sun.sun_family = AF_UNIX; 59dcaf1165Srenato strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 60ab0c2486Smichele 61dcaf1165Srenato if (unlink(path) == -1) 62ab0c2486Smichele if (errno != ENOENT) { 63dcaf1165Srenato log_warn("%s: unlink %s", __func__, path); 64ab0c2486Smichele close(fd); 65ab0c2486Smichele return (-1); 66ab0c2486Smichele } 67ab0c2486Smichele 68ab0c2486Smichele old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 69ab0c2486Smichele if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 70dcaf1165Srenato log_warn("%s: bind: %s", __func__, path); 71ab0c2486Smichele close(fd); 72ab0c2486Smichele umask(old_umask); 73ab0c2486Smichele return (-1); 74ab0c2486Smichele } 75ab0c2486Smichele umask(old_umask); 76ab0c2486Smichele 77dcaf1165Srenato if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { 78b7b4db73Srenato log_warn("%s: chmod", __func__); 79ab0c2486Smichele close(fd); 80dcaf1165Srenato (void)unlink(path); 81ab0c2486Smichele return (-1); 82ab0c2486Smichele } 83ab0c2486Smichele 844dda87d0Sclaudio control_fd = fd; 85ab0c2486Smichele 86ab0c2486Smichele return (0); 87ab0c2486Smichele } 88ab0c2486Smichele 89ab0c2486Smichele int 90ab0c2486Smichele control_listen(void) 91ab0c2486Smichele { 924dda87d0Sclaudio if (listen(control_fd, CONTROL_BACKLOG) == -1) { 93b7b4db73Srenato log_warn("%s: listen", __func__); 94ab0c2486Smichele return (-1); 95ab0c2486Smichele } 96ab0c2486Smichele 974dda87d0Sclaudio return (accept_add(control_fd, control_accept, NULL)); 98ab0c2486Smichele } 99ab0c2486Smichele 100ab0c2486Smichele void 101b0e92afdSmestre control_cleanup(void) 102ab0c2486Smichele { 1031222b811Srenato accept_del(control_fd); 1041222b811Srenato close(control_fd); 105ab0c2486Smichele } 106ab0c2486Smichele 107c28a25a1Srenato static void 108ab0c2486Smichele control_accept(int listenfd, short event, void *bula) 109ab0c2486Smichele { 110ab0c2486Smichele int connfd; 111ab0c2486Smichele socklen_t len; 112ab0c2486Smichele struct sockaddr_un sun; 113ab0c2486Smichele struct ctl_conn *c; 114ab0c2486Smichele 115ab0c2486Smichele len = sizeof(sun); 1165f3d6e22Sclaudio if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len, 1175f3d6e22Sclaudio SOCK_NONBLOCK | SOCK_CLOEXEC)) == -1) { 1184dda87d0Sclaudio /* 1194dda87d0Sclaudio * Pause accept if we are out of file descriptors, or 1204dda87d0Sclaudio * libevent will haunt us here too. 1214dda87d0Sclaudio */ 1224dda87d0Sclaudio if (errno == ENFILE || errno == EMFILE) 1234dda87d0Sclaudio accept_pause(); 12462e3c252Sderaadt else if (errno != EWOULDBLOCK && errno != EINTR && 12562e3c252Sderaadt errno != ECONNABORTED) 126d99a8fc3Srenato log_warn("%s: accept4", __func__); 127ab0c2486Smichele return; 128ab0c2486Smichele } 129ab0c2486Smichele 13088d8283aSclaudio if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 131b7b4db73Srenato log_warn(__func__); 132ab0c2486Smichele close(connfd); 133ab0c2486Smichele return; 134ab0c2486Smichele } 135ab0c2486Smichele 136*f1b790a5Sclaudio if (imsgbuf_init(&c->iev.ibuf, connfd) == -1) { 137*f1b790a5Sclaudio log_warn(__func__); 138*f1b790a5Sclaudio close(connfd); 139*f1b790a5Sclaudio free(c); 140*f1b790a5Sclaudio return; 141*f1b790a5Sclaudio } 142*f1b790a5Sclaudio 143cb77742aSpyr c->iev.handler = control_dispatch_imsg; 144cb77742aSpyr c->iev.events = EV_READ; 145cb77742aSpyr event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 146cb77742aSpyr c->iev.handler, &c->iev); 147cb77742aSpyr event_add(&c->iev.ev, NULL); 148ab0c2486Smichele 149ab0c2486Smichele TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 150ab0c2486Smichele } 151ab0c2486Smichele 152c28a25a1Srenato static struct ctl_conn * 153ab0c2486Smichele control_connbyfd(int fd) 154ab0c2486Smichele { 155ab0c2486Smichele struct ctl_conn *c; 156ab0c2486Smichele 157c39b7208Skrw TAILQ_FOREACH(c, &ctl_conns, entry) { 158c39b7208Skrw if (c->iev.ibuf.fd == fd) 159c39b7208Skrw break; 160c39b7208Skrw } 161ab0c2486Smichele 162ab0c2486Smichele return (c); 163ab0c2486Smichele } 164ab0c2486Smichele 165c28a25a1Srenato static struct ctl_conn * 166ab0c2486Smichele control_connbypid(pid_t pid) 167ab0c2486Smichele { 168ab0c2486Smichele struct ctl_conn *c; 169ab0c2486Smichele 170c39b7208Skrw TAILQ_FOREACH(c, &ctl_conns, entry) { 171c39b7208Skrw if (c->iev.ibuf.pid == pid) 172c39b7208Skrw break; 173c39b7208Skrw } 174ab0c2486Smichele 175ab0c2486Smichele return (c); 176ab0c2486Smichele } 177ab0c2486Smichele 178c28a25a1Srenato static void 179ab0c2486Smichele control_close(int fd) 180ab0c2486Smichele { 181ab0c2486Smichele struct ctl_conn *c; 182ab0c2486Smichele 183ab0c2486Smichele if ((c = control_connbyfd(fd)) == NULL) { 184d99a8fc3Srenato log_warnx("%s: fd %d: not found", __func__, fd); 185ab0c2486Smichele return; 186ab0c2486Smichele } 187ab0c2486Smichele 1889cbf9e90Sclaudio imsgbuf_clear(&c->iev.ibuf); 189ab0c2486Smichele TAILQ_REMOVE(&ctl_conns, c, entry); 190ab0c2486Smichele 191cb77742aSpyr event_del(&c->iev.ev); 192cb77742aSpyr close(c->iev.ibuf.fd); 1934dda87d0Sclaudio accept_unpause(); 194aac689acSrenato free(c); 195ab0c2486Smichele } 196ab0c2486Smichele 197c28a25a1Srenato static void 198ab0c2486Smichele control_dispatch_imsg(int fd, short event, void *bula) 199ab0c2486Smichele { 200ab0c2486Smichele struct ctl_conn *c; 201ab0c2486Smichele struct imsg imsg; 202c19c627aSrenato ssize_t n; 203ab0c2486Smichele unsigned int ifidx; 2047dc5fe12Sclaudio int verbose; 205ab0c2486Smichele 206ab0c2486Smichele if ((c = control_connbyfd(fd)) == NULL) { 207d99a8fc3Srenato log_warnx("%s: fd %d: not found", __func__, fd); 208ab0c2486Smichele return; 209ab0c2486Smichele } 210ab0c2486Smichele 211ab0c2486Smichele if (event & EV_READ) { 212668e5ba9Sclaudio if (imsgbuf_read(&c->iev.ibuf) != 1) { 213ab0c2486Smichele control_close(fd); 214ab0c2486Smichele return; 215ab0c2486Smichele } 216ab0c2486Smichele } 217ab0c2486Smichele if (event & EV_WRITE) { 218dd7efffeSclaudio if (imsgbuf_write(&c->iev.ibuf) == -1) { 219ab0c2486Smichele control_close(fd); 220ab0c2486Smichele return; 221ab0c2486Smichele } 222ab0c2486Smichele } 223ab0c2486Smichele 224ab0c2486Smichele for (;;) { 225cb77742aSpyr if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 226ab0c2486Smichele control_close(fd); 227ab0c2486Smichele return; 228ab0c2486Smichele } 229ab0c2486Smichele 230ab0c2486Smichele if (n == 0) 231ab0c2486Smichele break; 232ab0c2486Smichele 233ab0c2486Smichele switch (imsg.hdr.type) { 234970465c0Sclaudio case IMSG_CTL_FIB_COUPLE: 235970465c0Sclaudio case IMSG_CTL_FIB_DECOUPLE: 236ab0c2486Smichele case IMSG_CTL_RELOAD: 237cb77742aSpyr c->iev.ibuf.pid = imsg.hdr.pid; 238ab0c2486Smichele ldpe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0); 239ab0c2486Smichele break; 240ab0c2486Smichele case IMSG_CTL_KROUTE: 241ab0c2486Smichele case IMSG_CTL_KROUTE_ADDR: 242ab0c2486Smichele case IMSG_CTL_IFINFO: 243cb77742aSpyr c->iev.ibuf.pid = imsg.hdr.pid; 244ab0c2486Smichele ldpe_imsg_compose_parent(imsg.hdr.type, 245ab0c2486Smichele imsg.hdr.pid, imsg.data, 246ab0c2486Smichele imsg.hdr.len - IMSG_HEADER_SIZE); 247ab0c2486Smichele break; 248ab0c2486Smichele case IMSG_CTL_SHOW_INTERFACE: 249ab0c2486Smichele if (imsg.hdr.len == IMSG_HEADER_SIZE + 250ab0c2486Smichele sizeof(ifidx)) { 251ab0c2486Smichele memcpy(&ifidx, imsg.data, sizeof(ifidx)); 252ab0c2486Smichele ldpe_iface_ctl(c, ifidx); 253cb77742aSpyr imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 254cb77742aSpyr 0, -1, NULL, 0); 255ab0c2486Smichele } 256ab0c2486Smichele break; 25783dcf737Sclaudio case IMSG_CTL_SHOW_DISCOVERY: 25883dcf737Sclaudio ldpe_adj_ctl(c); 25983dcf737Sclaudio break; 260ab0c2486Smichele case IMSG_CTL_SHOW_LIB: 2616399cec1Srenato case IMSG_CTL_SHOW_L2VPN_PW: 2626399cec1Srenato case IMSG_CTL_SHOW_L2VPN_BINDING: 263cb77742aSpyr c->iev.ibuf.pid = imsg.hdr.pid; 264ab0c2486Smichele ldpe_imsg_compose_lde(imsg.hdr.type, 0, imsg.hdr.pid, 265ab0c2486Smichele imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 266ab0c2486Smichele break; 267ab0c2486Smichele case IMSG_CTL_SHOW_NBR: 268ab0c2486Smichele ldpe_nbr_ctl(c); 269ab0c2486Smichele break; 2705c91dd5bSrenato case IMSG_CTL_CLEAR_NBR: 2715c91dd5bSrenato if (imsg.hdr.len != IMSG_HEADER_SIZE + 2725c91dd5bSrenato sizeof(struct ctl_nbr)) 2735c91dd5bSrenato break; 2745c91dd5bSrenato 2755c91dd5bSrenato nbr_clear_ctl(imsg.data); 2765c91dd5bSrenato break; 2777dc5fe12Sclaudio case IMSG_CTL_LOG_VERBOSE: 2787dc5fe12Sclaudio if (imsg.hdr.len != IMSG_HEADER_SIZE + 2797dc5fe12Sclaudio sizeof(verbose)) 2807dc5fe12Sclaudio break; 2817dc5fe12Sclaudio 282307aca1bSjsg /* forward to other processes */ 2837dc5fe12Sclaudio ldpe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, 2847dc5fe12Sclaudio imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 2857dc5fe12Sclaudio ldpe_imsg_compose_lde(imsg.hdr.type, 0, imsg.hdr.pid, 2867dc5fe12Sclaudio imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 2877dc5fe12Sclaudio 2887dc5fe12Sclaudio memcpy(&verbose, imsg.data, sizeof(verbose)); 2897dc5fe12Sclaudio log_verbose(verbose); 2907dc5fe12Sclaudio break; 291ab0c2486Smichele default: 292b7b4db73Srenato log_debug("%s: error handling imsg %d", __func__, 293b7b4db73Srenato imsg.hdr.type); 294ab0c2486Smichele break; 295ab0c2486Smichele } 296ab0c2486Smichele imsg_free(&imsg); 297ab0c2486Smichele } 298ab0c2486Smichele 299cb77742aSpyr imsg_event_add(&c->iev); 300ab0c2486Smichele } 301ab0c2486Smichele 302ab0c2486Smichele int 303ab0c2486Smichele control_imsg_relay(struct imsg *imsg) 304ab0c2486Smichele { 305ab0c2486Smichele struct ctl_conn *c; 306ab0c2486Smichele 307ab0c2486Smichele if ((c = control_connbypid(imsg->hdr.pid)) == NULL) 308ab0c2486Smichele return (0); 309ab0c2486Smichele 310cb77742aSpyr return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, 311cb77742aSpyr -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); 312ab0c2486Smichele } 313