1*f1b790a5Sclaudio /* $OpenBSD: control.c,v 1.16 2024/11/21 13:38:14 claudio Exp $ */ 243509a12Srenato 343509a12Srenato /* 443509a12Srenato * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 543509a12Srenato * 643509a12Srenato * Permission to use, copy, modify, and distribute this software for any 743509a12Srenato * purpose with or without fee is hereby granted, provided that the above 843509a12Srenato * copyright notice and this permission notice appear in all copies. 943509a12Srenato * 1043509a12Srenato * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1143509a12Srenato * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1243509a12Srenato * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1343509a12Srenato * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1443509a12Srenato * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1543509a12Srenato * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1643509a12Srenato * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1743509a12Srenato */ 1843509a12Srenato 1943509a12Srenato #include <sys/types.h> 2043509a12Srenato #include <sys/stat.h> 2143509a12Srenato #include <sys/un.h> 228072de9bSrenato 2343509a12Srenato #include <errno.h> 2443509a12Srenato #include <stdlib.h> 2543509a12Srenato #include <string.h> 2643509a12Srenato #include <unistd.h> 2743509a12Srenato 2843509a12Srenato #include "eigrpd.h" 2943509a12Srenato #include "eigrpe.h" 3043509a12Srenato #include "control.h" 318072de9bSrenato #include "log.h" 3243509a12Srenato 339cf002a5Sclaudio TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns); 349cf002a5Sclaudio 3543509a12Srenato #define CONTROL_BACKLOG 5 3643509a12Srenato 37ab786365Srenato static void control_accept(int, short, void *); 38ab786365Srenato static struct ctl_conn *control_connbyfd(int); 39ab786365Srenato static struct ctl_conn *control_connbypid(pid_t); 40ab786365Srenato static void control_close(int); 41ab786365Srenato static void control_dispatch_imsg(int, short, void *); 4243509a12Srenato 439cf002a5Sclaudio struct { 449cf002a5Sclaudio struct event ev; 459cf002a5Sclaudio struct event evt; 469cf002a5Sclaudio int fd; 479cf002a5Sclaudio } control_state; 489cf002a5Sclaudio 499cf002a5Sclaudio 5043509a12Srenato int 5143509a12Srenato control_init(char *path) 5243509a12Srenato { 5343509a12Srenato struct sockaddr_un sun; 5443509a12Srenato int fd; 5543509a12Srenato mode_t old_umask; 5643509a12Srenato 5743509a12Srenato if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 5843509a12Srenato 0)) == -1) { 5943509a12Srenato log_warn("%s: socket", __func__); 6043509a12Srenato return (-1); 6143509a12Srenato } 6243509a12Srenato 6343509a12Srenato memset(&sun, 0, sizeof(sun)); 6443509a12Srenato sun.sun_family = AF_UNIX; 6543509a12Srenato strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 6643509a12Srenato 6743509a12Srenato if (unlink(path) == -1) 6843509a12Srenato if (errno != ENOENT) { 6943509a12Srenato log_warn("%s: unlink %s", __func__, path); 7043509a12Srenato close(fd); 7143509a12Srenato return (-1); 7243509a12Srenato } 7343509a12Srenato 7443509a12Srenato old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 7543509a12Srenato if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 7643509a12Srenato log_warn("%s: bind: %s", __func__, path); 7743509a12Srenato close(fd); 7843509a12Srenato umask(old_umask); 7943509a12Srenato return (-1); 8043509a12Srenato } 8143509a12Srenato umask(old_umask); 8243509a12Srenato 8343509a12Srenato if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { 8443509a12Srenato log_warn("%s: chmod", __func__); 8543509a12Srenato close(fd); 8643509a12Srenato (void)unlink(path); 8743509a12Srenato return (-1); 8843509a12Srenato } 8943509a12Srenato 9043509a12Srenato control_state.fd = fd; 9143509a12Srenato 9243509a12Srenato return (0); 9343509a12Srenato } 9443509a12Srenato 9543509a12Srenato int 9643509a12Srenato control_listen(void) 9743509a12Srenato { 9843509a12Srenato if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { 9943509a12Srenato log_warn("%s: listen", __func__); 10043509a12Srenato return (-1); 10143509a12Srenato } 10243509a12Srenato 10343509a12Srenato event_set(&control_state.ev, control_state.fd, EV_READ, 10443509a12Srenato control_accept, NULL); 10543509a12Srenato event_add(&control_state.ev, NULL); 10643509a12Srenato evtimer_set(&control_state.evt, control_accept, NULL); 10743509a12Srenato 10843509a12Srenato return (0); 10943509a12Srenato } 11043509a12Srenato 111ab786365Srenato static void 11243509a12Srenato control_accept(int listenfd, short event, void *bula) 11343509a12Srenato { 11443509a12Srenato int connfd; 11543509a12Srenato socklen_t len; 11643509a12Srenato struct sockaddr_un sun; 11743509a12Srenato struct ctl_conn *c; 11843509a12Srenato 11943509a12Srenato event_add(&control_state.ev, NULL); 12043509a12Srenato if ((event & EV_TIMEOUT)) 12143509a12Srenato return; 12243509a12Srenato 12343509a12Srenato len = sizeof(sun); 12443509a12Srenato if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len, 12543509a12Srenato SOCK_CLOEXEC | SOCK_NONBLOCK)) == -1) { 12643509a12Srenato /* 12743509a12Srenato * Pause accept if we are out of file descriptors, or 12843509a12Srenato * libevent will haunt us here too. 12943509a12Srenato */ 13043509a12Srenato if (errno == ENFILE || errno == EMFILE) { 13143509a12Srenato struct timeval evtpause = { 1, 0 }; 13243509a12Srenato 13343509a12Srenato event_del(&control_state.ev); 13443509a12Srenato evtimer_add(&control_state.evt, &evtpause); 13543509a12Srenato } else if (errno != EWOULDBLOCK && errno != EINTR && 13643509a12Srenato errno != ECONNABORTED) 13743509a12Srenato log_warn("%s: accept4", __func__); 13843509a12Srenato return; 13943509a12Srenato } 14043509a12Srenato 14143509a12Srenato if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 14243509a12Srenato log_warn("%s: calloc", __func__); 14343509a12Srenato close(connfd); 14443509a12Srenato return; 14543509a12Srenato } 14643509a12Srenato 147*f1b790a5Sclaudio if (imsgbuf_init(&c->iev.ibuf, connfd) == -1) { 148*f1b790a5Sclaudio log_warn("%s: imsgbuf_init", __func__); 149*f1b790a5Sclaudio close(connfd); 150*f1b790a5Sclaudio free(c); 151*f1b790a5Sclaudio return; 152*f1b790a5Sclaudio } 15343509a12Srenato c->iev.handler = control_dispatch_imsg; 15443509a12Srenato c->iev.events = EV_READ; 15543509a12Srenato event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 15643509a12Srenato c->iev.handler, &c->iev); 15743509a12Srenato event_add(&c->iev.ev, NULL); 15843509a12Srenato 15943509a12Srenato TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 16043509a12Srenato } 16143509a12Srenato 162ab786365Srenato static struct ctl_conn * 16343509a12Srenato control_connbyfd(int fd) 16443509a12Srenato { 16543509a12Srenato struct ctl_conn *c; 16643509a12Srenato 167c39b7208Skrw TAILQ_FOREACH(c, &ctl_conns, entry) { 168c39b7208Skrw if (c->iev.ibuf.fd == fd) 169c39b7208Skrw break; 170c39b7208Skrw } 17143509a12Srenato 17243509a12Srenato return (c); 17343509a12Srenato } 17443509a12Srenato 175ab786365Srenato static struct ctl_conn * 17643509a12Srenato control_connbypid(pid_t pid) 17743509a12Srenato { 17843509a12Srenato struct ctl_conn *c; 17943509a12Srenato 180c39b7208Skrw TAILQ_FOREACH(c, &ctl_conns, entry) { 181c39b7208Skrw if (c->iev.ibuf.pid == pid) 182c39b7208Skrw break; 183c39b7208Skrw } 18443509a12Srenato 18543509a12Srenato return (c); 18643509a12Srenato } 18743509a12Srenato 188ab786365Srenato static void 18943509a12Srenato control_close(int fd) 19043509a12Srenato { 19143509a12Srenato struct ctl_conn *c; 19243509a12Srenato 19343509a12Srenato if ((c = control_connbyfd(fd)) == NULL) { 19443509a12Srenato log_warnx("%s: fd %d: not found", __func__, fd); 19543509a12Srenato return; 19643509a12Srenato } 19743509a12Srenato 1989cbf9e90Sclaudio imsgbuf_clear(&c->iev.ibuf); 19943509a12Srenato TAILQ_REMOVE(&ctl_conns, c, entry); 20043509a12Srenato 20143509a12Srenato event_del(&c->iev.ev); 20243509a12Srenato close(c->iev.ibuf.fd); 20343509a12Srenato 20443509a12Srenato /* Some file descriptors are available again. */ 20543509a12Srenato if (evtimer_pending(&control_state.evt, NULL)) { 20643509a12Srenato evtimer_del(&control_state.evt); 20743509a12Srenato event_add(&control_state.ev, NULL); 20843509a12Srenato } 20943509a12Srenato 21043509a12Srenato free(c); 21143509a12Srenato } 21243509a12Srenato 213ab786365Srenato static void 21443509a12Srenato control_dispatch_imsg(int fd, short event, void *bula) 21543509a12Srenato { 21643509a12Srenato struct ctl_conn *c; 21743509a12Srenato struct imsg imsg; 21843509a12Srenato ssize_t n; 21943509a12Srenato unsigned int ifidx; 22043509a12Srenato int verbose; 22143509a12Srenato 22243509a12Srenato if ((c = control_connbyfd(fd)) == NULL) { 22343509a12Srenato log_warnx("%s: fd %d: not found", __func__, fd); 22443509a12Srenato return; 22543509a12Srenato } 22643509a12Srenato 22743509a12Srenato if (event & EV_READ) { 228668e5ba9Sclaudio if (imsgbuf_read(&c->iev.ibuf) != 1) { 22943509a12Srenato control_close(fd); 23043509a12Srenato return; 23143509a12Srenato } 23243509a12Srenato } 23343509a12Srenato if (event & EV_WRITE) { 234dd7efffeSclaudio if (imsgbuf_write(&c->iev.ibuf) == -1) { 23543509a12Srenato control_close(fd); 23643509a12Srenato return; 23743509a12Srenato } 23843509a12Srenato } 23943509a12Srenato 24043509a12Srenato for (;;) { 24143509a12Srenato if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 24243509a12Srenato control_close(fd); 24343509a12Srenato return; 24443509a12Srenato } 24543509a12Srenato 24643509a12Srenato if (n == 0) 24743509a12Srenato break; 24843509a12Srenato 24943509a12Srenato switch (imsg.hdr.type) { 25043509a12Srenato case IMSG_CTL_FIB_COUPLE: 25143509a12Srenato case IMSG_CTL_FIB_DECOUPLE: 25243509a12Srenato case IMSG_CTL_RELOAD: 25343509a12Srenato c->iev.ibuf.pid = imsg.hdr.pid; 25443509a12Srenato eigrpe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0); 25543509a12Srenato break; 25643509a12Srenato case IMSG_CTL_KROUTE: 25743509a12Srenato case IMSG_CTL_IFINFO: 25843509a12Srenato c->iev.ibuf.pid = imsg.hdr.pid; 25943509a12Srenato eigrpe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, 26043509a12Srenato imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 26143509a12Srenato break; 26243509a12Srenato case IMSG_CTL_SHOW_INTERFACE: 26343509a12Srenato if (imsg.hdr.len != IMSG_HEADER_SIZE + 26443509a12Srenato sizeof(ifidx)) 26543509a12Srenato break; 26643509a12Srenato 26743509a12Srenato memcpy(&ifidx, imsg.data, sizeof(ifidx)); 26843509a12Srenato eigrpe_iface_ctl(c, ifidx); 26943509a12Srenato imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 27043509a12Srenato 0, -1, NULL, 0); 27143509a12Srenato break; 27243509a12Srenato case IMSG_CTL_SHOW_TOPOLOGY: 27343509a12Srenato if (imsg.hdr.len != IMSG_HEADER_SIZE + 27443509a12Srenato sizeof(struct ctl_show_topology_req)) 27543509a12Srenato break; 27643509a12Srenato 27743509a12Srenato c->iev.ibuf.pid = imsg.hdr.pid; 27843509a12Srenato eigrpe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, 27943509a12Srenato imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 28043509a12Srenato break; 28143509a12Srenato case IMSG_CTL_SHOW_NBR: 28243509a12Srenato eigrpe_nbr_ctl(c); 28343509a12Srenato break; 284dcfaa8d4Srenato case IMSG_CTL_SHOW_STATS: 285dcfaa8d4Srenato eigrpe_stats_ctl(c); 286dcfaa8d4Srenato break; 2870e96235eSrenato case IMSG_CTL_CLEAR_NBR: 2880e96235eSrenato if (imsg.hdr.len != IMSG_HEADER_SIZE + 2890e96235eSrenato sizeof(struct ctl_nbr)) 2900e96235eSrenato break; 2910e96235eSrenato 2920e96235eSrenato nbr_clear_ctl(imsg.data); 2930e96235eSrenato break; 29443509a12Srenato case IMSG_CTL_LOG_VERBOSE: 29543509a12Srenato if (imsg.hdr.len != IMSG_HEADER_SIZE + 29643509a12Srenato sizeof(verbose)) 29743509a12Srenato break; 29843509a12Srenato 29943509a12Srenato /* forward to other processes */ 30043509a12Srenato eigrpe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, 30143509a12Srenato imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 30243509a12Srenato eigrpe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid, 30343509a12Srenato imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 30443509a12Srenato 30543509a12Srenato memcpy(&verbose, imsg.data, sizeof(verbose)); 30643509a12Srenato log_verbose(verbose); 30743509a12Srenato break; 30843509a12Srenato default: 30943509a12Srenato log_debug("%s: error handling imsg %d", __func__, 31043509a12Srenato imsg.hdr.type); 31143509a12Srenato break; 31243509a12Srenato } 31343509a12Srenato imsg_free(&imsg); 31443509a12Srenato } 31543509a12Srenato 31643509a12Srenato imsg_event_add(&c->iev); 31743509a12Srenato } 31843509a12Srenato 31943509a12Srenato int 32043509a12Srenato control_imsg_relay(struct imsg *imsg) 32143509a12Srenato { 32243509a12Srenato struct ctl_conn *c; 32343509a12Srenato 32443509a12Srenato if ((c = control_connbypid(imsg->hdr.pid)) == NULL) 32543509a12Srenato return (0); 32643509a12Srenato 32743509a12Srenato return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, 32843509a12Srenato -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); 32943509a12Srenato } 330