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