1 /* $OpenBSD: bgpctl.c,v 1.273 2021/08/09 08:24:36 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(u_int8_t); 58 void network_bulk(struct parse_result *); 59 int match_aspath(void *, u_int16_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 sun; 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(&sun, sizeof(sun)); 164 sun.sun_family = AF_UNIX; 165 if (strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)) >= 166 sizeof(sun.sun_path)) 167 errx(1, "socket name too long"); 168 if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -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_BUFS 8 579 #define TF_LEN 9 580 581 const char * 582 fmt_timeframe(time_t t) 583 { 584 char *buf; 585 static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ 586 static int idx = 0; 587 unsigned int sec, min, hrs, day; 588 unsigned long long week; 589 590 buf = tfbuf[idx++]; 591 if (idx == TF_BUFS) 592 idx = 0; 593 594 week = t; 595 596 sec = week % 60; 597 week /= 60; 598 min = week % 60; 599 week /= 60; 600 hrs = week % 24; 601 week /= 24; 602 day = week % 7; 603 week /= 7; 604 605 if (week > 0) 606 snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs); 607 else if (day > 0) 608 snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 609 else 610 snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 611 612 return (buf); 613 } 614 615 const char * 616 fmt_monotime(time_t t) 617 { 618 t = get_monotime(t); 619 620 if (t == -1) 621 return ("Never"); 622 623 return (fmt_timeframe(t)); 624 } 625 626 const char * 627 fmt_fib_flags(u_int16_t flags) 628 { 629 static char buf[8]; 630 631 if (flags & F_DOWN) 632 strlcpy(buf, " ", sizeof(buf)); 633 else 634 strlcpy(buf, "*", sizeof(buf)); 635 636 if (flags & F_BGPD_INSERTED) 637 strlcat(buf, "B", sizeof(buf)); 638 else if (flags & F_CONNECTED) 639 strlcat(buf, "C", sizeof(buf)); 640 else if (flags & F_STATIC) 641 strlcat(buf, "S", sizeof(buf)); 642 else if (flags & F_DYNAMIC) 643 strlcat(buf, "D", sizeof(buf)); 644 else 645 strlcat(buf, " ", sizeof(buf)); 646 647 if (flags & F_NEXTHOP) 648 strlcat(buf, "N", sizeof(buf)); 649 else 650 strlcat(buf, " ", sizeof(buf)); 651 652 if (flags & F_REJECT && flags & F_BLACKHOLE) 653 strlcat(buf, "f", sizeof(buf)); 654 else if (flags & F_REJECT) 655 strlcat(buf, "r", sizeof(buf)); 656 else if (flags & F_BLACKHOLE) 657 strlcat(buf, "b", sizeof(buf)); 658 else 659 strlcat(buf, " ", sizeof(buf)); 660 661 if (strlcat(buf, " ", sizeof(buf)) >= sizeof(buf)) 662 errx(1, "%s buffer too small", __func__); 663 664 return buf; 665 } 666 667 const char * 668 fmt_origin(u_int8_t origin, int sum) 669 { 670 switch (origin) { 671 case ORIGIN_IGP: 672 return (sum ? "i" : "IGP"); 673 case ORIGIN_EGP: 674 return (sum ? "e" : "EGP"); 675 case ORIGIN_INCOMPLETE: 676 return (sum ? "?" : "incomplete"); 677 default: 678 return (sum ? "X" : "bad origin"); 679 } 680 } 681 682 const char * 683 fmt_flags(u_int8_t flags, int sum) 684 { 685 static char buf[80]; 686 char flagstr[5]; 687 char *p = flagstr; 688 689 if (sum) { 690 if (flags & F_PREF_INVALID) 691 *p++ = 'E'; 692 if (flags & F_PREF_ANNOUNCE) 693 *p++ = 'A'; 694 if (flags & F_PREF_INTERNAL) 695 *p++ = 'I'; 696 if (flags & F_PREF_STALE) 697 *p++ = 'S'; 698 if (flags & F_PREF_ELIGIBLE) 699 *p++ = '*'; 700 if (flags & F_PREF_ACTIVE) 701 *p++ = '>'; 702 *p = '\0'; 703 snprintf(buf, sizeof(buf), "%-5s", flagstr); 704 } else { 705 if (flags & F_PREF_INTERNAL) 706 strlcpy(buf, "internal", sizeof(buf)); 707 else 708 strlcpy(buf, "external", sizeof(buf)); 709 710 if (flags & F_PREF_STALE) 711 strlcat(buf, ", stale", sizeof(buf)); 712 if (flags & F_PREF_ELIGIBLE) 713 strlcat(buf, ", valid", sizeof(buf)); 714 if (flags & F_PREF_ACTIVE) 715 strlcat(buf, ", best", sizeof(buf)); 716 if (flags & F_PREF_ANNOUNCE) 717 strlcat(buf, ", announced", sizeof(buf)); 718 if (strlen(buf) >= sizeof(buf) - 1) 719 errx(1, "%s buffer too small", __func__); 720 } 721 722 return buf; 723 } 724 725 const char * 726 fmt_ovs(u_int8_t validation_state, int sum) 727 { 728 switch (validation_state) { 729 case ROA_INVALID: 730 return (sum ? "!" : "invalid"); 731 case ROA_VALID: 732 return (sum ? "V" : "valid"); 733 default: 734 return (sum ? "N" : "not-found"); 735 } 736 } 737 738 const char * 739 fmt_mem(long long num) 740 { 741 static char buf[16]; 742 743 if (fmt_scaled(num, buf) == -1) 744 snprintf(buf, sizeof(buf), "%lldB", num); 745 746 return (buf); 747 } 748 749 const char * 750 fmt_errstr(u_int8_t errcode, u_int8_t subcode) 751 { 752 static char errbuf[256]; 753 const char *errstr = NULL; 754 const char *suberr = NULL; 755 int uk = 0; 756 757 if (errcode == 0) /* no error */ 758 return NULL; 759 760 if (errcode < sizeof(errnames)/sizeof(char *)) 761 errstr = errnames[errcode]; 762 763 switch (errcode) { 764 case ERR_HEADER: 765 if (subcode < sizeof(suberr_header_names)/sizeof(char *)) 766 suberr = suberr_header_names[subcode]; 767 else 768 uk = 1; 769 break; 770 case ERR_OPEN: 771 if (subcode < sizeof(suberr_open_names)/sizeof(char *)) 772 suberr = suberr_open_names[subcode]; 773 else 774 uk = 1; 775 break; 776 case ERR_UPDATE: 777 if (subcode < sizeof(suberr_update_names)/sizeof(char *)) 778 suberr = suberr_update_names[subcode]; 779 else 780 uk = 1; 781 break; 782 case ERR_HOLDTIMEREXPIRED: 783 if (subcode != 0) 784 uk = 1; 785 break; 786 case ERR_FSM: 787 if (subcode < sizeof(suberr_fsm_names)/sizeof(char *)) 788 suberr = suberr_fsm_names[subcode]; 789 else 790 uk = 1; 791 break; 792 case ERR_CEASE: 793 if (subcode < sizeof(suberr_cease_names)/sizeof(char *)) 794 suberr = suberr_cease_names[subcode]; 795 else 796 uk = 1; 797 break; 798 default: 799 snprintf(errbuf, sizeof(errbuf), 800 "unknown error code %u subcode %u", errcode, subcode); 801 return (errbuf); 802 } 803 804 if (uk) 805 snprintf(errbuf, sizeof(errbuf), 806 "%s, unknown subcode %u", errstr, subcode); 807 else if (suberr == NULL) 808 return (errstr); 809 else 810 snprintf(errbuf, sizeof(errbuf), 811 "%s, %s", errstr, suberr); 812 813 return (errbuf); 814 } 815 816 const char * 817 fmt_attr(u_int8_t type, int flags) 818 { 819 #define CHECK_FLAGS(s, t, m) \ 820 if (((s) & ~(ATTR_DEFMASK | (m))) != (t)) pflags = 1 821 822 static char cstr[48]; 823 int pflags = 0; 824 825 switch (type) { 826 case ATTR_ORIGIN: 827 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 828 strlcpy(cstr, "Origin", sizeof(cstr)); 829 break; 830 case ATTR_ASPATH: 831 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 832 strlcpy(cstr, "AS-Path", sizeof(cstr)); 833 break; 834 case ATTR_AS4_PATH: 835 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 836 strlcpy(cstr, "AS4-Path", sizeof(cstr)); 837 break; 838 case ATTR_NEXTHOP: 839 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 840 strlcpy(cstr, "Nexthop", sizeof(cstr)); 841 break; 842 case ATTR_MED: 843 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 844 strlcpy(cstr, "Med", sizeof(cstr)); 845 break; 846 case ATTR_LOCALPREF: 847 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 848 strlcpy(cstr, "Localpref", sizeof(cstr)); 849 break; 850 case ATTR_ATOMIC_AGGREGATE: 851 CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 852 strlcpy(cstr, "Atomic Aggregate", sizeof(cstr)); 853 break; 854 case ATTR_AGGREGATOR: 855 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 856 strlcpy(cstr, "Aggregator", sizeof(cstr)); 857 break; 858 case ATTR_AS4_AGGREGATOR: 859 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 860 strlcpy(cstr, "AS4-Aggregator", sizeof(cstr)); 861 break; 862 case ATTR_COMMUNITIES: 863 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 864 strlcpy(cstr, "Communities", sizeof(cstr)); 865 break; 866 case ATTR_ORIGINATOR_ID: 867 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 868 strlcpy(cstr, "Originator Id", sizeof(cstr)); 869 break; 870 case ATTR_CLUSTER_LIST: 871 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 872 strlcpy(cstr, "Cluster Id List", sizeof(cstr)); 873 break; 874 case ATTR_MP_REACH_NLRI: 875 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 876 strlcpy(cstr, "MP Reach NLRI", sizeof(cstr)); 877 break; 878 case ATTR_MP_UNREACH_NLRI: 879 CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 880 strlcpy(cstr, "MP Unreach NLRI", sizeof(cstr)); 881 break; 882 case ATTR_EXT_COMMUNITIES: 883 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 884 strlcpy(cstr, "Ext. Communities", sizeof(cstr)); 885 break; 886 case ATTR_LARGE_COMMUNITIES: 887 CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 888 strlcpy(cstr, "Large Communities", sizeof(cstr)); 889 break; 890 default: 891 /* ignore unknown attributes */ 892 snprintf(cstr, sizeof(cstr), "Unknown Attribute #%u", type); 893 pflags = 1; 894 break; 895 } 896 if (flags != -1 && pflags) { 897 strlcat(cstr, " flags [", sizeof(cstr)); 898 if (flags & ATTR_OPTIONAL) 899 strlcat(cstr, "O", sizeof(cstr)); 900 if (flags & ATTR_TRANSITIVE) 901 strlcat(cstr, "T", sizeof(cstr)); 902 if (flags & ATTR_PARTIAL) 903 strlcat(cstr, "P", sizeof(cstr)); 904 strlcat(cstr, "]", sizeof(cstr)); 905 } 906 return (cstr); 907 908 #undef CHECK_FLAGS 909 } 910 911 const char * 912 fmt_community(u_int16_t a, u_int16_t v) 913 { 914 static char buf[12]; 915 916 if (a == COMMUNITY_WELLKNOWN) 917 switch (v) { 918 case COMMUNITY_GRACEFUL_SHUTDOWN: 919 return "GRACEFUL_SHUTDOWN"; 920 case COMMUNITY_NO_EXPORT: 921 return "NO_EXPORT"; 922 case COMMUNITY_NO_ADVERTISE: 923 return "NO_ADVERTISE"; 924 case COMMUNITY_NO_EXPSUBCONFED: 925 return "NO_EXPORT_SUBCONFED"; 926 case COMMUNITY_NO_PEER: 927 return "NO_PEER"; 928 case COMMUNITY_BLACKHOLE: 929 return "BLACKHOLE"; 930 default: 931 break; 932 } 933 934 snprintf(buf, sizeof(buf), "%hu:%hu", a, v); 935 return buf; 936 } 937 938 const char * 939 fmt_large_community(u_int32_t d1, u_int32_t d2, u_int32_t d3) 940 { 941 static char buf[33]; 942 943 snprintf(buf, sizeof(buf), "%u:%u:%u", d1, d2, d3); 944 return buf; 945 } 946 947 const char * 948 fmt_ext_community(u_int8_t *data) 949 { 950 static char buf[32]; 951 u_int64_t ext; 952 struct in_addr ip; 953 u_int32_t as4, u32; 954 u_int16_t as2, u16; 955 u_int8_t type, subtype; 956 957 type = data[0]; 958 subtype = data[1]; 959 960 switch (type) { 961 case EXT_COMMUNITY_TRANS_TWO_AS: 962 memcpy(&as2, data + 2, sizeof(as2)); 963 memcpy(&u32, data + 4, sizeof(u32)); 964 snprintf(buf, sizeof(buf), "%s %s:%u", 965 log_ext_subtype(type, subtype), 966 log_as(ntohs(as2)), ntohl(u32)); 967 return buf; 968 case EXT_COMMUNITY_TRANS_IPV4: 969 memcpy(&ip, data + 2, sizeof(ip)); 970 memcpy(&u16, data + 6, sizeof(u16)); 971 snprintf(buf, sizeof(buf), "%s %s:%hu", 972 log_ext_subtype(type, subtype), 973 inet_ntoa(ip), ntohs(u16)); 974 return buf; 975 case EXT_COMMUNITY_TRANS_FOUR_AS: 976 memcpy(&as4, data + 2, sizeof(as4)); 977 memcpy(&u16, data + 6, sizeof(u16)); 978 snprintf(buf, sizeof(buf), "%s %s:%hu", 979 log_ext_subtype(type, subtype), 980 log_as(ntohl(as4)), ntohs(u16)); 981 return buf; 982 case EXT_COMMUNITY_TRANS_OPAQUE: 983 case EXT_COMMUNITY_TRANS_EVPN: 984 memcpy(&ext, data, sizeof(ext)); 985 ext = be64toh(ext) & 0xffffffffffffLL; 986 snprintf(buf, sizeof(buf), "%s 0x%llx", 987 log_ext_subtype(type, subtype), (unsigned long long)ext); 988 return buf; 989 case EXT_COMMUNITY_NON_TRANS_OPAQUE: 990 memcpy(&ext, data, sizeof(ext)); 991 ext = be64toh(ext) & 0xffffffffffffLL; 992 switch (ext) { 993 case EXT_COMMUNITY_OVS_VALID: 994 snprintf(buf, sizeof(buf), "%s valid ", 995 log_ext_subtype(type, subtype)); 996 return buf; 997 case EXT_COMMUNITY_OVS_NOTFOUND: 998 snprintf(buf, sizeof(buf), "%s not-found ", 999 log_ext_subtype(type, subtype)); 1000 return buf; 1001 case EXT_COMMUNITY_OVS_INVALID: 1002 snprintf(buf, sizeof(buf), "%s invalid ", 1003 log_ext_subtype(type, subtype)); 1004 return buf; 1005 default: 1006 snprintf(buf, sizeof(buf), "%s 0x%llx ", 1007 log_ext_subtype(type, subtype), 1008 (unsigned long long)ext); 1009 return buf; 1010 } 1011 break; 1012 default: 1013 memcpy(&ext, data, sizeof(ext)); 1014 snprintf(buf, sizeof(buf), "%s 0x%llx", 1015 log_ext_subtype(type, subtype), 1016 (unsigned long long)be64toh(ext)); 1017 return buf; 1018 } 1019 } 1020 1021 const char * 1022 fmt_set_type(struct ctl_show_set *set) 1023 { 1024 switch (set->type) { 1025 case ROA_SET: 1026 return "ROA"; 1027 case PREFIX_SET: 1028 return "PREFIX"; 1029 case ORIGIN_SET: 1030 return "ORIGIN"; 1031 case ASNUM_SET: 1032 return "ASNUM"; 1033 default: 1034 return "BULA"; 1035 } 1036 } 1037 1038 void 1039 send_filterset(struct imsgbuf *i, struct filter_set_head *set) 1040 { 1041 struct filter_set *s; 1042 1043 while ((s = TAILQ_FIRST(set)) != NULL) { 1044 imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s, 1045 sizeof(struct filter_set)); 1046 TAILQ_REMOVE(set, s, entry); 1047 free(s); 1048 } 1049 } 1050 1051 void 1052 network_bulk(struct parse_result *res) 1053 { 1054 struct network_config net; 1055 struct filter_set *s = NULL; 1056 struct bgpd_addr h; 1057 char *line = NULL; 1058 size_t linesize = 0; 1059 ssize_t linelen; 1060 u_int8_t len; 1061 FILE *f; 1062 1063 if ((f = fdopen(STDIN_FILENO, "r")) == NULL) 1064 err(1, "Failed to open stdin\n"); 1065 1066 while ((linelen = getline(&line, &linesize, f)) != -1) { 1067 char *b, *buf = line; 1068 while ((b = strsep(&buf, " \t\n")) != NULL) { 1069 if (*b == '\0') /* skip empty tokens */ 1070 continue; 1071 /* Stop processing after a comment */ 1072 if (*b == '#') 1073 break; 1074 bzero(&net, sizeof(net)); 1075 if (parse_prefix(b, strlen(b), &h, &len) != 1) 1076 errx(1, "bad prefix: %s", b); 1077 net.prefix = h; 1078 net.prefixlen = len; 1079 net.rd = res->rd; 1080 1081 if (res->action == NETWORK_BULK_ADD) { 1082 imsg_compose(ibuf, IMSG_NETWORK_ADD, 1083 0, 0, -1, &net, sizeof(net)); 1084 /* 1085 * can't use send_filterset since that 1086 * would free the set. 1087 */ 1088 TAILQ_FOREACH(s, &res->set, entry) { 1089 imsg_compose(ibuf, 1090 IMSG_FILTER_SET, 1091 0, 0, -1, s, sizeof(*s)); 1092 } 1093 imsg_compose(ibuf, IMSG_NETWORK_DONE, 1094 0, 0, -1, NULL, 0); 1095 } else 1096 imsg_compose(ibuf, IMSG_NETWORK_REMOVE, 1097 0, 0, -1, &net, sizeof(net)); 1098 } 1099 } 1100 free(line); 1101 if (ferror(f)) 1102 err(1, "getline"); 1103 fclose(f); 1104 } 1105 1106 void 1107 show_mrt_dump_neighbors(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1108 { 1109 struct mrt_peer_entry *p; 1110 struct in_addr ina; 1111 u_int16_t i; 1112 1113 ina.s_addr = htonl(mp->bgp_id); 1114 printf("view: %s BGP ID: %s Number of peers: %u\n\n", 1115 mp->view, inet_ntoa(ina), mp->npeers); 1116 printf("%-30s %8s %15s\n", "Neighbor", "AS", "BGP ID"); 1117 for (i = 0; i < mp->npeers; i++) { 1118 p = &mp->peers[i]; 1119 ina.s_addr = htonl(p->bgp_id); 1120 printf("%-30s %8u %15s\n", log_addr(&p->addr), p->asnum, 1121 inet_ntoa(ina)); 1122 } 1123 /* we only print the first message */ 1124 exit(0); 1125 } 1126 1127 void 1128 show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1129 { 1130 struct ctl_show_rib ctl; 1131 struct parse_result res; 1132 struct ctl_show_rib_request *req = arg; 1133 struct mrt_rib_entry *mre; 1134 time_t now; 1135 u_int16_t i, j; 1136 1137 memset(&res, 0, sizeof(res)); 1138 res.flags = req->flags; 1139 now = time(NULL); 1140 1141 for (i = 0; i < mr->nentries; i++) { 1142 mre = &mr->entries[i]; 1143 bzero(&ctl, sizeof(ctl)); 1144 ctl.prefix = mr->prefix; 1145 ctl.prefixlen = mr->prefixlen; 1146 if (mre->originated <= now) 1147 ctl.age = now - mre->originated; 1148 ctl.true_nexthop = mre->nexthop; 1149 ctl.exit_nexthop = mre->nexthop; 1150 ctl.origin = mre->origin; 1151 ctl.local_pref = mre->local_pref; 1152 ctl.med = mre->med; 1153 /* weight is not part of the mrt dump so it can't be set */ 1154 if (mr->add_path) { 1155 ctl.flags |= F_PREF_PATH_ID; 1156 ctl.path_id = mre->path_id; 1157 } 1158 1159 if (mre->peer_idx < mp->npeers) { 1160 ctl.remote_addr = mp->peers[mre->peer_idx].addr; 1161 ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; 1162 } 1163 1164 /* filter by neighbor */ 1165 if (req->neighbor.addr.aid != AID_UNSPEC && 1166 memcmp(&req->neighbor.addr, &ctl.remote_addr, 1167 sizeof(ctl.remote_addr)) != 0) 1168 continue; 1169 /* filter by AF */ 1170 if (req->aid && req->aid != ctl.prefix.aid) 1171 return; 1172 /* filter by prefix */ 1173 if (req->prefix.aid != AID_UNSPEC) { 1174 if (req->flags & F_LONGER) { 1175 if (req->prefixlen > ctl.prefixlen) 1176 return; 1177 if (prefix_compare(&req->prefix, &ctl.prefix, 1178 req->prefixlen)) 1179 return; 1180 } else if (req->flags & F_SHORTER) { 1181 if (req->prefixlen < ctl.prefixlen) 1182 return; 1183 if (prefix_compare(&req->prefix, &ctl.prefix, 1184 ctl.prefixlen)) 1185 return; 1186 } else { 1187 if (req->prefixlen != ctl.prefixlen) 1188 return; 1189 if (prefix_compare(&req->prefix, &ctl.prefix, 1190 req->prefixlen)) 1191 return; 1192 } 1193 } 1194 /* filter by AS */ 1195 if (req->as.type != AS_UNDEF && 1196 !match_aspath(mre->aspath, mre->aspath_len, &req->as)) 1197 continue; 1198 1199 output->rib(&ctl, mre->aspath, mre->aspath_len, &res); 1200 if (req->flags & F_CTL_DETAIL) { 1201 for (j = 0; j < mre->nattrs; j++) 1202 output->attr(mre->attrs[j].attr, 1203 mre->attrs[j].attr_len, req->flags, 0); 1204 } 1205 } 1206 } 1207 1208 void 1209 network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1210 { 1211 struct ctl_show_rib ctl; 1212 struct network_config net; 1213 struct ctl_show_rib_request *req = arg; 1214 struct mrt_rib_entry *mre; 1215 struct ibuf *msg; 1216 time_t now; 1217 u_int16_t i, j; 1218 1219 /* can't announce more than one path so ignore add-path */ 1220 if (mr->add_path) 1221 return; 1222 1223 now = time(NULL); 1224 for (i = 0; i < mr->nentries; i++) { 1225 mre = &mr->entries[i]; 1226 bzero(&ctl, sizeof(ctl)); 1227 ctl.prefix = mr->prefix; 1228 ctl.prefixlen = mr->prefixlen; 1229 if (mre->originated <= now) 1230 ctl.age = now - mre->originated; 1231 ctl.true_nexthop = mre->nexthop; 1232 ctl.exit_nexthop = mre->nexthop; 1233 ctl.origin = mre->origin; 1234 ctl.local_pref = mre->local_pref; 1235 ctl.med = mre->med; 1236 1237 if (mre->peer_idx < mp->npeers) { 1238 ctl.remote_addr = mp->peers[mre->peer_idx].addr; 1239 ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; 1240 } 1241 1242 /* filter by neighbor */ 1243 if (req->neighbor.addr.aid != AID_UNSPEC && 1244 memcmp(&req->neighbor.addr, &ctl.remote_addr, 1245 sizeof(ctl.remote_addr)) != 0) 1246 continue; 1247 /* filter by AF */ 1248 if (req->aid && req->aid != ctl.prefix.aid) 1249 return; 1250 /* filter by prefix */ 1251 if (req->prefix.aid != AID_UNSPEC) { 1252 if (!prefix_compare(&req->prefix, &ctl.prefix, 1253 req->prefixlen)) { 1254 if (req->flags & F_LONGER) { 1255 if (req->prefixlen > ctl.prefixlen) 1256 return; 1257 } else if (req->prefixlen != ctl.prefixlen) 1258 return; 1259 } else 1260 return; 1261 } 1262 /* filter by AS */ 1263 if (req->as.type != AS_UNDEF && 1264 !match_aspath(mre->aspath, mre->aspath_len, &req->as)) 1265 continue; 1266 1267 bzero(&net, sizeof(net)); 1268 net.prefix = ctl.prefix; 1269 net.prefixlen = ctl.prefixlen; 1270 net.type = NETWORK_MRTCLONE; 1271 /* XXX rd can't be set and will be 0 */ 1272 1273 imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1, 1274 &net, sizeof(net)); 1275 if ((msg = imsg_create(ibuf, IMSG_NETWORK_ASPATH, 1276 0, 0, sizeof(ctl) + mre->aspath_len)) == NULL) 1277 errx(1, "imsg_create failure"); 1278 if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 || 1279 imsg_add(msg, mre->aspath, mre->aspath_len) == -1) 1280 errx(1, "imsg_add failure"); 1281 imsg_close(ibuf, msg); 1282 for (j = 0; j < mre->nattrs; j++) 1283 imsg_compose(ibuf, IMSG_NETWORK_ATTR, 0, 0, -1, 1284 mre->attrs[j].attr, mre->attrs[j].attr_len); 1285 imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0); 1286 1287 while (ibuf->w.queued) { 1288 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 1289 err(1, "write error"); 1290 } 1291 } 1292 } 1293 1294 static const char * 1295 fmt_time(struct timespec *t) 1296 { 1297 static char timebuf[32]; 1298 static struct timespec prevtime; 1299 struct timespec temp; 1300 1301 timespecsub(t, &prevtime, &temp); 1302 snprintf(timebuf, sizeof(timebuf), "%lld.%06ld", 1303 (long long)temp.tv_sec, temp.tv_nsec / 1000); 1304 prevtime = *t; 1305 return (timebuf); 1306 } 1307 1308 void 1309 show_mrt_state(struct mrt_bgp_state *ms, void *arg) 1310 { 1311 printf("%s %s[%u] -> ", fmt_time(&ms->time), 1312 log_addr(&ms->src), ms->src_as); 1313 printf("%s[%u]: %s -> %s\n", log_addr(&ms->dst), ms->dst_as, 1314 statenames[ms->old_state], statenames[ms->new_state]); 1315 } 1316 1317 static void 1318 print_afi(u_char *p, u_int8_t len) 1319 { 1320 u_int16_t afi; 1321 u_int8_t safi, aid; 1322 1323 if (len != 4) { 1324 printf("bad length"); 1325 return; 1326 } 1327 1328 /* afi, 2 byte */ 1329 memcpy(&afi, p, sizeof(afi)); 1330 afi = ntohs(afi); 1331 p += 2; 1332 /* reserved, 1 byte */ 1333 p += 1; 1334 /* safi, 1 byte */ 1335 memcpy(&safi, p, sizeof(safi)); 1336 if (afi2aid(afi, safi, &aid) == -1) 1337 printf("unkown afi %u safi %u", afi, safi); 1338 else 1339 printf("%s", aid2str(aid)); 1340 } 1341 1342 static void 1343 print_capability(u_int8_t capa_code, u_char *p, u_int8_t len) 1344 { 1345 switch (capa_code) { 1346 case CAPA_MP: 1347 printf("multiprotocol capability: "); 1348 print_afi(p, len); 1349 break; 1350 case CAPA_REFRESH: 1351 printf("route refresh capability"); 1352 break; 1353 case CAPA_RESTART: 1354 printf("graceful restart capability"); 1355 /* XXX there is more needed here */ 1356 break; 1357 case CAPA_AS4BYTE: 1358 printf("4-byte AS num capability: "); 1359 if (len == 4) { 1360 u_int32_t as; 1361 memcpy(&as, p, sizeof(as)); 1362 as = ntohl(as); 1363 printf("AS %u", as); 1364 } else 1365 printf("bad length"); 1366 break; 1367 case CAPA_ADD_PATH: 1368 printf("add-path capability"); 1369 /* XXX there is more needed here */ 1370 break; 1371 case CAPA_ENHANCED_RR: 1372 printf("enhanced route refresh capability"); 1373 break; 1374 default: 1375 printf("unknown capability %u length %u", capa_code, len); 1376 break; 1377 } 1378 } 1379 1380 static void 1381 print_notification(u_int8_t errcode, u_int8_t subcode) 1382 { 1383 const char *suberrname = NULL; 1384 int uk = 0; 1385 1386 switch (errcode) { 1387 case ERR_HEADER: 1388 if (subcode >= sizeof(suberr_header_names)/sizeof(char *)) 1389 uk = 1; 1390 else 1391 suberrname = suberr_header_names[subcode]; 1392 break; 1393 case ERR_OPEN: 1394 if (subcode >= sizeof(suberr_open_names)/sizeof(char *)) 1395 uk = 1; 1396 else 1397 suberrname = suberr_open_names[subcode]; 1398 break; 1399 case ERR_UPDATE: 1400 if (subcode >= sizeof(suberr_update_names)/sizeof(char *)) 1401 uk = 1; 1402 else 1403 suberrname = suberr_update_names[subcode]; 1404 break; 1405 case ERR_CEASE: 1406 if (subcode >= sizeof(suberr_cease_names)/sizeof(char *)) 1407 uk = 1; 1408 else 1409 suberrname = suberr_cease_names[subcode]; 1410 break; 1411 case ERR_HOLDTIMEREXPIRED: 1412 if (subcode != 0) 1413 uk = 1; 1414 break; 1415 case ERR_FSM: 1416 if (subcode >= sizeof(suberr_fsm_names)/sizeof(char *)) 1417 uk = 1; 1418 else 1419 suberrname = suberr_fsm_names[subcode]; 1420 break; 1421 default: 1422 printf("unknown errcode %u, subcode %u", 1423 errcode, subcode); 1424 return; 1425 } 1426 1427 if (uk) 1428 printf("%s, unknown subcode %u", errnames[errcode], subcode); 1429 else { 1430 if (suberrname == NULL) 1431 printf("%s", errnames[errcode]); 1432 else 1433 printf("%s, %s", errnames[errcode], suberrname); 1434 } 1435 } 1436 1437 static int 1438 show_mrt_capabilities(u_char *p, u_int16_t len) 1439 { 1440 u_int16_t totlen = len; 1441 u_int8_t capa_code, capa_len; 1442 1443 while (len > 2) { 1444 memcpy(&capa_code, p, sizeof(capa_code)); 1445 p += sizeof(capa_code); 1446 len -= sizeof(capa_code); 1447 memcpy(&capa_len, p, sizeof(capa_len)); 1448 p += sizeof(capa_len); 1449 len -= sizeof(capa_len); 1450 if (len < capa_len) { 1451 printf("capa_len %u exceeds remaining length", 1452 capa_len); 1453 return (-1); 1454 } 1455 printf("\n "); 1456 print_capability(capa_code, p, capa_len); 1457 p += capa_len; 1458 len -= capa_len; 1459 } 1460 if (len != 0) { 1461 printf("length missmatch while capability parsing"); 1462 return (-1); 1463 } 1464 return (totlen); 1465 } 1466 1467 static void 1468 show_mrt_open(u_char *p, u_int16_t len) 1469 { 1470 u_int8_t version, optparamlen; 1471 u_int16_t short_as, holdtime; 1472 struct in_addr bgpid; 1473 1474 /* length check up to optparamlen already happened */ 1475 memcpy(&version, p, sizeof(version)); 1476 p += sizeof(version); 1477 len -= sizeof(version); 1478 memcpy(&short_as, p, sizeof(short_as)); 1479 p += sizeof(short_as); 1480 len -= sizeof(short_as); 1481 short_as = ntohs(short_as); 1482 memcpy(&holdtime, p, sizeof(holdtime)); 1483 holdtime = ntohs(holdtime); 1484 p += sizeof(holdtime); 1485 len -= sizeof(holdtime); 1486 memcpy(&bgpid, p, sizeof(bgpid)); 1487 p += sizeof(bgpid); 1488 len -= sizeof(bgpid); 1489 memcpy(&optparamlen, p, sizeof(optparamlen)); 1490 p += sizeof(optparamlen); 1491 len -= sizeof(optparamlen); 1492 1493 printf("\n "); 1494 printf("Version: %d AS: %u Holdtime: %u BGP Id: %s Paramlen: %u", 1495 version, short_as, holdtime, inet_ntoa(bgpid), optparamlen); 1496 if (optparamlen != len) { 1497 printf("optional parameter length mismatch"); 1498 return; 1499 } 1500 while (len > 2) { 1501 u_int8_t op_type, op_len; 1502 int r; 1503 1504 memcpy(&op_type, p, sizeof(op_type)); 1505 p += sizeof(op_type); 1506 len -= sizeof(op_type); 1507 memcpy(&op_len, p, sizeof(op_len)); 1508 p += sizeof(op_len); 1509 len -= sizeof(op_len); 1510 1511 printf("\n "); 1512 switch (op_type) { 1513 case OPT_PARAM_CAPABILITIES: 1514 printf("Capabilities: size %u", op_len); 1515 r = show_mrt_capabilities(p, op_len); 1516 if (r == -1) 1517 return; 1518 p += r; 1519 len -= r; 1520 break; 1521 case OPT_PARAM_AUTH: 1522 default: 1523 printf("unsupported optional parameter: type %u", 1524 op_type); 1525 return; 1526 } 1527 } 1528 if (len != 0) { 1529 printf("optional parameter encoding error"); 1530 return; 1531 } 1532 } 1533 1534 static void 1535 show_mrt_notification(u_char *p, u_int16_t len) 1536 { 1537 u_int16_t i; 1538 u_int8_t errcode, subcode; 1539 size_t reason_len; 1540 char reason[REASON_LEN]; 1541 1542 memcpy(&errcode, p, sizeof(errcode)); 1543 p += sizeof(errcode); 1544 len -= sizeof(errcode); 1545 1546 memcpy(&subcode, p, sizeof(subcode)); 1547 p += sizeof(subcode); 1548 len -= sizeof(subcode); 1549 1550 printf("\n "); 1551 print_notification(errcode, subcode); 1552 1553 if (errcode == ERR_CEASE && (subcode == ERR_CEASE_ADMIN_DOWN || 1554 subcode == ERR_CEASE_ADMIN_RESET)) { 1555 if (len > 1) { 1556 reason_len = *p++; 1557 len--; 1558 if (len < reason_len) { 1559 printf("truncated shutdown reason"); 1560 return; 1561 } 1562 if (reason_len > REASON_LEN - 1) { 1563 printf("overly long shutdown reason"); 1564 return; 1565 } 1566 memcpy(reason, p, reason_len); 1567 reason[reason_len] = '\0'; 1568 printf("shutdown reason: \"%s\"", 1569 log_reason(reason)); 1570 p += reason_len; 1571 len -= reason_len; 1572 } 1573 } 1574 if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) { 1575 int r; 1576 1577 r = show_mrt_capabilities(p, len); 1578 if (r == -1) 1579 return; 1580 p += r; 1581 len -= r; 1582 } 1583 1584 if (len > 0) { 1585 printf("\n additional data %u bytes", len); 1586 for (i = 0; i < len; i++) { 1587 if (i % 16 == 0) 1588 printf("\n "); 1589 if (i % 8 == 0) 1590 printf(" "); 1591 printf(" %02X", *p++); 1592 } 1593 } 1594 } 1595 1596 /* XXX this function does not handle JSON output */ 1597 static void 1598 show_mrt_update(u_char *p, u_int16_t len, int reqflags, int addpath) 1599 { 1600 struct bgpd_addr prefix; 1601 int pos; 1602 u_int32_t pathid; 1603 u_int16_t wlen, alen; 1604 u_int8_t prefixlen; 1605 1606 if (len < sizeof(wlen)) { 1607 printf("bad length"); 1608 return; 1609 } 1610 memcpy(&wlen, p, sizeof(wlen)); 1611 wlen = ntohs(wlen); 1612 p += sizeof(wlen); 1613 len -= sizeof(wlen); 1614 1615 if (len < wlen) { 1616 printf("bad withdraw length"); 1617 return; 1618 } 1619 if (wlen > 0) { 1620 printf("\n Withdrawn prefixes:"); 1621 while (wlen > 0) { 1622 if (addpath) { 1623 if (wlen <= sizeof(pathid)) { 1624 printf("bad withdraw prefix"); 1625 return; 1626 } 1627 memcpy(&pathid, p, sizeof(pathid)); 1628 pathid = ntohl(pathid); 1629 p += sizeof(pathid); 1630 len -= sizeof(pathid); 1631 wlen -= sizeof(pathid); 1632 } 1633 if ((pos = nlri_get_prefix(p, wlen, &prefix, 1634 &prefixlen)) == -1) { 1635 printf("bad withdraw prefix"); 1636 return; 1637 } 1638 printf(" %s/%u", log_addr(&prefix), prefixlen); 1639 if (addpath) 1640 printf(" path-id %u", pathid); 1641 p += pos; 1642 len -= pos; 1643 wlen -= pos; 1644 } 1645 } 1646 1647 if (len < sizeof(alen)) { 1648 printf("bad length"); 1649 return; 1650 } 1651 memcpy(&alen, p, sizeof(alen)); 1652 alen = ntohs(alen); 1653 p += sizeof(alen); 1654 len -= sizeof(alen); 1655 1656 if (len < alen) { 1657 printf("bad attribute length"); 1658 return; 1659 } 1660 printf("\n"); 1661 /* alen attributes here */ 1662 while (alen > 3) { 1663 u_int8_t flags; 1664 u_int16_t attrlen; 1665 1666 flags = p[0]; 1667 /* type = p[1]; */ 1668 1669 /* get the attribute length */ 1670 if (flags & ATTR_EXTLEN) { 1671 if (len < sizeof(attrlen) + 2) 1672 printf("bad attribute length"); 1673 memcpy(&attrlen, &p[2], sizeof(attrlen)); 1674 attrlen = ntohs(attrlen); 1675 attrlen += sizeof(attrlen) + 2; 1676 } else { 1677 attrlen = p[2]; 1678 attrlen += 1 + 2; 1679 } 1680 1681 output->attr(p, attrlen, reqflags, addpath); 1682 p += attrlen; 1683 alen -= attrlen; 1684 len -= attrlen; 1685 } 1686 1687 if (len > 0) { 1688 printf(" NLRI prefixes:"); 1689 while (len > 0) { 1690 if (addpath) { 1691 if (len <= sizeof(pathid)) { 1692 printf(" bad nlri prefix: pathid, len %d", len); 1693 return; 1694 } 1695 memcpy(&pathid, p, sizeof(pathid)); 1696 pathid = ntohl(pathid); 1697 p += sizeof(pathid); 1698 len -= sizeof(pathid); 1699 } 1700 if ((pos = nlri_get_prefix(p, len, &prefix, 1701 &prefixlen)) == -1) { 1702 printf(" bad nlri prefix"); 1703 return; 1704 } 1705 printf(" %s/%u", log_addr(&prefix), prefixlen); 1706 if (addpath) 1707 printf(" path-id %u", pathid); 1708 p += pos; 1709 len -= pos; 1710 } 1711 } 1712 } 1713 1714 void 1715 show_mrt_msg(struct mrt_bgp_msg *mm, void *arg) 1716 { 1717 static const u_int8_t marker[MSGSIZE_HEADER_MARKER] = { 1718 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1719 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 1720 u_char *p; 1721 u_int16_t len; 1722 u_int8_t type; 1723 struct ctl_show_rib_request *req = arg; 1724 1725 printf("%s %s[%u] -> ", fmt_time(&mm->time), 1726 log_addr(&mm->src), mm->src_as); 1727 printf("%s[%u]: size %u%s ", log_addr(&mm->dst), mm->dst_as, 1728 mm->msg_len, mm->add_path ? " addpath" : ""); 1729 p = mm->msg; 1730 len = mm->msg_len; 1731 1732 if (len < MSGSIZE_HEADER) { 1733 printf("illegal header length: %u byte\n", len); 1734 return; 1735 } 1736 1737 /* parse BGP message header */ 1738 if (memcmp(p, marker, sizeof(marker))) { 1739 printf("incorrect marker in BGP message\n"); 1740 return; 1741 } 1742 p += MSGSIZE_HEADER_MARKER; 1743 1744 memcpy(&len, p, 2); 1745 len = ntohs(len); 1746 p += 2; 1747 memcpy(&type, p, 1); 1748 p += 1; 1749 1750 if (len < MSGSIZE_HEADER || len > MAX_PKTSIZE) { 1751 printf("illegal header length: %u byte\n", len); 1752 return; 1753 } 1754 1755 switch (type) { 1756 case OPEN: 1757 printf("%s ", msgtypenames[type]); 1758 if (len < MSGSIZE_OPEN_MIN) { 1759 printf("illegal length: %u byte\n", len); 1760 return; 1761 } 1762 show_mrt_open(p, len - MSGSIZE_HEADER); 1763 break; 1764 case NOTIFICATION: 1765 printf("%s ", msgtypenames[type]); 1766 if (len < MSGSIZE_NOTIFICATION_MIN) { 1767 printf("illegal length: %u byte\n", len); 1768 return; 1769 } 1770 show_mrt_notification(p, len - MSGSIZE_HEADER); 1771 break; 1772 case UPDATE: 1773 printf("%s ", msgtypenames[type]); 1774 if (len < MSGSIZE_UPDATE_MIN) { 1775 printf("illegal length: %u byte\n", len); 1776 return; 1777 } 1778 show_mrt_update(p, len - MSGSIZE_HEADER, req->flags, 1779 mm->add_path); 1780 break; 1781 case KEEPALIVE: 1782 printf("%s ", msgtypenames[type]); 1783 if (len != MSGSIZE_KEEPALIVE) { 1784 printf("illegal length: %u byte\n", len); 1785 return; 1786 } 1787 /* nothing */ 1788 break; 1789 case RREFRESH: 1790 printf("%s ", msgtypenames[type]); 1791 if (len != MSGSIZE_RREFRESH) { 1792 printf("illegal length: %u byte\n", len); 1793 return; 1794 } 1795 print_afi(p, len); 1796 break; 1797 default: 1798 printf("unknown type %u\n", type); 1799 return; 1800 } 1801 printf("\n"); 1802 } 1803 1804 const char * 1805 msg_type(u_int8_t type) 1806 { 1807 if (type >= sizeof(msgtypenames)/sizeof(msgtypenames[0])) 1808 return "BAD"; 1809 return (msgtypenames[type]); 1810 } 1811 1812 int 1813 match_aspath(void *data, u_int16_t len, struct filter_as *f) 1814 { 1815 u_int8_t *seg; 1816 int final; 1817 u_int16_t seg_size; 1818 u_int8_t i, seg_len; 1819 u_int32_t as = 0; 1820 1821 if (f->type == AS_EMPTY) { 1822 if (len == 0) 1823 return (1); 1824 else 1825 return (0); 1826 } 1827 1828 seg = data; 1829 1830 /* just check the leftmost AS */ 1831 if (f->type == AS_PEER && len >= 6) { 1832 as = aspath_extract(seg, 0); 1833 if (f->as_min == as) 1834 return (1); 1835 else 1836 return (0); 1837 } 1838 1839 for (; len >= 6; len -= seg_size, seg += seg_size) { 1840 seg_len = seg[1]; 1841 seg_size = 2 + sizeof(u_int32_t) * seg_len; 1842 1843 final = (len == seg_size); 1844 1845 if (f->type == AS_SOURCE) { 1846 /* 1847 * Just extract the rightmost AS 1848 * but if that segment is an AS_SET then the rightmost 1849 * AS of a previous AS_SEQUENCE segment should be used. 1850 * Because of that just look at AS_SEQUENCE segments. 1851 */ 1852 if (seg[0] == AS_SEQUENCE) 1853 as = aspath_extract(seg, seg_len - 1); 1854 /* not yet in the final segment */ 1855 if (!final) 1856 continue; 1857 if (f->as_min == as) 1858 return (1); 1859 else 1860 return (0); 1861 } 1862 /* AS_TRANSIT or AS_ALL */ 1863 for (i = 0; i < seg_len; i++) { 1864 /* 1865 * the source (rightmost) AS is excluded from 1866 * AS_TRANSIT matches. 1867 */ 1868 if (final && i == seg_len - 1 && f->type == AS_TRANSIT) 1869 return (0); 1870 as = aspath_extract(seg, i); 1871 if (f->as_min == as) 1872 return (1); 1873 } 1874 } 1875 return (0); 1876 } 1877