1 /* $OpenBSD: bgpctl.c,v 1.270 2021/07/20 12:08:53 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 2004-2019 Claudio Jeker <claudio@openbsd.org> 6 * Copyright (c) 2016 Job Snijders <job@instituut.net> 7 * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/types.h> 23 #include <sys/socket.h> 24 #include <sys/stat.h> 25 #include <sys/un.h> 26 27 #include <endian.h> 28 #include <err.h> 29 #include <errno.h> 30 #include <fcntl.h> 31 #include <math.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <time.h> 36 #include <unistd.h> 37 #include <util.h> 38 39 #include "bgpd.h" 40 #include "session.h" 41 #include "rde.h" 42 #include "version.h" 43 44 #include "bgpctl.h" 45 #include "parser.h" 46 #include "mrtparser.h" 47 48 int main(int, char *[]); 49 int show(struct imsg *, struct parse_result *); 50 void send_filterset(struct imsgbuf *, struct filter_set_head *); 51 void show_mrt_dump_neighbors(struct mrt_rib *, struct mrt_peer *, 52 void *); 53 void show_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); 54 void network_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); 55 void show_mrt_state(struct mrt_bgp_state *, void *); 56 void show_mrt_msg(struct mrt_bgp_msg *, void *); 57 const char *msg_type(u_int8_t); 58 void network_bulk(struct parse_result *); 59 int match_aspath(void *, u_int16_t, struct filter_as *); 60 61 struct imsgbuf *ibuf; 62 struct mrt_parser show_mrt = { show_mrt_dump, show_mrt_state, show_mrt_msg }; 63 struct mrt_parser net_mrt = { network_mrt_dump, NULL, NULL }; 64 const struct output *output = &show_output; 65 int tableid; 66 int nodescr; 67 68 __dead void 69 usage(void) 70 { 71 extern char *__progname; 72 73 fprintf(stderr, "usage: %s [-jnV] [-s socket] command [argument ...]\n", 74 __progname); 75 exit(1); 76 } 77 78 int 79 main(int argc, char *argv[]) 80 { 81 struct sockaddr_un sun; 82 int fd, n, done, ch, verbose = 0; 83 struct imsg imsg; 84 struct network_config net; 85 struct parse_result *res; 86 struct ctl_neighbor neighbor; 87 struct ctl_show_rib_request ribreq; 88 char *sockname; 89 enum imsg_type type; 90 91 if (pledge("stdio rpath wpath cpath unix inet dns", NULL) == -1) 92 err(1, "pledge"); 93 94 tableid = getrtable(); 95 if (asprintf(&sockname, "%s.%d", SOCKET_NAME, tableid) == -1) 96 err(1, "asprintf"); 97 98 while ((ch = getopt(argc, argv, "jns:V")) != -1) { 99 switch (ch) { 100 case 'n': 101 if (++nodescr > 1) 102 usage(); 103 break; 104 case 'j': 105 output = &json_output; 106 break; 107 case 's': 108 sockname = optarg; 109 break; 110 case 'V': 111 fprintf(stderr, "OpenBGPD %s\n", BGPD_VERSION); 112 return 0; 113 default: 114 usage(); 115 /* NOTREACHED */ 116 } 117 } 118 argc -= optind; 119 argv += optind; 120 121 if ((res = parse(argc, argv)) == NULL) 122 exit(1); 123 124 memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr)); 125 strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr)); 126 neighbor.is_group = res->is_group; 127 strlcpy(neighbor.reason, res->reason, sizeof(neighbor.reason)); 128 129 switch (res->action) { 130 case SHOW_MRT: 131 if (pledge("stdio", NULL) == -1) 132 err(1, "pledge"); 133 134 bzero(&ribreq, sizeof(ribreq)); 135 if (res->as.type != AS_UNDEF) 136 ribreq.as = res->as; 137 if (res->addr.aid) { 138 ribreq.prefix = res->addr; 139 ribreq.prefixlen = res->prefixlen; 140 } 141 /* XXX currently no communities support */ 142 ribreq.neighbor = neighbor; 143 ribreq.aid = res->aid; 144 ribreq.flags = res->flags; 145 ribreq.validation_state = res->validation_state; 146 show_mrt.arg = &ribreq; 147 if (res->flags & F_CTL_NEIGHBORS) 148 show_mrt.dump = show_mrt_dump_neighbors; 149 else 150 output->head(res); 151 mrt_parse(res->mrtfd, &show_mrt, 1); 152 exit(0); 153 default: 154 break; 155 } 156 157 if (pledge("stdio unix", NULL) == -1) 158 err(1, "pledge"); 159 160 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 161 err(1, "control_init: socket"); 162 163 bzero(&sun, sizeof(sun)); 164 sun.sun_family = AF_UNIX; 165 if (strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)) >= 166 sizeof(sun.sun_path)) 167 errx(1, "socket name too long"); 168 if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) 169 err(1, "connect: %s", sockname); 170 171 if (pledge("stdio", NULL) == -1) 172 err(1, "pledge"); 173 174 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 175 err(1, NULL); 176 imsg_init(ibuf, fd); 177 done = 0; 178 179 switch (res->action) { 180 case NONE: 181 case SHOW_MRT: 182 usage(); 183 /* NOTREACHED */ 184 case SHOW: 185 case SHOW_SUMMARY: 186 imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, NULL, 0); 187 break; 188 case SHOW_SUMMARY_TERSE: 189 imsg_compose(ibuf, IMSG_CTL_SHOW_TERSE, 0, 0, -1, NULL, 0); 190 break; 191 case SHOW_FIB: 192 if (!res->addr.aid) { 193 struct ibuf *msg; 194 sa_family_t af; 195 196 af = aid2af(res->aid); 197 if ((msg = imsg_create(ibuf, IMSG_CTL_KROUTE, 198 res->rtableid, 0, sizeof(res->flags) + 199 sizeof(af))) == NULL) 200 errx(1, "imsg_create failure"); 201 if (imsg_add(msg, &res->flags, sizeof(res->flags)) == 202 -1 || 203 imsg_add(msg, &af, sizeof(af)) == -1) 204 errx(1, "imsg_add failure"); 205 imsg_close(ibuf, msg); 206 } else 207 imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, res->rtableid, 208 0, -1, &res->addr, sizeof(res->addr)); 209 break; 210 case SHOW_FIB_TABLES: 211 imsg_compose(ibuf, IMSG_CTL_SHOW_FIB_TABLES, 0, 0, -1, NULL, 0); 212 break; 213 case SHOW_NEXTHOP: 214 imsg_compose(ibuf, IMSG_CTL_SHOW_NEXTHOP, res->rtableid, 0, -1, 215 NULL, 0); 216 break; 217 case SHOW_INTERFACE: 218 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, NULL, 0); 219 break; 220 case SHOW_SET: 221 imsg_compose(ibuf, IMSG_CTL_SHOW_SET, 0, 0, -1, NULL, 0); 222 break; 223 case SHOW_RTR: 224 imsg_compose(ibuf, IMSG_CTL_SHOW_RTR, 0, 0, -1, NULL, 0); 225 break; 226 case SHOW_NEIGHBOR: 227 case SHOW_NEIGHBOR_TIMERS: 228 case SHOW_NEIGHBOR_TERSE: 229 neighbor.show_timers = (res->action == SHOW_NEIGHBOR_TIMERS); 230 if (res->peeraddr.aid || res->peerdesc[0]) 231 imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, 232 &neighbor, sizeof(neighbor)); 233 else 234 imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, 235 NULL, 0); 236 break; 237 case SHOW_RIB: 238 bzero(&ribreq, sizeof(ribreq)); 239 type = IMSG_CTL_SHOW_RIB; 240 if (res->addr.aid) { 241 ribreq.prefix = res->addr; 242 ribreq.prefixlen = res->prefixlen; 243 type = IMSG_CTL_SHOW_RIB_PREFIX; 244 } 245 if (res->as.type != AS_UNDEF) 246 ribreq.as = res->as; 247 if (res->community.flags != 0) 248 ribreq.community = res->community; 249 ribreq.neighbor = neighbor; 250 strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); 251 ribreq.aid = res->aid; 252 ribreq.flags = res->flags; 253 imsg_compose(ibuf, type, 0, 0, -1, &ribreq, sizeof(ribreq)); 254 break; 255 case SHOW_RIB_MEM: 256 imsg_compose(ibuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0); 257 break; 258 case RELOAD: 259 imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, 260 res->reason, sizeof(res->reason)); 261 if (res->reason[0]) 262 printf("reload request sent: %s\n", res->reason); 263 else 264 printf("reload request sent.\n"); 265 break; 266 case FIB: 267 errx(1, "action==FIB"); 268 break; 269 case FIB_COUPLE: 270 imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, res->rtableid, 0, -1, 271 NULL, 0); 272 printf("couple request sent.\n"); 273 done = 1; 274 break; 275 case FIB_DECOUPLE: 276 imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, res->rtableid, 0, -1, 277 NULL, 0); 278 printf("decouple request sent.\n"); 279 done = 1; 280 break; 281 case NEIGHBOR: 282 errx(1, "action==NEIGHBOR"); 283 break; 284 case NEIGHBOR_UP: 285 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_UP, 0, 0, -1, 286 &neighbor, sizeof(neighbor)); 287 break; 288 case NEIGHBOR_DOWN: 289 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DOWN, 0, 0, -1, 290 &neighbor, sizeof(neighbor)); 291 break; 292 case NEIGHBOR_CLEAR: 293 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_CLEAR, 0, 0, -1, 294 &neighbor, sizeof(neighbor)); 295 break; 296 case NEIGHBOR_RREFRESH: 297 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_RREFRESH, 0, 0, -1, 298 &neighbor, sizeof(neighbor)); 299 break; 300 case NEIGHBOR_DESTROY: 301 imsg_compose(ibuf, IMSG_CTL_NEIGHBOR_DESTROY, 0, 0, -1, 302 &neighbor, sizeof(neighbor)); 303 break; 304 case NETWORK_BULK_ADD: 305 case NETWORK_BULK_REMOVE: 306 network_bulk(res); 307 printf("requests sent.\n"); 308 done = 1; 309 break; 310 case NETWORK_ADD: 311 case NETWORK_REMOVE: 312 bzero(&net, sizeof(net)); 313 net.prefix = res->addr; 314 net.prefixlen = res->prefixlen; 315 net.rd = res->rd; 316 /* attribute sets are not supported */ 317 if (res->action == NETWORK_ADD) { 318 imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1, 319 &net, sizeof(net)); 320 send_filterset(ibuf, &res->set); 321 imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, 322 NULL, 0); 323 } else 324 imsg_compose(ibuf, IMSG_NETWORK_REMOVE, 0, 0, -1, 325 &net, sizeof(net)); 326 printf("request sent.\n"); 327 done = 1; 328 break; 329 case NETWORK_FLUSH: 330 imsg_compose(ibuf, IMSG_NETWORK_FLUSH, 0, 0, -1, NULL, 0); 331 printf("request sent.\n"); 332 done = 1; 333 break; 334 case NETWORK_SHOW: 335 bzero(&ribreq, sizeof(ribreq)); 336 ribreq.aid = res->aid; 337 strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); 338 imsg_compose(ibuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1, 339 &ribreq, sizeof(ribreq)); 340 break; 341 case NETWORK_MRT: 342 bzero(&ribreq, sizeof(ribreq)); 343 if (res->as.type != AS_UNDEF) 344 ribreq.as = res->as; 345 if (res->addr.aid) { 346 ribreq.prefix = res->addr; 347 ribreq.prefixlen = res->prefixlen; 348 } 349 /* XXX currently no community support */ 350 ribreq.neighbor = neighbor; 351 ribreq.aid = res->aid; 352 ribreq.flags = res->flags; 353 net_mrt.arg = &ribreq; 354 mrt_parse(res->mrtfd, &net_mrt, 1); 355 done = 1; 356 break; 357 case LOG_VERBOSE: 358 verbose = 1; 359 /* FALLTHROUGH */ 360 case LOG_BRIEF: 361 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 362 &verbose, sizeof(verbose)); 363 printf("logging request sent.\n"); 364 done = 1; 365 break; 366 } 367 368 while (ibuf->w.queued) 369 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 370 err(1, "write error"); 371 372 output->head(res); 373 374 while (!done) { 375 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 376 err(1, "imsg_read error"); 377 if (n == 0) 378 errx(1, "pipe closed"); 379 380 while (!done) { 381 if ((n = imsg_get(ibuf, &imsg)) == -1) 382 err(1, "imsg_get error"); 383 if (n == 0) 384 break; 385 386 done = show(&imsg, res); 387 imsg_free(&imsg); 388 } 389 } 390 391 output->tail(); 392 393 close(fd); 394 free(ibuf); 395 396 exit(0); 397 } 398 399 int 400 show(struct imsg *imsg, struct parse_result *res) 401 { 402 struct peer *p; 403 struct ctl_timer t; 404 struct ctl_show_interface *iface; 405 struct ctl_show_nexthop *nh; 406 struct ctl_show_set set; 407 struct ctl_show_rtr rtr; 408 struct kroute_full *kf; 409 struct ktable *kt; 410 struct ctl_show_rib rib; 411 struct rde_memstats stats; 412 struct rde_hashstats hash; 413 u_char *asdata; 414 u_int rescode, ilen; 415 size_t aslen; 416 417 switch (imsg->hdr.type) { 418 case IMSG_CTL_SHOW_NEIGHBOR: 419 p = imsg->data; 420 output->neighbor(p, res); 421 break; 422 case IMSG_CTL_SHOW_TIMER: 423 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(t)) 424 errx(1, "wrong imsg len"); 425 memcpy(&t, imsg->data, sizeof(t)); 426 if (t.type > 0 && t.type < Timer_Max) 427 output->timer(&t); 428 break; 429 case IMSG_CTL_SHOW_INTERFACE: 430 iface = imsg->data; 431 output->interface(iface); 432 break; 433 case IMSG_CTL_SHOW_NEXTHOP: 434 nh = imsg->data; 435 output->nexthop(nh); 436 break; 437 case IMSG_CTL_KROUTE: 438 case IMSG_CTL_SHOW_NETWORK: 439 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kf)) 440 errx(1, "wrong imsg len"); 441 kf = imsg->data; 442 output->fib(kf); 443 break; 444 case IMSG_CTL_SHOW_FIB_TABLES: 445 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kt)) 446 errx(1, "wrong imsg len"); 447 kt = imsg->data; 448 output->fib_table(kt); 449 break; 450 case IMSG_CTL_SHOW_RIB: 451 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(rib)) 452 errx(1, "wrong imsg len"); 453 memcpy(&rib, imsg->data, sizeof(rib)); 454 aslen = imsg->hdr.len - IMSG_HEADER_SIZE - sizeof(rib); 455 asdata = imsg->data; 456 asdata += sizeof(rib); 457 output->rib(&rib, asdata, aslen, res); 458 break; 459 case IMSG_CTL_SHOW_RIB_COMMUNITIES: 460 ilen = imsg->hdr.len - IMSG_HEADER_SIZE; 461 if (ilen % sizeof(struct community)) { 462 warnx("bad IMSG_CTL_SHOW_RIB_COMMUNITIES received"); 463 break; 464 } 465 output->communities(imsg->data, ilen, res); 466 break; 467 case IMSG_CTL_SHOW_RIB_ATTR: 468 ilen = imsg->hdr.len - IMSG_HEADER_SIZE; 469 if (ilen < 3) { 470 warnx("bad IMSG_CTL_SHOW_RIB_ATTR received"); 471 break; 472 } 473 output->attr(imsg->data, ilen, res->flags); 474 break; 475 case IMSG_CTL_SHOW_RIB_MEM: 476 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(stats)) 477 errx(1, "wrong imsg len"); 478 memcpy(&stats, imsg->data, sizeof(stats)); 479 output->rib_mem(&stats); 480 break; 481 case IMSG_CTL_SHOW_RIB_HASH: 482 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(hash)) 483 errx(1, "wrong imsg len"); 484 memcpy(&hash, imsg->data, sizeof(hash)); 485 output->rib_hash(&hash); 486 break; 487 case IMSG_CTL_SHOW_SET: 488 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(set)) 489 errx(1, "wrong imsg len"); 490 memcpy(&set, imsg->data, sizeof(set)); 491 output->set(&set); 492 break; 493 case IMSG_CTL_SHOW_RTR: 494 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(rtr)) 495 errx(1, "wrong imsg len"); 496 memcpy(&rtr, imsg->data, sizeof(rtr)); 497 output->rtr(&rtr); 498 break; 499 case IMSG_CTL_RESULT: 500 if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(rescode)) { 501 warnx("got IMSG_CTL_RESULT with wrong len"); 502 break; 503 } 504 memcpy(&rescode, imsg->data, sizeof(rescode)); 505 output->result(rescode); 506 return (1); 507 case IMSG_CTL_END: 508 return (1); 509 default: 510 warnx("unknown imsg %d received", imsg->hdr.type); 511 break; 512 } 513 514 return (0); 515 } 516 517 time_t 518 get_monotime(time_t t) 519 { 520 struct timespec ts; 521 522 if (t == 0) 523 return -1; 524 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) 525 err(1, "clock_gettime"); 526 if (t > ts.tv_sec) /* time in the future is not possible */ 527 t = ts.tv_sec; 528 return (ts.tv_sec - t); 529 } 530 531 char * 532 fmt_peer(const char *descr, const struct bgpd_addr *remote_addr, 533 int masklen) 534 { 535 const char *ip; 536 char *p; 537 538 if (descr && descr[0] && !nodescr) { 539 if ((p = strdup(descr)) == NULL) 540 err(1, NULL); 541 return (p); 542 } 543 544 ip = log_addr(remote_addr); 545 if (masklen != -1 && ((remote_addr->aid == AID_INET && masklen != 32) || 546 (remote_addr->aid == AID_INET6 && masklen != 128))) { 547 if (asprintf(&p, "%s/%u", ip, masklen) == -1) 548 err(1, NULL); 549 } else { 550 if ((p = strdup(ip)) == NULL) 551 err(1, NULL); 552 } 553 554 return (p); 555 } 556 557 const char * 558 fmt_auth_method(enum auth_method method) 559 { 560 switch (method) { 561 case AUTH_MD5SIG: 562 return ", using md5sig"; 563 case AUTH_IPSEC_MANUAL_ESP: 564 return ", using ipsec manual esp"; 565 case AUTH_IPSEC_MANUAL_AH: 566 return ", using ipsec manual ah"; 567 case AUTH_IPSEC_IKE_ESP: 568 return ", using ipsec ike esp"; 569 case AUTH_IPSEC_IKE_AH: 570 return ", using ipsec ike ah"; 571 case AUTH_NONE: /* FALLTHROUGH */ 572 default: 573 return ""; 574 } 575 } 576 577 #define TF_BUFS 8 578 #define TF_LEN 9 579 580 const char * 581 fmt_timeframe(time_t t) 582 { 583 char *buf; 584 static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ 585 static int idx = 0; 586 unsigned int sec, min, hrs, day; 587 unsigned long long week; 588 589 buf = tfbuf[idx++]; 590 if (idx == TF_BUFS) 591 idx = 0; 592 593 week = t; 594 595 sec = week % 60; 596 week /= 60; 597 min = week % 60; 598 week /= 60; 599 hrs = week % 24; 600 week /= 24; 601 day = week % 7; 602 week /= 7; 603 604 if (week > 0) 605 snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs); 606 else if (day > 0) 607 snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 608 else 609 snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 610 611 return (buf); 612 } 613 614 const char * 615 fmt_monotime(time_t t) 616 { 617 t = get_monotime(t); 618 619 if (t == -1) 620 return ("Never"); 621 622 return (fmt_timeframe(t)); 623 } 624 625 const char * 626 fmt_fib_flags(u_int16_t flags) 627 { 628 static char buf[8]; 629 630 if (flags & F_DOWN) 631 strlcpy(buf, " ", sizeof(buf)); 632 else 633 strlcpy(buf, "*", sizeof(buf)); 634 635 if (flags & F_BGPD_INSERTED) 636 strlcat(buf, "B", sizeof(buf)); 637 else if (flags & F_CONNECTED) 638 strlcat(buf, "C", sizeof(buf)); 639 else if (flags & F_STATIC) 640 strlcat(buf, "S", sizeof(buf)); 641 else if (flags & F_DYNAMIC) 642 strlcat(buf, "D", sizeof(buf)); 643 else 644 strlcat(buf, " ", sizeof(buf)); 645 646 if (flags & F_NEXTHOP) 647 strlcat(buf, "N", sizeof(buf)); 648 else 649 strlcat(buf, " ", sizeof(buf)); 650 651 if (flags & F_REJECT && flags & F_BLACKHOLE) 652 strlcat(buf, "f", sizeof(buf)); 653 else if (flags & F_REJECT) 654 strlcat(buf, "r", sizeof(buf)); 655 else if (flags & F_BLACKHOLE) 656 strlcat(buf, "b", sizeof(buf)); 657 else 658 strlcat(buf, " ", sizeof(buf)); 659 660 if (strlcat(buf, " ", sizeof(buf)) >= sizeof(buf)) 661 errx(1, "%s buffer too small", __func__); 662 663 return buf; 664 } 665 666 const char * 667 fmt_origin(u_int8_t origin, int sum) 668 { 669 switch (origin) { 670 case ORIGIN_IGP: 671 return (sum ? "i" : "IGP"); 672 case ORIGIN_EGP: 673 return (sum ? "e" : "EGP"); 674 case ORIGIN_INCOMPLETE: 675 return (sum ? "?" : "incomplete"); 676 default: 677 return (sum ? "X" : "bad origin"); 678 } 679 } 680 681 const char * 682 fmt_flags(u_int8_t flags, int sum) 683 { 684 static char buf[80]; 685 char flagstr[5]; 686 char *p = flagstr; 687 688 if (sum) { 689 if (flags & F_PREF_INVALID) 690 *p++ = 'E'; 691 if (flags & F_PREF_ANNOUNCE) 692 *p++ = 'A'; 693 if (flags & F_PREF_INTERNAL) 694 *p++ = 'I'; 695 if (flags & F_PREF_STALE) 696 *p++ = 'S'; 697 if (flags & F_PREF_ELIGIBLE) 698 *p++ = '*'; 699 if (flags & F_PREF_ACTIVE) 700 *p++ = '>'; 701 *p = '\0'; 702 snprintf(buf, sizeof(buf), "%-5s", flagstr); 703 } else { 704 if (flags & F_PREF_INTERNAL) 705 strlcpy(buf, "internal", sizeof(buf)); 706 else 707 strlcpy(buf, "external", sizeof(buf)); 708 709 if (flags & F_PREF_STALE) 710 strlcat(buf, ", stale", sizeof(buf)); 711 if (flags & F_PREF_ELIGIBLE) 712 strlcat(buf, ", valid", sizeof(buf)); 713 if (flags & F_PREF_ACTIVE) 714 strlcat(buf, ", best", sizeof(buf)); 715 if (flags & F_PREF_ANNOUNCE) 716 strlcat(buf, ", announced", sizeof(buf)); 717 if (strlen(buf) >= sizeof(buf) - 1) 718 errx(1, "%s buffer too small", __func__); 719 } 720 721 return buf; 722 } 723 724 const char * 725 fmt_ovs(u_int8_t validation_state, int sum) 726 { 727 switch (validation_state) { 728 case ROA_INVALID: 729 return (sum ? "!" : "invalid"); 730 case ROA_VALID: 731 return (sum ? "V" : "valid"); 732 default: 733 return (sum ? "N" : "not-found"); 734 } 735 } 736 737 const char * 738 fmt_mem(long long num) 739 { 740 static char buf[16]; 741 742 if (fmt_scaled(num, buf) == -1) 743 snprintf(buf, sizeof(buf), "%lldB", num); 744 745 return (buf); 746 } 747 748 const char * 749 fmt_errstr(u_int8_t errcode, u_int8_t subcode) 750 { 751 static char errbuf[256]; 752 const char *errstr = NULL; 753 const char *suberr = NULL; 754 int uk = 0; 755 756 if (errcode == 0) /* no error */ 757 return NULL; 758 759 if (errcode < sizeof(errnames)/sizeof(char *)) 760 errstr = errnames[errcode]; 761 762 switch (errcode) { 763 case ERR_HEADER: 764 if (subcode < sizeof(suberr_header_names)/sizeof(char *)) 765 suberr = suberr_header_names[subcode]; 766 else 767 uk = 1; 768 break; 769 case ERR_OPEN: 770 if (subcode < sizeof(suberr_open_names)/sizeof(char *)) 771 suberr = suberr_open_names[subcode]; 772 else 773 uk = 1; 774 break; 775 case ERR_UPDATE: 776 if (subcode < sizeof(suberr_update_names)/sizeof(char *)) 777 suberr = suberr_update_names[subcode]; 778 else 779 uk = 1; 780 break; 781 case ERR_HOLDTIMEREXPIRED: 782 if (subcode != 0) 783 uk = 1; 784 break; 785 case ERR_FSM: 786 if (subcode < sizeof(suberr_fsm_names)/sizeof(char *)) 787 suberr = suberr_fsm_names[subcode]; 788 else 789 uk = 1; 790 break; 791 case ERR_CEASE: 792 if (subcode < sizeof(suberr_cease_names)/sizeof(char *)) 793 suberr = suberr_cease_names[subcode]; 794 else 795 uk = 1; 796 break; 797 default: 798 snprintf(errbuf, sizeof(errbuf), 799 "unknown error code %u subcode %u", errcode, subcode); 800 return (errbuf); 801 } 802 803 if (uk) 804 snprintf(errbuf, sizeof(errbuf), 805 "%s, unknown subcode %u", errstr, subcode); 806 else if (suberr == NULL) 807 return (errstr); 808 else 809 snprintf(errbuf, sizeof(errbuf), 810 "%s, %s", errstr, suberr); 811 812 return (errbuf); 813 } 814 815 const char * 816 fmt_attr(u_int8_t type, int flags) 817 { 818 #define CHECK_FLAGS(s, t, m) \ 819 if (((s) & ~(ATTR_DEFMASK | (m))) != (t)) pflags = 1 820 821 static char cstr[48]; 822 int pflags = 0; 823 824 switch (type) { 825 case ATTR_ORIGIN: 826 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 827 strlcpy(cstr, "Origin", sizeof(cstr)); 828 break; 829 case ATTR_ASPATH: 830 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 831 strlcpy(cstr, "AS-Path", sizeof(cstr)); 832 break; 833 case ATTR_AS4_PATH: 834 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 835 strlcpy(cstr, "AS4-Path", sizeof(cstr)); 836 break; 837 case ATTR_NEXTHOP: 838 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 839 strlcpy(cstr, "Nexthop", sizeof(cstr)); 840 break; 841 case ATTR_MED: 842 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 843 strlcpy(cstr, "Med", sizeof(cstr)); 844 break; 845 case ATTR_LOCALPREF: 846 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 847 strlcpy(cstr, "Localpref", sizeof(cstr)); 848 break; 849 case ATTR_ATOMIC_AGGREGATE: 850 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 851 strlcpy(cstr, "Atomic Aggregate", sizeof(cstr)); 852 break; 853 case ATTR_AGGREGATOR: 854 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 855 strlcpy(cstr, "Aggregator", sizeof(cstr)); 856 break; 857 case ATTR_AS4_AGGREGATOR: 858 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 859 strlcpy(cstr, "AS4-Aggregator", sizeof(cstr)); 860 break; 861 case ATTR_COMMUNITIES: 862 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 863 strlcpy(cstr, "Communities", sizeof(cstr)); 864 break; 865 case ATTR_ORIGINATOR_ID: 866 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 867 strlcpy(cstr, "Originator Id", sizeof(cstr)); 868 break; 869 case ATTR_CLUSTER_LIST: 870 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 871 strlcpy(cstr, "Cluster Id List", sizeof(cstr)); 872 break; 873 case ATTR_MP_REACH_NLRI: 874 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 875 strlcpy(cstr, "MP Reach NLRI", sizeof(cstr)); 876 break; 877 case ATTR_MP_UNREACH_NLRI: 878 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 879 strlcpy(cstr, "MP Unreach NLRI", sizeof(cstr)); 880 break; 881 case ATTR_EXT_COMMUNITIES: 882 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 883 strlcpy(cstr, "Ext. Communities", sizeof(cstr)); 884 break; 885 case ATTR_LARGE_COMMUNITIES: 886 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 887 strlcpy(cstr, "Large Communities", sizeof(cstr)); 888 break; 889 default: 890 /* ignore unknown attributes */ 891 snprintf(cstr, sizeof(cstr), "Unknown Attribute #%u", type); 892 pflags = 1; 893 break; 894 } 895 if (flags != -1 && pflags) { 896 strlcat(cstr, " flags [", sizeof(cstr)); 897 if (flags & ATTR_OPTIONAL) 898 strlcat(cstr, "O", sizeof(cstr)); 899 if (flags & ATTR_TRANSITIVE) 900 strlcat(cstr, "T", sizeof(cstr)); 901 if (flags & ATTR_PARTIAL) 902 strlcat(cstr, "P", sizeof(cstr)); 903 strlcat(cstr, "]", sizeof(cstr)); 904 } 905 return (cstr); 906 907 #undef CHECK_FLAGS 908 } 909 910 const char * 911 fmt_community(u_int16_t a, u_int16_t v) 912 { 913 static char buf[12]; 914 915 if (a == COMMUNITY_WELLKNOWN) 916 switch (v) { 917 case COMMUNITY_GRACEFUL_SHUTDOWN: 918 return "GRACEFUL_SHUTDOWN"; 919 case COMMUNITY_NO_EXPORT: 920 return "NO_EXPORT"; 921 case COMMUNITY_NO_ADVERTISE: 922 return "NO_ADVERTISE"; 923 case COMMUNITY_NO_EXPSUBCONFED: 924 return "NO_EXPORT_SUBCONFED"; 925 case COMMUNITY_NO_PEER: 926 return "NO_PEER"; 927 case COMMUNITY_BLACKHOLE: 928 return "BLACKHOLE"; 929 default: 930 break; 931 } 932 933 snprintf(buf, sizeof(buf), "%hu:%hu", a, v); 934 return buf; 935 } 936 937 const char * 938 fmt_large_community(u_int32_t d1, u_int32_t d2, u_int32_t d3) 939 { 940 static char buf[33]; 941 942 snprintf(buf, sizeof(buf), "%u:%u:%u", d1, d2, d3); 943 return buf; 944 } 945 946 const char * 947 fmt_ext_community(u_int8_t *data) 948 { 949 static char buf[32]; 950 u_int64_t ext; 951 struct in_addr ip; 952 u_int32_t as4, u32; 953 u_int16_t as2, u16; 954 u_int8_t type, subtype; 955 956 type = data[0]; 957 subtype = data[1]; 958 959 switch (type) { 960 case EXT_COMMUNITY_TRANS_TWO_AS: 961 memcpy(&as2, data + 2, sizeof(as2)); 962 memcpy(&u32, data + 4, sizeof(u32)); 963 snprintf(buf, sizeof(buf), "%s %s:%u", 964 log_ext_subtype(type, subtype), 965 log_as(ntohs(as2)), ntohl(u32)); 966 return buf; 967 case EXT_COMMUNITY_TRANS_IPV4: 968 memcpy(&ip, data + 2, sizeof(ip)); 969 memcpy(&u16, data + 6, sizeof(u16)); 970 snprintf(buf, sizeof(buf), "%s %s:%hu", 971 log_ext_subtype(type, subtype), 972 inet_ntoa(ip), ntohs(u16)); 973 return buf; 974 case EXT_COMMUNITY_TRANS_FOUR_AS: 975 memcpy(&as4, data + 2, sizeof(as4)); 976 memcpy(&u16, data + 6, sizeof(u16)); 977 snprintf(buf, sizeof(buf), "%s %s:%hu", 978 log_ext_subtype(type, subtype), 979 log_as(ntohl(as4)), ntohs(u16)); 980 return buf; 981 case EXT_COMMUNITY_TRANS_OPAQUE: 982 case EXT_COMMUNITY_TRANS_EVPN: 983 memcpy(&ext, data, sizeof(ext)); 984 ext = be64toh(ext) & 0xffffffffffffLL; 985 snprintf(buf, sizeof(buf), "%s 0x%llx", 986 log_ext_subtype(type, subtype), (unsigned long long)ext); 987 return buf; 988 case EXT_COMMUNITY_NON_TRANS_OPAQUE: 989 memcpy(&ext, data, sizeof(ext)); 990 ext = be64toh(ext) & 0xffffffffffffLL; 991 switch (ext) { 992 case EXT_COMMUNITY_OVS_VALID: 993 snprintf(buf, sizeof(buf), "%s valid ", 994 log_ext_subtype(type, subtype)); 995 return buf; 996 case EXT_COMMUNITY_OVS_NOTFOUND: 997 snprintf(buf, sizeof(buf), "%s not-found ", 998 log_ext_subtype(type, subtype)); 999 return buf; 1000 case EXT_COMMUNITY_OVS_INVALID: 1001 snprintf(buf, sizeof(buf), "%s invalid ", 1002 log_ext_subtype(type, subtype)); 1003 return buf; 1004 default: 1005 snprintf(buf, sizeof(buf), "%s 0x%llx ", 1006 log_ext_subtype(type, subtype), 1007 (unsigned long long)ext); 1008 return buf; 1009 } 1010 break; 1011 default: 1012 memcpy(&ext, data, sizeof(ext)); 1013 snprintf(buf, sizeof(buf), "%s 0x%llx", 1014 log_ext_subtype(type, subtype), 1015 (unsigned long long)be64toh(ext)); 1016 return buf; 1017 } 1018 } 1019 1020 const char * 1021 fmt_set_type(struct ctl_show_set *set) 1022 { 1023 switch (set->type) { 1024 case ROA_SET: 1025 return "ROA"; 1026 case PREFIX_SET: 1027 return "PREFIX"; 1028 case ORIGIN_SET: 1029 return "ORIGIN"; 1030 case ASNUM_SET: 1031 return "ASNUM"; 1032 default: 1033 return "BULA"; 1034 } 1035 } 1036 1037 void 1038 send_filterset(struct imsgbuf *i, struct filter_set_head *set) 1039 { 1040 struct filter_set *s; 1041 1042 while ((s = TAILQ_FIRST(set)) != NULL) { 1043 imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s, 1044 sizeof(struct filter_set)); 1045 TAILQ_REMOVE(set, s, entry); 1046 free(s); 1047 } 1048 } 1049 1050 void 1051 network_bulk(struct parse_result *res) 1052 { 1053 struct network_config net; 1054 struct filter_set *s = NULL; 1055 struct bgpd_addr h; 1056 char *line = NULL; 1057 size_t linesize = 0; 1058 ssize_t linelen; 1059 u_int8_t len; 1060 FILE *f; 1061 1062 if ((f = fdopen(STDIN_FILENO, "r")) == NULL) 1063 err(1, "Failed to open stdin\n"); 1064 1065 while ((linelen = getline(&line, &linesize, f)) != -1) { 1066 char *b, *buf = line; 1067 while ((b = strsep(&buf, " \t\n")) != NULL) { 1068 if (*b == '\0') /* skip empty tokens */ 1069 continue; 1070 /* Stop processing after a comment */ 1071 if (*b == '#') 1072 break; 1073 bzero(&net, sizeof(net)); 1074 if (parse_prefix(b, strlen(b), &h, &len) != 1) 1075 errx(1, "bad prefix: %s", b); 1076 net.prefix = h; 1077 net.prefixlen = len; 1078 net.rd = res->rd; 1079 1080 if (res->action == NETWORK_BULK_ADD) { 1081 imsg_compose(ibuf, IMSG_NETWORK_ADD, 1082 0, 0, -1, &net, sizeof(net)); 1083 /* 1084 * can't use send_filterset since that 1085 * would free the set. 1086 */ 1087 TAILQ_FOREACH(s, &res->set, entry) { 1088 imsg_compose(ibuf, 1089 IMSG_FILTER_SET, 1090 0, 0, -1, s, sizeof(*s)); 1091 } 1092 imsg_compose(ibuf, IMSG_NETWORK_DONE, 1093 0, 0, -1, NULL, 0); 1094 } else 1095 imsg_compose(ibuf, IMSG_NETWORK_REMOVE, 1096 0, 0, -1, &net, sizeof(net)); 1097 } 1098 } 1099 free(line); 1100 if (ferror(f)) 1101 err(1, "getline"); 1102 fclose(f); 1103 } 1104 1105 void 1106 show_mrt_dump_neighbors(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1107 { 1108 struct mrt_peer_entry *p; 1109 struct in_addr ina; 1110 u_int16_t i; 1111 1112 ina.s_addr = htonl(mp->bgp_id); 1113 printf("view: %s BGP ID: %s Number of peers: %u\n\n", 1114 mp->view, inet_ntoa(ina), mp->npeers); 1115 printf("%-30s %8s %15s\n", "Neighbor", "AS", "BGP ID"); 1116 for (i = 0; i < mp->npeers; i++) { 1117 p = &mp->peers[i]; 1118 ina.s_addr = htonl(p->bgp_id); 1119 printf("%-30s %8u %15s\n", log_addr(&p->addr), p->asnum, 1120 inet_ntoa(ina)); 1121 } 1122 /* we only print the first message */ 1123 exit(0); 1124 } 1125 1126 void 1127 show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1128 { 1129 struct ctl_show_rib ctl; 1130 struct parse_result res; 1131 struct ctl_show_rib_request *req = arg; 1132 struct mrt_rib_entry *mre; 1133 time_t now; 1134 u_int16_t i, j; 1135 1136 memset(&res, 0, sizeof(res)); 1137 res.flags = req->flags; 1138 now = time(NULL); 1139 1140 for (i = 0; i < mr->nentries; i++) { 1141 mre = &mr->entries[i]; 1142 bzero(&ctl, sizeof(ctl)); 1143 ctl.prefix = mr->prefix; 1144 ctl.prefixlen = mr->prefixlen; 1145 if (mre->originated <= now) 1146 ctl.age = now - mre->originated; 1147 ctl.true_nexthop = mre->nexthop; 1148 ctl.exit_nexthop = mre->nexthop; 1149 ctl.origin = mre->origin; 1150 ctl.local_pref = mre->local_pref; 1151 ctl.med = mre->med; 1152 /* weight is not part of the mrt dump so it can't be set */ 1153 1154 if (mre->peer_idx < mp->npeers) { 1155 ctl.remote_addr = mp->peers[mre->peer_idx].addr; 1156 ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; 1157 } 1158 1159 /* filter by neighbor */ 1160 if (req->neighbor.addr.aid != AID_UNSPEC && 1161 memcmp(&req->neighbor.addr, &ctl.remote_addr, 1162 sizeof(ctl.remote_addr)) != 0) 1163 continue; 1164 /* filter by AF */ 1165 if (req->aid && req->aid != ctl.prefix.aid) 1166 return; 1167 /* filter by prefix */ 1168 if (req->prefix.aid != AID_UNSPEC) { 1169 if (req->flags & F_LONGER) { 1170 if (req->prefixlen > ctl.prefixlen) 1171 return; 1172 if (prefix_compare(&req->prefix, &ctl.prefix, 1173 req->prefixlen)) 1174 return; 1175 } else if (req->flags & F_SHORTER) { 1176 if (req->prefixlen < ctl.prefixlen) 1177 return; 1178 if (prefix_compare(&req->prefix, &ctl.prefix, 1179 ctl.prefixlen)) 1180 return; 1181 } else { 1182 if (req->prefixlen != ctl.prefixlen) 1183 return; 1184 if (prefix_compare(&req->prefix, &ctl.prefix, 1185 req->prefixlen)) 1186 return; 1187 } 1188 } 1189 /* filter by AS */ 1190 if (req->as.type != AS_UNDEF && 1191 !match_aspath(mre->aspath, mre->aspath_len, &req->as)) 1192 continue; 1193 1194 output->rib(&ctl, mre->aspath, mre->aspath_len, &res); 1195 if (req->flags & F_CTL_DETAIL) { 1196 for (j = 0; j < mre->nattrs; j++) 1197 output->attr(mre->attrs[j].attr, 1198 mre->attrs[j].attr_len, req->flags); 1199 } 1200 } 1201 } 1202 1203 void 1204 network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1205 { 1206 struct ctl_show_rib ctl; 1207 struct network_config net; 1208 struct ctl_show_rib_request *req = arg; 1209 struct mrt_rib_entry *mre; 1210 struct ibuf *msg; 1211 time_t now; 1212 u_int16_t i, j; 1213 1214 now = time(NULL); 1215 for (i = 0; i < mr->nentries; i++) { 1216 mre = &mr->entries[i]; 1217 bzero(&ctl, sizeof(ctl)); 1218 ctl.prefix = mr->prefix; 1219 ctl.prefixlen = mr->prefixlen; 1220 if (mre->originated <= now) 1221 ctl.age = now - mre->originated; 1222 ctl.true_nexthop = mre->nexthop; 1223 ctl.exit_nexthop = mre->nexthop; 1224 ctl.origin = mre->origin; 1225 ctl.local_pref = mre->local_pref; 1226 ctl.med = mre->med; 1227 1228 if (mre->peer_idx < mp->npeers) { 1229 ctl.remote_addr = mp->peers[mre->peer_idx].addr; 1230 ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; 1231 } 1232 1233 /* filter by neighbor */ 1234 if (req->neighbor.addr.aid != AID_UNSPEC && 1235 memcmp(&req->neighbor.addr, &ctl.remote_addr, 1236 sizeof(ctl.remote_addr)) != 0) 1237 continue; 1238 /* filter by AF */ 1239 if (req->aid && req->aid != ctl.prefix.aid) 1240 return; 1241 /* filter by prefix */ 1242 if (req->prefix.aid != AID_UNSPEC) { 1243 if (!prefix_compare(&req->prefix, &ctl.prefix, 1244 req->prefixlen)) { 1245 if (req->flags & F_LONGER) { 1246 if (req->prefixlen > ctl.prefixlen) 1247 return; 1248 } else if (req->prefixlen != ctl.prefixlen) 1249 return; 1250 } else 1251 return; 1252 } 1253 /* filter by AS */ 1254 if (req->as.type != AS_UNDEF && 1255 !match_aspath(mre->aspath, mre->aspath_len, &req->as)) 1256 continue; 1257 1258 bzero(&net, sizeof(net)); 1259 net.prefix = ctl.prefix; 1260 net.prefixlen = ctl.prefixlen; 1261 net.type = NETWORK_MRTCLONE; 1262 /* XXX rd can't be set and will be 0 */ 1263 1264 imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1, 1265 &net, sizeof(net)); 1266 if ((msg = imsg_create(ibuf, IMSG_NETWORK_ASPATH, 1267 0, 0, sizeof(ctl) + mre->aspath_len)) == NULL) 1268 errx(1, "imsg_create failure"); 1269 if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 || 1270 imsg_add(msg, mre->aspath, mre->aspath_len) == -1) 1271 errx(1, "imsg_add failure"); 1272 imsg_close(ibuf, msg); 1273 for (j = 0; j < mre->nattrs; j++) 1274 imsg_compose(ibuf, IMSG_NETWORK_ATTR, 0, 0, -1, 1275 mre->attrs[j].attr, mre->attrs[j].attr_len); 1276 imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0); 1277 1278 while (ibuf->w.queued) { 1279 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 1280 err(1, "write error"); 1281 } 1282 } 1283 } 1284 1285 static const char * 1286 fmt_time(struct timespec *t) 1287 { 1288 static char timebuf[32]; 1289 static struct timespec prevtime; 1290 struct timespec temp; 1291 1292 timespecsub(t, &prevtime, &temp); 1293 snprintf(timebuf, sizeof(timebuf), "%lld.%06ld", 1294 (long long)temp.tv_sec, temp.tv_nsec / 1000); 1295 prevtime = *t; 1296 return (timebuf); 1297 } 1298 1299 void 1300 show_mrt_state(struct mrt_bgp_state *ms, void *arg) 1301 { 1302 printf("%s %s[%u] -> ", fmt_time(&ms->time), 1303 log_addr(&ms->src), ms->src_as); 1304 printf("%s[%u]: %s -> %s\n", log_addr(&ms->dst), ms->dst_as, 1305 statenames[ms->old_state], statenames[ms->new_state]); 1306 } 1307 1308 static void 1309 print_afi(u_char *p, u_int8_t len) 1310 { 1311 u_int16_t afi; 1312 u_int8_t safi, aid; 1313 1314 if (len != 4) { 1315 printf("bad length"); 1316 return; 1317 } 1318 1319 /* afi, 2 byte */ 1320 memcpy(&afi, p, sizeof(afi)); 1321 afi = ntohs(afi); 1322 p += 2; 1323 /* reserved, 1 byte */ 1324 p += 1; 1325 /* safi, 1 byte */ 1326 memcpy(&safi, p, sizeof(safi)); 1327 if (afi2aid(afi, safi, &aid) == -1) 1328 printf("unkown afi %u safi %u", afi, safi); 1329 else 1330 printf("%s", aid2str(aid)); 1331 } 1332 1333 static void 1334 print_capability(u_int8_t capa_code, u_char *p, u_int8_t len) 1335 { 1336 switch (capa_code) { 1337 case CAPA_MP: 1338 printf("multiprotocol capability: "); 1339 print_afi(p, len); 1340 break; 1341 case CAPA_REFRESH: 1342 printf("route refresh capability"); 1343 break; 1344 case CAPA_RESTART: 1345 printf("graceful restart capability"); 1346 /* XXX there is more needed here */ 1347 break; 1348 case CAPA_AS4BYTE: 1349 printf("4-byte AS num capability: "); 1350 if (len == 4) { 1351 u_int32_t as; 1352 memcpy(&as, p, sizeof(as)); 1353 as = ntohl(as); 1354 printf("AS %u", as); 1355 } else 1356 printf("bad length"); 1357 break; 1358 case CAPA_ADD_PATH: 1359 printf("add-path capability"); 1360 /* XXX there is more needed here */ 1361 break; 1362 case CAPA_ENHANCED_RR: 1363 printf("enhanced route refresh capability"); 1364 break; 1365 default: 1366 printf("unknown capability %u length %u", capa_code, len); 1367 break; 1368 } 1369 } 1370 1371 static void 1372 print_notification(u_int8_t errcode, u_int8_t subcode) 1373 { 1374 const char *suberrname = NULL; 1375 int uk = 0; 1376 1377 switch (errcode) { 1378 case ERR_HEADER: 1379 if (subcode >= sizeof(suberr_header_names)/sizeof(char *)) 1380 uk = 1; 1381 else 1382 suberrname = suberr_header_names[subcode]; 1383 break; 1384 case ERR_OPEN: 1385 if (subcode >= sizeof(suberr_open_names)/sizeof(char *)) 1386 uk = 1; 1387 else 1388 suberrname = suberr_open_names[subcode]; 1389 break; 1390 case ERR_UPDATE: 1391 if (subcode >= sizeof(suberr_update_names)/sizeof(char *)) 1392 uk = 1; 1393 else 1394 suberrname = suberr_update_names[subcode]; 1395 break; 1396 case ERR_CEASE: 1397 if (subcode >= sizeof(suberr_cease_names)/sizeof(char *)) 1398 uk = 1; 1399 else 1400 suberrname = suberr_cease_names[subcode]; 1401 break; 1402 case ERR_HOLDTIMEREXPIRED: 1403 if (subcode != 0) 1404 uk = 1; 1405 break; 1406 case ERR_FSM: 1407 if (subcode >= sizeof(suberr_fsm_names)/sizeof(char *)) 1408 uk = 1; 1409 else 1410 suberrname = suberr_fsm_names[subcode]; 1411 break; 1412 default: 1413 printf("unknown errcode %u, subcode %u", 1414 errcode, subcode); 1415 return; 1416 } 1417 1418 if (uk) 1419 printf("%s, unknown subcode %u", errnames[errcode], subcode); 1420 else { 1421 if (suberrname == NULL) 1422 printf("%s", errnames[errcode]); 1423 else 1424 printf("%s, %s", errnames[errcode], suberrname); 1425 } 1426 } 1427 1428 static int 1429 show_mrt_capabilities(u_char *p, u_int16_t len) 1430 { 1431 u_int16_t totlen = len; 1432 u_int8_t capa_code, capa_len; 1433 1434 while (len > 2) { 1435 memcpy(&capa_code, p, sizeof(capa_code)); 1436 p += sizeof(capa_code); 1437 len -= sizeof(capa_code); 1438 memcpy(&capa_len, p, sizeof(capa_len)); 1439 p += sizeof(capa_len); 1440 len -= sizeof(capa_len); 1441 if (len < capa_len) { 1442 printf("capa_len %u exceeds remaining length", 1443 capa_len); 1444 return (-1); 1445 } 1446 printf("\n "); 1447 print_capability(capa_code, p, capa_len); 1448 p += capa_len; 1449 len -= capa_len; 1450 } 1451 if (len != 0) { 1452 printf("length missmatch while capability parsing"); 1453 return (-1); 1454 } 1455 return (totlen); 1456 } 1457 1458 static void 1459 show_mrt_open(u_char *p, u_int16_t len) 1460 { 1461 u_int8_t version, optparamlen; 1462 u_int16_t short_as, holdtime; 1463 struct in_addr bgpid; 1464 1465 /* length check up to optparamlen already happened */ 1466 memcpy(&version, p, sizeof(version)); 1467 p += sizeof(version); 1468 len -= sizeof(version); 1469 memcpy(&short_as, p, sizeof(short_as)); 1470 p += sizeof(short_as); 1471 len -= sizeof(short_as); 1472 short_as = ntohs(short_as); 1473 memcpy(&holdtime, p, sizeof(holdtime)); 1474 holdtime = ntohs(holdtime); 1475 p += sizeof(holdtime); 1476 len -= sizeof(holdtime); 1477 memcpy(&bgpid, p, sizeof(bgpid)); 1478 p += sizeof(bgpid); 1479 len -= sizeof(bgpid); 1480 memcpy(&optparamlen, p, sizeof(optparamlen)); 1481 p += sizeof(optparamlen); 1482 len -= sizeof(optparamlen); 1483 1484 printf("\n "); 1485 printf("Version: %d AS: %u Holdtime: %u BGP Id: %s Paramlen: %u", 1486 version, short_as, holdtime, inet_ntoa(bgpid), optparamlen); 1487 if (optparamlen != len) { 1488 printf("optional parameter length mismatch"); 1489 return; 1490 } 1491 while (len > 2) { 1492 u_int8_t op_type, op_len; 1493 int r; 1494 1495 memcpy(&op_type, p, sizeof(op_type)); 1496 p += sizeof(op_type); 1497 len -= sizeof(op_type); 1498 memcpy(&op_len, p, sizeof(op_len)); 1499 p += sizeof(op_len); 1500 len -= sizeof(op_len); 1501 1502 printf("\n "); 1503 switch (op_type) { 1504 case OPT_PARAM_CAPABILITIES: 1505 printf("Capabilities: size %u", op_len); 1506 r = show_mrt_capabilities(p, op_len); 1507 if (r == -1) 1508 return; 1509 p += r; 1510 len -= r; 1511 break; 1512 case OPT_PARAM_AUTH: 1513 default: 1514 printf("unsupported optional parameter: type %u", 1515 op_type); 1516 return; 1517 } 1518 } 1519 if (len != 0) { 1520 printf("optional parameter encoding error"); 1521 return; 1522 } 1523 } 1524 1525 static void 1526 show_mrt_notification(u_char *p, u_int16_t len) 1527 { 1528 u_int16_t i; 1529 u_int8_t errcode, subcode; 1530 size_t reason_len; 1531 char reason[REASON_LEN]; 1532 1533 memcpy(&errcode, p, sizeof(errcode)); 1534 p += sizeof(errcode); 1535 len -= sizeof(errcode); 1536 1537 memcpy(&subcode, p, sizeof(subcode)); 1538 p += sizeof(subcode); 1539 len -= sizeof(subcode); 1540 1541 printf("\n "); 1542 print_notification(errcode, subcode); 1543 1544 if (errcode == ERR_CEASE && (subcode == ERR_CEASE_ADMIN_DOWN || 1545 subcode == ERR_CEASE_ADMIN_RESET)) { 1546 if (len > 1) { 1547 reason_len = *p++; 1548 len--; 1549 if (len < reason_len) { 1550 printf("truncated shutdown reason"); 1551 return; 1552 } 1553 if (reason_len > REASON_LEN - 1) { 1554 printf("overly long shutdown reason"); 1555 return; 1556 } 1557 memcpy(reason, p, reason_len); 1558 reason[reason_len] = '\0'; 1559 printf("shutdown reason: \"%s\"", 1560 log_reason(reason)); 1561 p += reason_len; 1562 len -= reason_len; 1563 } 1564 } 1565 if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) { 1566 int r; 1567 1568 r = show_mrt_capabilities(p, len); 1569 if (r == -1) 1570 return; 1571 p += r; 1572 len -= r; 1573 } 1574 1575 if (len > 0) { 1576 printf("\n additional data %u bytes", len); 1577 for (i = 0; i < len; i++) { 1578 if (i % 16 == 0) 1579 printf("\n "); 1580 if (i % 8 == 0) 1581 printf(" "); 1582 printf(" %02X", *p++); 1583 } 1584 } 1585 } 1586 1587 /* XXX this function does not handle JSON output */ 1588 static void 1589 show_mrt_update(u_char *p, u_int16_t len, int reqflags) 1590 { 1591 struct bgpd_addr prefix; 1592 int pos; 1593 u_int16_t wlen, alen; 1594 u_int8_t prefixlen; 1595 1596 if (len < sizeof(wlen)) { 1597 printf("bad length"); 1598 return; 1599 } 1600 memcpy(&wlen, p, sizeof(wlen)); 1601 wlen = ntohs(wlen); 1602 p += sizeof(wlen); 1603 len -= sizeof(wlen); 1604 1605 if (len < wlen) { 1606 printf("bad withdraw length"); 1607 return; 1608 } 1609 if (wlen > 0) { 1610 printf("\n Withdrawn prefixes:"); 1611 while (wlen > 0) { 1612 if ((pos = nlri_get_prefix(p, wlen, &prefix, 1613 &prefixlen)) == -1) { 1614 printf("bad withdraw prefix"); 1615 return; 1616 } 1617 printf(" %s/%u", log_addr(&prefix), prefixlen); 1618 p += pos; 1619 len -= pos; 1620 wlen -= pos; 1621 } 1622 } 1623 1624 if (len < sizeof(alen)) { 1625 printf("bad length"); 1626 return; 1627 } 1628 memcpy(&alen, p, sizeof(alen)); 1629 alen = ntohs(alen); 1630 p += sizeof(alen); 1631 len -= sizeof(alen); 1632 1633 if (len < alen) { 1634 printf("bad attribute length"); 1635 return; 1636 } 1637 printf("\n"); 1638 /* alen attributes here */ 1639 while (alen > 3) { 1640 u_int8_t flags; 1641 u_int16_t attrlen; 1642 1643 flags = p[0]; 1644 /* type = p[1]; */ 1645 1646 /* get the attribute length */ 1647 if (flags & ATTR_EXTLEN) { 1648 if (len < sizeof(attrlen) + 2) 1649 printf("bad attribute length"); 1650 memcpy(&attrlen, &p[2], sizeof(attrlen)); 1651 attrlen = ntohs(attrlen); 1652 attrlen += sizeof(attrlen) + 2; 1653 } else { 1654 attrlen = p[2]; 1655 attrlen += 1 + 2; 1656 } 1657 1658 output->attr(p, attrlen, reqflags); 1659 p += attrlen; 1660 alen -= attrlen; 1661 len -= attrlen; 1662 } 1663 1664 if (len > 0) { 1665 printf(" NLRI prefixes:"); 1666 while (len > 0) { 1667 if ((pos = nlri_get_prefix(p, len, &prefix, 1668 &prefixlen)) == -1) { 1669 printf("bad withdraw prefix"); 1670 return; 1671 } 1672 printf(" %s/%u", log_addr(&prefix), prefixlen); 1673 p += pos; 1674 len -= pos; 1675 } 1676 } 1677 } 1678 1679 void 1680 show_mrt_msg(struct mrt_bgp_msg *mm, void *arg) 1681 { 1682 static const u_int8_t marker[MSGSIZE_HEADER_MARKER] = { 1683 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1684 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 1685 u_char *p; 1686 u_int16_t len; 1687 u_int8_t type; 1688 struct ctl_show_rib_request *req = arg; 1689 1690 printf("%s %s[%u] -> ", fmt_time(&mm->time), 1691 log_addr(&mm->src), mm->src_as); 1692 printf("%s[%u]: size %u ", log_addr(&mm->dst), mm->dst_as, mm->msg_len); 1693 p = mm->msg; 1694 len = mm->msg_len; 1695 1696 if (len < MSGSIZE_HEADER) { 1697 printf("illegal header length: %u byte\n", len); 1698 return; 1699 } 1700 1701 /* parse BGP message header */ 1702 if (memcmp(p, marker, sizeof(marker))) { 1703 printf("incorrect marker in BGP message\n"); 1704 return; 1705 } 1706 p += MSGSIZE_HEADER_MARKER; 1707 1708 memcpy(&len, p, 2); 1709 len = ntohs(len); 1710 p += 2; 1711 memcpy(&type, p, 1); 1712 p += 1; 1713 1714 if (len < MSGSIZE_HEADER || len > MAX_PKTSIZE) { 1715 printf("illegal header length: %u byte\n", len); 1716 return; 1717 } 1718 1719 switch (type) { 1720 case OPEN: 1721 printf("%s ", msgtypenames[type]); 1722 if (len < MSGSIZE_OPEN_MIN) { 1723 printf("illegal length: %u byte\n", len); 1724 return; 1725 } 1726 show_mrt_open(p, len - MSGSIZE_HEADER); 1727 break; 1728 case NOTIFICATION: 1729 printf("%s ", msgtypenames[type]); 1730 if (len < MSGSIZE_NOTIFICATION_MIN) { 1731 printf("illegal length: %u byte\n", len); 1732 return; 1733 } 1734 show_mrt_notification(p, len - MSGSIZE_HEADER); 1735 break; 1736 case UPDATE: 1737 printf("%s ", msgtypenames[type]); 1738 if (len < MSGSIZE_UPDATE_MIN) { 1739 printf("illegal length: %u byte\n", len); 1740 return; 1741 } 1742 show_mrt_update(p, len - MSGSIZE_HEADER, req->flags); 1743 break; 1744 case KEEPALIVE: 1745 printf("%s ", msgtypenames[type]); 1746 if (len != MSGSIZE_KEEPALIVE) { 1747 printf("illegal length: %u byte\n", len); 1748 return; 1749 } 1750 /* nothing */ 1751 break; 1752 case RREFRESH: 1753 printf("%s ", msgtypenames[type]); 1754 if (len != MSGSIZE_RREFRESH) { 1755 printf("illegal length: %u byte\n", len); 1756 return; 1757 } 1758 print_afi(p, len); 1759 break; 1760 default: 1761 printf("unknown type %u\n", type); 1762 return; 1763 } 1764 printf("\n"); 1765 } 1766 1767 const char * 1768 msg_type(u_int8_t type) 1769 { 1770 if (type >= sizeof(msgtypenames)/sizeof(msgtypenames[0])) 1771 return "BAD"; 1772 return (msgtypenames[type]); 1773 } 1774 1775 int 1776 match_aspath(void *data, u_int16_t len, struct filter_as *f) 1777 { 1778 u_int8_t *seg; 1779 int final; 1780 u_int16_t seg_size; 1781 u_int8_t i, seg_len; 1782 u_int32_t as = 0; 1783 1784 if (f->type == AS_EMPTY) { 1785 if (len == 0) 1786 return (1); 1787 else 1788 return (0); 1789 } 1790 1791 seg = data; 1792 1793 /* just check the leftmost AS */ 1794 if (f->type == AS_PEER && len >= 6) { 1795 as = aspath_extract(seg, 0); 1796 if (f->as_min == as) 1797 return (1); 1798 else 1799 return (0); 1800 } 1801 1802 for (; len >= 6; len -= seg_size, seg += seg_size) { 1803 seg_len = seg[1]; 1804 seg_size = 2 + sizeof(u_int32_t) * seg_len; 1805 1806 final = (len == seg_size); 1807 1808 if (f->type == AS_SOURCE) { 1809 /* 1810 * Just extract the rightmost AS 1811 * but if that segment is an AS_SET then the rightmost 1812 * AS of a previous AS_SEQUENCE segment should be used. 1813 * Because of that just look at AS_SEQUENCE segments. 1814 */ 1815 if (seg[0] == AS_SEQUENCE) 1816 as = aspath_extract(seg, seg_len - 1); 1817 /* not yet in the final segment */ 1818 if (!final) 1819 continue; 1820 if (f->as_min == as) 1821 return (1); 1822 else 1823 return (0); 1824 } 1825 /* AS_TRANSIT or AS_ALL */ 1826 for (i = 0; i < seg_len; i++) { 1827 /* 1828 * the source (rightmost) AS is excluded from 1829 * AS_TRANSIT matches. 1830 */ 1831 if (final && i == seg_len - 1 && f->type == AS_TRANSIT) 1832 return (0); 1833 as = aspath_extract(seg, i); 1834 if (f->as_min == as) 1835 return (1); 1836 } 1837 } 1838 return (0); 1839 } 1840