1 /* $OpenBSD: bgpctl.c,v 1.289 2023/01/24 11:29:34 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 2004-2019 Claudio Jeker <claudio@openbsd.org> 6 * Copyright (c) 2016 Job Snijders <job@instituut.net> 7 * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/types.h> 23 #include <sys/socket.h> 24 #include <sys/stat.h> 25 #include <sys/un.h> 26 27 #include <endian.h> 28 #include <err.h> 29 #include <errno.h> 30 #include <fcntl.h> 31 #include <math.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <time.h> 36 #include <unistd.h> 37 #include <util.h> 38 39 #include "bgpd.h" 40 #include "session.h" 41 #include "rde.h" 42 #include "version.h" 43 44 #include "bgpctl.h" 45 #include "parser.h" 46 #include "mrtparser.h" 47 48 int main(int, char *[]); 49 int show(struct imsg *, struct parse_result *); 50 void send_filterset(struct imsgbuf *, struct filter_set_head *); 51 void show_mrt_dump_neighbors(struct mrt_rib *, struct mrt_peer *, 52 void *); 53 void show_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); 54 void network_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); 55 void show_mrt_state(struct mrt_bgp_state *, void *); 56 void show_mrt_msg(struct mrt_bgp_msg *, void *); 57 const char *msg_type(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_avs(uint8_t validation_state, int sum) 776 { 777 switch (validation_state) { 778 case ASPA_INVALID: 779 return (sum ? "!" : "invalid"); 780 case ASPA_VALID: 781 return (sum ? "V" : "valid"); 782 default: 783 return (sum ? "?" : "unknown"); 784 } 785 } 786 787 const char * 788 fmt_mem(long long num) 789 { 790 static char buf[16]; 791 792 if (fmt_scaled(num, buf) == -1) 793 snprintf(buf, sizeof(buf), "%lldB", num); 794 795 return (buf); 796 } 797 798 const char * 799 fmt_errstr(uint8_t errcode, uint8_t subcode) 800 { 801 static char errbuf[256]; 802 const char *errstr = NULL; 803 const char *suberr = NULL; 804 int uk = 0; 805 806 if (errcode == 0) /* no error */ 807 return NULL; 808 809 if (errcode < sizeof(errnames)/sizeof(char *)) 810 errstr = errnames[errcode]; 811 812 switch (errcode) { 813 case ERR_HEADER: 814 if (subcode < sizeof(suberr_header_names)/sizeof(char *)) 815 suberr = suberr_header_names[subcode]; 816 else 817 uk = 1; 818 break; 819 case ERR_OPEN: 820 if (subcode < sizeof(suberr_open_names)/sizeof(char *)) 821 suberr = suberr_open_names[subcode]; 822 else 823 uk = 1; 824 break; 825 case ERR_UPDATE: 826 if (subcode < sizeof(suberr_update_names)/sizeof(char *)) 827 suberr = suberr_update_names[subcode]; 828 else 829 uk = 1; 830 break; 831 case ERR_HOLDTIMEREXPIRED: 832 if (subcode != 0) 833 uk = 1; 834 break; 835 case ERR_FSM: 836 if (subcode < sizeof(suberr_fsm_names)/sizeof(char *)) 837 suberr = suberr_fsm_names[subcode]; 838 else 839 uk = 1; 840 break; 841 case ERR_CEASE: 842 if (subcode < sizeof(suberr_cease_names)/sizeof(char *)) 843 suberr = suberr_cease_names[subcode]; 844 else 845 uk = 1; 846 break; 847 default: 848 snprintf(errbuf, sizeof(errbuf), 849 "unknown error code %u subcode %u", errcode, subcode); 850 return (errbuf); 851 } 852 853 if (uk) 854 snprintf(errbuf, sizeof(errbuf), 855 "%s, unknown subcode %u", errstr, subcode); 856 else if (suberr == NULL) 857 return (errstr); 858 else 859 snprintf(errbuf, sizeof(errbuf), 860 "%s, %s", errstr, suberr); 861 862 return (errbuf); 863 } 864 865 const char * 866 fmt_attr(uint8_t type, int flags) 867 { 868 #define CHECK_FLAGS(s, t, m) \ 869 if (((s) & ~(ATTR_DEFMASK | (m))) != (t)) pflags = 1 870 871 static char cstr[48]; 872 int pflags = 0; 873 874 switch (type) { 875 case ATTR_ORIGIN: 876 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 877 strlcpy(cstr, "Origin", sizeof(cstr)); 878 break; 879 case ATTR_ASPATH: 880 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 881 strlcpy(cstr, "AS-Path", sizeof(cstr)); 882 break; 883 case ATTR_AS4_PATH: 884 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 885 strlcpy(cstr, "AS4-Path", sizeof(cstr)); 886 break; 887 case ATTR_NEXTHOP: 888 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 889 strlcpy(cstr, "Nexthop", sizeof(cstr)); 890 break; 891 case ATTR_MED: 892 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 893 strlcpy(cstr, "Med", sizeof(cstr)); 894 break; 895 case ATTR_LOCALPREF: 896 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 897 strlcpy(cstr, "Localpref", sizeof(cstr)); 898 break; 899 case ATTR_ATOMIC_AGGREGATE: 900 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 901 strlcpy(cstr, "Atomic Aggregate", sizeof(cstr)); 902 break; 903 case ATTR_AGGREGATOR: 904 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 905 strlcpy(cstr, "Aggregator", sizeof(cstr)); 906 break; 907 case ATTR_AS4_AGGREGATOR: 908 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 909 strlcpy(cstr, "AS4-Aggregator", sizeof(cstr)); 910 break; 911 case ATTR_COMMUNITIES: 912 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 913 strlcpy(cstr, "Communities", sizeof(cstr)); 914 break; 915 case ATTR_ORIGINATOR_ID: 916 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 917 strlcpy(cstr, "Originator Id", sizeof(cstr)); 918 break; 919 case ATTR_CLUSTER_LIST: 920 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 921 strlcpy(cstr, "Cluster Id List", sizeof(cstr)); 922 break; 923 case ATTR_MP_REACH_NLRI: 924 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 925 strlcpy(cstr, "MP Reach NLRI", sizeof(cstr)); 926 break; 927 case ATTR_MP_UNREACH_NLRI: 928 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 929 strlcpy(cstr, "MP Unreach NLRI", sizeof(cstr)); 930 break; 931 case ATTR_EXT_COMMUNITIES: 932 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 933 strlcpy(cstr, "Ext. Communities", sizeof(cstr)); 934 break; 935 case ATTR_LARGE_COMMUNITIES: 936 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 937 strlcpy(cstr, "Large Communities", sizeof(cstr)); 938 break; 939 case ATTR_OTC: 940 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 941 strlcpy(cstr, "OTC", sizeof(cstr)); 942 break; 943 default: 944 /* ignore unknown attributes */ 945 snprintf(cstr, sizeof(cstr), "Unknown Attribute #%u", type); 946 pflags = 1; 947 break; 948 } 949 if (flags != -1 && pflags) { 950 strlcat(cstr, " flags [", sizeof(cstr)); 951 if (flags & ATTR_OPTIONAL) 952 strlcat(cstr, "O", sizeof(cstr)); 953 if (flags & ATTR_TRANSITIVE) 954 strlcat(cstr, "T", sizeof(cstr)); 955 if (flags & ATTR_PARTIAL) 956 strlcat(cstr, "P", sizeof(cstr)); 957 strlcat(cstr, "]", sizeof(cstr)); 958 } 959 return (cstr); 960 961 #undef CHECK_FLAGS 962 } 963 964 const char * 965 fmt_community(uint16_t a, uint16_t v) 966 { 967 static char buf[12]; 968 969 if (a == COMMUNITY_WELLKNOWN) 970 switch (v) { 971 case COMMUNITY_GRACEFUL_SHUTDOWN: 972 return "GRACEFUL_SHUTDOWN"; 973 case COMMUNITY_NO_EXPORT: 974 return "NO_EXPORT"; 975 case COMMUNITY_NO_ADVERTISE: 976 return "NO_ADVERTISE"; 977 case COMMUNITY_NO_EXPSUBCONFED: 978 return "NO_EXPORT_SUBCONFED"; 979 case COMMUNITY_NO_PEER: 980 return "NO_PEER"; 981 case COMMUNITY_BLACKHOLE: 982 return "BLACKHOLE"; 983 default: 984 break; 985 } 986 987 snprintf(buf, sizeof(buf), "%hu:%hu", a, v); 988 return buf; 989 } 990 991 const char * 992 fmt_large_community(uint32_t d1, uint32_t d2, uint32_t d3) 993 { 994 static char buf[33]; 995 996 snprintf(buf, sizeof(buf), "%u:%u:%u", d1, d2, d3); 997 return buf; 998 } 999 1000 const char * 1001 fmt_ext_community(uint8_t *data) 1002 { 1003 static char buf[32]; 1004 uint64_t ext; 1005 struct in_addr ip; 1006 uint32_t as4, u32; 1007 uint16_t as2, u16; 1008 uint8_t type, subtype; 1009 1010 type = data[0]; 1011 subtype = data[1]; 1012 1013 switch (type) { 1014 case EXT_COMMUNITY_TRANS_TWO_AS: 1015 memcpy(&as2, data + 2, sizeof(as2)); 1016 memcpy(&u32, data + 4, sizeof(u32)); 1017 snprintf(buf, sizeof(buf), "%s %s:%u", 1018 log_ext_subtype(type, subtype), 1019 log_as(ntohs(as2)), ntohl(u32)); 1020 return buf; 1021 case EXT_COMMUNITY_TRANS_IPV4: 1022 memcpy(&ip, data + 2, sizeof(ip)); 1023 memcpy(&u16, data + 6, sizeof(u16)); 1024 snprintf(buf, sizeof(buf), "%s %s:%hu", 1025 log_ext_subtype(type, subtype), 1026 inet_ntoa(ip), ntohs(u16)); 1027 return buf; 1028 case EXT_COMMUNITY_TRANS_FOUR_AS: 1029 memcpy(&as4, data + 2, sizeof(as4)); 1030 memcpy(&u16, data + 6, sizeof(u16)); 1031 snprintf(buf, sizeof(buf), "%s %s:%hu", 1032 log_ext_subtype(type, subtype), 1033 log_as(ntohl(as4)), ntohs(u16)); 1034 return buf; 1035 case EXT_COMMUNITY_TRANS_OPAQUE: 1036 case EXT_COMMUNITY_TRANS_EVPN: 1037 memcpy(&ext, data, sizeof(ext)); 1038 ext = be64toh(ext) & 0xffffffffffffLL; 1039 snprintf(buf, sizeof(buf), "%s 0x%llx", 1040 log_ext_subtype(type, subtype), (unsigned long long)ext); 1041 return buf; 1042 case EXT_COMMUNITY_NON_TRANS_OPAQUE: 1043 memcpy(&ext, data, sizeof(ext)); 1044 ext = be64toh(ext) & 0xffffffffffffLL; 1045 switch (ext) { 1046 case EXT_COMMUNITY_OVS_VALID: 1047 snprintf(buf, sizeof(buf), "%s valid", 1048 log_ext_subtype(type, subtype)); 1049 return buf; 1050 case EXT_COMMUNITY_OVS_NOTFOUND: 1051 snprintf(buf, sizeof(buf), "%s not-found", 1052 log_ext_subtype(type, subtype)); 1053 return buf; 1054 case EXT_COMMUNITY_OVS_INVALID: 1055 snprintf(buf, sizeof(buf), "%s invalid", 1056 log_ext_subtype(type, subtype)); 1057 return buf; 1058 default: 1059 snprintf(buf, sizeof(buf), "%s 0x%llx", 1060 log_ext_subtype(type, subtype), 1061 (unsigned long long)ext); 1062 return buf; 1063 } 1064 break; 1065 default: 1066 memcpy(&ext, data, sizeof(ext)); 1067 snprintf(buf, sizeof(buf), "%s 0x%llx", 1068 log_ext_subtype(type, subtype), 1069 (unsigned long long)be64toh(ext)); 1070 return buf; 1071 } 1072 } 1073 1074 const char * 1075 fmt_set_type(struct ctl_show_set *set) 1076 { 1077 switch (set->type) { 1078 case ASPA_SET: 1079 return "ASPA"; 1080 case ROA_SET: 1081 return "ROA"; 1082 case PREFIX_SET: 1083 return "PREFIX"; 1084 case ORIGIN_SET: 1085 return "ORIGIN"; 1086 case ASNUM_SET: 1087 return "ASNUM"; 1088 default: 1089 return "BULA"; 1090 } 1091 } 1092 1093 void 1094 send_filterset(struct imsgbuf *i, struct filter_set_head *set) 1095 { 1096 struct filter_set *s; 1097 1098 while ((s = TAILQ_FIRST(set)) != NULL) { 1099 imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s, 1100 sizeof(struct filter_set)); 1101 TAILQ_REMOVE(set, s, entry); 1102 free(s); 1103 } 1104 } 1105 1106 void 1107 network_bulk(struct parse_result *res) 1108 { 1109 struct network_config net; 1110 struct filter_set *s = NULL; 1111 struct bgpd_addr h; 1112 char *line = NULL; 1113 size_t linesize = 0; 1114 ssize_t linelen; 1115 uint8_t len; 1116 FILE *f; 1117 1118 if ((f = fdopen(STDIN_FILENO, "r")) == NULL) 1119 err(1, "Failed to open stdin\n"); 1120 1121 while ((linelen = getline(&line, &linesize, f)) != -1) { 1122 char *b, *buf = line; 1123 while ((b = strsep(&buf, " \t\n")) != NULL) { 1124 if (*b == '\0') /* skip empty tokens */ 1125 continue; 1126 /* Stop processing after a comment */ 1127 if (*b == '#') 1128 break; 1129 memset(&net, 0, sizeof(net)); 1130 if (parse_prefix(b, strlen(b), &h, &len) != 1) 1131 errx(1, "bad prefix: %s", b); 1132 net.prefix = h; 1133 net.prefixlen = len; 1134 net.rd = res->rd; 1135 1136 if (res->action == NETWORK_BULK_ADD) { 1137 imsg_compose(ibuf, IMSG_NETWORK_ADD, 1138 0, 0, -1, &net, sizeof(net)); 1139 /* 1140 * can't use send_filterset since that 1141 * would free the set. 1142 */ 1143 TAILQ_FOREACH(s, &res->set, entry) { 1144 imsg_compose(ibuf, 1145 IMSG_FILTER_SET, 1146 0, 0, -1, s, sizeof(*s)); 1147 } 1148 imsg_compose(ibuf, IMSG_NETWORK_DONE, 1149 0, 0, -1, NULL, 0); 1150 } else 1151 imsg_compose(ibuf, IMSG_NETWORK_REMOVE, 1152 0, 0, -1, &net, sizeof(net)); 1153 } 1154 } 1155 free(line); 1156 if (ferror(f)) 1157 err(1, "getline"); 1158 fclose(f); 1159 } 1160 1161 void 1162 show_mrt_dump_neighbors(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1163 { 1164 struct mrt_peer_entry *p; 1165 struct in_addr ina; 1166 uint16_t i; 1167 1168 ina.s_addr = htonl(mp->bgp_id); 1169 printf("view: %s BGP ID: %s Number of peers: %u\n\n", 1170 mp->view, inet_ntoa(ina), mp->npeers); 1171 printf("%-30s %8s %15s\n", "Neighbor", "AS", "BGP ID"); 1172 for (i = 0; i < mp->npeers; i++) { 1173 p = &mp->peers[i]; 1174 ina.s_addr = htonl(p->bgp_id); 1175 printf("%-30s %8u %15s\n", log_addr(&p->addr), p->asnum, 1176 inet_ntoa(ina)); 1177 } 1178 /* we only print the first message */ 1179 exit(0); 1180 } 1181 1182 void 1183 show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1184 { 1185 struct ctl_show_rib ctl; 1186 struct parse_result res; 1187 struct ctl_show_rib_request *req = arg; 1188 struct mrt_rib_entry *mre; 1189 time_t now; 1190 uint16_t i, j; 1191 1192 memset(&res, 0, sizeof(res)); 1193 res.flags = req->flags; 1194 now = time(NULL); 1195 1196 for (i = 0; i < mr->nentries; i++) { 1197 mre = &mr->entries[i]; 1198 memset(&ctl, 0, sizeof(ctl)); 1199 ctl.prefix = mr->prefix; 1200 ctl.prefixlen = mr->prefixlen; 1201 if (mre->originated <= now) 1202 ctl.age = now - mre->originated; 1203 ctl.true_nexthop = mre->nexthop; 1204 ctl.exit_nexthop = mre->nexthop; 1205 ctl.origin = mre->origin; 1206 ctl.local_pref = mre->local_pref; 1207 ctl.med = mre->med; 1208 /* weight is not part of the mrt dump so it can't be set */ 1209 if (mr->add_path) { 1210 ctl.flags |= F_PREF_PATH_ID; 1211 ctl.path_id = mre->path_id; 1212 } 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 (req->flags & F_LONGER) { 1230 if (req->prefixlen > ctl.prefixlen) 1231 return; 1232 if (prefix_compare(&req->prefix, &ctl.prefix, 1233 req->prefixlen)) 1234 return; 1235 } else if (req->flags & F_SHORTER) { 1236 if (req->prefixlen < ctl.prefixlen) 1237 return; 1238 if (prefix_compare(&req->prefix, &ctl.prefix, 1239 ctl.prefixlen)) 1240 return; 1241 } else { 1242 if (req->prefixlen != ctl.prefixlen) 1243 return; 1244 if (prefix_compare(&req->prefix, &ctl.prefix, 1245 req->prefixlen)) 1246 return; 1247 } 1248 } 1249 /* filter by AS */ 1250 if (req->as.type != AS_UNDEF && 1251 !match_aspath(mre->aspath, mre->aspath_len, &req->as)) 1252 continue; 1253 1254 output->rib(&ctl, mre->aspath, mre->aspath_len, &res); 1255 if (req->flags & F_CTL_DETAIL) { 1256 for (j = 0; j < mre->nattrs; j++) 1257 output->attr(mre->attrs[j].attr, 1258 mre->attrs[j].attr_len, req->flags, 0); 1259 } 1260 } 1261 } 1262 1263 void 1264 network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1265 { 1266 struct ctl_show_rib ctl; 1267 struct network_config net; 1268 struct ctl_show_rib_request *req = arg; 1269 struct mrt_rib_entry *mre; 1270 struct ibuf *msg; 1271 time_t now; 1272 uint16_t i, j; 1273 1274 /* can't announce more than one path so ignore add-path */ 1275 if (mr->add_path) 1276 return; 1277 1278 now = time(NULL); 1279 for (i = 0; i < mr->nentries; i++) { 1280 mre = &mr->entries[i]; 1281 memset(&ctl, 0, sizeof(ctl)); 1282 ctl.prefix = mr->prefix; 1283 ctl.prefixlen = mr->prefixlen; 1284 if (mre->originated <= now) 1285 ctl.age = now - mre->originated; 1286 ctl.true_nexthop = mre->nexthop; 1287 ctl.exit_nexthop = mre->nexthop; 1288 ctl.origin = mre->origin; 1289 ctl.local_pref = mre->local_pref; 1290 ctl.med = mre->med; 1291 1292 if (mre->peer_idx < mp->npeers) { 1293 ctl.remote_addr = mp->peers[mre->peer_idx].addr; 1294 ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; 1295 } 1296 1297 /* filter by neighbor */ 1298 if (req->neighbor.addr.aid != AID_UNSPEC && 1299 memcmp(&req->neighbor.addr, &ctl.remote_addr, 1300 sizeof(ctl.remote_addr)) != 0) 1301 continue; 1302 /* filter by AF */ 1303 if (req->aid && req->aid != ctl.prefix.aid) 1304 return; 1305 /* filter by prefix */ 1306 if (req->prefix.aid != AID_UNSPEC) { 1307 if (!prefix_compare(&req->prefix, &ctl.prefix, 1308 req->prefixlen)) { 1309 if (req->flags & F_LONGER) { 1310 if (req->prefixlen > ctl.prefixlen) 1311 return; 1312 } else if (req->prefixlen != ctl.prefixlen) 1313 return; 1314 } else 1315 return; 1316 } 1317 /* filter by AS */ 1318 if (req->as.type != AS_UNDEF && 1319 !match_aspath(mre->aspath, mre->aspath_len, &req->as)) 1320 continue; 1321 1322 memset(&net, 0, sizeof(net)); 1323 net.prefix = ctl.prefix; 1324 net.prefixlen = ctl.prefixlen; 1325 net.type = NETWORK_MRTCLONE; 1326 /* XXX rd can't be set and will be 0 */ 1327 1328 imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1, 1329 &net, sizeof(net)); 1330 if ((msg = imsg_create(ibuf, IMSG_NETWORK_ASPATH, 1331 0, 0, sizeof(ctl) + mre->aspath_len)) == NULL) 1332 errx(1, "imsg_create failure"); 1333 if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 || 1334 imsg_add(msg, mre->aspath, mre->aspath_len) == -1) 1335 errx(1, "imsg_add failure"); 1336 imsg_close(ibuf, msg); 1337 for (j = 0; j < mre->nattrs; j++) 1338 imsg_compose(ibuf, IMSG_NETWORK_ATTR, 0, 0, -1, 1339 mre->attrs[j].attr, mre->attrs[j].attr_len); 1340 imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0); 1341 1342 while (ibuf->w.queued) { 1343 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 1344 err(1, "write error"); 1345 } 1346 } 1347 } 1348 1349 static const char * 1350 fmt_time(struct timespec *t) 1351 { 1352 static char timebuf[32]; 1353 static struct timespec prevtime; 1354 struct timespec temp; 1355 1356 timespecsub(t, &prevtime, &temp); 1357 snprintf(timebuf, sizeof(timebuf), "%lld.%06ld", 1358 (long long)temp.tv_sec, temp.tv_nsec / 1000); 1359 prevtime = *t; 1360 return (timebuf); 1361 } 1362 1363 void 1364 show_mrt_state(struct mrt_bgp_state *ms, void *arg) 1365 { 1366 printf("%s %s[%u] -> ", fmt_time(&ms->time), 1367 log_addr(&ms->src), ms->src_as); 1368 printf("%s[%u]: %s -> %s\n", log_addr(&ms->dst), ms->dst_as, 1369 statenames[ms->old_state], statenames[ms->new_state]); 1370 } 1371 1372 static void 1373 print_afi(u_char *p, uint8_t len) 1374 { 1375 uint16_t afi; 1376 uint8_t safi, aid; 1377 1378 if (len != 4) { 1379 printf("bad length"); 1380 return; 1381 } 1382 1383 /* afi, 2 byte */ 1384 memcpy(&afi, p, sizeof(afi)); 1385 afi = ntohs(afi); 1386 p += 2; 1387 /* reserved, 1 byte */ 1388 p += 1; 1389 /* safi, 1 byte */ 1390 memcpy(&safi, p, sizeof(safi)); 1391 if (afi2aid(afi, safi, &aid) == -1) 1392 printf("unknown afi %u safi %u", afi, safi); 1393 else 1394 printf("%s", aid2str(aid)); 1395 } 1396 1397 static void 1398 print_capability(uint8_t capa_code, u_char *p, uint8_t len) 1399 { 1400 switch (capa_code) { 1401 case CAPA_MP: 1402 printf("multiprotocol capability: "); 1403 print_afi(p, len); 1404 break; 1405 case CAPA_REFRESH: 1406 printf("route refresh capability"); 1407 break; 1408 case CAPA_RESTART: 1409 printf("graceful restart capability"); 1410 /* XXX there is more needed here */ 1411 break; 1412 case CAPA_AS4BYTE: 1413 printf("4-byte AS num capability: "); 1414 if (len == 4) { 1415 uint32_t as; 1416 memcpy(&as, p, sizeof(as)); 1417 as = ntohl(as); 1418 printf("AS %u", as); 1419 } else 1420 printf("bad length"); 1421 break; 1422 case CAPA_ADD_PATH: 1423 printf("add-path capability"); 1424 /* XXX there is more needed here */ 1425 break; 1426 case CAPA_ENHANCED_RR: 1427 printf("enhanced route refresh capability"); 1428 break; 1429 default: 1430 printf("unknown capability %u length %u", capa_code, len); 1431 break; 1432 } 1433 } 1434 1435 static void 1436 print_notification(uint8_t errcode, uint8_t subcode) 1437 { 1438 const char *suberrname = NULL; 1439 int uk = 0; 1440 1441 switch (errcode) { 1442 case ERR_HEADER: 1443 if (subcode >= sizeof(suberr_header_names)/sizeof(char *)) 1444 uk = 1; 1445 else 1446 suberrname = suberr_header_names[subcode]; 1447 break; 1448 case ERR_OPEN: 1449 if (subcode >= sizeof(suberr_open_names)/sizeof(char *)) 1450 uk = 1; 1451 else 1452 suberrname = suberr_open_names[subcode]; 1453 break; 1454 case ERR_UPDATE: 1455 if (subcode >= sizeof(suberr_update_names)/sizeof(char *)) 1456 uk = 1; 1457 else 1458 suberrname = suberr_update_names[subcode]; 1459 break; 1460 case ERR_CEASE: 1461 if (subcode >= sizeof(suberr_cease_names)/sizeof(char *)) 1462 uk = 1; 1463 else 1464 suberrname = suberr_cease_names[subcode]; 1465 break; 1466 case ERR_HOLDTIMEREXPIRED: 1467 if (subcode != 0) 1468 uk = 1; 1469 break; 1470 case ERR_FSM: 1471 if (subcode >= sizeof(suberr_fsm_names)/sizeof(char *)) 1472 uk = 1; 1473 else 1474 suberrname = suberr_fsm_names[subcode]; 1475 break; 1476 default: 1477 printf("unknown errcode %u, subcode %u", 1478 errcode, subcode); 1479 return; 1480 } 1481 1482 if (uk) 1483 printf("%s, unknown subcode %u", errnames[errcode], subcode); 1484 else { 1485 if (suberrname == NULL) 1486 printf("%s", errnames[errcode]); 1487 else 1488 printf("%s, %s", errnames[errcode], suberrname); 1489 } 1490 } 1491 1492 static int 1493 show_mrt_capabilities(u_char *p, uint16_t len) 1494 { 1495 uint16_t totlen = len; 1496 uint8_t capa_code, capa_len; 1497 1498 while (len > 2) { 1499 memcpy(&capa_code, p, sizeof(capa_code)); 1500 p += sizeof(capa_code); 1501 len -= sizeof(capa_code); 1502 memcpy(&capa_len, p, sizeof(capa_len)); 1503 p += sizeof(capa_len); 1504 len -= sizeof(capa_len); 1505 if (len < capa_len) { 1506 printf("capa_len %u exceeds remaining length", 1507 capa_len); 1508 return (-1); 1509 } 1510 printf("\n "); 1511 print_capability(capa_code, p, capa_len); 1512 p += capa_len; 1513 len -= capa_len; 1514 } 1515 if (len != 0) { 1516 printf("length mismatch while capability parsing"); 1517 return (-1); 1518 } 1519 return (totlen); 1520 } 1521 1522 static void 1523 show_mrt_open(u_char *p, uint16_t len) 1524 { 1525 uint16_t short_as, holdtime; 1526 uint8_t version, optparamlen; 1527 struct in_addr bgpid; 1528 1529 /* length check up to optparamlen already happened */ 1530 memcpy(&version, p, sizeof(version)); 1531 p += sizeof(version); 1532 len -= sizeof(version); 1533 memcpy(&short_as, p, sizeof(short_as)); 1534 p += sizeof(short_as); 1535 len -= sizeof(short_as); 1536 short_as = ntohs(short_as); 1537 memcpy(&holdtime, p, sizeof(holdtime)); 1538 holdtime = ntohs(holdtime); 1539 p += sizeof(holdtime); 1540 len -= sizeof(holdtime); 1541 memcpy(&bgpid, p, sizeof(bgpid)); 1542 p += sizeof(bgpid); 1543 len -= sizeof(bgpid); 1544 memcpy(&optparamlen, p, sizeof(optparamlen)); 1545 p += sizeof(optparamlen); 1546 len -= sizeof(optparamlen); 1547 1548 printf("\n "); 1549 printf("Version: %d AS: %u Holdtime: %u BGP Id: %s Paramlen: %u", 1550 version, short_as, holdtime, inet_ntoa(bgpid), optparamlen); 1551 if (optparamlen != len) { 1552 printf("optional parameter length mismatch"); 1553 return; 1554 } 1555 while (len > 2) { 1556 uint8_t op_type, op_len; 1557 int r; 1558 1559 memcpy(&op_type, p, sizeof(op_type)); 1560 p += sizeof(op_type); 1561 len -= sizeof(op_type); 1562 memcpy(&op_len, p, sizeof(op_len)); 1563 p += sizeof(op_len); 1564 len -= sizeof(op_len); 1565 1566 printf("\n "); 1567 switch (op_type) { 1568 case OPT_PARAM_CAPABILITIES: 1569 printf("Capabilities: size %u", op_len); 1570 r = show_mrt_capabilities(p, op_len); 1571 if (r == -1) 1572 return; 1573 p += r; 1574 len -= r; 1575 break; 1576 case OPT_PARAM_AUTH: 1577 default: 1578 printf("unsupported optional parameter: type %u", 1579 op_type); 1580 return; 1581 } 1582 } 1583 if (len != 0) { 1584 printf("optional parameter encoding error"); 1585 return; 1586 } 1587 } 1588 1589 static void 1590 show_mrt_notification(u_char *p, uint16_t len) 1591 { 1592 uint16_t i; 1593 uint8_t errcode, subcode; 1594 size_t reason_len; 1595 char reason[REASON_LEN]; 1596 1597 memcpy(&errcode, p, sizeof(errcode)); 1598 p += sizeof(errcode); 1599 len -= sizeof(errcode); 1600 1601 memcpy(&subcode, p, sizeof(subcode)); 1602 p += sizeof(subcode); 1603 len -= sizeof(subcode); 1604 1605 printf("\n "); 1606 print_notification(errcode, subcode); 1607 1608 if (errcode == ERR_CEASE && (subcode == ERR_CEASE_ADMIN_DOWN || 1609 subcode == ERR_CEASE_ADMIN_RESET)) { 1610 if (len > 1) { 1611 reason_len = *p++; 1612 len--; 1613 if (len < reason_len) { 1614 printf("truncated shutdown reason"); 1615 return; 1616 } 1617 if (reason_len > REASON_LEN - 1) { 1618 printf("overly long shutdown reason"); 1619 return; 1620 } 1621 memcpy(reason, p, reason_len); 1622 reason[reason_len] = '\0'; 1623 printf("shutdown reason: \"%s\"", 1624 log_reason(reason)); 1625 p += reason_len; 1626 len -= reason_len; 1627 } 1628 } 1629 if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) { 1630 int r; 1631 1632 r = show_mrt_capabilities(p, len); 1633 if (r == -1) 1634 return; 1635 p += r; 1636 len -= r; 1637 } 1638 1639 if (len > 0) { 1640 printf("\n additional data %u bytes", len); 1641 for (i = 0; i < len; i++) { 1642 if (i % 16 == 0) 1643 printf("\n "); 1644 if (i % 8 == 0) 1645 printf(" "); 1646 printf(" %02X", *p++); 1647 } 1648 } 1649 } 1650 1651 /* XXX this function does not handle JSON output */ 1652 static void 1653 show_mrt_update(u_char *p, uint16_t len, int reqflags, int addpath) 1654 { 1655 struct bgpd_addr prefix; 1656 int pos; 1657 uint32_t pathid; 1658 uint16_t wlen, alen; 1659 uint8_t prefixlen; 1660 1661 if (len < sizeof(wlen)) { 1662 printf("bad length"); 1663 return; 1664 } 1665 memcpy(&wlen, p, sizeof(wlen)); 1666 wlen = ntohs(wlen); 1667 p += sizeof(wlen); 1668 len -= sizeof(wlen); 1669 1670 if (len < wlen) { 1671 printf("bad withdraw length"); 1672 return; 1673 } 1674 if (wlen > 0) { 1675 printf("\n Withdrawn prefixes:"); 1676 while (wlen > 0) { 1677 if (addpath) { 1678 if (wlen <= sizeof(pathid)) { 1679 printf("bad withdraw prefix"); 1680 return; 1681 } 1682 memcpy(&pathid, p, sizeof(pathid)); 1683 pathid = ntohl(pathid); 1684 p += sizeof(pathid); 1685 len -= sizeof(pathid); 1686 wlen -= sizeof(pathid); 1687 } 1688 if ((pos = nlri_get_prefix(p, wlen, &prefix, 1689 &prefixlen)) == -1) { 1690 printf("bad withdraw prefix"); 1691 return; 1692 } 1693 printf(" %s/%u", log_addr(&prefix), prefixlen); 1694 if (addpath) 1695 printf(" path-id %u", pathid); 1696 p += pos; 1697 len -= pos; 1698 wlen -= pos; 1699 } 1700 } 1701 1702 if (len < sizeof(alen)) { 1703 printf("bad length"); 1704 return; 1705 } 1706 memcpy(&alen, p, sizeof(alen)); 1707 alen = ntohs(alen); 1708 p += sizeof(alen); 1709 len -= sizeof(alen); 1710 1711 if (len < alen) { 1712 printf("bad attribute length"); 1713 return; 1714 } 1715 printf("\n"); 1716 /* alen attributes here */ 1717 while (alen > 3) { 1718 uint8_t flags; 1719 uint16_t attrlen; 1720 1721 flags = p[0]; 1722 /* type = p[1]; */ 1723 1724 /* get the attribute length */ 1725 if (flags & ATTR_EXTLEN) { 1726 if (len < sizeof(attrlen) + 2) 1727 printf("bad attribute length"); 1728 memcpy(&attrlen, &p[2], sizeof(attrlen)); 1729 attrlen = ntohs(attrlen); 1730 attrlen += sizeof(attrlen) + 2; 1731 } else { 1732 attrlen = p[2]; 1733 attrlen += 1 + 2; 1734 } 1735 1736 output->attr(p, attrlen, reqflags, addpath); 1737 p += attrlen; 1738 alen -= attrlen; 1739 len -= attrlen; 1740 } 1741 1742 if (len > 0) { 1743 printf(" NLRI prefixes:"); 1744 while (len > 0) { 1745 if (addpath) { 1746 if (len <= sizeof(pathid)) { 1747 printf(" bad nlri prefix: pathid, len %d", len); 1748 return; 1749 } 1750 memcpy(&pathid, p, sizeof(pathid)); 1751 pathid = ntohl(pathid); 1752 p += sizeof(pathid); 1753 len -= sizeof(pathid); 1754 } 1755 if ((pos = nlri_get_prefix(p, len, &prefix, 1756 &prefixlen)) == -1) { 1757 printf(" bad nlri prefix"); 1758 return; 1759 } 1760 printf(" %s/%u", log_addr(&prefix), prefixlen); 1761 if (addpath) 1762 printf(" path-id %u", pathid); 1763 p += pos; 1764 len -= pos; 1765 } 1766 } 1767 } 1768 1769 void 1770 show_mrt_msg(struct mrt_bgp_msg *mm, void *arg) 1771 { 1772 static const uint8_t marker[MSGSIZE_HEADER_MARKER] = { 1773 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1774 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 1775 u_char *p; 1776 uint16_t len; 1777 uint8_t type; 1778 struct ctl_show_rib_request *req = arg; 1779 1780 printf("%s %s[%u] -> ", fmt_time(&mm->time), 1781 log_addr(&mm->src), mm->src_as); 1782 printf("%s[%u]: size %u%s ", log_addr(&mm->dst), mm->dst_as, 1783 mm->msg_len, mm->add_path ? " addpath" : ""); 1784 p = mm->msg; 1785 len = mm->msg_len; 1786 1787 if (len < MSGSIZE_HEADER) { 1788 printf("illegal header length: %u byte\n", len); 1789 return; 1790 } 1791 1792 /* parse BGP message header */ 1793 if (memcmp(p, marker, sizeof(marker))) { 1794 printf("incorrect marker in BGP message\n"); 1795 return; 1796 } 1797 p += MSGSIZE_HEADER_MARKER; 1798 1799 memcpy(&len, p, 2); 1800 len = ntohs(len); 1801 p += 2; 1802 memcpy(&type, p, 1); 1803 p += 1; 1804 1805 if (len < MSGSIZE_HEADER || len > MAX_PKTSIZE) { 1806 printf("illegal header length: %u byte\n", len); 1807 return; 1808 } 1809 1810 switch (type) { 1811 case OPEN: 1812 printf("%s ", msgtypenames[type]); 1813 if (len < MSGSIZE_OPEN_MIN) { 1814 printf("illegal length: %u byte\n", len); 1815 return; 1816 } 1817 show_mrt_open(p, len - MSGSIZE_HEADER); 1818 break; 1819 case NOTIFICATION: 1820 printf("%s ", msgtypenames[type]); 1821 if (len < MSGSIZE_NOTIFICATION_MIN) { 1822 printf("illegal length: %u byte\n", len); 1823 return; 1824 } 1825 show_mrt_notification(p, len - MSGSIZE_HEADER); 1826 break; 1827 case UPDATE: 1828 printf("%s ", msgtypenames[type]); 1829 if (len < MSGSIZE_UPDATE_MIN) { 1830 printf("illegal length: %u byte\n", len); 1831 return; 1832 } 1833 show_mrt_update(p, len - MSGSIZE_HEADER, req->flags, 1834 mm->add_path); 1835 break; 1836 case KEEPALIVE: 1837 printf("%s ", msgtypenames[type]); 1838 if (len != MSGSIZE_KEEPALIVE) { 1839 printf("illegal length: %u byte\n", len); 1840 return; 1841 } 1842 /* nothing */ 1843 break; 1844 case RREFRESH: 1845 printf("%s ", msgtypenames[type]); 1846 if (len != MSGSIZE_RREFRESH) { 1847 printf("illegal length: %u byte\n", len); 1848 return; 1849 } 1850 print_afi(p, len); 1851 break; 1852 default: 1853 printf("unknown type %u\n", type); 1854 return; 1855 } 1856 printf("\n"); 1857 } 1858 1859 const char * 1860 msg_type(uint8_t type) 1861 { 1862 if (type >= sizeof(msgtypenames)/sizeof(msgtypenames[0])) 1863 return "BAD"; 1864 return (msgtypenames[type]); 1865 } 1866 1867 int 1868 match_aspath(void *data, uint16_t len, struct filter_as *f) 1869 { 1870 uint8_t *seg; 1871 int final; 1872 uint16_t seg_size; 1873 uint8_t i, seg_len; 1874 uint32_t as = 0; 1875 1876 if (f->type == AS_EMPTY) { 1877 if (len == 0) 1878 return (1); 1879 else 1880 return (0); 1881 } 1882 1883 seg = data; 1884 1885 /* just check the leftmost AS */ 1886 if (f->type == AS_PEER && len >= 6) { 1887 as = aspath_extract(seg, 0); 1888 if (f->as_min == as) 1889 return (1); 1890 else 1891 return (0); 1892 } 1893 1894 for (; len >= 6; len -= seg_size, seg += seg_size) { 1895 seg_len = seg[1]; 1896 seg_size = 2 + sizeof(uint32_t) * seg_len; 1897 1898 final = (len == seg_size); 1899 1900 if (f->type == AS_SOURCE) { 1901 /* 1902 * Just extract the rightmost AS 1903 * but if that segment is an AS_SET then the rightmost 1904 * AS of a previous AS_SEQUENCE segment should be used. 1905 * Because of that just look at AS_SEQUENCE segments. 1906 */ 1907 if (seg[0] == AS_SEQUENCE) 1908 as = aspath_extract(seg, seg_len - 1); 1909 /* not yet in the final segment */ 1910 if (!final) 1911 continue; 1912 if (f->as_min == as) 1913 return (1); 1914 else 1915 return (0); 1916 } 1917 /* AS_TRANSIT or AS_ALL */ 1918 for (i = 0; i < seg_len; i++) { 1919 /* 1920 * the source (rightmost) AS is excluded from 1921 * AS_TRANSIT matches. 1922 */ 1923 if (final && i == seg_len - 1 && f->type == AS_TRANSIT) 1924 return (0); 1925 as = aspath_extract(seg, i); 1926 if (f->as_min == as) 1927 return (1); 1928 } 1929 } 1930 return (0); 1931 } 1932