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