1 /* $OpenBSD: printconf.c,v 1.176 2024/10/09 10:01:29 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
print_prefix(struct filter_prefix * p)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 *
community_type(struct community * c)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
print_community(struct community * c)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
print_origin(uint8_t o)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
print_set(struct filter_set_head * set)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
print_mainconf(struct bgpd_config * conf)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
398 if (conf->flags & BGPD_FLAG_DECISION_ROUTEAGE)
399 printf("rde route-age evaluate\n");
400 if (conf->flags & BGPD_FLAG_DECISION_MED_ALWAYS)
401 printf("rde med compare always\n");
402 if (conf->flags & BGPD_FLAG_DECISION_ALL_PATHS)
403 printf("rde evaluate all\n");
404
405 if (conf->flags & BGPD_FLAG_NO_AS_SET)
406 printf("reject as-set yes\n");
407
408 if (conf->log & BGPD_LOG_UPDATES)
409 printf("log updates\n");
410
411 TAILQ_FOREACH(la, conf->listen_addrs, entry) {
412 struct bgpd_addr addr;
413 uint16_t port;
414
415 sa2addr((struct sockaddr *)&la->sa, &addr, &port);
416 printf("listen on %s",
417 log_sockaddr((struct sockaddr *)&la->sa, la->sa_len));
418 if (port != BGP_PORT)
419 printf(" port %hu", port);
420 printf("\n");
421 }
422
423 if (conf->flags & BGPD_FLAG_NEXTHOP_BGP)
424 printf("nexthop qualify via bgp\n");
425 if (conf->flags & BGPD_FLAG_NEXTHOP_DEFAULT)
426 printf("nexthop qualify via default\n");
427 if (conf->fib_priority != kr_default_prio())
428 printf("fib-priority %hhu\n", conf->fib_priority);
429 printf("\n");
430 }
431
432 void
print_l3vpn_targets(struct filter_set_head * set,const char * tgt)433 print_l3vpn_targets(struct filter_set_head *set, const char *tgt)
434 {
435 struct filter_set *s;
436 TAILQ_FOREACH(s, set, entry) {
437 printf("\t%s ", tgt);
438 print_community(&s->action.community);
439 printf("\n");
440 }
441 }
442
443 void
print_l3vpn(struct l3vpn * vpn)444 print_l3vpn(struct l3vpn *vpn)
445 {
446 struct network *n;
447
448 printf("vpn \"%s\" on %s {\n", vpn->descr, vpn->ifmpe);
449 printf("\t%s\n", log_rd(vpn->rd));
450
451 print_l3vpn_targets(&vpn->export, "export-target");
452 print_l3vpn_targets(&vpn->import, "import-target");
453
454 if (vpn->flags & F_RIB_NOFIBSYNC)
455 printf("\tfib-update no\n");
456 else
457 printf("\tfib-update yes\n");
458
459 TAILQ_FOREACH(n, &vpn->net_l, entry)
460 print_network(&n->net, "\t");
461
462 printf("}\n");
463 }
464
465 const char *
print_af(uint8_t aid)466 print_af(uint8_t aid)
467 {
468 /*
469 * Hack around the fact that aid2str() will return "IPv4 unicast"
470 * for AID_INET. AID_INET, AID_INET6 and the flowspec AID need
471 * special handling and the other AID should never end up here.
472 */
473 if (aid == AID_INET || aid == AID_FLOWSPECv4)
474 return ("inet");
475 if (aid == AID_INET6 || aid == AID_FLOWSPECv6)
476 return ("inet6");
477 return (aid2str(aid));
478 }
479
480 void
print_network(struct network_config * n,const char * c)481 print_network(struct network_config *n, const char *c)
482 {
483 switch (n->type) {
484 case NETWORK_STATIC:
485 printf("%snetwork %s static", c, print_af(n->prefix.aid));
486 break;
487 case NETWORK_CONNECTED:
488 printf("%snetwork %s connected", c, print_af(n->prefix.aid));
489 break;
490 case NETWORK_RTLABEL:
491 printf("%snetwork %s rtlabel \"%s\"", c,
492 print_af(n->prefix.aid), rtlabel_id2name(n->rtlabel));
493 break;
494 case NETWORK_PRIORITY:
495 printf("%snetwork %s priority %d", c,
496 print_af(n->prefix.aid), n->priority);
497 break;
498 case NETWORK_PREFIXSET:
499 printf("%snetwork prefix-set %s", c, n->psname);
500 break;
501 default:
502 printf("%snetwork %s/%u", c, log_addr(&n->prefix),
503 n->prefixlen);
504 break;
505 }
506 if (!TAILQ_EMPTY(&n->attrset))
507 printf(" ");
508 print_set(&n->attrset);
509 printf("\n");
510 }
511
512 static void
print_flowspec_list(struct flowspec * f,int type,int is_v6)513 print_flowspec_list(struct flowspec *f, int type, int is_v6)
514 {
515 const uint8_t *comp;
516 const char *fmt;
517 int complen, off = 0;
518
519 if (flowspec_get_component(f->data, f->len, type, is_v6,
520 &comp, &complen) != 1)
521 return;
522
523 printf("%s ", flowspec_fmt_label(type));
524 fmt = flowspec_fmt_num_op(comp, complen, &off);
525 if (off == -1) {
526 printf("%s ", fmt);
527 } else {
528 printf("{ %s ", fmt);
529 do {
530 fmt = flowspec_fmt_num_op(comp, complen, &off);
531 printf("%s ", fmt);
532 } while (off != -1);
533 printf("} ");
534 }
535 }
536
537 static void
print_flowspec_flags(struct flowspec * f,int type,int is_v6)538 print_flowspec_flags(struct flowspec *f, int type, int is_v6)
539 {
540 const uint8_t *comp;
541 const char *fmt, *flags;
542 int complen, off = 0;
543
544 switch (type) {
545 case FLOWSPEC_TYPE_TCP_FLAGS:
546 flags = FLOWSPEC_TCP_FLAG_STRING;
547 break;
548 case FLOWSPEC_TYPE_FRAG:
549 if (!is_v6)
550 flags = FLOWSPEC_FRAG_STRING4;
551 else
552 flags = FLOWSPEC_FRAG_STRING6;
553 break;
554 default:
555 printf("??? ");
556 return;
557 }
558
559 if (flowspec_get_component(f->data, f->len, type, is_v6,
560 &comp, &complen) != 1)
561 return;
562
563 printf("%s ", flowspec_fmt_label(type));
564
565 fmt = flowspec_fmt_bin_op(comp, complen, &off, flags);
566 if (off == -1) {
567 printf("%s ", fmt);
568 } else {
569 printf("{ %s ", fmt);
570 do {
571 fmt = flowspec_fmt_bin_op(comp, complen, &off, flags);
572 printf("%s ", fmt);
573 } while (off != -1);
574 printf("} ");
575 }
576 }
577
578 static void
print_flowspec_addr(struct flowspec * f,int type,int is_v6)579 print_flowspec_addr(struct flowspec *f, int type, int is_v6)
580 {
581 struct bgpd_addr addr;
582 uint8_t plen;
583
584 flowspec_get_addr(f->data, f->len, type, is_v6, &addr, &plen, NULL);
585 if (plen == 0)
586 printf("%s any ", flowspec_fmt_label(type));
587 else
588 printf("%s %s/%u ", flowspec_fmt_label(type),
589 log_addr(&addr), plen);
590 }
591
592 void
print_flowspec(struct flowspec_config * fconf,const char * c)593 print_flowspec(struct flowspec_config *fconf, const char *c)
594 {
595 struct flowspec *f = fconf->flow;
596 int is_v6 = (f->aid == AID_FLOWSPECv6);
597
598 printf("%sflowspec %s ", c, print_af(f->aid));
599
600 print_flowspec_list(f, FLOWSPEC_TYPE_PROTO, is_v6);
601
602 print_flowspec_addr(f, FLOWSPEC_TYPE_SOURCE, is_v6);
603 print_flowspec_list(f, FLOWSPEC_TYPE_SRC_PORT, is_v6);
604
605 print_flowspec_addr(f, FLOWSPEC_TYPE_DEST, is_v6);
606 print_flowspec_list(f, FLOWSPEC_TYPE_DST_PORT, is_v6);
607
608 print_flowspec_list(f, FLOWSPEC_TYPE_DSCP, is_v6);
609 print_flowspec_list(f, FLOWSPEC_TYPE_PKT_LEN, is_v6);
610 print_flowspec_flags(f, FLOWSPEC_TYPE_TCP_FLAGS, is_v6);
611 print_flowspec_flags(f, FLOWSPEC_TYPE_FRAG, is_v6);
612
613 /* TODO: fixup the code handling to be like in the parser */
614 print_flowspec_list(f, FLOWSPEC_TYPE_ICMP_TYPE, is_v6);
615 print_flowspec_list(f, FLOWSPEC_TYPE_ICMP_CODE, is_v6);
616
617 print_set(&fconf->attrset);
618 printf("\n");
619 }
620
621 void
print_as_sets(struct as_set_head * as_sets)622 print_as_sets(struct as_set_head *as_sets)
623 {
624 struct as_set *aset;
625 uint32_t *as;
626 size_t i, n;
627 int len;
628
629 SIMPLEQ_FOREACH(aset, as_sets, entry) {
630 printf("as-set \"%s\" {\n\t", aset->name);
631 as = set_get(aset->set, &n);
632 for (i = 0, len = 8; i < n; i++) {
633 if (len > 72) {
634 printf("\n\t");
635 len = 8;
636 }
637 len += printf("%u ", as[i]);
638 }
639 printf("\n}\n\n");
640 }
641 }
642
643 void
print_prefixsets(struct prefixset_head * psh)644 print_prefixsets(struct prefixset_head *psh)
645 {
646 struct prefixset *ps;
647 struct prefixset_item *psi;
648
649 SIMPLEQ_FOREACH(ps, psh, entry) {
650 int count = 0;
651 printf("prefix-set \"%s\" {", ps->name);
652 RB_FOREACH(psi, prefixset_tree, &ps->psitems) {
653 if (count++ % 2 == 0)
654 printf("\n\t");
655 else
656 printf(", ");
657 print_prefix(&psi->p);
658 }
659 printf("\n}\n\n");
660 }
661 }
662
663 void
print_originsets(struct prefixset_head * psh)664 print_originsets(struct prefixset_head *psh)
665 {
666 struct prefixset *ps;
667 struct roa *roa;
668 struct bgpd_addr addr;
669
670 SIMPLEQ_FOREACH(ps, psh, entry) {
671 printf("origin-set \"%s\" {", ps->name);
672 RB_FOREACH(roa, roa_tree, &ps->roaitems) {
673 printf("\n\t");
674 addr.aid = roa->aid;
675 addr.v6 = roa->prefix.inet6;
676 printf("%s/%u", log_addr(&addr), roa->prefixlen);
677 if (roa->prefixlen != roa->maxlen)
678 printf(" maxlen %u", roa->maxlen);
679 printf(" source-as %u", roa->asnum);
680 }
681 printf("\n}\n\n");
682 }
683 }
684
685 void
print_roa(struct roa_tree * r)686 print_roa(struct roa_tree *r)
687 {
688 struct roa *roa;
689
690 if (RB_EMPTY(r))
691 return;
692
693 printf("roa-set {");
694 RB_FOREACH(roa, roa_tree, r) {
695 printf("\n\t%s", log_roa(roa));
696 }
697 printf("\n}\n\n");
698 }
699
700 void
print_aspa(struct aspa_tree * a)701 print_aspa(struct aspa_tree *a)
702 {
703 struct aspa_set *aspa;
704
705 if (RB_EMPTY(a))
706 return;
707
708 printf("aspa-set {");
709 RB_FOREACH(aspa, aspa_tree, a) {
710 printf("\n\t%s", log_aspa(aspa));
711 }
712 printf("\n}\n\n");
713 }
714
715 static void
print_auth(struct auth_config * auth,const char * c)716 print_auth(struct auth_config *auth, const char *c)
717 {
718 char *method;
719
720 if (auth->method == AUTH_MD5SIG)
721 printf("%s\ttcp md5sig\n", c);
722 else if (auth->method == AUTH_IPSEC_MANUAL_ESP ||
723 auth->method == AUTH_IPSEC_MANUAL_AH) {
724 if (auth->method == AUTH_IPSEC_MANUAL_ESP)
725 method = "esp";
726 else
727 method = "ah";
728
729 printf("%s\tipsec %s in spi %u %s XXXXXX", c, method,
730 auth->spi_in, print_auth_alg(auth->auth_alg_in));
731 if (auth->enc_alg_in)
732 printf(" %s XXXXXX", print_enc_alg(auth->enc_alg_in));
733 printf("\n");
734
735 printf("%s\tipsec %s out spi %u %s XXXXXX", c, method,
736 auth->spi_out, print_auth_alg(auth->auth_alg_out));
737 if (auth->enc_alg_out)
738 printf(" %s XXXXXX",
739 print_enc_alg(auth->enc_alg_out));
740 printf("\n");
741 } else if (auth->method == AUTH_IPSEC_IKE_AH)
742 printf("%s\tipsec ah ike\n", c);
743 else if (auth->method == AUTH_IPSEC_IKE_ESP)
744 printf("%s\tipsec esp ike\n", c);
745
746 }
747
748 void
print_rtrs(struct rtr_config_head * rh)749 print_rtrs(struct rtr_config_head *rh)
750 {
751 struct rtr_config *r;
752
753 SIMPLEQ_FOREACH(r, rh, entry) {
754 printf("rtr %s {\n", log_addr(&r->remote_addr));
755 printf("\tdescr \"%s\"\n", r->descr);
756 printf("\tport %u\n", r->remote_port);
757 if (r->local_addr.aid != AID_UNSPEC)
758 printf("local-addr %s\n", log_addr(&r->local_addr));
759 print_auth(&r->auth, "");
760 printf("}\n\n");
761 }
762 }
763
764 void
print_peer(struct peer * peer,struct bgpd_config * conf,const char * c)765 print_peer(struct peer *peer, struct bgpd_config *conf, const char *c)
766 {
767 struct in_addr ina;
768 struct peer_config *p = &peer->conf;
769
770 if ((p->remote_addr.aid == AID_INET && p->remote_masklen != 32) ||
771 (p->remote_addr.aid == AID_INET6 && p->remote_masklen != 128))
772 printf("%sneighbor %s/%u {\n", c, log_addr(&p->remote_addr),
773 p->remote_masklen);
774 else
775 printf("%sneighbor %s {\n", c, log_addr(&p->remote_addr));
776 if (p->descr[0])
777 printf("%s\tdescr \"%s\"\n", c, p->descr);
778 if (p->rib[0])
779 printf("%s\trib \"%s\"\n", c, p->rib);
780 if (p->remote_as)
781 printf("%s\tremote-as %s\n", c, log_as(p->remote_as));
782 if (p->local_as != conf->as) {
783 printf("%s\tlocal-as %s", c, log_as(p->local_as));
784 if (p->local_as > USHRT_MAX && p->local_short_as != AS_TRANS)
785 printf(" %u", p->local_short_as);
786 printf("\n");
787 }
788 if (p->down)
789 printf("%s\tdown\n", c);
790 if (p->distance > 1)
791 printf("%s\tmultihop %u\n", c, p->distance);
792 if (p->passive)
793 printf("%s\tpassive\n", c);
794 if (p->local_addr_v4.aid)
795 printf("%s\tlocal-address %s\n", c,
796 log_addr(&p->local_addr_v4));
797 if (p->local_addr_v6.aid)
798 printf("%s\tlocal-address %s\n", c,
799 log_addr(&p->local_addr_v6));
800 if (p->remote_port != BGP_PORT)
801 printf("%s\tport %hu\n", c, p->remote_port);
802 if (p->role != ROLE_NONE)
803 printf("%s\trole %s\n", c, log_policy(p->role));
804 if (p->max_prefix) {
805 printf("%s\tmax-prefix %u", c, p->max_prefix);
806 if (p->max_prefix_restart)
807 printf(" restart %u", p->max_prefix_restart);
808 printf("\n");
809 }
810 if (p->max_out_prefix) {
811 printf("%s\tmax-prefix %u out", c, p->max_out_prefix);
812 if (p->max_out_prefix_restart)
813 printf(" restart %u", p->max_out_prefix_restart);
814 printf("\n");
815 }
816 if (p->holdtime)
817 printf("%s\tholdtime %u\n", c, p->holdtime);
818 if (p->min_holdtime)
819 printf("%s\tholdtime min %u\n", c, p->min_holdtime);
820 if (p->export_type == EXPORT_NONE)
821 printf("%s\texport none\n", c);
822 else if (p->export_type == EXPORT_DEFAULT_ROUTE)
823 printf("%s\texport default-route\n", c);
824 if (p->enforce_as == ENFORCE_AS_ON)
825 printf("%s\tenforce neighbor-as yes\n", c);
826 else
827 printf("%s\tenforce neighbor-as no\n", c);
828 if (p->enforce_local_as == ENFORCE_AS_ON)
829 printf("%s\tenforce local-as yes\n", c);
830 else
831 printf("%s\tenforce local-as no\n", c);
832 if (p->reflector_client) {
833 if (conf->clusterid == 0)
834 printf("%s\troute-reflector\n", c);
835 else {
836 ina.s_addr = htonl(conf->clusterid);
837 printf("%s\troute-reflector %s\n", c,
838 inet_ntoa(ina));
839 }
840 }
841 if (p->demote_group[0])
842 printf("%s\tdemote %s\n", c, p->demote_group);
843 if (p->if_depend[0])
844 printf("%s\tdepend on \"%s\"\n", c, p->if_depend);
845 if (p->flags & PEERFLAG_TRANS_AS)
846 printf("%s\ttransparent-as yes\n", c);
847
848 if (conf->flags & BGPD_FLAG_DECISION_ALL_PATHS) {
849 if (!(p->flags & PEERFLAG_EVALUATE_ALL))
850 printf("%s\trde evaluate default\n", c);
851 } else {
852 if (p->flags & PEERFLAG_EVALUATE_ALL)
853 printf("%s\trde evaluate all\n", c);
854 }
855
856 if (conf->flags & BGPD_FLAG_NO_AS_SET) {
857 if (!(p->flags & PEERFLAG_NO_AS_SET))
858 printf("%s\treject as-set no\n", c);
859 } else {
860 if (p->flags & PEERFLAG_NO_AS_SET)
861 printf("%s\treject as-set yes\n", c);
862 }
863
864 if (p->flags & PEERFLAG_LOG_UPDATES)
865 printf("%s\tlog updates\n", c);
866
867 print_auth(&peer->auth_conf, c);
868
869 if (p->ttlsec)
870 printf("%s\tttl-security yes\n", c);
871
872 print_announce(p, c);
873
874 print_mrt(conf, p->id, p->groupid, c, "\t");
875
876 printf("%s}\n", c);
877 }
878
879 const char *
print_auth_alg(enum auth_alg alg)880 print_auth_alg(enum auth_alg alg)
881 {
882 switch (alg) {
883 case AUTH_AALG_SHA1HMAC:
884 return ("sha1");
885 case AUTH_AALG_MD5HMAC:
886 return ("md5");
887 default:
888 return ("???");
889 }
890 }
891
892 const char *
print_enc_alg(enum auth_enc_alg alg)893 print_enc_alg(enum auth_enc_alg alg)
894 {
895 switch (alg) {
896 case AUTH_EALG_3DESCBC:
897 return ("3des");
898 case AUTH_EALG_AES:
899 return ("aes");
900 default:
901 return ("???");
902 }
903 }
904
905 static const char *
print_addpath_mode(enum addpath_mode mode)906 print_addpath_mode(enum addpath_mode mode)
907 {
908 switch (mode) {
909 case ADDPATH_EVAL_NONE:
910 return "none";
911 case ADDPATH_EVAL_BEST:
912 return "best";
913 case ADDPATH_EVAL_ECMP:
914 return "ecmp";
915 case ADDPATH_EVAL_AS_WIDE:
916 return "as-wide-best";
917 case ADDPATH_EVAL_ALL:
918 return "all";
919 default:
920 return "???";
921 }
922 }
923
924 void
print_announce(struct peer_config * p,const char * c)925 print_announce(struct peer_config *p, const char *c)
926 {
927 uint8_t aid;
928 int match = 0;
929
930 for (aid = AID_MIN; aid < AID_MAX; aid++)
931 if (p->capabilities.mp[aid] == 2) {
932 printf("%s\tannounce %s enforce\n", c, aid2str(aid));
933 match = 1;
934 } else if (p->capabilities.mp[aid]) {
935 printf("%s\tannounce %s\n", c, aid2str(aid));
936 match = 1;
937 }
938 if (!match) {
939 printf("%s\tannounce IPv4 none\n", c);
940 printf("%s\tannounce IPv6 none\n", c);
941 }
942
943 if (p->capabilities.refresh == 2)
944 printf("%s\tannounce refresh enforce\n", c);
945 else if (p->capabilities.refresh == 0)
946 printf("%s\tannounce refresh no\n", c);
947
948 if (p->capabilities.enhanced_rr == 2)
949 printf("%s\tannounce enhanced refresh enforce\n", c);
950 else if (p->capabilities.enhanced_rr == 1)
951 printf("%s\tannounce enhanced refresh yes\n", c);
952
953 if (p->capabilities.grestart.restart == 2)
954 printf("%s\tannounce restart enforce\n", c);
955 else if (p->capabilities.grestart.restart == 0)
956 printf("%s\tannounce restart no\n", c);
957
958 if (p->capabilities.as4byte == 2)
959 printf("%s\tannounce as4byte enforce\n", c);
960 else if (p->capabilities.as4byte == 0)
961 printf("%s\tannounce as4byte no\n", c);
962
963 if (p->capabilities.add_path[AID_MIN] & CAPA_AP_RECV_ENFORCE)
964 printf("%s\tannounce add-path recv enforce\n", c);
965 else if (p->capabilities.add_path[AID_MIN] & CAPA_AP_RECV)
966 printf("%s\tannounce add-path recv yes\n", c);
967
968 if (p->capabilities.add_path[AID_MIN] & CAPA_AP_SEND) {
969 printf("%s\tannounce add-path send %s", c,
970 print_addpath_mode(p->eval.mode));
971 if (p->eval.extrapaths != 0)
972 printf(" plus %d", p->eval.extrapaths);
973 if (p->eval.maxpaths != 0)
974 printf(" max %d", p->eval.maxpaths);
975 if (p->capabilities.add_path[AID_MIN] & CAPA_AP_SEND_ENFORCE)
976 printf(" enforce");
977 printf("\n");
978 }
979
980 if (p->capabilities.policy == 2)
981 printf("%s\tannounce policy enforce\n", c);
982 else if (p->capabilities.policy == 1)
983 printf("%s\tannounce policy yes\n", c);
984 else
985 printf("%s\tannounce policy no\n", c);
986 }
987
988 void
print_as(struct filter_rule * r)989 print_as(struct filter_rule *r)
990 {
991 if (r->match.as.flags & AS_FLAG_AS_SET_NAME) {
992 printf("as-set \"%s\" ", r->match.as.name);
993 return;
994 }
995 switch (r->match.as.op) {
996 case OP_RANGE:
997 printf("%s - ", log_as(r->match.as.as_min));
998 printf("%s ", log_as(r->match.as.as_max));
999 break;
1000 case OP_XRANGE:
1001 printf("%s >< ", log_as(r->match.as.as_min));
1002 printf("%s ", log_as(r->match.as.as_max));
1003 break;
1004 case OP_NE:
1005 printf("!= %s ", log_as(r->match.as.as_min));
1006 break;
1007 default:
1008 printf("%s ", log_as(r->match.as.as_min));
1009 break;
1010 }
1011 }
1012
1013 void
print_rule(struct bgpd_config * conf,struct filter_rule * r)1014 print_rule(struct bgpd_config *conf, struct filter_rule *r)
1015 {
1016 struct peer *p;
1017 int i;
1018
1019 if (r->action == ACTION_ALLOW)
1020 printf("allow ");
1021 else if (r->action == ACTION_DENY)
1022 printf("deny ");
1023 else
1024 printf("match ");
1025 if (r->quick)
1026 printf("quick ");
1027
1028 if (r->rib[0])
1029 printf("rib %s ", r->rib);
1030
1031 if (r->dir == DIR_IN)
1032 printf("from ");
1033 else if (r->dir == DIR_OUT)
1034 printf("to ");
1035 else
1036 printf("eeeeeeeps. ");
1037
1038 if (r->peer.peerid) {
1039 RB_FOREACH(p, peer_head, &conf->peers)
1040 if (p->conf.id == r->peer.peerid)
1041 break;
1042 if (p == NULL)
1043 printf("? ");
1044 else
1045 printf("%s ", log_addr(&p->conf.remote_addr));
1046 } else if (r->peer.groupid) {
1047 RB_FOREACH(p, peer_head, &conf->peers)
1048 if (p->conf.groupid == r->peer.groupid)
1049 break;
1050 if (p == NULL)
1051 printf("group ? ");
1052 else
1053 printf("group \"%s\" ", p->conf.group);
1054 } else if (r->peer.remote_as) {
1055 printf("AS %s ", log_as(r->peer.remote_as));
1056 } else if (r->peer.ebgp) {
1057 printf("ebgp ");
1058 } else if (r->peer.ibgp) {
1059 printf("ibgp ");
1060 } else
1061 printf("any ");
1062
1063 if (r->match.ovs.is_set) {
1064 switch (r->match.ovs.validity) {
1065 case ROA_VALID:
1066 printf("ovs valid ");
1067 break;
1068 case ROA_INVALID:
1069 printf("ovs invalid ");
1070 break;
1071 case ROA_NOTFOUND:
1072 printf("ovs not-found ");
1073 break;
1074 default:
1075 printf("ovs ??? %d ??? ", r->match.ovs.validity);
1076 }
1077 }
1078
1079 if (r->match.avs.is_set) {
1080 switch (r->match.avs.validity) {
1081 case ASPA_VALID:
1082 printf("avs valid ");
1083 break;
1084 case ASPA_INVALID:
1085 printf("avs invalid ");
1086 break;
1087 case ASPA_UNKNOWN:
1088 printf("avs unknown ");
1089 break;
1090 default:
1091 printf("avs ??? %d ??? ", r->match.avs.validity);
1092 }
1093 }
1094
1095 if (r->match.prefix.addr.aid != AID_UNSPEC) {
1096 printf("prefix ");
1097 print_prefix(&r->match.prefix);
1098 printf(" ");
1099 }
1100
1101 if (r->match.prefixset.name[0] != '\0')
1102 printf("prefix-set \"%s\" ", r->match.prefixset.name);
1103 if (r->match.prefixset.flags & PREFIXSET_FLAG_LONGER)
1104 printf("or-longer ");
1105
1106 if (r->match.originset.name[0] != '\0')
1107 printf("origin-set \"%s\" ", r->match.originset.name);
1108
1109 if (r->match.nexthop.flags) {
1110 if (r->match.nexthop.flags == FILTER_NEXTHOP_NEIGHBOR)
1111 printf("nexthop neighbor ");
1112 else
1113 printf("nexthop %s ", log_addr(&r->match.nexthop.addr));
1114 }
1115
1116 if (r->match.as.type) {
1117 if (r->match.as.type == AS_ALL)
1118 printf("AS ");
1119 else if (r->match.as.type == AS_SOURCE)
1120 printf("source-as ");
1121 else if (r->match.as.type == AS_TRANSIT)
1122 printf("transit-as ");
1123 else if (r->match.as.type == AS_PEER)
1124 printf("peer-as ");
1125 else
1126 printf("unfluffy-as ");
1127 print_as(r);
1128 }
1129
1130 if (r->match.aslen.type) {
1131 printf("%s %u ", r->match.aslen.type == ASLEN_MAX ?
1132 "max-as-len" : "max-as-seq", r->match.aslen.aslen);
1133 }
1134
1135 for (i = 0; i < MAX_COMM_MATCH; i++) {
1136 struct community *c = &r->match.community[i];
1137 if (c->flags != 0) {
1138 printf("%s ", community_type(c));
1139 print_community(c);
1140 }
1141 }
1142
1143 if (r->match.maxcomm != 0)
1144 printf("max-communities %d ", r->match.maxcomm - 1);
1145 if (r->match.maxextcomm != 0)
1146 printf("max-ext-communities %d ", r->match.maxextcomm - 1);
1147 if (r->match.maxlargecomm != 0)
1148 printf("max-large-communities %d ", r->match.maxlargecomm - 1);
1149
1150 print_set(&r->set);
1151
1152 printf("\n");
1153 }
1154
1155 const char *
mrt_type(enum mrt_type t)1156 mrt_type(enum mrt_type t)
1157 {
1158 switch (t) {
1159 case MRT_NONE:
1160 break;
1161 case MRT_TABLE_DUMP:
1162 return "table";
1163 case MRT_TABLE_DUMP_MP:
1164 return "table-mp";
1165 case MRT_TABLE_DUMP_V2:
1166 return "table-v2";
1167 case MRT_ALL_IN:
1168 return "all in";
1169 case MRT_ALL_OUT:
1170 return "all out";
1171 case MRT_UPDATE_IN:
1172 return "updates in";
1173 case MRT_UPDATE_OUT:
1174 return "updates out";
1175 }
1176 return "unfluffy MRT";
1177 }
1178
1179 void
print_mrt(struct bgpd_config * conf,uint32_t pid,uint32_t gid,const char * prep,const char * prep2)1180 print_mrt(struct bgpd_config *conf, uint32_t pid, uint32_t gid,
1181 const char *prep, const char *prep2)
1182 {
1183 struct mrt *m;
1184
1185 if (conf->mrt == NULL)
1186 return;
1187
1188 LIST_FOREACH(m, conf->mrt, entry)
1189 if ((gid != 0 && m->group_id == gid) ||
1190 (m->peer_id == pid && m->group_id == gid)) {
1191 printf("%s%sdump ", prep, prep2);
1192 if (m->rib[0])
1193 printf("rib %s ", m->rib);
1194 printf("%s \"%s\"", mrt_type(m->type),
1195 MRT2MC(m)->name);
1196 if (MRT2MC(m)->ReopenTimerInterval == 0)
1197 printf("\n");
1198 else
1199 printf(" %d\n", MRT2MC(m)->ReopenTimerInterval);
1200 }
1201 if (!LIST_EMPTY(conf->mrt))
1202 printf("\n");
1203 }
1204
1205 void
print_groups(struct bgpd_config * conf)1206 print_groups(struct bgpd_config *conf)
1207 {
1208 struct peer **peerlist;
1209 struct peer *p;
1210 u_int peer_cnt, i;
1211 uint32_t prev_groupid;
1212 const char *c;
1213
1214 peer_cnt = 0;
1215 RB_FOREACH(p, peer_head, &conf->peers)
1216 peer_cnt++;
1217 if ((peerlist = calloc(peer_cnt, sizeof(*peerlist))) == NULL)
1218 fatal("print_groups calloc");
1219 i = 0;
1220 RB_FOREACH(p, peer_head, &conf->peers)
1221 peerlist[i++] = p;
1222
1223 qsort(peerlist, peer_cnt, sizeof(*peerlist), peer_compare);
1224
1225 prev_groupid = 0;
1226 for (i = 0; i < peer_cnt; i++) {
1227 if (peerlist[i]->conf.groupid) {
1228 c = "\t";
1229 if (peerlist[i]->conf.groupid != prev_groupid) {
1230 if (prev_groupid)
1231 printf("}\n\n");
1232 printf("group \"%s\" {\n",
1233 peerlist[i]->conf.group);
1234 prev_groupid = peerlist[i]->conf.groupid;
1235 }
1236 } else
1237 c = "";
1238
1239 print_peer(peerlist[i], conf, c);
1240 }
1241
1242 if (prev_groupid)
1243 printf("}\n\n");
1244
1245 free(peerlist);
1246 }
1247
1248 int
peer_compare(const void * aa,const void * bb)1249 peer_compare(const void *aa, const void *bb)
1250 {
1251 const struct peer * const *a;
1252 const struct peer * const *b;
1253
1254 a = aa;
1255 b = bb;
1256
1257 return ((*a)->conf.groupid - (*b)->conf.groupid);
1258 }
1259
1260 void
print_config(struct bgpd_config * conf,struct rib_names * rib_l)1261 print_config(struct bgpd_config *conf, struct rib_names *rib_l)
1262 {
1263 struct filter_rule *r;
1264 struct network *n;
1265 struct flowspec_config *f;
1266 struct rde_rib *rr;
1267 struct l3vpn *vpn;
1268
1269 print_mainconf(conf);
1270 print_rtrs(&conf->rtrs);
1271 print_roa(&conf->roa);
1272 print_aspa(&conf->aspa);
1273 print_as_sets(&conf->as_sets);
1274 print_prefixsets(&conf->prefixsets);
1275 print_originsets(&conf->originsets);
1276 TAILQ_FOREACH(n, &conf->networks, entry)
1277 print_network(&n->net, "");
1278 RB_FOREACH(f, flowspec_tree, &conf->flowspecs)
1279 print_flowspec(f, "");
1280 if (!SIMPLEQ_EMPTY(&conf->l3vpns))
1281 printf("\n");
1282 SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry)
1283 print_l3vpn(vpn);
1284 printf("\n");
1285 if (conf->filtered_in_locrib)
1286 printf("rde rib Loc-RIB include filtered\n");
1287 SIMPLEQ_FOREACH(rr, rib_l, entry) {
1288 if (rr->flags & F_RIB_NOEVALUATE)
1289 printf("rde rib %s no evaluate\n", rr->name);
1290 else if (rr->flags & F_RIB_NOFIB)
1291 printf("rde rib %s\n", rr->name);
1292 else
1293 printf("rde rib %s rtable %u fib-update %s\n", rr->name,
1294 rr->rtableid, rr->flags & F_RIB_NOFIBSYNC ?
1295 "no" : "yes");
1296 }
1297 printf("\n");
1298 print_mrt(conf, 0, 0, "", "");
1299 print_groups(conf);
1300 TAILQ_FOREACH(r, conf->filters, entry)
1301 print_rule(conf, r);
1302 }
1303