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