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