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