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