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