1*04e12482Sclaudio /* $OpenBSD: control.c,v 1.132 2024/12/02 15:03:17 claudio Exp $ */ 227157683Shenning 327157683Shenning /* 4050527e1Shenning * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 527157683Shenning * 627157683Shenning * Permission to use, copy, modify, and distribute this software for any 727157683Shenning * purpose with or without fee is hereby granted, provided that the above 827157683Shenning * copyright notice and this permission notice appear in all copies. 927157683Shenning * 1027157683Shenning * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1127157683Shenning * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1227157683Shenning * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1327157683Shenning * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1427157683Shenning * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1527157683Shenning * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1627157683Shenning * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1727157683Shenning */ 1827157683Shenning 1927157683Shenning #include <sys/types.h> 20322c71cfShenning #include <sys/stat.h> 2127157683Shenning #include <sys/socket.h> 2227157683Shenning #include <sys/un.h> 2327157683Shenning #include <errno.h> 2427157683Shenning #include <stdlib.h> 2527157683Shenning #include <string.h> 2627157683Shenning #include <unistd.h> 2727157683Shenning 2827157683Shenning #include "bgpd.h" 2927157683Shenning #include "session.h" 305e3f6f95Sbenno #include "log.h" 3127157683Shenning 3276e39a7cSclaudio TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns); 3376e39a7cSclaudio 3427157683Shenning #define CONTROL_BACKLOG 5 3527157683Shenning 3627157683Shenning struct ctl_conn *control_connbyfd(int); 37f4ecf7d5Shenning struct ctl_conn *control_connbypid(pid_t); 3876e39a7cSclaudio int control_close(struct ctl_conn *); 39f58eb34cShenning void control_result(struct ctl_conn *, u_int); 4027157683Shenning 4127157683Shenning int 421adf6159Sremi control_check(char *path) 431adf6159Sremi { 44db04565aSclaudio struct sockaddr_un sa_un; 451adf6159Sremi int fd; 461adf6159Sremi 47eafe309eSclaudio memset(&sa_un, 0, sizeof(sa_un)); 48db04565aSclaudio sa_un.sun_family = AF_UNIX; 49db04565aSclaudio strlcpy(sa_un.sun_path, path, sizeof(sa_un.sun_path)); 501adf6159Sremi 513ac77e71Sclaudio if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) { 521adf6159Sremi log_warn("%s: socket", __func__); 531adf6159Sremi return (-1); 541adf6159Sremi } 551adf6159Sremi 56db04565aSclaudio if (connect(fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) == 0) { 571adf6159Sremi log_warnx("control socket %s already in use", path); 581adf6159Sremi close(fd); 591adf6159Sremi return (-1); 601adf6159Sremi } 611adf6159Sremi 621adf6159Sremi close(fd); 631adf6159Sremi 641adf6159Sremi return (0); 651adf6159Sremi } 661adf6159Sremi 671adf6159Sremi int 6841928d45Shenning control_init(int restricted, char *path) 6927157683Shenning { 70db04565aSclaudio struct sockaddr_un sa_un; 7127157683Shenning int fd; 7241928d45Shenning mode_t old_umask, mode; 7327157683Shenning 745ba20998Sclaudio if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 755ba20998Sclaudio 0)) == -1) { 768013a801Shenning log_warn("control_init: socket"); 7727157683Shenning return (-1); 7827157683Shenning } 7927157683Shenning 80eafe309eSclaudio memset(&sa_un, 0, sizeof(sa_un)); 81db04565aSclaudio sa_un.sun_family = AF_UNIX; 82db04565aSclaudio if (strlcpy(sa_un.sun_path, path, sizeof(sa_un.sun_path)) >= 83db04565aSclaudio sizeof(sa_un.sun_path)) { 84339bb5e0Sbenno log_warn("control_init: socket name too long"); 85339bb5e0Sbenno close(fd); 86339bb5e0Sbenno return (-1); 87339bb5e0Sbenno } 88322c71cfShenning 8941928d45Shenning if (unlink(path) == -1) 90322c71cfShenning if (errno != ENOENT) { 91e7464dffSmk log_warn("control_init: unlink %s", path); 92efc32651Shenning close(fd); 93322c71cfShenning return (-1); 94322c71cfShenning } 95322c71cfShenning 9641928d45Shenning if (restricted) { 9741928d45Shenning old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH); 9841928d45Shenning mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 9941928d45Shenning } else { 100126a8a1bSderaadt old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 10141928d45Shenning mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP; 10241928d45Shenning } 10341928d45Shenning 104db04565aSclaudio if (bind(fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) == -1) { 10541928d45Shenning log_warn("control_init: bind: %s", path); 106efc32651Shenning close(fd); 107126a8a1bSderaadt umask(old_umask); 10827157683Shenning return (-1); 10927157683Shenning } 11027157683Shenning 111126a8a1bSderaadt umask(old_umask); 112126a8a1bSderaadt 11341928d45Shenning if (chmod(path, mode) == -1) { 11441928d45Shenning log_warn("control_init: chmod: %s", path); 115efc32651Shenning close(fd); 11641928d45Shenning unlink(path); 117322c71cfShenning return (-1); 118322c71cfShenning } 119322c71cfShenning 12027157683Shenning return (fd); 12127157683Shenning } 12227157683Shenning 12327157683Shenning int 12441928d45Shenning control_listen(int fd) 12527157683Shenning { 12641928d45Shenning if (fd != -1 && listen(fd, CONTROL_BACKLOG) == -1) { 1278013a801Shenning log_warn("control_listen: listen"); 12827157683Shenning return (-1); 12927157683Shenning } 13027157683Shenning 13141928d45Shenning return (0); 13227157683Shenning } 13327157683Shenning 13427157683Shenning void 13541928d45Shenning control_shutdown(int fd) 13627157683Shenning { 13741928d45Shenning close(fd); 13827157683Shenning } 13927157683Shenning 14076e39a7cSclaudio size_t 14176e39a7cSclaudio control_fill_pfds(struct pollfd *pfd, size_t size) 14276e39a7cSclaudio { 14376e39a7cSclaudio struct ctl_conn *ctl_conn; 14476e39a7cSclaudio size_t i = 0; 14576e39a7cSclaudio 14676e39a7cSclaudio TAILQ_FOREACH(ctl_conn, &ctl_conns, entry) { 147c8f6e08eSclaudio pfd[i].fd = ctl_conn->imsgbuf.fd; 14876e39a7cSclaudio pfd[i].events = POLLIN; 14931be28caSclaudio if (imsgbuf_queuelen(&ctl_conn->imsgbuf) > 0) 15076e39a7cSclaudio pfd[i].events |= POLLOUT; 15176e39a7cSclaudio i++; 15276e39a7cSclaudio } 15376e39a7cSclaudio return i; 15476e39a7cSclaudio } 15576e39a7cSclaudio 15699bf90ffSclaudio unsigned int 15741928d45Shenning control_accept(int listenfd, int restricted) 15827157683Shenning { 15927157683Shenning int connfd; 16027157683Shenning socklen_t len; 161db04565aSclaudio struct sockaddr_un sa_un; 16227157683Shenning struct ctl_conn *ctl_conn; 16327157683Shenning 164db04565aSclaudio len = sizeof(sa_un); 1655ba20998Sclaudio if ((connfd = accept4(listenfd, 166db04565aSclaudio (struct sockaddr *)&sa_un, &len, 1675ba20998Sclaudio SOCK_NONBLOCK | SOCK_CLOEXEC)) == -1) { 16878c7f42bSclaudio if (errno == ENFILE || errno == EMFILE) { 16978c7f42bSclaudio pauseaccept = getmonotime(); 17078c7f42bSclaudio return (0); 17162e3c252Sderaadt } else if (errno != EWOULDBLOCK && errno != EINTR && 17262e3c252Sderaadt errno != ECONNABORTED) 173e7464dffSmk log_warn("control_accept: accept"); 174edf7a95aShenning return (0); 17527157683Shenning } 17627157683Shenning 177d923c008Shenning if ((ctl_conn = calloc(1, sizeof(struct ctl_conn))) == NULL) { 178e7464dffSmk log_warn("control_accept"); 179ac50b3daShenning close(connfd); 180edf7a95aShenning return (0); 18127157683Shenning } 18227157683Shenning 183*04e12482Sclaudio if (imsgbuf_init(&ctl_conn->imsgbuf, connfd) == -1 || 184*04e12482Sclaudio imsgbuf_set_maxsize(&ctl_conn->imsgbuf, MAX_BGPD_IMSGSIZE) == -1) { 185f1b790a5Sclaudio log_warn("control_accept"); 186*04e12482Sclaudio imsgbuf_clear(&ctl_conn->imsgbuf); 187f1b790a5Sclaudio close(connfd); 188f1b790a5Sclaudio free(ctl_conn); 189f1b790a5Sclaudio return (0); 190f1b790a5Sclaudio } 19141928d45Shenning ctl_conn->restricted = restricted; 19227157683Shenning 193435f34f3Shenning TAILQ_INSERT_TAIL(&ctl_conns, ctl_conn, entry); 194edf7a95aShenning 195edf7a95aShenning return (1); 19627157683Shenning } 19727157683Shenning 19827157683Shenning struct ctl_conn * 19927157683Shenning control_connbyfd(int fd) 20027157683Shenning { 20127157683Shenning struct ctl_conn *c; 20227157683Shenning 203c39b7208Skrw TAILQ_FOREACH(c, &ctl_conns, entry) { 204c8f6e08eSclaudio if (c->imsgbuf.fd == fd) 205c39b7208Skrw break; 206c39b7208Skrw } 20727157683Shenning 20827157683Shenning return (c); 20927157683Shenning } 21027157683Shenning 211f4ecf7d5Shenning struct ctl_conn * 212f4ecf7d5Shenning control_connbypid(pid_t pid) 213f4ecf7d5Shenning { 214f4ecf7d5Shenning struct ctl_conn *c; 215f4ecf7d5Shenning 216c39b7208Skrw TAILQ_FOREACH(c, &ctl_conns, entry) { 217c8f6e08eSclaudio if (c->imsgbuf.pid == pid) 218c39b7208Skrw break; 219c39b7208Skrw } 220f4ecf7d5Shenning 221f4ecf7d5Shenning return (c); 222f4ecf7d5Shenning } 223f4ecf7d5Shenning 224edf7a95aShenning int 22576e39a7cSclaudio control_close(struct ctl_conn *c) 22627157683Shenning { 227c8f6e08eSclaudio if (c->terminate && c->imsgbuf.pid) 228c8f6e08eSclaudio imsg_ctl_rde_msg(IMSG_CTL_TERMINATE, 0, c->imsgbuf.pid); 229fb02cdf0Sclaudio 2309cbf9e90Sclaudio imsgbuf_clear(&c->imsgbuf); 231435f34f3Shenning TAILQ_REMOVE(&ctl_conns, c, entry); 23227157683Shenning 233c8f6e08eSclaudio close(c->imsgbuf.fd); 23427157683Shenning free(c); 23578c7f42bSclaudio pauseaccept = 0; 236edf7a95aShenning return (1); 23727157683Shenning } 23827157683Shenning 23927157683Shenning int 24076e39a7cSclaudio control_dispatch_msg(struct pollfd *pfd, struct peer_head *peers) 24127157683Shenning { 24227157683Shenning struct imsg imsg; 2430b920bb9Sclaudio struct ctl_neighbor neighbor; 2440b920bb9Sclaudio struct ctl_show_rib_request ribreq; 24527157683Shenning struct ctl_conn *c; 24627157683Shenning struct peer *p; 2470b920bb9Sclaudio ssize_t n; 2480b920bb9Sclaudio uint32_t type; 2490b920bb9Sclaudio pid_t pid; 2500b920bb9Sclaudio int verbose, matched; 25127157683Shenning 25227157683Shenning if ((c = control_connbyfd(pfd->fd)) == NULL) { 2538013a801Shenning log_warn("control_dispatch_msg: fd %d: not found", pfd->fd); 25427157683Shenning return (0); 25527157683Shenning } 25627157683Shenning 257383bcad8Sclaudio if (pfd->revents & POLLOUT) { 258dd7efffeSclaudio if (imsgbuf_write(&c->imsgbuf) == -1) 25976e39a7cSclaudio return control_close(c); 26031be28caSclaudio if (c->throttled && 26131be28caSclaudio imsgbuf_queuelen(&c->imsgbuf) < CTL_MSG_LOW_MARK) { 262c8f6e08eSclaudio if (imsg_ctl_rde_msg(IMSG_XON, 0, c->imsgbuf.pid) != -1) 263383bcad8Sclaudio c->throttled = 0; 264383bcad8Sclaudio } 265383bcad8Sclaudio } 2660d8c7131Shenning 2670d8c7131Shenning if (!(pfd->revents & POLLIN)) 2680d8c7131Shenning return (0); 2690d8c7131Shenning 27098435822Sclaudio if (imsgbuf_read(&c->imsgbuf) != 1) 27176e39a7cSclaudio return control_close(c); 27227157683Shenning 27327157683Shenning for (;;) { 274c8f6e08eSclaudio if ((n = imsg_get(&c->imsgbuf, &imsg)) == -1) 27576e39a7cSclaudio return control_close(c); 27627157683Shenning 27727157683Shenning if (n == 0) 27827157683Shenning break; 27927157683Shenning 2800b920bb9Sclaudio type = imsg_get_type(&imsg); 2810b920bb9Sclaudio pid = imsg_get_pid(&imsg); 28241928d45Shenning if (c->restricted) { 2830b920bb9Sclaudio switch (type) { 28427157683Shenning case IMSG_CTL_SHOW_NEIGHBOR: 28541928d45Shenning case IMSG_CTL_SHOW_NEXTHOP: 28641928d45Shenning case IMSG_CTL_SHOW_INTERFACE: 28741928d45Shenning case IMSG_CTL_SHOW_RIB_MEM: 28816fcf8d2Shenning case IMSG_CTL_SHOW_TERSE: 2896251e4e2Shenning case IMSG_CTL_SHOW_TIMER: 290fb02cdf0Sclaudio case IMSG_CTL_SHOW_NETWORK: 291f7b38103Sclaudio case IMSG_CTL_SHOW_FLOWSPEC: 292fb02cdf0Sclaudio case IMSG_CTL_SHOW_RIB: 293fb02cdf0Sclaudio case IMSG_CTL_SHOW_RIB_PREFIX: 2947ff9bf35Sclaudio case IMSG_CTL_SHOW_SET: 2959647b4ffSclaudio case IMSG_CTL_SHOW_RTR: 29641928d45Shenning break; 29741928d45Shenning default: 29841928d45Shenning /* clear imsg type to prevent processing */ 2990b920bb9Sclaudio type = IMSG_NONE; 30041928d45Shenning control_result(c, CTL_RES_DENIED); 30141928d45Shenning break; 30241928d45Shenning } 30341928d45Shenning } 30441928d45Shenning 3050b920bb9Sclaudio /* 3060b920bb9Sclaudio * TODO: this is wrong and shoud work the other way around. 3070b920bb9Sclaudio * The imsg.hdr.pid is from the remote end and should not 3080b920bb9Sclaudio * be trusted. 3090b920bb9Sclaudio */ 310c8f6e08eSclaudio c->imsgbuf.pid = pid; 3110b920bb9Sclaudio switch (type) { 31241928d45Shenning case IMSG_NONE: 31341928d45Shenning /* message was filtered out, nothing to do */ 31441928d45Shenning break; 315514180acSclaudio case IMSG_CTL_FIB_COUPLE: 316514180acSclaudio case IMSG_CTL_FIB_DECOUPLE: 3170b920bb9Sclaudio imsg_ctl_parent(&imsg); 318514180acSclaudio break; 319514180acSclaudio case IMSG_CTL_SHOW_TERSE: 3207876190cSclaudio RB_FOREACH(p, peer_head, peers) 321c8f6e08eSclaudio imsg_compose(&c->imsgbuf, 322c8f6e08eSclaudio IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, 323c8f6e08eSclaudio p, sizeof(struct peer)); 324c8f6e08eSclaudio imsg_compose(&c->imsgbuf, IMSG_CTL_END, 0, 0, -1, 325c8f6e08eSclaudio NULL, 0); 326514180acSclaudio break; 32741928d45Shenning case IMSG_CTL_SHOW_NEIGHBOR: 3280b920bb9Sclaudio if (imsg_get_data(&imsg, &neighbor, 3290b920bb9Sclaudio sizeof(neighbor)) == -1) 3300b920bb9Sclaudio memset(&neighbor, 0, sizeof(neighbor)); 331514180acSclaudio 33282fc6237Sclaudio matched = 0; 3337876190cSclaudio RB_FOREACH(p, peer_head, peers) { 3340b920bb9Sclaudio if (!peer_matched(p, &neighbor)) 335514180acSclaudio continue; 336514180acSclaudio 337514180acSclaudio matched = 1; 3380b920bb9Sclaudio if (!neighbor.show_timers) { 3390b920bb9Sclaudio imsg_ctl_rde_msg(type, 3400b920bb9Sclaudio p->conf.id, pid); 3415641005aShenning } else { 3420d594c94Shenning u_int i; 3430d594c94Shenning time_t d; 3440d594c94Shenning struct ctl_timer ct; 3450d594c94Shenning 346c8f6e08eSclaudio imsg_compose(&c->imsgbuf, 3470d594c94Shenning IMSG_CTL_SHOW_NEIGHBOR, 3480d594c94Shenning 0, 0, -1, p, sizeof(*p)); 3490d594c94Shenning for (i = 1; i < Timer_Max; i++) { 35082fcfa8bSclaudio if (!timer_running(&p->timers, 35182fcfa8bSclaudio i, &d)) 3520d594c94Shenning continue; 3530d594c94Shenning ct.type = i; 3540d594c94Shenning ct.val = d; 355c8f6e08eSclaudio imsg_compose(&c->imsgbuf, 3560d594c94Shenning IMSG_CTL_SHOW_TIMER, 3570d594c94Shenning 0, 0, -1, &ct, sizeof(ct)); 3580d594c94Shenning } 3590d594c94Shenning } 360514180acSclaudio } 361baad1f5dSclaudio if (!matched && !RB_EMPTY(peers)) { 362514180acSclaudio control_result(c, CTL_RES_NOSUCHPEER); 3630b920bb9Sclaudio } else if (!neighbor.show_timers) { 3640b920bb9Sclaudio imsg_ctl_rde_msg(IMSG_CTL_END, 0, pid); 365514180acSclaudio } else { 366c8f6e08eSclaudio imsg_compose(&c->imsgbuf, IMSG_CTL_END, 0, 0, 367c8f6e08eSclaudio -1, NULL, 0); 3680d594c94Shenning } 36927157683Shenning break; 37041e05cf3Shenning case IMSG_CTL_NEIGHBOR_UP: 37141e05cf3Shenning case IMSG_CTL_NEIGHBOR_DOWN: 37292b49885Shenning case IMSG_CTL_NEIGHBOR_CLEAR: 373b51efe11Shenning case IMSG_CTL_NEIGHBOR_RREFRESH: 37417098ec8Sclaudio case IMSG_CTL_NEIGHBOR_DESTROY: 3750b920bb9Sclaudio if (imsg_get_data(&imsg, &neighbor, 3760b920bb9Sclaudio sizeof(neighbor)) == -1) { 377514180acSclaudio log_warnx("got IMSG_CTL_NEIGHBOR_ with " 378514180acSclaudio "wrong length"); 3790bdee4bbShenning break; 3800bdee4bbShenning } 381514180acSclaudio 38282fc6237Sclaudio matched = 0; 3837876190cSclaudio RB_FOREACH(p, peer_head, peers) { 3840b920bb9Sclaudio if (!peer_matched(p, &neighbor)) 385514180acSclaudio continue; 386514180acSclaudio 387514180acSclaudio matched = 1; 388514180acSclaudio 3890b920bb9Sclaudio switch (type) { 3900bdee4bbShenning case IMSG_CTL_NEIGHBOR_UP: 391c9c4d4e4Sclaudio bgp_fsm(p, EVNT_START, NULL); 3920561b344Sphessler p->conf.down = 0; 393a78f83ceSderaadt p->conf.reason[0] = '\0'; 3940239f306Sclaudio p->IdleHoldTime = 3950239f306Sclaudio INTERVAL_IDLE_HOLD_INITIAL; 3960239f306Sclaudio p->errcnt = 0; 397b51efe11Shenning control_result(c, CTL_RES_OK); 3980bdee4bbShenning break; 3990bdee4bbShenning case IMSG_CTL_NEIGHBOR_DOWN: 4000b920bb9Sclaudio neighbor.reason[ 4010b920bb9Sclaudio sizeof(neighbor.reason) - 1] = '\0'; 4029af396adSclaudio p->conf.down = 1; 4033a82eff3Sclaudio session_stop(p, ERR_CEASE_ADMIN_DOWN, 4043a82eff3Sclaudio neighbor.reason); 405b51efe11Shenning control_result(c, CTL_RES_OK); 4060bdee4bbShenning break; 40792b49885Shenning case IMSG_CTL_NEIGHBOR_CLEAR: 4080b920bb9Sclaudio neighbor.reason[ 4090b920bb9Sclaudio sizeof(neighbor.reason) - 1] = '\0'; 4100239f306Sclaudio p->IdleHoldTime = 4110239f306Sclaudio INTERVAL_IDLE_HOLD_INITIAL; 4120239f306Sclaudio p->errcnt = 0; 413ad45d28fSclaudio if (!p->conf.down) { 414ad45d28fSclaudio session_stop(p, 4153a82eff3Sclaudio ERR_CEASE_ADMIN_RESET, 4163a82eff3Sclaudio neighbor.reason); 41782fcfa8bSclaudio timer_set(&p->timers, 41882fcfa8bSclaudio Timer_IdleHold, 4191b5a1903Shenning SESSION_CLEAR_DELAY); 420ad45d28fSclaudio } else { 421ad45d28fSclaudio session_stop(p, 4223a82eff3Sclaudio ERR_CEASE_ADMIN_DOWN, 4233a82eff3Sclaudio neighbor.reason); 424ad45d28fSclaudio } 425b51efe11Shenning control_result(c, CTL_RES_OK); 426b51efe11Shenning break; 427b51efe11Shenning case IMSG_CTL_NEIGHBOR_RREFRESH: 428b51efe11Shenning if (session_neighbor_rrefresh(p)) 429b51efe11Shenning control_result(c, 430b51efe11Shenning CTL_RES_NOCAP); 431b51efe11Shenning else 432b51efe11Shenning control_result(c, CTL_RES_OK); 43392b49885Shenning break; 43417098ec8Sclaudio case IMSG_CTL_NEIGHBOR_DESTROY: 43517098ec8Sclaudio if (!p->template) 43617098ec8Sclaudio control_result(c, 43717098ec8Sclaudio CTL_RES_BADPEER); 43817098ec8Sclaudio else if (p->state != STATE_IDLE) 43917098ec8Sclaudio control_result(c, 44017098ec8Sclaudio CTL_RES_BADSTATE); 44117098ec8Sclaudio else { 44217098ec8Sclaudio /* 44317098ec8Sclaudio * Mark as deleted, will be 44417098ec8Sclaudio * collected on next poll loop. 44517098ec8Sclaudio */ 44682fc6237Sclaudio p->reconf_action = 44717098ec8Sclaudio RECONF_DELETE; 44817098ec8Sclaudio control_result(c, CTL_RES_OK); 44917098ec8Sclaudio } 45017098ec8Sclaudio break; 4510bdee4bbShenning default: 4520bdee4bbShenning fatal("king bula wants more humppa"); 4530bdee4bbShenning } 454514180acSclaudio } 455514180acSclaudio if (!matched) 456514180acSclaudio control_result(c, CTL_RES_NOSUCHPEER); 45741e05cf3Shenning break; 4581721f25bSclaudio case IMSG_CTL_RELOAD: 459459fcfe4Sclaudio case IMSG_CTL_SHOW_INTERFACE: 460459fcfe4Sclaudio case IMSG_CTL_SHOW_FIB_TABLES: 461bd9df44eSclaudio case IMSG_CTL_SHOW_RTR: 4620b920bb9Sclaudio imsg_ctl_parent(&imsg); 463459fcfe4Sclaudio break; 464f4ecf7d5Shenning case IMSG_CTL_KROUTE: 46552ef641bShenning case IMSG_CTL_KROUTE_ADDR: 466e949080fShenning case IMSG_CTL_SHOW_NEXTHOP: 4670b920bb9Sclaudio imsg_ctl_parent(&imsg); 468f4ecf7d5Shenning break; 469e37c0eabSclaudio case IMSG_CTL_SHOW_RIB: 470ad926354Sclaudio case IMSG_CTL_SHOW_RIB_PREFIX: 4710b920bb9Sclaudio if (imsg_get_data(&imsg, &ribreq, sizeof(ribreq)) == 4720b920bb9Sclaudio -1) { 473514180acSclaudio log_warnx("got IMSG_CTL_SHOW_RIB with " 474514180acSclaudio "wrong length"); 475514180acSclaudio break; 476514180acSclaudio } 477514180acSclaudio 478514180acSclaudio /* check if at least one neighbor exists */ 4797876190cSclaudio RB_FOREACH(p, peer_head, peers) 4800b920bb9Sclaudio if (peer_matched(p, &ribreq.neighbor)) 481dae6dd81Sclaudio break; 482baad1f5dSclaudio if (p == NULL && !RB_EMPTY(peers)) { 4832b5ebfecSbenno control_result(c, CTL_RES_NOSUCHPEER); 4842b5ebfecSbenno break; 4852b5ebfecSbenno } 486514180acSclaudio 4870b920bb9Sclaudio if (type == IMSG_CTL_SHOW_RIB_PREFIX && 4880b920bb9Sclaudio ribreq.prefix.aid == AID_UNSPEC) { 4892b2440b0Ssthen /* malformed request, must specify af */ 4902b2440b0Ssthen control_result(c, CTL_RES_PARSE_ERROR); 4912b2440b0Ssthen break; 4922b2440b0Ssthen } 493514180acSclaudio 494fb02cdf0Sclaudio c->terminate = 1; 4950b920bb9Sclaudio imsg_ctl_rde(&imsg); 496dae6dd81Sclaudio break; 49797f08015Sclaudio case IMSG_CTL_SHOW_NETWORK: 498f7b38103Sclaudio case IMSG_CTL_SHOW_FLOWSPEC: 499fb02cdf0Sclaudio c->terminate = 1; 500fb02cdf0Sclaudio /* FALLTHROUGH */ 501fb02cdf0Sclaudio case IMSG_CTL_SHOW_RIB_MEM: 5027ff9bf35Sclaudio case IMSG_CTL_SHOW_SET: 5030b920bb9Sclaudio imsg_ctl_rde(&imsg); 504e37c0eabSclaudio break; 50597f08015Sclaudio case IMSG_NETWORK_ADD: 506abf4b724Sclaudio case IMSG_NETWORK_ASPATH: 507abf4b724Sclaudio case IMSG_NETWORK_ATTR: 50897f08015Sclaudio case IMSG_NETWORK_REMOVE: 50997f08015Sclaudio case IMSG_NETWORK_FLUSH: 51098d902b5Sclaudio case IMSG_NETWORK_DONE: 511f7b38103Sclaudio case IMSG_FLOWSPEC_ADD: 512f7b38103Sclaudio case IMSG_FLOWSPEC_REMOVE: 513f7b38103Sclaudio case IMSG_FLOWSPEC_DONE: 514f7b38103Sclaudio case IMSG_FLOWSPEC_FLUSH: 51598d902b5Sclaudio case IMSG_FILTER_SET: 5160b920bb9Sclaudio imsg_ctl_rde(&imsg); 51797f08015Sclaudio break; 518d6b35cfbSclaudio case IMSG_CTL_LOG_VERBOSE: 5190b920bb9Sclaudio if (imsg_get_data(&imsg, &verbose, sizeof(verbose)) == 5200b920bb9Sclaudio -1) 521d6b35cfbSclaudio break; 522d6b35cfbSclaudio 523307aca1bSjsg /* forward to other processes */ 5240b920bb9Sclaudio imsg_ctl_parent(&imsg); 5250b920bb9Sclaudio imsg_ctl_rde(&imsg); 5265e3f6f95Sbenno log_setverbose(verbose); 527d6b35cfbSclaudio break; 52827157683Shenning default: 52927157683Shenning break; 53027157683Shenning } 53127157683Shenning imsg_free(&imsg); 53227157683Shenning } 53327157683Shenning 53427157683Shenning return (0); 53527157683Shenning } 536f4ecf7d5Shenning 537f4ecf7d5Shenning int 53882625ff8Sclaudio control_imsg_relay(struct imsg *imsg, struct peer *p) 539f4ecf7d5Shenning { 540f4ecf7d5Shenning struct ctl_conn *c; 5410b920bb9Sclaudio uint32_t type; 5420b920bb9Sclaudio pid_t pid; 543f4ecf7d5Shenning 5440b920bb9Sclaudio type = imsg_get_type(imsg); 5450b920bb9Sclaudio pid = imsg_get_pid(imsg); 5460b920bb9Sclaudio 5470b920bb9Sclaudio if ((c = control_connbypid(pid)) == NULL) 548f4ecf7d5Shenning return (0); 549f4ecf7d5Shenning 55082625ff8Sclaudio /* special handling for peers since only the stats are sent from RDE */ 5510b920bb9Sclaudio if (type == IMSG_CTL_SHOW_NEIGHBOR) { 55282625ff8Sclaudio struct rde_peer_stats stats; 553d7629114Sclaudio struct peer peer; 55482625ff8Sclaudio 55582625ff8Sclaudio if (p == NULL) { 5560b920bb9Sclaudio log_warnx("%s: no such peer: id=%u", __func__, 5570b920bb9Sclaudio imsg_get_id(imsg)); 55882625ff8Sclaudio return (0); 55982625ff8Sclaudio } 5600b920bb9Sclaudio if (imsg_get_data(imsg, &stats, sizeof(stats)) == -1) { 5610b920bb9Sclaudio log_warnx("%s: imsg_get_data", __func__); 5620b920bb9Sclaudio return (0); 5630b920bb9Sclaudio } 564d7629114Sclaudio peer = *p; 565d7629114Sclaudio explicit_bzero(&peer.auth_conf, sizeof(peer.auth_conf)); 56663c2b496Sclaudio peer.auth_conf.method = p->auth_conf.method; 567d7629114Sclaudio peer.stats.prefix_cnt = stats.prefix_cnt; 568d7629114Sclaudio peer.stats.prefix_out_cnt = stats.prefix_out_cnt; 569d7629114Sclaudio peer.stats.prefix_rcvd_update = stats.prefix_rcvd_update; 570d7629114Sclaudio peer.stats.prefix_rcvd_withdraw = stats.prefix_rcvd_withdraw; 571d7629114Sclaudio peer.stats.prefix_rcvd_eor = stats.prefix_rcvd_eor; 572d7629114Sclaudio peer.stats.prefix_sent_update = stats.prefix_sent_update; 573d7629114Sclaudio peer.stats.prefix_sent_withdraw = stats.prefix_sent_withdraw; 574d7629114Sclaudio peer.stats.prefix_sent_eor = stats.prefix_sent_eor; 575d7629114Sclaudio peer.stats.pending_update = stats.pending_update; 576d7629114Sclaudio peer.stats.pending_withdraw = stats.pending_withdraw; 57705453d67Sclaudio peer.stats.msg_queue_len = msgbuf_queuelen(p->wbuf); 57882625ff8Sclaudio 579c8f6e08eSclaudio return imsg_compose(&c->imsgbuf, type, 0, pid, -1, 580d7629114Sclaudio &peer, sizeof(peer)); 58182625ff8Sclaudio } 58282625ff8Sclaudio 583fb02cdf0Sclaudio /* if command finished no need to send exit message */ 5840b920bb9Sclaudio if (type == IMSG_CTL_END || type == IMSG_CTL_RESULT) 585fb02cdf0Sclaudio c->terminate = 0; 586fb02cdf0Sclaudio 58731be28caSclaudio if (!c->throttled && 58831be28caSclaudio imsgbuf_queuelen(&c->imsgbuf) > CTL_MSG_HIGH_MARK) { 5890b920bb9Sclaudio if (imsg_ctl_rde_msg(IMSG_XOFF, 0, pid) != -1) 590383bcad8Sclaudio c->throttled = 1; 591383bcad8Sclaudio } 592383bcad8Sclaudio 593c8f6e08eSclaudio return (imsg_forward(&c->imsgbuf, imsg)); 594f4ecf7d5Shenning } 595f58eb34cShenning 596f58eb34cShenning void 597f58eb34cShenning control_result(struct ctl_conn *c, u_int code) 598f58eb34cShenning { 599c8f6e08eSclaudio imsg_compose(&c->imsgbuf, IMSG_CTL_RESULT, 0, c->imsgbuf.pid, -1, 600f58eb34cShenning &code, sizeof(code)); 601f58eb34cShenning } 602