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