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