1 /* $OpenBSD: printconf.c,v 1.167 2023/04/28 13:23:52 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 2016 Job Snijders <job@instituut.net> 6 * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA, PROFITS OR MIND, WHETHER IN 17 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 18 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <limits.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 #include "bgpd.h" 27 #include "session.h" 28 #include "rde.h" 29 #include "log.h" 30 31 void print_prefix(struct filter_prefix *p); 32 const char *community_type(struct community *c); 33 void print_community(struct community *c); 34 void print_origin(uint8_t); 35 void print_set(struct filter_set_head *); 36 void print_mainconf(struct bgpd_config *); 37 void print_l3vpn_targets(struct filter_set_head *, const char *); 38 void print_l3vpn(struct l3vpn *); 39 const char *print_af(uint8_t); 40 void print_network(struct network_config *, const char *); 41 void print_flowspec(struct flowspec_config *, const char *); 42 void print_as_sets(struct as_set_head *); 43 void print_prefixsets(struct prefixset_head *); 44 void print_originsets(struct prefixset_head *); 45 void print_roa(struct roa_tree *); 46 void print_aspa(struct aspa_tree *); 47 void print_rtrs(struct rtr_config_head *); 48 void print_peer(struct peer_config *, struct bgpd_config *, 49 const char *); 50 const char *print_auth_alg(enum auth_alg); 51 const char *print_enc_alg(enum auth_enc_alg); 52 void print_announce(struct peer_config *, const char *); 53 void print_as(struct filter_rule *); 54 void print_rule(struct bgpd_config *, struct filter_rule *); 55 const char *mrt_type(enum mrt_type); 56 void print_mrt(struct bgpd_config *, uint32_t, uint32_t, 57 const char *, const char *); 58 void print_groups(struct bgpd_config *); 59 int peer_compare(const void *, const void *); 60 61 void 62 print_prefix(struct filter_prefix *p) 63 { 64 uint8_t max_len = 0; 65 66 switch (p->addr.aid) { 67 case AID_INET: 68 case AID_VPN_IPv4: 69 max_len = 32; 70 break; 71 case AID_INET6: 72 case AID_VPN_IPv6: 73 max_len = 128; 74 break; 75 case AID_UNSPEC: 76 /* no prefix to print */ 77 return; 78 } 79 80 printf("%s/%u", log_addr(&p->addr), p->len); 81 82 switch (p->op) { 83 case OP_NONE: 84 break; 85 case OP_NE: 86 printf(" prefixlen != %u", p->len_min); 87 break; 88 case OP_XRANGE: 89 printf(" prefixlen %u >< %u ", p->len_min, p->len_max); 90 break; 91 case OP_RANGE: 92 if (p->len_min == p->len_max && p->len != p->len_min) 93 printf(" prefixlen = %u", p->len_min); 94 else if (p->len == p->len_min && p->len_max == max_len) 95 printf(" or-longer"); 96 else if (p->len == p->len_min && p->len != p->len_max) 97 printf(" maxlen %u", p->len_max); 98 else if (p->len_max == max_len) 99 printf(" prefixlen >= %u", p->len_min); 100 else 101 printf(" prefixlen %u - %u", p->len_min, p->len_max); 102 break; 103 default: 104 printf(" prefixlen %u ??? %u", p->len_min, p->len_max); 105 break; 106 } 107 } 108 109 const char * 110 community_type(struct community *c) 111 { 112 switch ((uint8_t)c->flags) { 113 case COMMUNITY_TYPE_BASIC: 114 return "community"; 115 case COMMUNITY_TYPE_LARGE: 116 return "large-community"; 117 case COMMUNITY_TYPE_EXT: 118 return "ext-community"; 119 default: 120 return "???"; 121 } 122 } 123 124 void 125 print_community(struct community *c) 126 { 127 struct in_addr addr; 128 int type; 129 uint8_t subtype; 130 131 switch ((uint8_t)c->flags) { 132 case COMMUNITY_TYPE_BASIC: 133 switch ((c->flags >> 8) & 0xff) { 134 case COMMUNITY_ANY: 135 printf("*:"); 136 break; 137 case COMMUNITY_NEIGHBOR_AS: 138 printf("neighbor-as:"); 139 break; 140 case COMMUNITY_LOCAL_AS: 141 printf("local-as:"); 142 break; 143 default: 144 printf("%u:", c->data1); 145 break; 146 } 147 switch ((c->flags >> 16) & 0xff) { 148 case COMMUNITY_ANY: 149 printf("* "); 150 break; 151 case COMMUNITY_NEIGHBOR_AS: 152 printf("neighbor-as "); 153 break; 154 case COMMUNITY_LOCAL_AS: 155 printf("local-as "); 156 break; 157 default: 158 printf("%u ", c->data2); 159 break; 160 } 161 break; 162 case COMMUNITY_TYPE_LARGE: 163 switch ((c->flags >> 8) & 0xff) { 164 case COMMUNITY_ANY: 165 printf("*:"); 166 break; 167 case COMMUNITY_NEIGHBOR_AS: 168 printf("neighbor-as:"); 169 break; 170 case COMMUNITY_LOCAL_AS: 171 printf("local-as:"); 172 break; 173 default: 174 printf("%u:", c->data1); 175 break; 176 } 177 switch ((c->flags >> 16) & 0xff) { 178 case COMMUNITY_ANY: 179 printf("*:"); 180 break; 181 case COMMUNITY_NEIGHBOR_AS: 182 printf("neighbor-as:"); 183 break; 184 case COMMUNITY_LOCAL_AS: 185 printf("local-as:"); 186 break; 187 default: 188 printf("%u:", c->data2); 189 break; 190 } 191 switch ((c->flags >> 24) & 0xff) { 192 case COMMUNITY_ANY: 193 printf("* "); 194 break; 195 case COMMUNITY_NEIGHBOR_AS: 196 printf("neighbor-as "); 197 break; 198 case COMMUNITY_LOCAL_AS: 199 printf("local-as "); 200 break; 201 default: 202 printf("%u ", c->data3); 203 break; 204 } 205 break; 206 case COMMUNITY_TYPE_EXT: 207 if ((c->flags >> 24 & 0xff) == COMMUNITY_ANY) { 208 printf("* * "); 209 break; 210 } 211 type = (int32_t)c->data3 >> 8; 212 subtype = c->data3; 213 printf("%s ", log_ext_subtype(type, subtype)); 214 if ((c->flags >> 8 & 0xff) == COMMUNITY_ANY) { 215 printf("* "); 216 break; 217 } 218 219 switch (type) { 220 case EXT_COMMUNITY_TRANS_TWO_AS: 221 case EXT_COMMUNITY_TRANS_FOUR_AS: 222 case EXT_COMMUNITY_GEN_TWO_AS: 223 case EXT_COMMUNITY_GEN_FOUR_AS: 224 if ((c->flags >> 8 & 0xff) == COMMUNITY_NEIGHBOR_AS) 225 printf("neighbor-as:"); 226 else if ((c->flags >> 8 & 0xff) == COMMUNITY_LOCAL_AS) 227 printf("local-as:"); 228 else 229 printf("%s:", log_as(c->data1)); 230 break; 231 case EXT_COMMUNITY_TRANS_IPV4: 232 case EXT_COMMUNITY_GEN_IPV4: 233 addr.s_addr = htonl(c->data1); 234 printf("%s:", inet_ntoa(addr)); 235 break; 236 } 237 238 switch (type) { 239 case EXT_COMMUNITY_TRANS_TWO_AS: 240 case EXT_COMMUNITY_TRANS_FOUR_AS: 241 case EXT_COMMUNITY_TRANS_IPV4: 242 case EXT_COMMUNITY_GEN_TWO_AS: 243 case EXT_COMMUNITY_GEN_FOUR_AS: 244 case EXT_COMMUNITY_GEN_IPV4: 245 if ((c->flags >> 16 & 0xff) == COMMUNITY_ANY) 246 printf("* "); 247 else if ((c->flags >> 16 & 0xff) == 248 COMMUNITY_NEIGHBOR_AS) 249 printf("neighbor-as "); 250 else if ((c->flags >> 16 & 0xff) == COMMUNITY_LOCAL_AS) 251 printf("local-as "); 252 else 253 printf("%u ", c->data2); 254 break; 255 case EXT_COMMUNITY_NON_TRANS_OPAQUE: 256 if (subtype == EXT_COMMUNITY_SUBTYPE_OVS) { 257 switch (c->data2) { 258 case EXT_COMMUNITY_OVS_VALID: 259 printf("valid "); 260 break; 261 case EXT_COMMUNITY_OVS_NOTFOUND: 262 printf("not-found "); 263 break; 264 case EXT_COMMUNITY_OVS_INVALID: 265 printf("invalid "); 266 break; 267 } 268 break; 269 } 270 printf("0x%x%08x ", c->data1 & 0xffff, c->data2); 271 break; 272 case EXT_COMMUNITY_TRANS_OPAQUE: 273 case EXT_COMMUNITY_TRANS_EVPN: 274 default: 275 printf("0x%x%08x ", c->data1 & 0xffff, c->data2); 276 break; 277 } 278 } 279 } 280 281 void 282 print_origin(uint8_t o) 283 { 284 if (o == ORIGIN_IGP) 285 printf("igp "); 286 else if (o == ORIGIN_EGP) 287 printf("egp "); 288 else if (o == ORIGIN_INCOMPLETE) 289 printf("incomplete "); 290 else 291 printf("%u ", o); 292 } 293 294 void 295 print_set(struct filter_set_head *set) 296 { 297 struct filter_set *s; 298 299 if (TAILQ_EMPTY(set)) 300 return; 301 302 printf("set { "); 303 TAILQ_FOREACH(s, set, entry) { 304 switch (s->type) { 305 case ACTION_SET_LOCALPREF: 306 printf("localpref %u ", s->action.metric); 307 break; 308 case ACTION_SET_RELATIVE_LOCALPREF: 309 printf("localpref %+d ", s->action.relative); 310 break; 311 case ACTION_SET_MED: 312 printf("metric %u ", s->action.metric); 313 break; 314 case ACTION_SET_RELATIVE_MED: 315 printf("metric %+d ", s->action.relative); 316 break; 317 case ACTION_SET_WEIGHT: 318 printf("weight %u ", s->action.metric); 319 break; 320 case ACTION_SET_RELATIVE_WEIGHT: 321 printf("weight %+d ", s->action.relative); 322 break; 323 case ACTION_SET_NEXTHOP: 324 printf("nexthop %s ", log_addr(&s->action.nexthop)); 325 break; 326 case ACTION_SET_NEXTHOP_REJECT: 327 printf("nexthop reject "); 328 break; 329 case ACTION_SET_NEXTHOP_BLACKHOLE: 330 printf("nexthop blackhole "); 331 break; 332 case ACTION_SET_NEXTHOP_NOMODIFY: 333 printf("nexthop no-modify "); 334 break; 335 case ACTION_SET_NEXTHOP_SELF: 336 printf("nexthop self "); 337 break; 338 case ACTION_SET_PREPEND_SELF: 339 printf("prepend-self %u ", s->action.prepend); 340 break; 341 case ACTION_SET_PREPEND_PEER: 342 printf("prepend-neighbor %u ", s->action.prepend); 343 break; 344 case ACTION_SET_AS_OVERRIDE: 345 printf("as-override "); 346 break; 347 case ACTION_DEL_COMMUNITY: 348 printf("%s delete ", 349 community_type(&s->action.community)); 350 print_community(&s->action.community); 351 break; 352 case ACTION_SET_COMMUNITY: 353 printf("%s ", community_type(&s->action.community)); 354 print_community(&s->action.community); 355 break; 356 case ACTION_PFTABLE: 357 printf("pftable %s ", s->action.pftable); 358 break; 359 case ACTION_RTLABEL: 360 printf("rtlabel %s ", s->action.rtlabel); 361 break; 362 case ACTION_SET_ORIGIN: 363 printf("origin "); 364 print_origin(s->action.origin); 365 break; 366 case ACTION_RTLABEL_ID: 367 case ACTION_PFTABLE_ID: 368 case ACTION_SET_NEXTHOP_REF: 369 /* not possible */ 370 printf("king bula saiz: config broken"); 371 break; 372 } 373 } 374 printf("}"); 375 } 376 377 void 378 print_mainconf(struct bgpd_config *conf) 379 { 380 struct in_addr ina; 381 struct listen_addr *la; 382 383 printf("AS %s", log_as(conf->as)); 384 if (conf->as > USHRT_MAX && conf->short_as != AS_TRANS) 385 printf(" %u", conf->short_as); 386 ina.s_addr = conf->bgpid; 387 printf("\nrouter-id %s\n", inet_ntoa(ina)); 388 389 printf("socket \"%s\"\n", conf->csock); 390 if (conf->rcsock) 391 printf("socket \"%s\" restricted\n", conf->rcsock); 392 if (conf->holdtime != INTERVAL_HOLD) 393 printf("holdtime %u\n", conf->holdtime); 394 if (conf->min_holdtime != MIN_HOLDTIME) 395 printf("holdtime min %u\n", conf->min_holdtime); 396 if (conf->connectretry != INTERVAL_CONNECTRETRY) 397 printf("connect-retry %u\n", conf->connectretry); 398 399 if (conf->flags & BGPD_FLAG_DECISION_ROUTEAGE) 400 printf("rde route-age evaluate\n"); 401 if (conf->flags & BGPD_FLAG_DECISION_MED_ALWAYS) 402 printf("rde med compare always\n"); 403 if (conf->flags & BGPD_FLAG_DECISION_ALL_PATHS) 404 printf("rde evaluate all\n"); 405 406 if (conf->flags & BGPD_FLAG_NO_AS_SET) 407 printf("reject as-set yes\n"); 408 409 if (conf->log & BGPD_LOG_UPDATES) 410 printf("log updates\n"); 411 412 TAILQ_FOREACH(la, conf->listen_addrs, entry) { 413 struct bgpd_addr addr; 414 uint16_t port; 415 416 sa2addr((struct sockaddr *)&la->sa, &addr, &port); 417 printf("listen on %s", 418 log_sockaddr((struct sockaddr *)&la->sa, la->sa_len)); 419 if (port != BGP_PORT) 420 printf(" port %hu", port); 421 printf("\n"); 422 } 423 424 if (conf->flags & BGPD_FLAG_NEXTHOP_BGP) 425 printf("nexthop qualify via bgp\n"); 426 if (conf->flags & BGPD_FLAG_NEXTHOP_DEFAULT) 427 printf("nexthop qualify via default\n"); 428 if (conf->fib_priority != kr_default_prio()) 429 printf("fib-priority %hhu\n", conf->fib_priority); 430 printf("\n"); 431 } 432 433 void 434 print_l3vpn_targets(struct filter_set_head *set, const char *tgt) 435 { 436 struct filter_set *s; 437 TAILQ_FOREACH(s, set, entry) { 438 printf("\t%s ", tgt); 439 print_community(&s->action.community); 440 printf("\n"); 441 } 442 } 443 444 void 445 print_l3vpn(struct l3vpn *vpn) 446 { 447 struct network *n; 448 449 printf("vpn \"%s\" on %s {\n", vpn->descr, vpn->ifmpe); 450 printf("\t%s\n", log_rd(vpn->rd)); 451 452 print_l3vpn_targets(&vpn->export, "export-target"); 453 print_l3vpn_targets(&vpn->import, "import-target"); 454 455 if (vpn->flags & F_RIB_NOFIBSYNC) 456 printf("\tfib-update no\n"); 457 else 458 printf("\tfib-update yes\n"); 459 460 TAILQ_FOREACH(n, &vpn->net_l, entry) 461 print_network(&n->net, "\t"); 462 463 printf("}\n"); 464 } 465 466 const char * 467 print_af(uint8_t aid) 468 { 469 /* 470 * Hack around the fact that aid2str() will return "IPv4 unicast" 471 * for AID_INET. AID_INET, AID_INET6 and the flowspec AID need 472 * special handling and the other AID should never end up here. 473 */ 474 if (aid == AID_INET || aid == AID_FLOWSPECv4) 475 return ("inet"); 476 if (aid == AID_INET6 || aid == AID_FLOWSPECv6) 477 return ("inet6"); 478 return (aid2str(aid)); 479 } 480 481 void 482 print_network(struct network_config *n, const char *c) 483 { 484 switch (n->type) { 485 case NETWORK_STATIC: 486 printf("%snetwork %s static", c, print_af(n->prefix.aid)); 487 break; 488 case NETWORK_CONNECTED: 489 printf("%snetwork %s connected", c, print_af(n->prefix.aid)); 490 break; 491 case NETWORK_RTLABEL: 492 printf("%snetwork %s rtlabel \"%s\"", c, 493 print_af(n->prefix.aid), rtlabel_id2name(n->rtlabel)); 494 break; 495 case NETWORK_PRIORITY: 496 printf("%snetwork %s priority %d", c, 497 print_af(n->prefix.aid), n->priority); 498 break; 499 case NETWORK_PREFIXSET: 500 printf("%snetwork prefix-set %s", c, n->psname); 501 break; 502 default: 503 printf("%snetwork %s/%u", c, log_addr(&n->prefix), 504 n->prefixlen); 505 break; 506 } 507 if (!TAILQ_EMPTY(&n->attrset)) 508 printf(" "); 509 print_set(&n->attrset); 510 printf("\n"); 511 } 512 513 static void 514 print_flowspec_list(struct flowspec *f, int type, int is_v6) 515 { 516 const uint8_t *comp; 517 const char *fmt; 518 int complen, off = 0; 519 520 if (flowspec_get_component(f->data, f->len, type, is_v6, 521 &comp, &complen) != 1) 522 return; 523 524 printf("%s ", flowspec_fmt_label(type)); 525 fmt = flowspec_fmt_num_op(comp, complen, &off); 526 if (off == -1) { 527 printf("%s ", fmt); 528 } else { 529 printf("{ %s ", fmt); 530 do { 531 fmt = flowspec_fmt_num_op(comp, complen, &off); 532 printf("%s ", fmt); 533 } while (off != -1); 534 printf("} "); 535 } 536 } 537 538 static void 539 print_flowspec_flags(struct flowspec *f, int type, int is_v6) 540 { 541 const uint8_t *comp; 542 const char *fmt, *flags; 543 int complen, off = 0; 544 545 switch (type) { 546 case FLOWSPEC_TYPE_TCP_FLAGS: 547 flags = FLOWSPEC_TCP_FLAG_STRING; 548 break; 549 case FLOWSPEC_TYPE_FRAG: 550 if (!is_v6) 551 flags = FLOWSPEC_FRAG_STRING4; 552 else 553 flags = FLOWSPEC_FRAG_STRING6; 554 break; 555 default: 556 printf("??? "); 557 return; 558 } 559 560 if (flowspec_get_component(f->data, f->len, type, is_v6, 561 &comp, &complen) != 1) 562 return; 563 564 printf("%s ", flowspec_fmt_label(type)); 565 566 fmt = flowspec_fmt_bin_op(comp, complen, &off, flags); 567 if (off == -1) { 568 printf("%s ", fmt); 569 } else { 570 printf("{ %s ", fmt); 571 do { 572 fmt = flowspec_fmt_bin_op(comp, complen, &off, flags); 573 printf("%s ", fmt); 574 } while (off != -1); 575 printf("} "); 576 } 577 } 578 579 static void 580 print_flowspec_addr(struct flowspec *f, int type, int is_v6) 581 { 582 struct bgpd_addr addr; 583 uint8_t plen; 584 585 flowspec_get_addr(f->data, f->len, type, is_v6, &addr, &plen, NULL); 586 if (plen == 0) 587 printf("%s any ", flowspec_fmt_label(type)); 588 else 589 printf("%s %s/%u ", flowspec_fmt_label(type), 590 log_addr(&addr), plen); 591 } 592 593 void 594 print_flowspec(struct flowspec_config *fconf, const char *c) 595 { 596 struct flowspec *f = fconf->flow; 597 int is_v6 = (f->aid == AID_FLOWSPECv6); 598 599 printf("%sflowspec %s ", c, print_af(f->aid)); 600 601 print_flowspec_list(f, FLOWSPEC_TYPE_PROTO, is_v6); 602 603 print_flowspec_addr(f, FLOWSPEC_TYPE_SOURCE, is_v6); 604 print_flowspec_list(f, FLOWSPEC_TYPE_SRC_PORT, is_v6); 605 606 print_flowspec_addr(f, FLOWSPEC_TYPE_DEST, is_v6); 607 print_flowspec_list(f, FLOWSPEC_TYPE_DST_PORT, is_v6); 608 609 print_flowspec_list(f, FLOWSPEC_TYPE_DSCP, is_v6); 610 print_flowspec_list(f, FLOWSPEC_TYPE_PKT_LEN, is_v6); 611 print_flowspec_flags(f, FLOWSPEC_TYPE_TCP_FLAGS, is_v6); 612 print_flowspec_flags(f, FLOWSPEC_TYPE_FRAG, is_v6); 613 614 /* TODO: fixup the code handling to be like in the parser */ 615 print_flowspec_list(f, FLOWSPEC_TYPE_ICMP_TYPE, is_v6); 616 print_flowspec_list(f, FLOWSPEC_TYPE_ICMP_CODE, is_v6); 617 618 print_set(&fconf->attrset); 619 printf("\n"); 620 } 621 622 void 623 print_as_sets(struct as_set_head *as_sets) 624 { 625 struct as_set *aset; 626 uint32_t *as; 627 size_t i, n; 628 int len; 629 630 SIMPLEQ_FOREACH(aset, as_sets, entry) { 631 printf("as-set \"%s\" {\n\t", aset->name); 632 as = set_get(aset->set, &n); 633 for (i = 0, len = 8; i < n; i++) { 634 if (len > 72) { 635 printf("\n\t"); 636 len = 8; 637 } 638 len += printf("%u ", as[i]); 639 } 640 printf("\n}\n\n"); 641 } 642 } 643 644 void 645 print_prefixsets(struct prefixset_head *psh) 646 { 647 struct prefixset *ps; 648 struct prefixset_item *psi; 649 650 SIMPLEQ_FOREACH(ps, psh, entry) { 651 int count = 0; 652 printf("prefix-set \"%s\" {", ps->name); 653 RB_FOREACH(psi, prefixset_tree, &ps->psitems) { 654 if (count++ % 2 == 0) 655 printf("\n\t"); 656 else 657 printf(", "); 658 print_prefix(&psi->p); 659 } 660 printf("\n}\n\n"); 661 } 662 } 663 664 void 665 print_originsets(struct prefixset_head *psh) 666 { 667 struct prefixset *ps; 668 struct roa *roa; 669 struct bgpd_addr addr; 670 671 SIMPLEQ_FOREACH(ps, psh, entry) { 672 printf("origin-set \"%s\" {", ps->name); 673 RB_FOREACH(roa, roa_tree, &ps->roaitems) { 674 printf("\n\t"); 675 addr.aid = roa->aid; 676 addr.v6 = roa->prefix.inet6; 677 printf("%s/%u", log_addr(&addr), roa->prefixlen); 678 if (roa->prefixlen != roa->maxlen) 679 printf(" maxlen %u", roa->maxlen); 680 printf(" source-as %u", roa->asnum); 681 } 682 printf("\n}\n\n"); 683 } 684 } 685 686 void 687 print_roa(struct roa_tree *r) 688 { 689 struct roa *roa; 690 struct bgpd_addr addr; 691 692 if (RB_EMPTY(r)) 693 return; 694 695 printf("roa-set {"); 696 RB_FOREACH(roa, roa_tree, r) { 697 printf("\n\t"); 698 addr.aid = roa->aid; 699 addr.v6 = roa->prefix.inet6; 700 printf("%s/%u", log_addr(&addr), roa->prefixlen); 701 if (roa->prefixlen != roa->maxlen) 702 printf(" maxlen %u", roa->maxlen); 703 printf(" source-as %u", roa->asnum); 704 if (roa->expires != 0) 705 printf(" expires %lld", (long long)roa->expires); 706 } 707 printf("\n}\n\n"); 708 } 709 710 void 711 print_aspa(struct aspa_tree *a) 712 { 713 struct aspa_set *aspa; 714 uint32_t i; 715 716 if (RB_EMPTY(a)) 717 return; 718 719 printf("aspa-set {"); 720 RB_FOREACH(aspa, aspa_tree, a) { 721 printf("\n\t"); 722 printf("customer-as %s", log_as(aspa->as)); 723 if (aspa->expires != 0) 724 printf(" expires %lld", (long long)aspa->expires); 725 printf(" provider-as { "); 726 for (i = 0; i < aspa->num; i++) { 727 printf("%s ", log_as(aspa->tas[i])); 728 if (aspa->tas_aid[i] != AID_UNSPEC) 729 printf("%s ", print_af(aspa->tas_aid[i])); 730 } 731 printf("}"); 732 } 733 printf("\n}\n\n"); 734 } 735 736 void 737 print_rtrs(struct rtr_config_head *rh) 738 { 739 struct rtr_config *r; 740 741 SIMPLEQ_FOREACH(r, rh, entry) { 742 printf("rtr %s {\n", log_addr(&r->remote_addr)); 743 printf("\tdescr \"%s\"\n", r->descr); 744 printf("\tport %u\n", r->remote_port); 745 if (r->local_addr.aid != AID_UNSPEC) 746 printf("local-addr %s\n", log_addr(&r->local_addr)); 747 printf("}\n\n"); 748 } 749 } 750 751 void 752 print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c) 753 { 754 char *method; 755 struct in_addr ina; 756 757 if ((p->remote_addr.aid == AID_INET && p->remote_masklen != 32) || 758 (p->remote_addr.aid == AID_INET6 && p->remote_masklen != 128)) 759 printf("%sneighbor %s/%u {\n", c, log_addr(&p->remote_addr), 760 p->remote_masklen); 761 else 762 printf("%sneighbor %s {\n", c, log_addr(&p->remote_addr)); 763 if (p->descr[0]) 764 printf("%s\tdescr \"%s\"\n", c, p->descr); 765 if (p->rib[0]) 766 printf("%s\trib \"%s\"\n", c, p->rib); 767 if (p->remote_as) 768 printf("%s\tremote-as %s\n", c, log_as(p->remote_as)); 769 if (p->local_as != conf->as) { 770 printf("%s\tlocal-as %s", c, log_as(p->local_as)); 771 if (p->local_as > USHRT_MAX && p->local_short_as != AS_TRANS) 772 printf(" %u", p->local_short_as); 773 printf("\n"); 774 } 775 if (p->down) 776 printf("%s\tdown\n", c); 777 if (p->distance > 1) 778 printf("%s\tmultihop %u\n", c, p->distance); 779 if (p->passive) 780 printf("%s\tpassive\n", c); 781 if (p->local_addr_v4.aid) 782 printf("%s\tlocal-address %s\n", c, 783 log_addr(&p->local_addr_v4)); 784 if (p->local_addr_v6.aid) 785 printf("%s\tlocal-address %s\n", c, 786 log_addr(&p->local_addr_v6)); 787 if (p->remote_port != BGP_PORT) 788 printf("%s\tport %hu\n", c, p->remote_port); 789 if (p->role != ROLE_NONE) 790 printf("%s\trole %s\n", c, log_policy(p->role)); 791 if (p->max_prefix) { 792 printf("%s\tmax-prefix %u", c, p->max_prefix); 793 if (p->max_prefix_restart) 794 printf(" restart %u", p->max_prefix_restart); 795 printf("\n"); 796 } 797 if (p->max_out_prefix) { 798 printf("%s\tmax-prefix %u out", c, p->max_out_prefix); 799 if (p->max_out_prefix_restart) 800 printf(" restart %u", p->max_out_prefix_restart); 801 printf("\n"); 802 } 803 if (p->holdtime) 804 printf("%s\tholdtime %u\n", c, p->holdtime); 805 if (p->min_holdtime) 806 printf("%s\tholdtime min %u\n", c, p->min_holdtime); 807 if (p->export_type == EXPORT_NONE) 808 printf("%s\texport none\n", c); 809 else if (p->export_type == EXPORT_DEFAULT_ROUTE) 810 printf("%s\texport default-route\n", c); 811 if (p->enforce_as == ENFORCE_AS_ON) 812 printf("%s\tenforce neighbor-as yes\n", c); 813 else 814 printf("%s\tenforce neighbor-as no\n", c); 815 if (p->enforce_local_as == ENFORCE_AS_ON) 816 printf("%s\tenforce local-as yes\n", c); 817 else 818 printf("%s\tenforce local-as no\n", c); 819 if (p->reflector_client) { 820 if (conf->clusterid == 0) 821 printf("%s\troute-reflector\n", c); 822 else { 823 ina.s_addr = conf->clusterid; 824 printf("%s\troute-reflector %s\n", c, 825 inet_ntoa(ina)); 826 } 827 } 828 if (p->demote_group[0]) 829 printf("%s\tdemote %s\n", c, p->demote_group); 830 if (p->if_depend[0]) 831 printf("%s\tdepend on \"%s\"\n", c, p->if_depend); 832 if (p->flags & PEERFLAG_TRANS_AS) 833 printf("%s\ttransparent-as yes\n", c); 834 835 if (conf->flags & BGPD_FLAG_DECISION_ALL_PATHS) { 836 if (!(p->flags & PEERFLAG_EVALUATE_ALL)) 837 printf("%s\trde evaluate default\n", c); 838 } else { 839 if (p->flags & PEERFLAG_EVALUATE_ALL) 840 printf("%s\trde evaluate all\n", c); 841 } 842 843 if (conf->flags & BGPD_FLAG_NO_AS_SET) { 844 if (!(p->flags & PEERFLAG_NO_AS_SET)) 845 printf("%s\treject as-set no\n", c); 846 } else { 847 if (p->flags & PEERFLAG_NO_AS_SET) 848 printf("%s\treject as-set yes\n", c); 849 } 850 851 if (p->flags & PEERFLAG_LOG_UPDATES) 852 printf("%s\tlog updates\n", c); 853 854 if (p->auth.method == AUTH_MD5SIG) 855 printf("%s\ttcp md5sig\n", c); 856 else if (p->auth.method == AUTH_IPSEC_MANUAL_ESP || 857 p->auth.method == AUTH_IPSEC_MANUAL_AH) { 858 if (p->auth.method == AUTH_IPSEC_MANUAL_ESP) 859 method = "esp"; 860 else 861 method = "ah"; 862 863 printf("%s\tipsec %s in spi %u %s XXXXXX", c, method, 864 p->auth.spi_in, print_auth_alg(p->auth.auth_alg_in)); 865 if (p->auth.enc_alg_in) 866 printf(" %s XXXXXX", print_enc_alg(p->auth.enc_alg_in)); 867 printf("\n"); 868 869 printf("%s\tipsec %s out spi %u %s XXXXXX", c, method, 870 p->auth.spi_out, print_auth_alg(p->auth.auth_alg_out)); 871 if (p->auth.enc_alg_out) 872 printf(" %s XXXXXX", 873 print_enc_alg(p->auth.enc_alg_out)); 874 printf("\n"); 875 } else if (p->auth.method == AUTH_IPSEC_IKE_AH) 876 printf("%s\tipsec ah ike\n", c); 877 else if (p->auth.method == AUTH_IPSEC_IKE_ESP) 878 printf("%s\tipsec esp ike\n", c); 879 880 if (p->ttlsec) 881 printf("%s\tttl-security yes\n", c); 882 883 print_announce(p, c); 884 885 print_mrt(conf, p->id, p->groupid, c, "\t"); 886 887 printf("%s}\n", c); 888 } 889 890 const char * 891 print_auth_alg(enum auth_alg alg) 892 { 893 switch (alg) { 894 case AUTH_AALG_SHA1HMAC: 895 return ("sha1"); 896 case AUTH_AALG_MD5HMAC: 897 return ("md5"); 898 default: 899 return ("???"); 900 } 901 } 902 903 const char * 904 print_enc_alg(enum auth_enc_alg alg) 905 { 906 switch (alg) { 907 case AUTH_EALG_3DESCBC: 908 return ("3des"); 909 case AUTH_EALG_AES: 910 return ("aes"); 911 default: 912 return ("???"); 913 } 914 } 915 916 static const char * 917 print_addpath_mode(enum addpath_mode mode) 918 { 919 switch (mode) { 920 case ADDPATH_EVAL_NONE: 921 return "none"; 922 case ADDPATH_EVAL_BEST: 923 return "best"; 924 case ADDPATH_EVAL_ECMP: 925 return "ecmp"; 926 case ADDPATH_EVAL_AS_WIDE: 927 return "as-wide-best"; 928 case ADDPATH_EVAL_ALL: 929 return "all"; 930 default: 931 return "???"; 932 } 933 } 934 935 void 936 print_announce(struct peer_config *p, const char *c) 937 { 938 uint8_t aid; 939 940 if (p->announce_capa == 0) 941 printf("%s\tannounce capabilities no\n", c); 942 943 for (aid = 0; aid < AID_MAX; aid++) 944 if (p->capabilities.mp[aid]) 945 printf("%s\tannounce %s\n", c, aid2str(aid)); 946 947 if (p->capabilities.refresh == 0) 948 printf("%s\tannounce refresh no\n", c); 949 if (p->capabilities.enhanced_rr == 1) 950 printf("%s\tannounce enhanced refresh yes\n", c); 951 if (p->capabilities.grestart.restart == 0) 952 printf("%s\tannounce restart no\n", c); 953 if (p->capabilities.as4byte == 0) 954 printf("%s\tannounce as4byte no\n", c); 955 if (p->capabilities.add_path[0] & CAPA_AP_RECV) 956 printf("%s\tannounce add-path recv yes\n", c); 957 if (p->capabilities.add_path[0] & CAPA_AP_SEND) { 958 printf("%s\tannounce add-path send %s", c, 959 print_addpath_mode(p->eval.mode)); 960 if (p->eval.extrapaths != 0) 961 printf(" plus %d", p->eval.extrapaths); 962 if (p->eval.maxpaths != 0) 963 printf(" max %d", p->eval.maxpaths); 964 printf("\n"); 965 } 966 if (p->capabilities.policy) { 967 printf("%s\tannounce policy %s\n", c, 968 p->capabilities.policy == 2 ? "enforce" : "yes"); 969 } 970 } 971 972 void 973 print_as(struct filter_rule *r) 974 { 975 if (r->match.as.flags & AS_FLAG_AS_SET_NAME) { 976 printf("as-set \"%s\" ", r->match.as.name); 977 return; 978 } 979 switch (r->match.as.op) { 980 case OP_RANGE: 981 printf("%s - ", log_as(r->match.as.as_min)); 982 printf("%s ", log_as(r->match.as.as_max)); 983 break; 984 case OP_XRANGE: 985 printf("%s >< ", log_as(r->match.as.as_min)); 986 printf("%s ", log_as(r->match.as.as_max)); 987 break; 988 case OP_NE: 989 printf("!= %s ", log_as(r->match.as.as_min)); 990 break; 991 default: 992 printf("%s ", log_as(r->match.as.as_min)); 993 break; 994 } 995 } 996 997 void 998 print_rule(struct bgpd_config *conf, struct filter_rule *r) 999 { 1000 struct peer *p; 1001 int i; 1002 1003 if (r->action == ACTION_ALLOW) 1004 printf("allow "); 1005 else if (r->action == ACTION_DENY) 1006 printf("deny "); 1007 else 1008 printf("match "); 1009 if (r->quick) 1010 printf("quick "); 1011 1012 if (r->rib[0]) 1013 printf("rib %s ", r->rib); 1014 1015 if (r->dir == DIR_IN) 1016 printf("from "); 1017 else if (r->dir == DIR_OUT) 1018 printf("to "); 1019 else 1020 printf("eeeeeeeps. "); 1021 1022 if (r->peer.peerid) { 1023 RB_FOREACH(p, peer_head, &conf->peers) 1024 if (p->conf.id == r->peer.peerid) 1025 break; 1026 if (p == NULL) 1027 printf("? "); 1028 else 1029 printf("%s ", log_addr(&p->conf.remote_addr)); 1030 } else if (r->peer.groupid) { 1031 RB_FOREACH(p, peer_head, &conf->peers) 1032 if (p->conf.groupid == r->peer.groupid) 1033 break; 1034 if (p == NULL) 1035 printf("group ? "); 1036 else 1037 printf("group \"%s\" ", p->conf.group); 1038 } else if (r->peer.remote_as) { 1039 printf("AS %s ", log_as(r->peer.remote_as)); 1040 } else if (r->peer.ebgp) { 1041 printf("ebgp "); 1042 } else if (r->peer.ibgp) { 1043 printf("ibgp "); 1044 } else 1045 printf("any "); 1046 1047 if (r->match.ovs.is_set) { 1048 switch (r->match.ovs.validity) { 1049 case ROA_VALID: 1050 printf("ovs valid "); 1051 break; 1052 case ROA_INVALID: 1053 printf("ovs invalid "); 1054 break; 1055 case ROA_NOTFOUND: 1056 printf("ovs not-found "); 1057 break; 1058 default: 1059 printf("ovs ??? %d ??? ", r->match.ovs.validity); 1060 } 1061 } 1062 1063 if (r->match.avs.is_set) { 1064 switch (r->match.avs.validity) { 1065 case ASPA_VALID: 1066 printf("avs valid "); 1067 break; 1068 case ASPA_INVALID: 1069 printf("avs invalid "); 1070 break; 1071 case ASPA_UNKNOWN: 1072 printf("avs unknown "); 1073 break; 1074 default: 1075 printf("avs ??? %d ??? ", r->match.avs.validity); 1076 } 1077 } 1078 1079 if (r->match.prefix.addr.aid != AID_UNSPEC) { 1080 printf("prefix "); 1081 print_prefix(&r->match.prefix); 1082 printf(" "); 1083 } 1084 1085 if (r->match.prefixset.name[0] != '\0') 1086 printf("prefix-set \"%s\" ", r->match.prefixset.name); 1087 if (r->match.prefixset.flags & PREFIXSET_FLAG_LONGER) 1088 printf("or-longer "); 1089 1090 if (r->match.originset.name[0] != '\0') 1091 printf("origin-set \"%s\" ", r->match.originset.name); 1092 1093 if (r->match.nexthop.flags) { 1094 if (r->match.nexthop.flags == FILTER_NEXTHOP_NEIGHBOR) 1095 printf("nexthop neighbor "); 1096 else 1097 printf("nexthop %s ", log_addr(&r->match.nexthop.addr)); 1098 } 1099 1100 if (r->match.as.type) { 1101 if (r->match.as.type == AS_ALL) 1102 printf("AS "); 1103 else if (r->match.as.type == AS_SOURCE) 1104 printf("source-as "); 1105 else if (r->match.as.type == AS_TRANSIT) 1106 printf("transit-as "); 1107 else if (r->match.as.type == AS_PEER) 1108 printf("peer-as "); 1109 else 1110 printf("unfluffy-as "); 1111 print_as(r); 1112 } 1113 1114 if (r->match.aslen.type) { 1115 printf("%s %u ", r->match.aslen.type == ASLEN_MAX ? 1116 "max-as-len" : "max-as-seq", r->match.aslen.aslen); 1117 } 1118 1119 for (i = 0; i < MAX_COMM_MATCH; i++) { 1120 struct community *c = &r->match.community[i]; 1121 if (c->flags != 0) { 1122 printf("%s ", community_type(c)); 1123 print_community(c); 1124 } 1125 } 1126 1127 if (r->match.maxcomm != 0) 1128 printf("max-communities %d ", r->match.maxcomm - 1); 1129 if (r->match.maxextcomm != 0) 1130 printf("max-ext-communities %d ", r->match.maxextcomm - 1); 1131 if (r->match.maxlargecomm != 0) 1132 printf("max-large-communities %d ", r->match.maxlargecomm - 1); 1133 1134 print_set(&r->set); 1135 1136 printf("\n"); 1137 } 1138 1139 const char * 1140 mrt_type(enum mrt_type t) 1141 { 1142 switch (t) { 1143 case MRT_NONE: 1144 break; 1145 case MRT_TABLE_DUMP: 1146 return "table"; 1147 case MRT_TABLE_DUMP_MP: 1148 return "table-mp"; 1149 case MRT_TABLE_DUMP_V2: 1150 return "table-v2"; 1151 case MRT_ALL_IN: 1152 return "all in"; 1153 case MRT_ALL_OUT: 1154 return "all out"; 1155 case MRT_UPDATE_IN: 1156 return "updates in"; 1157 case MRT_UPDATE_OUT: 1158 return "updates out"; 1159 } 1160 return "unfluffy MRT"; 1161 } 1162 1163 void 1164 print_mrt(struct bgpd_config *conf, uint32_t pid, uint32_t gid, 1165 const char *prep, const char *prep2) 1166 { 1167 struct mrt *m; 1168 1169 if (conf->mrt == NULL) 1170 return; 1171 1172 LIST_FOREACH(m, conf->mrt, entry) 1173 if ((gid != 0 && m->group_id == gid) || 1174 (m->peer_id == pid && m->group_id == gid)) { 1175 printf("%s%sdump ", prep, prep2); 1176 if (m->rib[0]) 1177 printf("rib %s ", m->rib); 1178 printf("%s \"%s\"", mrt_type(m->type), 1179 MRT2MC(m)->name); 1180 if (MRT2MC(m)->ReopenTimerInterval == 0) 1181 printf("\n"); 1182 else 1183 printf(" %d\n", MRT2MC(m)->ReopenTimerInterval); 1184 } 1185 if (!LIST_EMPTY(conf->mrt)) 1186 printf("\n"); 1187 } 1188 1189 void 1190 print_groups(struct bgpd_config *conf) 1191 { 1192 struct peer_config **peerlist; 1193 struct peer *p; 1194 u_int peer_cnt, i; 1195 uint32_t prev_groupid; 1196 const char *tab = "\t"; 1197 const char *nada = ""; 1198 const char *c; 1199 1200 peer_cnt = 0; 1201 RB_FOREACH(p, peer_head, &conf->peers) 1202 peer_cnt++; 1203 1204 if ((peerlist = calloc(peer_cnt, sizeof(struct peer_config *))) == NULL) 1205 fatal("print_groups calloc"); 1206 1207 i = 0; 1208 RB_FOREACH(p, peer_head, &conf->peers) 1209 peerlist[i++] = &p->conf; 1210 1211 qsort(peerlist, peer_cnt, sizeof(struct peer_config *), peer_compare); 1212 1213 prev_groupid = 0; 1214 for (i = 0; i < peer_cnt; i++) { 1215 if (peerlist[i]->groupid) { 1216 c = tab; 1217 if (peerlist[i]->groupid != prev_groupid) { 1218 if (prev_groupid) 1219 printf("}\n\n"); 1220 printf("group \"%s\" {\n", peerlist[i]->group); 1221 prev_groupid = peerlist[i]->groupid; 1222 } 1223 } else 1224 c = nada; 1225 1226 print_peer(peerlist[i], conf, c); 1227 } 1228 1229 if (prev_groupid) 1230 printf("}\n\n"); 1231 1232 free(peerlist); 1233 } 1234 1235 int 1236 peer_compare(const void *aa, const void *bb) 1237 { 1238 const struct peer_config * const *a; 1239 const struct peer_config * const *b; 1240 1241 a = aa; 1242 b = bb; 1243 1244 return ((*a)->groupid - (*b)->groupid); 1245 } 1246 1247 void 1248 print_config(struct bgpd_config *conf, struct rib_names *rib_l) 1249 { 1250 struct filter_rule *r; 1251 struct network *n; 1252 struct flowspec_config *f; 1253 struct rde_rib *rr; 1254 struct l3vpn *vpn; 1255 1256 print_mainconf(conf); 1257 print_rtrs(&conf->rtrs); 1258 print_roa(&conf->roa); 1259 print_aspa(&conf->aspa); 1260 print_as_sets(&conf->as_sets); 1261 print_prefixsets(&conf->prefixsets); 1262 print_originsets(&conf->originsets); 1263 TAILQ_FOREACH(n, &conf->networks, entry) 1264 print_network(&n->net, ""); 1265 RB_FOREACH(f, flowspec_tree, &conf->flowspecs) 1266 print_flowspec(f, ""); 1267 if (!SIMPLEQ_EMPTY(&conf->l3vpns)) 1268 printf("\n"); 1269 SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry) 1270 print_l3vpn(vpn); 1271 printf("\n"); 1272 SIMPLEQ_FOREACH(rr, rib_l, entry) { 1273 if (rr->flags & F_RIB_NOEVALUATE) 1274 printf("rde rib %s no evaluate\n", rr->name); 1275 else if (rr->flags & F_RIB_NOFIB) 1276 printf("rde rib %s\n", rr->name); 1277 else 1278 printf("rde rib %s rtable %u fib-update %s\n", rr->name, 1279 rr->rtableid, rr->flags & F_RIB_NOFIBSYNC ? 1280 "no" : "yes"); 1281 } 1282 printf("\n"); 1283 print_mrt(conf, 0, 0, "", ""); 1284 print_groups(conf); 1285 TAILQ_FOREACH(r, conf->filters, entry) 1286 print_rule(conf, r); 1287 } 1288