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