1 /* $OpenBSD: control.c,v 1.85 2017/01/13 18:59:12 phessler Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/stat.h> 21 #include <sys/socket.h> 22 #include <sys/un.h> 23 #include <errno.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include "bgpd.h" 29 #include "session.h" 30 31 #define CONTROL_BACKLOG 5 32 33 struct ctl_conn *control_connbyfd(int); 34 struct ctl_conn *control_connbypid(pid_t); 35 int control_close(int); 36 void control_result(struct ctl_conn *, u_int); 37 ssize_t imsg_read_nofd(struct imsgbuf *); 38 39 int 40 control_init(int restricted, char *path) 41 { 42 struct sockaddr_un sun; 43 int fd; 44 mode_t old_umask, mode; 45 46 if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 47 0)) == -1) { 48 log_warn("control_init: socket"); 49 return (-1); 50 } 51 52 bzero(&sun, sizeof(sun)); 53 sun.sun_family = AF_UNIX; 54 if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= 55 sizeof(sun.sun_path)) { 56 log_warn("control_init: socket name too long"); 57 close(fd); 58 return (-1); 59 } 60 61 if (unlink(path) == -1) 62 if (errno != ENOENT) { 63 log_warn("control_init: unlink %s", path); 64 close(fd); 65 return (-1); 66 } 67 68 if (restricted) { 69 old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH); 70 mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 71 } else { 72 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 73 mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP; 74 } 75 76 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 77 log_warn("control_init: bind: %s", path); 78 close(fd); 79 umask(old_umask); 80 return (-1); 81 } 82 83 umask(old_umask); 84 85 if (chmod(path, mode) == -1) { 86 log_warn("control_init: chmod: %s", path); 87 close(fd); 88 unlink(path); 89 return (-1); 90 } 91 92 return (fd); 93 } 94 95 int 96 control_listen(int fd) 97 { 98 if (fd != -1 && listen(fd, CONTROL_BACKLOG) == -1) { 99 log_warn("control_listen: listen"); 100 return (-1); 101 } 102 103 return (0); 104 } 105 106 void 107 control_shutdown(int fd) 108 { 109 close(fd); 110 } 111 112 void 113 control_cleanup(const char *path) 114 { 115 if (path) 116 unlink(path); 117 } 118 119 unsigned int 120 control_accept(int listenfd, int restricted) 121 { 122 int connfd; 123 socklen_t len; 124 struct sockaddr_un sun; 125 struct ctl_conn *ctl_conn; 126 127 len = sizeof(sun); 128 if ((connfd = accept4(listenfd, 129 (struct sockaddr *)&sun, &len, 130 SOCK_NONBLOCK | SOCK_CLOEXEC)) == -1) { 131 if (errno == ENFILE || errno == EMFILE) { 132 pauseaccept = getmonotime(); 133 return (0); 134 } else if (errno != EWOULDBLOCK && errno != EINTR && 135 errno != ECONNABORTED) 136 log_warn("control_accept: accept"); 137 return (0); 138 } 139 140 if ((ctl_conn = calloc(1, sizeof(struct ctl_conn))) == NULL) { 141 log_warn("control_accept"); 142 close(connfd); 143 return (0); 144 } 145 146 imsg_init(&ctl_conn->ibuf, connfd); 147 ctl_conn->restricted = restricted; 148 149 TAILQ_INSERT_TAIL(&ctl_conns, ctl_conn, entry); 150 151 return (1); 152 } 153 154 struct ctl_conn * 155 control_connbyfd(int fd) 156 { 157 struct ctl_conn *c; 158 159 TAILQ_FOREACH(c, &ctl_conns, entry) { 160 if (c->ibuf.fd == fd) 161 break; 162 } 163 164 return (c); 165 } 166 167 struct ctl_conn * 168 control_connbypid(pid_t pid) 169 { 170 struct ctl_conn *c; 171 172 TAILQ_FOREACH(c, &ctl_conns, entry) { 173 if (c->ibuf.pid == pid) 174 break; 175 } 176 177 return (c); 178 } 179 180 int 181 control_close(int fd) 182 { 183 struct ctl_conn *c; 184 185 if ((c = control_connbyfd(fd)) == NULL) { 186 log_warn("control_close: fd %d: not found", fd); 187 return (0); 188 } 189 190 msgbuf_clear(&c->ibuf.w); 191 TAILQ_REMOVE(&ctl_conns, c, entry); 192 193 close(c->ibuf.fd); 194 free(c); 195 pauseaccept = 0; 196 return (1); 197 } 198 199 int 200 control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) 201 { 202 struct imsg imsg; 203 struct ctl_conn *c; 204 ssize_t n; 205 int verbose; 206 struct peer *p; 207 struct ctl_neighbor *neighbor; 208 struct ctl_show_rib_request *ribreq; 209 210 if ((c = control_connbyfd(pfd->fd)) == NULL) { 211 log_warn("control_dispatch_msg: fd %d: not found", pfd->fd); 212 return (0); 213 } 214 215 if (pfd->revents & POLLOUT) 216 if (msgbuf_write(&c->ibuf.w) <= 0 && errno != EAGAIN) { 217 *ctl_cnt -= control_close(pfd->fd); 218 return (1); 219 } 220 221 if (!(pfd->revents & POLLIN)) 222 return (0); 223 224 if (((n = imsg_read_nofd(&c->ibuf)) == -1 && errno != EAGAIN) || 225 n == 0) { 226 *ctl_cnt -= control_close(pfd->fd); 227 return (1); 228 } 229 230 for (;;) { 231 if ((n = imsg_get(&c->ibuf, &imsg)) == -1) { 232 *ctl_cnt -= control_close(pfd->fd); 233 return (1); 234 } 235 236 if (n == 0) 237 break; 238 239 if (c->restricted) { 240 switch (imsg.hdr.type) { 241 case IMSG_CTL_SHOW_NEIGHBOR: 242 case IMSG_CTL_SHOW_NEXTHOP: 243 case IMSG_CTL_SHOW_INTERFACE: 244 case IMSG_CTL_SHOW_RIB: 245 case IMSG_CTL_SHOW_RIB_AS: 246 case IMSG_CTL_SHOW_RIB_PREFIX: 247 case IMSG_CTL_SHOW_RIB_MEM: 248 case IMSG_CTL_SHOW_RIB_COMMUNITY: 249 case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY: 250 case IMSG_CTL_SHOW_NETWORK: 251 case IMSG_CTL_SHOW_TERSE: 252 case IMSG_CTL_SHOW_TIMER: 253 break; 254 default: 255 /* clear imsg type to prevent processing */ 256 imsg.hdr.type = IMSG_NONE; 257 control_result(c, CTL_RES_DENIED); 258 break; 259 } 260 } 261 262 switch (imsg.hdr.type) { 263 case IMSG_NONE: 264 /* message was filtered out, nothing to do */ 265 break; 266 case IMSG_CTL_SHOW_NEIGHBOR: 267 c->ibuf.pid = imsg.hdr.pid; 268 if (imsg.hdr.len == IMSG_HEADER_SIZE + 269 sizeof(struct ctl_neighbor)) { 270 neighbor = imsg.data; 271 p = getpeerbyaddr(&neighbor->addr); 272 if (p == NULL) 273 p = getpeerbydesc(neighbor->descr); 274 if (p == NULL) { 275 control_result(c, CTL_RES_NOSUCHPEER); 276 break; 277 } 278 if (!neighbor->show_timers) { 279 imsg_ctl_rde(imsg.hdr.type, 280 imsg.hdr.pid, 281 p, sizeof(struct peer)); 282 imsg_ctl_rde(IMSG_CTL_END, 283 imsg.hdr.pid, NULL, 0); 284 } else { 285 u_int i; 286 time_t d; 287 struct ctl_timer ct; 288 289 imsg_compose(&c->ibuf, 290 IMSG_CTL_SHOW_NEIGHBOR, 291 0, 0, -1, p, sizeof(*p)); 292 for (i = 1; i < Timer_Max; i++) { 293 if (!timer_running(p, i, &d)) 294 continue; 295 ct.type = i; 296 ct.val = d; 297 imsg_compose(&c->ibuf, 298 IMSG_CTL_SHOW_TIMER, 299 0, 0, -1, &ct, sizeof(ct)); 300 } 301 imsg_compose(&c->ibuf, IMSG_CTL_END, 302 0, 0, -1, NULL, 0); 303 } 304 } else { 305 for (p = peers; p != NULL; p = p->next) 306 imsg_ctl_rde(imsg.hdr.type, 307 imsg.hdr.pid, 308 p, sizeof(struct peer)); 309 imsg_ctl_rde(IMSG_CTL_END, imsg.hdr.pid, 310 NULL, 0); 311 } 312 break; 313 case IMSG_CTL_SHOW_TERSE: 314 for (p = peers; p != NULL; p = p->next) 315 imsg_compose(&c->ibuf, IMSG_CTL_SHOW_NEIGHBOR, 316 0, 0, -1, p, sizeof(struct peer)); 317 imsg_compose(&c->ibuf, IMSG_CTL_END, 0, 0, -1, NULL, 0); 318 break; 319 case IMSG_CTL_FIB_COUPLE: 320 case IMSG_CTL_FIB_DECOUPLE: 321 imsg_ctl_parent(imsg.hdr.type, imsg.hdr.peerid, 322 0, NULL, 0); 323 break; 324 case IMSG_CTL_NEIGHBOR_UP: 325 case IMSG_CTL_NEIGHBOR_DOWN: 326 case IMSG_CTL_NEIGHBOR_CLEAR: 327 case IMSG_CTL_NEIGHBOR_RREFRESH: 328 case IMSG_CTL_NEIGHBOR_DESTROY: 329 if (imsg.hdr.len == IMSG_HEADER_SIZE + 330 sizeof(struct ctl_neighbor)) { 331 neighbor = imsg.data; 332 neighbor->descr[PEER_DESCR_LEN - 1] = 0; 333 p = getpeerbyaddr(&neighbor->addr); 334 if (p == NULL) 335 p = getpeerbydesc(neighbor->descr); 336 if (p == NULL) { 337 control_result(c, CTL_RES_NOSUCHPEER); 338 break; 339 } 340 switch (imsg.hdr.type) { 341 case IMSG_CTL_NEIGHBOR_UP: 342 bgp_fsm(p, EVNT_START); 343 p->conf.down = 0; 344 p->conf.shutcomm[0] = '\0'; 345 control_result(c, CTL_RES_OK); 346 break; 347 case IMSG_CTL_NEIGHBOR_DOWN: 348 p->conf.down = 1; 349 strlcpy(p->conf.shutcomm, 350 neighbor->shutcomm, 351 sizeof(neighbor->shutcomm)); 352 session_stop(p, ERR_CEASE_ADMIN_DOWN); 353 control_result(c, CTL_RES_OK); 354 break; 355 case IMSG_CTL_NEIGHBOR_CLEAR: 356 if (!p->conf.down) { 357 session_stop(p, 358 ERR_CEASE_ADMIN_RESET); 359 timer_set(p, Timer_IdleHold, 360 SESSION_CLEAR_DELAY); 361 } else { 362 session_stop(p, 363 ERR_CEASE_ADMIN_DOWN); 364 } 365 control_result(c, CTL_RES_OK); 366 break; 367 case IMSG_CTL_NEIGHBOR_RREFRESH: 368 if (session_neighbor_rrefresh(p)) 369 control_result(c, 370 CTL_RES_NOCAP); 371 else 372 control_result(c, CTL_RES_OK); 373 break; 374 case IMSG_CTL_NEIGHBOR_DESTROY: 375 if (!p->template) 376 control_result(c, 377 CTL_RES_BADPEER); 378 else if (p->state != STATE_IDLE) 379 control_result(c, 380 CTL_RES_BADSTATE); 381 else { 382 /* 383 * Mark as deleted, will be 384 * collected on next poll loop. 385 */ 386 p->conf.reconf_action = 387 RECONF_DELETE; 388 control_result(c, CTL_RES_OK); 389 } 390 break; 391 default: 392 fatal("king bula wants more humppa"); 393 } 394 } else 395 log_warnx("got IMSG_CTL_NEIGHBOR_ with " 396 "wrong length"); 397 break; 398 case IMSG_CTL_RELOAD: 399 case IMSG_CTL_SHOW_INTERFACE: 400 case IMSG_CTL_SHOW_FIB_TABLES: 401 c->ibuf.pid = imsg.hdr.pid; 402 imsg_ctl_parent(imsg.hdr.type, 0, imsg.hdr.pid, 403 imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 404 break; 405 case IMSG_CTL_KROUTE: 406 case IMSG_CTL_KROUTE_ADDR: 407 case IMSG_CTL_SHOW_NEXTHOP: 408 c->ibuf.pid = imsg.hdr.pid; 409 imsg_ctl_parent(imsg.hdr.type, imsg.hdr.peerid, 410 imsg.hdr.pid, imsg.data, imsg.hdr.len - 411 IMSG_HEADER_SIZE); 412 break; 413 case IMSG_CTL_SHOW_RIB: 414 case IMSG_CTL_SHOW_RIB_AS: 415 case IMSG_CTL_SHOW_RIB_PREFIX: 416 if (imsg.hdr.len == IMSG_HEADER_SIZE + 417 sizeof(struct ctl_show_rib_request)) { 418 ribreq = imsg.data; 419 neighbor = &ribreq->neighbor; 420 neighbor->descr[PEER_DESCR_LEN - 1] = 0; 421 ribreq->peerid = 0; 422 p = NULL; 423 if (neighbor->addr.aid) { 424 p = getpeerbyaddr(&neighbor->addr); 425 if (p == NULL) { 426 control_result(c, 427 CTL_RES_NOSUCHPEER); 428 break; 429 } 430 ribreq->peerid = p->conf.id; 431 } else if (neighbor->descr[0]) { 432 p = getpeerbydesc(neighbor->descr); 433 if (p == NULL) { 434 control_result(c, 435 CTL_RES_NOSUCHPEER); 436 break; 437 } 438 ribreq->peerid = p->conf.id; 439 } 440 if ((ribreq->flags & 441 (F_CTL_ADJ_OUT | F_CTL_ADJ_IN)) && !p) { 442 /* 443 * both in and out tables are only 444 * meaningful if used on a single 445 * peer. 446 */ 447 control_result(c, CTL_RES_NOSUCHPEER); 448 break; 449 } 450 if ((ribreq->flags & F_CTL_ADJ_IN) && p && 451 !p->conf.softreconfig_in) { 452 /* 453 * without softreconfig_in we do not 454 * have an Adj-RIB-In table 455 */ 456 control_result(c, CTL_RES_NOCAP); 457 break; 458 } 459 if ((imsg.hdr.type == IMSG_CTL_SHOW_RIB_PREFIX) 460 && (ribreq->prefix.aid == AID_UNSPEC)) { 461 /* malformed request, must specify af */ 462 control_result(c, CTL_RES_PARSE_ERROR); 463 break; 464 } 465 c->ibuf.pid = imsg.hdr.pid; 466 imsg_ctl_rde(imsg.hdr.type, imsg.hdr.pid, 467 imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 468 } else 469 log_warnx("got IMSG_CTL_SHOW_RIB with " 470 "wrong length"); 471 break; 472 case IMSG_CTL_SHOW_RIB_MEM: 473 case IMSG_CTL_SHOW_RIB_COMMUNITY: 474 case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY: 475 case IMSG_CTL_SHOW_NETWORK: 476 c->ibuf.pid = imsg.hdr.pid; 477 imsg_ctl_rde(imsg.hdr.type, imsg.hdr.pid, 478 imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 479 break; 480 case IMSG_NETWORK_ADD: 481 case IMSG_NETWORK_ASPATH: 482 case IMSG_NETWORK_ATTR: 483 case IMSG_NETWORK_REMOVE: 484 case IMSG_NETWORK_FLUSH: 485 case IMSG_NETWORK_DONE: 486 case IMSG_FILTER_SET: 487 imsg_ctl_rde(imsg.hdr.type, 0, 488 imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 489 break; 490 case IMSG_CTL_LOG_VERBOSE: 491 if (imsg.hdr.len != IMSG_HEADER_SIZE + 492 sizeof(verbose)) 493 break; 494 495 /* forward to other processes */ 496 imsg_ctl_parent(imsg.hdr.type, 0, imsg.hdr.pid, 497 imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 498 imsg_ctl_rde(imsg.hdr.type, 0, 499 imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); 500 501 memcpy(&verbose, imsg.data, sizeof(verbose)); 502 log_verbose(verbose); 503 break; 504 default: 505 break; 506 } 507 imsg_free(&imsg); 508 } 509 510 return (0); 511 } 512 513 int 514 control_imsg_relay(struct imsg *imsg) 515 { 516 struct ctl_conn *c; 517 518 if ((c = control_connbypid(imsg->hdr.pid)) == NULL) 519 return (0); 520 521 return (imsg_compose(&c->ibuf, imsg->hdr.type, 0, imsg->hdr.pid, -1, 522 imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); 523 } 524 525 void 526 control_result(struct ctl_conn *c, u_int code) 527 { 528 imsg_compose(&c->ibuf, IMSG_CTL_RESULT, 0, c->ibuf.pid, -1, 529 &code, sizeof(code)); 530 } 531 532 /* This should go into libutil, from smtpd/mproc.c */ 533 ssize_t 534 imsg_read_nofd(struct imsgbuf *ibuf) 535 { 536 ssize_t n; 537 char *buf; 538 size_t len; 539 540 buf = ibuf->r.buf + ibuf->r.wpos; 541 len = sizeof(ibuf->r.buf) - ibuf->r.wpos; 542 543 while ((n = recv(ibuf->fd, buf, len, 0)) == -1) { 544 if (errno != EINTR) 545 return (n); 546 } 547 548 ibuf->r.wpos += n; 549 return (n); 550 } 551