xref: /openbsd-src/usr.sbin/bgpd/printconf.c (revision 7350f337b9e3eb4461d99580e625c7ef148d107c)
1 /*	$OpenBSD: printconf.c,v 1.137 2019/06/17 13:35:43 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 "mrt.h"
28 #include "session.h"
29 #include "rde.h"
30 #include "log.h"
31 
32 void		 print_prefix(struct filter_prefix *p);
33 const char	*community_type(struct community *c);
34 void		 print_community(struct community *c);
35 void		 print_origin(u_int8_t);
36 void		 print_set(struct filter_set_head *);
37 void		 print_mainconf(struct bgpd_config *);
38 void		 print_l3vpn_targets(struct filter_set_head *, const char *);
39 void		 print_l3vpn(struct l3vpn *);
40 const char	*print_af(u_int8_t);
41 void		 print_network(struct network_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 prefixset_tree *p);
46 void		 print_peer(struct peer_config *, struct bgpd_config *,
47 		    const char *);
48 const char	*print_auth_alg(u_int8_t);
49 const char	*print_enc_alg(u_int8_t);
50 void		 print_announce(struct peer_config *, const char *);
51 void		 print_as(struct filter_rule *);
52 void		 print_rule(struct bgpd_config *, struct filter_rule *);
53 const char	*mrt_type(enum mrt_type);
54 void		 print_mrt(struct bgpd_config *, u_int32_t, u_int32_t,
55 		    const char *, const char *);
56 void		 print_groups(struct bgpd_config *);
57 int		 peer_compare(const void *, const void *);
58 
59 void
60 print_prefix(struct filter_prefix *p)
61 {
62 	u_int8_t max_len = 0;
63 
64 	switch (p->addr.aid) {
65 	case AID_INET:
66 	case AID_VPN_IPv4:
67 		max_len = 32;
68 		break;
69 	case AID_INET6:
70 	case AID_VPN_IPv6:
71 		max_len = 128;
72 		break;
73 	case AID_UNSPEC:
74 		/* no prefix to print */
75 		return;
76 	}
77 
78 	printf("%s/%u", log_addr(&p->addr), p->len);
79 
80 	switch (p->op) {
81 	case OP_NONE:
82 		break;
83 	case OP_NE:
84 		printf(" prefixlen != %u", p->len_min);
85 		break;
86 	case OP_XRANGE:
87 		printf(" prefixlen %u >< %u ", p->len_min, p->len_max);
88 		break;
89 	case OP_RANGE:
90 		if (p->len_min == p->len_max && p->len != p->len_min)
91 			printf(" prefixlen = %u", p->len_min);
92 		else if (p->len == p->len_min && p->len_max == max_len)
93 			printf(" or-longer");
94 		else if (p->len == p->len_min && p->len != p->len_max)
95 			printf(" maxlen %u", p->len_max);
96 		else if (p->len_max == max_len)
97 			printf(" prefixlen >= %u", p->len_min);
98 		else
99 			printf(" prefixlen %u - %u", p->len_min, p->len_max);
100 		break;
101 	default:
102 		printf(" prefixlen %u ??? %u", p->len_min, p->len_max);
103 		break;
104 	}
105 }
106 
107 const char *
108 community_type(struct community *c)
109 {
110 	switch ((u_int8_t)c->flags) {
111 	case COMMUNITY_TYPE_BASIC:
112 		return "community";
113 	case COMMUNITY_TYPE_LARGE:
114 		return "large-community";
115 	case COMMUNITY_TYPE_EXT:
116 		return "ext-community";
117 	default:
118 		return "???";
119 	}
120 }
121 
122 void
123 print_community(struct community *c)
124 {
125 	struct in_addr addr;
126 	short type;
127 	u_int8_t subtype;
128 
129 	switch ((u_int8_t)c->flags) {
130 	case COMMUNITY_TYPE_BASIC:
131 		switch ((c->flags >> 8) & 0xff) {
132 		case COMMUNITY_ANY:
133 			printf("*:");
134 			break;
135 		case COMMUNITY_NEIGHBOR_AS:
136 			printf("neighbor-as:");
137 			break;
138 		case COMMUNITY_LOCAL_AS:
139 			printf("local-as:");
140 			break;
141 		default:
142 			printf("%u:", c->data1);
143 			break;
144 		}
145 		switch ((c->flags >> 16) & 0xff) {
146 		case COMMUNITY_ANY:
147 			printf("* ");
148 			break;
149 		case COMMUNITY_NEIGHBOR_AS:
150 			printf("neighbor-as ");
151 			break;
152 		case COMMUNITY_LOCAL_AS:
153 			printf("local-as ");
154 			break;
155 		default:
156 			printf("%u ", c->data2);
157 			break;
158 		}
159 		break;
160 	case COMMUNITY_TYPE_LARGE:
161 		switch ((c->flags >> 8) & 0xff) {
162 		case COMMUNITY_ANY:
163 			printf("*:");
164 			break;
165 		case COMMUNITY_NEIGHBOR_AS:
166 			printf("neighbor-as:");
167 			break;
168 		case COMMUNITY_LOCAL_AS:
169 			printf("local-as:");
170 			break;
171 		default:
172 			printf("%u:", c->data1);
173 			break;
174 		}
175 		switch ((c->flags >> 16) & 0xff) {
176 		case COMMUNITY_ANY:
177 			printf("*:");
178 			break;
179 		case COMMUNITY_NEIGHBOR_AS:
180 			printf("neighbor-as:");
181 			break;
182 		case COMMUNITY_LOCAL_AS:
183 			printf("local-as:");
184 			break;
185 		default:
186 			printf("%u:", c->data2);
187 			break;
188 		}
189 		switch ((c->flags >> 24) & 0xff) {
190 		case COMMUNITY_ANY:
191 			printf("* ");
192 			break;
193 		case COMMUNITY_NEIGHBOR_AS:
194 			printf("neighbor-as ");
195 			break;
196 		case COMMUNITY_LOCAL_AS:
197 			printf("local-as ");
198 			break;
199 		default:
200 			printf("%u ", c->data3);
201 			break;
202 		}
203 		break;
204 	case COMMUNITY_TYPE_EXT:
205 		if ((c->flags >> 24 & 0xff) == COMMUNITY_ANY) {
206 			printf("* * ");
207 			break;
208 		}
209 		type = (int32_t)c->data3 >> 8;
210 		subtype = c->data3;
211 		printf("%s ", log_ext_subtype(type, subtype));
212 		if ((c->flags >> 8 & 0xff) == COMMUNITY_ANY) {
213 			printf("* ");
214 			break;
215 		}
216 
217 		switch (type) {
218 		case EXT_COMMUNITY_TRANS_TWO_AS:
219 		case EXT_COMMUNITY_TRANS_FOUR_AS:
220 			if ((c->flags >> 8 & 0xff) == COMMUNITY_NEIGHBOR_AS)
221 				printf("neighbor-as:");
222 			else if ((c->flags >> 8 & 0xff) == COMMUNITY_LOCAL_AS)
223 				printf("local-as:");
224 			else
225 				printf("%s:", log_as(c->data1));
226 			break;
227 		case EXT_COMMUNITY_TRANS_IPV4:
228 			addr.s_addr = htonl(c->data1);
229 			printf("%s:", inet_ntoa(addr));
230 			break;
231 		}
232 
233 		switch (type) {
234 		case EXT_COMMUNITY_TRANS_TWO_AS:
235 		case EXT_COMMUNITY_TRANS_FOUR_AS:
236 		case EXT_COMMUNITY_TRANS_IPV4:
237 			if ((c->flags >> 16 & 0xff) == COMMUNITY_ANY)
238 				printf("* ");
239 			else if ((c->flags >> 16 & 0xff) ==
240 			    COMMUNITY_NEIGHBOR_AS)
241 				printf("neighbor-as ");
242 			else if ((c->flags >> 16 & 0xff) == COMMUNITY_LOCAL_AS)
243 				printf("local-as ");
244 			else
245 				printf("%u ", c->data2);
246 			break;
247 		case EXT_COMMUNITY_NON_TRANS_OPAQUE:
248 			if (subtype == EXT_COMMUNITY_SUBTYPE_OVS) {
249 				switch (c->data2) {
250 				case EXT_COMMUNITY_OVS_VALID:
251 					printf("valid ");
252 					break;
253 				case EXT_COMMUNITY_OVS_NOTFOUND:
254 					printf("not-found ");
255 					break;
256 				case EXT_COMMUNITY_OVS_INVALID:
257 					printf("invalid ");
258 					break;
259 				}
260 				break;
261 			}
262 			printf("0x%x%08x ", c->data1 & 0xffff, c->data2);
263 			break;
264 		case EXT_COMMUNITY_TRANS_OPAQUE:
265 		case EXT_COMMUNITY_TRANS_EVPN:
266 		default:
267 			printf("0x%x%08x ", c->data1 & 0xffff, c->data2);
268 			break;
269 		}
270 	}
271 }
272 
273 void
274 print_origin(u_int8_t o)
275 {
276 	if (o == ORIGIN_IGP)
277 		printf("igp ");
278 	else if (o == ORIGIN_EGP)
279 		printf("egp ");
280 	else if (o == ORIGIN_INCOMPLETE)
281 		printf("incomplete ");
282 	else
283 		printf("%u ", o);
284 }
285 
286 void
287 print_set(struct filter_set_head *set)
288 {
289 	struct filter_set	*s;
290 
291 	if (TAILQ_EMPTY(set))
292 		return;
293 
294 	printf("set { ");
295 	TAILQ_FOREACH(s, set, entry) {
296 		switch (s->type) {
297 		case ACTION_SET_LOCALPREF:
298 			printf("localpref %u ", s->action.metric);
299 			break;
300 		case ACTION_SET_RELATIVE_LOCALPREF:
301 			printf("localpref %+d ", s->action.relative);
302 			break;
303 		case ACTION_SET_MED:
304 			printf("metric %u ", s->action.metric);
305 			break;
306 		case ACTION_SET_RELATIVE_MED:
307 			printf("metric %+d ", s->action.relative);
308 			break;
309 		case ACTION_SET_WEIGHT:
310 			printf("weight %u ", s->action.metric);
311 			break;
312 		case ACTION_SET_RELATIVE_WEIGHT:
313 			printf("weight %+d ", s->action.relative);
314 			break;
315 		case ACTION_SET_NEXTHOP:
316 			printf("nexthop %s ", log_addr(&s->action.nexthop));
317 			break;
318 		case ACTION_SET_NEXTHOP_REJECT:
319 			printf("nexthop reject ");
320 			break;
321 		case ACTION_SET_NEXTHOP_BLACKHOLE:
322 			printf("nexthop blackhole ");
323 			break;
324 		case ACTION_SET_NEXTHOP_NOMODIFY:
325 			printf("nexthop no-modify ");
326 			break;
327 		case ACTION_SET_NEXTHOP_SELF:
328 			printf("nexthop self ");
329 			break;
330 		case ACTION_SET_PREPEND_SELF:
331 			printf("prepend-self %u ", s->action.prepend);
332 			break;
333 		case ACTION_SET_PREPEND_PEER:
334 			printf("prepend-neighbor %u ", s->action.prepend);
335 			break;
336 		case ACTION_SET_AS_OVERRIDE:
337 			printf("as-override ");
338 			break;
339 		case ACTION_DEL_COMMUNITY:
340 			printf("%s delete ",
341 			    community_type(&s->action.community));
342 			print_community(&s->action.community);
343 			break;
344 		case ACTION_SET_COMMUNITY:
345 			printf("%s ", community_type(&s->action.community));
346 			print_community(&s->action.community);
347 			break;
348 		case ACTION_PFTABLE:
349 			printf("pftable %s ", s->action.pftable);
350 			break;
351 		case ACTION_RTLABEL:
352 			printf("rtlabel %s ", s->action.rtlabel);
353 			break;
354 		case ACTION_SET_ORIGIN:
355 			printf("origin ");
356 			print_origin(s->action.origin);
357 			break;
358 		case ACTION_RTLABEL_ID:
359 		case ACTION_PFTABLE_ID:
360 			/* not possible */
361 			printf("king bula saiz: config broken");
362 			break;
363 		}
364 	}
365 	printf("}");
366 }
367 
368 void
369 print_mainconf(struct bgpd_config *conf)
370 {
371 	struct in_addr		 ina;
372 	struct listen_addr	*la;
373 
374 	printf("AS %s", log_as(conf->as));
375 	if (conf->as > USHRT_MAX && conf->short_as != AS_TRANS)
376 		printf(" %u", conf->short_as);
377 	ina.s_addr = conf->bgpid;
378 	printf("\nrouter-id %s\n", inet_ntoa(ina));
379 
380 	printf("socket \"%s\"\n", conf->csock);
381 	if (conf->rcsock)
382 		printf("socket \"%s\" restricted\n", conf->rcsock);
383 	if (conf->holdtime != INTERVAL_HOLD)
384 		printf("holdtime %u\n", conf->holdtime);
385 	if (conf->min_holdtime != MIN_HOLDTIME)
386 		printf("holdtime min %u\n", conf->min_holdtime);
387 	if (conf->connectretry != INTERVAL_CONNECTRETRY)
388 		printf("connect-retry %u\n", conf->connectretry);
389 
390 	if (conf->flags & BGPD_FLAG_NO_EVALUATE)
391 		printf("route-collector yes\n");
392 
393 	if (conf->flags & BGPD_FLAG_DECISION_ROUTEAGE)
394 		printf("rde route-age evaluate\n");
395 
396 	if (conf->flags & BGPD_FLAG_DECISION_MED_ALWAYS)
397 		printf("rde med compare always\n");
398 
399 	if (conf->log & BGPD_LOG_UPDATES)
400 		printf("log updates\n");
401 
402 	TAILQ_FOREACH(la, conf->listen_addrs, entry)
403 		printf("listen on %s\n",
404 		    log_sockaddr((struct sockaddr *)&la->sa, la->sa_len));
405 
406 	if (conf->flags & BGPD_FLAG_NEXTHOP_BGP)
407 		printf("nexthop qualify via bgp\n");
408 	if (conf->flags & BGPD_FLAG_NEXTHOP_DEFAULT)
409 		printf("nexthop qualify via default\n");
410 	if (conf->fib_priority != RTP_BGP)
411 		printf("fib-priority %hhu\n", conf->fib_priority);
412 	printf("\n");
413 }
414 
415 void
416 print_l3vpn_targets(struct filter_set_head *set, const char *tgt)
417 {
418 	struct filter_set	*s;
419 	TAILQ_FOREACH(s, set, entry) {
420 		printf("\t%s ", tgt);
421 		print_community(&s->action.community);
422 		printf("\n");
423 	}
424 }
425 
426 void
427 print_l3vpn(struct l3vpn *vpn)
428 {
429 	struct network *n;
430 
431 	printf("vpn \"%s\" on %s {\n", vpn->descr, vpn->ifmpe);
432 	printf("\t%s\n", log_rd(vpn->rd));
433 
434 	print_l3vpn_targets(&vpn->export, "export-target");
435 	print_l3vpn_targets(&vpn->import, "import-target");
436 
437 	if (vpn->flags & F_RIB_NOFIBSYNC)
438 		printf("\tfib-update no\n");
439 	else
440 		printf("\tfib-update yes\n");
441 
442 	TAILQ_FOREACH(n, &vpn->net_l, entry)
443 		print_network(&n->net, "\t");
444 
445 	printf("}\n");
446 }
447 
448 const char *
449 print_af(u_int8_t aid)
450 {
451 	/*
452 	 * Hack around the fact that aid2str() will return "IPv4 unicast"
453 	 * for AID_INET. AID_INET and AID_INET6 need special handling and
454 	 * the other AID should never end up here (at least for now).
455 	 */
456 	if (aid == AID_INET)
457 		return ("inet");
458 	if (aid == AID_INET6)
459 		return ("inet6");
460 	return (aid2str(aid));
461 }
462 
463 void
464 print_network(struct network_config *n, const char *c)
465 {
466 	switch (n->type) {
467 	case NETWORK_STATIC:
468 		printf("%snetwork %s static", c, print_af(n->prefix.aid));
469 		break;
470 	case NETWORK_CONNECTED:
471 		printf("%snetwork %s connected", c, print_af(n->prefix.aid));
472 		break;
473 	case NETWORK_RTLABEL:
474 		printf("%snetwork %s rtlabel \"%s\"", c,
475 		    print_af(n->prefix.aid), rtlabel_id2name(n->rtlabel));
476 		break;
477 	case NETWORK_PRIORITY:
478 		printf("%snetwork %s priority %d", c,
479 		    print_af(n->prefix.aid), n->priority);
480 		break;
481 	case NETWORK_PREFIXSET:
482 		printf("%snetwork prefix-set %s", c, n->psname);
483 		break;
484 	default:
485 		printf("%snetwork %s/%u", c, log_addr(&n->prefix),
486 		    n->prefixlen);
487 		break;
488 	}
489 	if (!TAILQ_EMPTY(&n->attrset))
490 		printf(" ");
491 	print_set(&n->attrset);
492 	printf("\n");
493 }
494 
495 void
496 print_as_sets(struct as_set_head *as_sets)
497 {
498 	struct as_set *aset;
499 	u_int32_t *as;
500 	size_t i, n;
501 	int len;
502 
503 	SIMPLEQ_FOREACH(aset, as_sets, entry) {
504 		printf("as-set \"%s\" {\n\t", aset->name);
505 		as = set_get(aset->set, &n);
506 		for (i = 0, len = 8; i < n; i++) {
507 			if (len > 72) {
508 				printf("\n\t");
509 				len = 8;
510 			}
511 			len += printf("%u ", as[i]);
512 		}
513 		printf("\n}\n\n");
514 	}
515 }
516 
517 void
518 print_prefixsets(struct prefixset_head *psh)
519 {
520 	struct prefixset	*ps;
521 	struct prefixset_item	*psi;
522 
523 	SIMPLEQ_FOREACH(ps, psh, entry) {
524 		int count = 0;
525 		printf("prefix-set \"%s\" {", ps->name);
526 		RB_FOREACH(psi, prefixset_tree, &ps->psitems) {
527 			if (count++ % 2 == 0)
528 				printf("\n\t");
529 			else
530 				printf(", ");
531 			print_prefix(&psi->p);
532 		}
533 		printf("\n}\n\n");
534 	}
535 }
536 
537 void
538 print_originsets(struct prefixset_head *psh)
539 {
540 	struct prefixset	*ps;
541 	struct prefixset_item	*psi;
542 	struct roa_set		*rs;
543 	size_t			 i, n;
544 
545 	SIMPLEQ_FOREACH(ps, psh, entry) {
546 		printf("origin-set \"%s\" {", ps->name);
547 		RB_FOREACH(psi, prefixset_tree, &ps->psitems) {
548 			rs = set_get(psi->set, &n);
549 			for (i = 0; i < n; i++) {
550 				printf("\n\t");
551 				print_prefix(&psi->p);
552 				if (psi->p.len != rs[i].maxlen)
553 					printf(" maxlen %u", rs[i].maxlen);
554 				printf(" source-as %u", rs[i].as);
555 			}
556 		}
557 		printf("\n}\n\n");
558 	}
559 }
560 
561 void
562 print_roa(struct prefixset_tree *p)
563 {
564 	struct prefixset_item	*psi;
565 	struct roa_set		*rs;
566 	size_t			 i, n;
567 
568 	if (RB_EMPTY(p))
569 		return;
570 
571 	printf("roa-set {");
572 	RB_FOREACH(psi, prefixset_tree, p) {
573 		rs = set_get(psi->set, &n);
574 		for (i = 0; i < n; i++) {
575 			printf("\n\t");
576 			print_prefix(&psi->p);
577 			if (psi->p.len != rs[i].maxlen)
578 				printf(" maxlen %u", rs[i].maxlen);
579 			printf(" source-as %u", rs[i].as);
580 		}
581 	}
582 	printf("\n}\n\n");
583 }
584 
585 void
586 print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
587 {
588 	char		*method;
589 	struct in_addr	 ina;
590 
591 	if ((p->remote_addr.aid == AID_INET && p->remote_masklen != 32) ||
592 	    (p->remote_addr.aid == AID_INET6 && p->remote_masklen != 128))
593 		printf("%sneighbor %s/%u {\n", c, log_addr(&p->remote_addr),
594 		    p->remote_masklen);
595 	else
596 		printf("%sneighbor %s {\n", c, log_addr(&p->remote_addr));
597 	if (p->descr[0])
598 		printf("%s\tdescr \"%s\"\n", c, p->descr);
599 	if (p->rib[0])
600 		printf("%s\trib \"%s\"\n", c, p->rib);
601 	if (p->remote_as)
602 		printf("%s\tremote-as %s\n", c, log_as(p->remote_as));
603 	if (p->local_as != conf->as) {
604 		printf("%s\tlocal-as %s", c, log_as(p->local_as));
605 		if (p->local_as > USHRT_MAX && p->local_short_as != AS_TRANS)
606 			printf(" %u", p->local_short_as);
607 		printf("\n");
608 	}
609 	if (p->down)
610 		printf("%s\tdown\n", c);
611 	if (p->distance > 1)
612 		printf("%s\tmultihop %u\n", c, p->distance);
613 	if (p->passive)
614 		printf("%s\tpassive\n", c);
615 	if (p->local_addr.aid)
616 		printf("%s\tlocal-address %s\n", c, log_addr(&p->local_addr));
617 	if (p->max_prefix) {
618 		printf("%s\tmax-prefix %u", c, p->max_prefix);
619 		if (p->max_prefix_restart)
620 			printf(" restart %u", p->max_prefix_restart);
621 		printf("\n");
622 	}
623 	if (p->holdtime)
624 		printf("%s\tholdtime %u\n", c, p->holdtime);
625 	if (p->min_holdtime)
626 		printf("%s\tholdtime min %u\n", c, p->min_holdtime);
627 	if (p->announce_capa == 0)
628 		printf("%s\tannounce capabilities no\n", c);
629 	if (p->capabilities.refresh == 0)
630 		printf("%s\tannounce refresh no\n", c);
631 	if (p->capabilities.grestart.restart == 0)
632 		printf("%s\tannounce restart no\n", c);
633 	if (p->capabilities.as4byte == 0)
634 		printf("%s\tannounce as4byte no\n", c);
635 	if (p->export_type == EXPORT_NONE)
636 		printf("%s\texport none\n", c);
637 	else if (p->export_type == EXPORT_DEFAULT_ROUTE)
638 		printf("%s\texport default-route\n", c);
639 	if (p->enforce_as == ENFORCE_AS_ON)
640 		printf("%s\tenforce neighbor-as yes\n", c);
641 	else
642 		printf("%s\tenforce neighbor-as no\n", c);
643 	if (p->enforce_local_as == ENFORCE_AS_ON)
644 		printf("%s\tenforce local-as yes\n", c);
645 	else
646 		printf("%s\tenforce local-as no\n", c);
647 	if (p->reflector_client) {
648 		if (conf->clusterid == 0)
649 			printf("%s\troute-reflector\n", c);
650 		else {
651 			ina.s_addr = conf->clusterid;
652 			printf("%s\troute-reflector %s\n", c,
653 			    inet_ntoa(ina));
654 		}
655 	}
656 	if (p->demote_group[0])
657 		printf("%s\tdemote %s\n", c, p->demote_group);
658 	if (p->if_depend[0])
659 		printf("%s\tdepend on \"%s\"\n", c, p->if_depend);
660 	if (p->flags & PEERFLAG_TRANS_AS)
661 		printf("%s\ttransparent-as yes\n", c);
662 
663 	if (p->flags & PEERFLAG_LOG_UPDATES)
664 		printf("%s\tlog updates\n", c);
665 
666 	if (p->auth.method == AUTH_MD5SIG)
667 		printf("%s\ttcp md5sig\n", c);
668 	else if (p->auth.method == AUTH_IPSEC_MANUAL_ESP ||
669 	    p->auth.method == AUTH_IPSEC_MANUAL_AH) {
670 		if (p->auth.method == AUTH_IPSEC_MANUAL_ESP)
671 			method = "esp";
672 		else
673 			method = "ah";
674 
675 		printf("%s\tipsec %s in spi %u %s XXXXXX", c, method,
676 		    p->auth.spi_in, print_auth_alg(p->auth.auth_alg_in));
677 		if (p->auth.enc_alg_in)
678 			printf(" %s XXXXXX", print_enc_alg(p->auth.enc_alg_in));
679 		printf("\n");
680 
681 		printf("%s\tipsec %s out spi %u %s XXXXXX", c, method,
682 		    p->auth.spi_out, print_auth_alg(p->auth.auth_alg_out));
683 		if (p->auth.enc_alg_out)
684 			printf(" %s XXXXXX",
685 			    print_enc_alg(p->auth.enc_alg_out));
686 		printf("\n");
687 	} else if (p->auth.method == AUTH_IPSEC_IKE_AH)
688 		printf("%s\tipsec ah ike\n", c);
689 	else if (p->auth.method == AUTH_IPSEC_IKE_ESP)
690 		printf("%s\tipsec esp ike\n", c);
691 
692 	if (p->ttlsec)
693 		printf("%s\tttl-security yes\n", c);
694 
695 	print_announce(p, c);
696 
697 	print_mrt(conf, p->id, p->groupid, c, "\t");
698 
699 	printf("%s}\n", c);
700 }
701 
702 const char *
703 print_auth_alg(u_int8_t alg)
704 {
705 	switch (alg) {
706 	case SADB_AALG_SHA1HMAC:
707 		return ("sha1");
708 	case SADB_AALG_MD5HMAC:
709 		return ("md5");
710 	default:
711 		return ("???");
712 	}
713 }
714 
715 const char *
716 print_enc_alg(u_int8_t alg)
717 {
718 	switch (alg) {
719 	case SADB_EALG_3DESCBC:
720 		return ("3des");
721 	case SADB_X_EALG_AES:
722 		return ("aes");
723 	default:
724 		return ("???");
725 	}
726 }
727 
728 void
729 print_announce(struct peer_config *p, const char *c)
730 {
731 	u_int8_t	aid;
732 
733 	for (aid = 0; aid < AID_MAX; aid++)
734 		if (p->capabilities.mp[aid])
735 			printf("%s\tannounce %s\n", c, aid2str(aid));
736 }
737 
738 void
739 print_as(struct filter_rule *r)
740 {
741 	if (r->match.as.flags & AS_FLAG_AS_SET_NAME) {
742 		printf("as-set \"%s\" ", r->match.as.name);
743 		return;
744 	}
745 	switch (r->match.as.op) {
746 	case OP_RANGE:
747 		printf("%s - ", log_as(r->match.as.as_min));
748 		printf("%s ", log_as(r->match.as.as_max));
749 		break;
750 	case OP_XRANGE:
751 		printf("%s >< ", log_as(r->match.as.as_min));
752 		printf("%s ", log_as(r->match.as.as_max));
753 		break;
754 	case OP_NE:
755 		printf("!= %s ", log_as(r->match.as.as_min));
756 		break;
757 	default:
758 		printf("%s ", log_as(r->match.as.as_min));
759 		break;
760 	}
761 }
762 
763 void
764 print_rule(struct bgpd_config *conf, struct filter_rule *r)
765 {
766 	struct peer *p;
767 	int i;
768 
769 	if (r->action == ACTION_ALLOW)
770 		printf("allow ");
771 	else if (r->action == ACTION_DENY)
772 		printf("deny ");
773 	else
774 		printf("match ");
775 	if (r->quick)
776 		printf("quick ");
777 
778 	if (r->rib[0])
779 		printf("rib %s ", r->rib);
780 
781 	if (r->dir == DIR_IN)
782 		printf("from ");
783 	else if (r->dir == DIR_OUT)
784 		printf("to ");
785 	else
786 		printf("eeeeeeeps. ");
787 
788 	if (r->peer.peerid) {
789 		RB_FOREACH(p, peer_head, &conf->peers)
790 			if (p->conf.id == r->peer.peerid)
791 				break;
792 		if (p == NULL)
793 			printf("? ");
794 		else
795 			printf("%s ", log_addr(&p->conf.remote_addr));
796 	} else if (r->peer.groupid) {
797 		RB_FOREACH(p, peer_head, &conf->peers)
798 			if (p->conf.groupid == r->peer.groupid)
799 				break;
800 		if (p == NULL)
801 			printf("group ? ");
802 		else
803 			printf("group \"%s\" ", p->conf.group);
804 	} else if (r->peer.remote_as) {
805 		printf("AS %s ", log_as(r->peer.remote_as));
806 	} else if (r->peer.ebgp) {
807 		printf("ebgp ");
808 	} else if (r->peer.ibgp) {
809 		printf("ibgp ");
810 	} else
811 		printf("any ");
812 
813 	if (r->match.ovs.is_set) {
814 		switch (r->match.ovs.validity) {
815 		case ROA_VALID:
816 			printf("ovs valid ");
817 			break;
818 		case ROA_INVALID:
819 			printf("ovs invalid ");
820 			break;
821 		case ROA_NOTFOUND:
822 			printf("ovs not-found ");
823 			break;
824 		default:
825 			printf("ovs ??? %d ??? ", r->match.ovs.validity);
826 		}
827 	}
828 
829 	if (r->match.prefix.addr.aid != AID_UNSPEC) {
830 		printf("prefix ");
831 		print_prefix(&r->match.prefix);
832 		printf(" ");
833 	}
834 
835 	if (r->match.prefixset.name[0] != '\0')
836 		printf("prefix-set \"%s\" ", r->match.prefixset.name);
837 	if (r->match.prefixset.flags & PREFIXSET_FLAG_LONGER)
838 		printf("or-longer ");
839 
840 	if (r->match.originset.name[0] != '\0')
841 		printf("origin-set \"%s\" ", r->match.originset.name);
842 
843 	if (r->match.nexthop.flags) {
844 		if (r->match.nexthop.flags == FILTER_NEXTHOP_NEIGHBOR)
845 			printf("nexthop neighbor ");
846 		else
847 			printf("nexthop %s ", log_addr(&r->match.nexthop.addr));
848 	}
849 
850 	if (r->match.as.type) {
851 		if (r->match.as.type == AS_ALL)
852 			printf("AS ");
853 		else if (r->match.as.type == AS_SOURCE)
854 			printf("source-as ");
855 		else if (r->match.as.type == AS_TRANSIT)
856 			printf("transit-as ");
857 		else if (r->match.as.type == AS_PEER)
858 			printf("peer-as ");
859 		else
860 			printf("unfluffy-as ");
861 		print_as(r);
862 	}
863 
864 	if (r->match.aslen.type) {
865 		printf("%s %u ", r->match.aslen.type == ASLEN_MAX ?
866 		    "max-as-len" : "max-as-seq", r->match.aslen.aslen);
867 	}
868 
869 	for (i = 0; i < MAX_COMM_MATCH; i++) {
870 		struct community *c = &r->match.community[i];
871 		if (c->flags != 0) {
872 			printf("%s ", community_type(c));
873 			print_community(c);
874 		}
875 	}
876 
877 	print_set(&r->set);
878 
879 	printf("\n");
880 }
881 
882 const char *
883 mrt_type(enum mrt_type t)
884 {
885 	switch (t) {
886 	case MRT_NONE:
887 		break;
888 	case MRT_TABLE_DUMP:
889 		return "table";
890 	case MRT_TABLE_DUMP_MP:
891 		return "table-mp";
892 	case MRT_TABLE_DUMP_V2:
893 		return "table-v2";
894 	case MRT_ALL_IN:
895 		return "all in";
896 	case MRT_ALL_OUT:
897 		return "all out";
898 	case MRT_UPDATE_IN:
899 		return "updates in";
900 	case MRT_UPDATE_OUT:
901 		return "updates out";
902 	}
903 	return "unfluffy MRT";
904 }
905 
906 void
907 print_mrt(struct bgpd_config *conf, u_int32_t pid, u_int32_t gid,
908     const char *prep, const char *prep2)
909 {
910 	struct mrt	*m;
911 
912 	if (conf->mrt == NULL)
913 		return;
914 
915 	LIST_FOREACH(m, conf->mrt, entry)
916 		if ((gid != 0 && m->group_id == gid) ||
917 		    (m->peer_id == pid && m->group_id == gid)) {
918 			printf("%s%sdump ", prep, prep2);
919 			if (m->rib[0])
920 				printf("rib %s ", m->rib);
921 			printf("%s \"%s\"", mrt_type(m->type),
922 			    MRT2MC(m)->name);
923 			if (MRT2MC(m)->ReopenTimerInterval == 0)
924 				printf("\n");
925 			else
926 				printf(" %d\n", MRT2MC(m)->ReopenTimerInterval);
927 		}
928 	if (!LIST_EMPTY(conf->mrt))
929 		printf("\n");
930 }
931 
932 void
933 print_groups(struct bgpd_config *conf)
934 {
935 	struct peer_config	**peerlist;
936 	struct peer		 *p;
937 	u_int			  peer_cnt, i;
938 	u_int32_t		  prev_groupid;
939 	const char		 *tab	= "\t";
940 	const char		 *nada	= "";
941 	const char		 *c;
942 
943 	peer_cnt = 0;
944 	RB_FOREACH(p, peer_head, &conf->peers)
945 		peer_cnt++;
946 
947 	if ((peerlist = calloc(peer_cnt, sizeof(struct peer_config *))) == NULL)
948 		fatal("print_groups calloc");
949 
950 	i = 0;
951 	RB_FOREACH(p, peer_head, &conf->peers)
952 		peerlist[i++] = &p->conf;
953 
954 	qsort(peerlist, peer_cnt, sizeof(struct peer_config *), peer_compare);
955 
956 	prev_groupid = 0;
957 	for (i = 0; i < peer_cnt; i++) {
958 		if (peerlist[i]->groupid) {
959 			c = tab;
960 			if (peerlist[i]->groupid != prev_groupid) {
961 				if (prev_groupid)
962 					printf("}\n\n");
963 				printf("group \"%s\" {\n", peerlist[i]->group);
964 				prev_groupid = peerlist[i]->groupid;
965 			}
966 		} else
967 			c = nada;
968 
969 		print_peer(peerlist[i], conf, c);
970 	}
971 
972 	if (prev_groupid)
973 		printf("}\n\n");
974 
975 	free(peerlist);
976 }
977 
978 int
979 peer_compare(const void *aa, const void *bb)
980 {
981 	const struct peer_config * const *a;
982 	const struct peer_config * const *b;
983 
984 	a = aa;
985 	b = bb;
986 
987 	return ((*a)->groupid - (*b)->groupid);
988 }
989 
990 void
991 print_config(struct bgpd_config *conf, struct rib_names *rib_l)
992 {
993 	struct filter_rule	*r;
994 	struct network		*n;
995 	struct rde_rib		*rr;
996 	struct l3vpn		*vpn;
997 
998 	print_mainconf(conf);
999 	print_roa(&conf->roa);
1000 	print_as_sets(conf->as_sets);
1001 	print_prefixsets(&conf->prefixsets);
1002 	print_originsets(&conf->originsets);
1003 	TAILQ_FOREACH(n, &conf->networks, entry)
1004 		print_network(&n->net, "");
1005 	if (!SIMPLEQ_EMPTY(&conf->l3vpns))
1006 		printf("\n");
1007 	SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry)
1008 		print_l3vpn(vpn);
1009 	printf("\n");
1010 	SIMPLEQ_FOREACH(rr, rib_l, entry) {
1011 		if (rr->flags & F_RIB_NOEVALUATE)
1012 			printf("rde rib %s no evaluate\n", rr->name);
1013 		else if (rr->flags & F_RIB_NOFIB)
1014 			printf("rde rib %s\n", rr->name);
1015 		else
1016 			printf("rde rib %s rtable %u fib-update %s\n", rr->name,
1017 			    rr->rtableid, rr->flags & F_RIB_NOFIBSYNC ?
1018 			    "no" : "yes");
1019 	}
1020 	printf("\n");
1021 	print_mrt(conf, 0, 0, "", "");
1022 	print_groups(conf);
1023 	TAILQ_FOREACH(r, conf->filters, entry)
1024 		print_rule(conf, r);
1025 }
1026