xref: /openbsd-src/usr.sbin/bgpd/printconf.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: printconf.c,v 1.67 2009/03/26 13:59:30 henning Exp $	*/
2 
3 /*
4  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA, PROFITS OR MIND, WHETHER IN
15  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include "bgpd.h"
24 #include "mrt.h"
25 #include "session.h"
26 
27 void		 print_op(enum comp_ops);
28 void		 print_community(int, int);
29 void		 print_set(struct filter_set_head *);
30 void		 print_mainconf(struct bgpd_config *);
31 void		 print_network(struct network_config *);
32 void		 print_peer(struct peer_config *, struct bgpd_config *,
33 		    const char *);
34 const char	*print_auth_alg(u_int8_t);
35 const char	*print_enc_alg(u_int8_t);
36 const char	*print_safi(u_int8_t);
37 void		 print_rule(struct peer *, struct filter_rule *);
38 const char *	 mrt_type(enum mrt_type);
39 void		 print_mrt(u_int32_t, u_int32_t, const char *, const char *);
40 void		 print_groups(struct bgpd_config *, struct peer *);
41 int		 peer_compare(const void *, const void *);
42 
43 void
44 print_op(enum comp_ops op)
45 {
46 	switch (op) {
47 	case OP_RANGE:
48 		printf("-");
49 		break;
50 	case OP_XRANGE:
51 		printf("><");
52 		break;
53 	case OP_EQ:
54 		printf("=");
55 		break;
56 	case OP_NE:
57 		printf("!=");
58 		break;
59 	case OP_LE:
60 		printf("<=");
61 		break;
62 	case OP_LT:
63 		printf("<");
64 		break;
65 	case OP_GE:
66 		printf(">=");
67 		break;
68 	case OP_GT:
69 		printf(">");
70 		break;
71 	default:
72 		printf("?");
73 		break;
74 	}
75 }
76 
77 void
78 print_community(int as, int type)
79 {
80 	if (as == COMMUNITY_ANY)
81 		printf("*:");
82 	else if (as == COMMUNITY_NEIGHBOR_AS)
83 		printf("neighbor-as:");
84 	else
85 		printf("%d:", as);
86 
87 	if (type == COMMUNITY_ANY)
88 		printf("* ");
89 	else if (type == COMMUNITY_NEIGHBOR_AS)
90 		printf("neighbor-as ");
91 	else
92 		printf("%d ", type);
93 }
94 
95 void
96 print_set(struct filter_set_head *set)
97 {
98 	struct filter_set	*s;
99 
100 	if (TAILQ_EMPTY(set))
101 		return;
102 
103 	printf("set { ");
104 	TAILQ_FOREACH(s, set, entry) {
105 		switch (s->type) {
106 		case ACTION_SET_LOCALPREF:
107 			printf("localpref %u ", s->action.metric);
108 			break;
109 		case ACTION_SET_RELATIVE_LOCALPREF:
110 			printf("localpref %+d ", s->action.relative);
111 			break;
112 		case ACTION_SET_MED:
113 			printf("metric %u ", s->action.metric);
114 			break;
115 		case ACTION_SET_RELATIVE_MED:
116 			printf("metric %+d ", s->action.relative);
117 			break;
118 		case ACTION_SET_WEIGHT:
119 			printf("weight %u ", s->action.metric);
120 			break;
121 		case ACTION_SET_RELATIVE_WEIGHT:
122 			printf("weight %+d ", s->action.relative);
123 			break;
124 		case ACTION_SET_NEXTHOP:
125 			printf("nexthop %s ", log_addr(&s->action.nexthop));
126 			break;
127 		case ACTION_SET_NEXTHOP_REJECT:
128 			printf("nexthop reject ");
129 			break;
130 		case ACTION_SET_NEXTHOP_BLACKHOLE:
131 			printf("nexthop blackhole ");
132 			break;
133 		case ACTION_SET_NEXTHOP_NOMODIFY:
134 			printf("nexthop no-modify ");
135 			break;
136 		case ACTION_SET_NEXTHOP_SELF:
137 			printf("nexthop self ");
138 			break;
139 		case ACTION_SET_PREPEND_SELF:
140 			printf("prepend-self %u ", s->action.prepend);
141 			break;
142 		case ACTION_SET_PREPEND_PEER:
143 			printf("prepend-neighbor %u ", s->action.prepend);
144 			break;
145 		case ACTION_DEL_COMMUNITY:
146 			printf("community delete ");
147 			print_community(s->action.community.as,
148 			    s->action.community.type);
149 			printf(" ");
150 			break;
151 		case ACTION_SET_COMMUNITY:
152 			printf("community ");
153 			print_community(s->action.community.as,
154 			    s->action.community.type);
155 			printf(" ");
156 			break;
157 		case ACTION_PFTABLE:
158 			printf("pftable %s ", s->action.pftable);
159 			break;
160 		case ACTION_RTLABEL:
161 			printf("rtlabel %s ", s->action.rtlabel);
162 			break;
163 		case ACTION_RTLABEL_ID:
164 		case ACTION_PFTABLE_ID:
165 			/* not possible */
166 			printf("king bula saiz: config broken");
167 			break;
168 		}
169 	}
170 	printf("}");
171 }
172 
173 void
174 print_mainconf(struct bgpd_config *conf)
175 {
176 	struct in_addr		 ina;
177 	struct listen_addr	*la;
178 
179 	printf("AS %s", log_as(conf->as));
180 	if (conf->as > USHRT_MAX && conf->short_as != AS_TRANS)
181 		printf(" %u", conf->short_as);
182 	ina.s_addr = conf->bgpid;
183 	printf("\nrouter-id %s\n", inet_ntoa(ina));
184 	if (conf->holdtime)
185 		printf("holdtime %u\n", conf->holdtime);
186 	if (conf->min_holdtime)
187 		printf("holdtime min %u\n", conf->min_holdtime);
188 
189 	if (conf->flags & BGPD_FLAG_NO_FIB_UPDATE)
190 		printf("fib-update no\n");
191 	else
192 		printf("fib-update yes\n");
193 
194 	if (conf->flags & BGPD_FLAG_NO_EVALUATE)
195 		printf("route-collector yes\n");
196 
197 	if (conf->flags & BGPD_FLAG_DECISION_ROUTEAGE)
198 		printf("rde route-age evaluate\n");
199 
200 	if (conf->flags & BGPD_FLAG_DECISION_MED_ALWAYS)
201 		printf("rde med compare always\n");
202 
203 	if (conf->log & BGPD_LOG_UPDATES)
204 		printf("log updates\n");
205 
206 	TAILQ_FOREACH(la, conf->listen_addrs, entry)
207 		printf("listen on %s\n",
208 		    log_sockaddr((struct sockaddr *)&la->sa));
209 
210 	if (conf->flags & BGPD_FLAG_NEXTHOP_BGP)
211 		printf("nexthop qualify via bgp\n");
212 	if (conf->flags & BGPD_FLAG_NEXTHOP_DEFAULT)
213 		printf("nexthop qualify via default\n");
214 
215 	if (conf->flags & BGPD_FLAG_REDIST_CONNECTED) {
216 		printf("network inet connected");
217 		if (!TAILQ_EMPTY(&conf->connectset))
218 			printf(" ");
219 		print_set(&conf->connectset);
220 		printf("\n");
221 	}
222 	if (conf->flags & BGPD_FLAG_REDIST_STATIC) {
223 		printf("network inet static");
224 		if (!TAILQ_EMPTY(&conf->staticset))
225 			printf(" ");
226 		print_set(&conf->staticset);
227 		printf("\n");
228 	}
229 	if (conf->flags & BGPD_FLAG_REDIST6_CONNECTED) {
230 		printf("network inet6 connected");
231 		if (!TAILQ_EMPTY(&conf->connectset6))
232 			printf(" ");
233 		print_set(&conf->connectset6);
234 		printf("\n");
235 	}
236 	if (conf->flags & BGPD_FLAG_REDIST_STATIC) {
237 		printf("network inet6 static");
238 		if (!TAILQ_EMPTY(&conf->staticset6))
239 			printf(" ");
240 		print_set(&conf->staticset6);
241 		printf("\n");
242 	}
243 	if (conf->rtableid)
244 		printf("rtable %u\n", conf->rtableid);
245 }
246 
247 void
248 print_network(struct network_config *n)
249 {
250 	printf("network %s/%u", log_addr(&n->prefix), n->prefixlen);
251 	if (!TAILQ_EMPTY(&n->attrset))
252 		printf(" ");
253 	print_set(&n->attrset);
254 	printf("\n");
255 }
256 
257 void
258 print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
259 {
260 	char		*method;
261 	struct in_addr	 ina;
262 
263 	if ((p->remote_addr.af == AF_INET && p->remote_masklen != 32) ||
264 	    (p->remote_addr.af == AF_INET6 && p->remote_masklen != 128))
265 		printf("%sneighbor %s/%u {\n", c, log_addr(&p->remote_addr),
266 		    p->remote_masklen);
267 	else
268 		printf("%sneighbor %s {\n", c, log_addr(&p->remote_addr));
269 	if (p->descr[0])
270 		printf("%s\tdescr \"%s\"\n", c, p->descr);
271 	if (p->remote_as)
272 		printf("%s\tremote-as %s\n", c, log_as(p->remote_as));
273 	if (p->down)
274 		printf("%s\tdown\n", c);
275 	if (p->distance > 1)
276 		printf("%s\tmultihop %u\n", c, p->distance);
277 	if (p->passive)
278 		printf("%s\tpassive\n", c);
279 	if (p->local_addr.af)
280 		printf("%s\tlocal-address %s\n", c, log_addr(&p->local_addr));
281 	if (p->max_prefix) {
282 		printf("%s\tmax-prefix %u", c, p->max_prefix);
283 		if (p->max_prefix_restart)
284 			printf(" restart %u", p->max_prefix_restart);
285 		printf("\n");
286 	}
287 	if (p->holdtime)
288 		printf("%s\tholdtime %u\n", c, p->holdtime);
289 	if (p->min_holdtime)
290 		printf("%s\tholdtime min %u\n", c, p->min_holdtime);
291 	if (p->announce_capa == 0)
292 		printf("%s\tannounce capabilities no\n", c);
293 	if (p->announce_type == ANNOUNCE_SELF)
294 		printf("%s\tannounce self\n", c);
295 	else if (p->announce_type == ANNOUNCE_NONE)
296 		printf("%s\tannounce none\n", c);
297 	else if (p->announce_type == ANNOUNCE_ALL)
298 		printf("%s\tannounce all\n", c);
299 	else if (p->announce_type == ANNOUNCE_DEFAULT_ROUTE)
300 		printf("%s\tannounce default-route\n", c);
301 	else
302 		printf("%s\tannounce ???\n", c);
303 	if (p->enforce_as == ENFORCE_AS_ON)
304 		printf("%s\tenforce neighbor-as yes\n", c);
305 	else
306 		printf("%s\tenforce neighbor-as no\n", c);
307 	if (p->reflector_client) {
308 		if (conf->clusterid == 0)
309 			printf("%s\troute-reflector\n", c);
310 		else {
311 			ina.s_addr = conf->clusterid;
312 			printf("%s\troute-reflector %s\n", c,
313 			    inet_ntoa(ina));
314 		}
315 	}
316 	if (p->demote_group[0])
317 		printf("%s\tdemote %s\n", c, p->demote_group);
318 	if (p->if_depend[0])
319 		printf("%s\tdepend on \"%s\"\n", c, p->if_depend);
320 	if (p->flags & PEERFLAG_TRANS_AS)
321 		printf("%s\ttransparent-as yes\n", c);
322 
323 	if (p->auth.method == AUTH_MD5SIG)
324 		printf("%s\ttcp md5sig\n", c);
325 	else if (p->auth.method == AUTH_IPSEC_MANUAL_ESP ||
326 	    p->auth.method == AUTH_IPSEC_MANUAL_AH) {
327 		if (p->auth.method == AUTH_IPSEC_MANUAL_ESP)
328 			method = "esp";
329 		else
330 			method = "ah";
331 
332 		printf("%s\tipsec %s in spi %u %s XXXXXX", c, method,
333 		    p->auth.spi_in, print_auth_alg(p->auth.auth_alg_in));
334 		if (p->auth.enc_alg_in)
335 			printf(" %s XXXXXX", print_enc_alg(p->auth.enc_alg_in));
336 		printf("\n");
337 
338 		printf("%s\tipsec %s out spi %u %s XXXXXX", c, method,
339 		    p->auth.spi_out, print_auth_alg(p->auth.auth_alg_out));
340 		if (p->auth.enc_alg_out)
341 			printf(" %s XXXXXX",
342 			    print_enc_alg(p->auth.enc_alg_out));
343 		printf("\n");
344 	} else if (p->auth.method == AUTH_IPSEC_IKE_AH)
345 		printf("%s\tipsec ah ike\n", c);
346 	else if (p->auth.method == AUTH_IPSEC_IKE_ESP)
347 		printf("%s\tipsec esp ike\n", c);
348 
349 	if (p->ttlsec)
350 		printf("%s\tttl-security yes\n", c);
351 
352 	printf("%s\tannounce IPv4 %s\n", c, print_safi(p->capabilities.mp_v4));
353 	printf("%s\tannounce IPv6 %s\n", c, print_safi(p->capabilities.mp_v6));
354 
355 	if (p->softreconfig_in == 1)
356 		printf("%s\tsoftreconfig in yes\n", c);
357 	else
358 		printf("%s\tsoftreconfig in no\n", c);
359 
360 	if (p->softreconfig_out == 1)
361 		printf("%s\tsoftreconfig out yes\n", c);
362 	else
363 		printf("%s\tsoftreconfig out no\n", c);
364 
365 
366 	print_mrt(p->id, p->groupid, c, "\t");
367 
368 	printf("%s}\n", c);
369 }
370 
371 const char *
372 print_auth_alg(u_int8_t alg)
373 {
374 	switch (alg) {
375 	case SADB_AALG_SHA1HMAC:
376 		return ("sha1");
377 	case SADB_AALG_MD5HMAC:
378 		return ("md5");
379 	default:
380 		return ("???");
381 	}
382 }
383 
384 const char *
385 print_enc_alg(u_int8_t alg)
386 {
387 	switch (alg) {
388 	case SADB_EALG_3DESCBC:
389 		return ("3des");
390 	case SADB_X_EALG_AES:
391 		return ("aes");
392 	default:
393 		return ("???");
394 	}
395 }
396 
397 const char *
398 print_safi(u_int8_t safi)
399 {
400 	switch (safi) {
401 	case SAFI_NONE:
402 		return ("none");
403 	case SAFI_UNICAST:
404 		return ("unicast");
405 	default:
406 		return ("?");
407 	}
408 }
409 
410 void
411 print_rule(struct peer *peer_l, struct filter_rule *r)
412 {
413 	struct peer	*p;
414 
415 	if (r->action == ACTION_ALLOW)
416 		printf("allow ");
417 	else if (r->action == ACTION_DENY)
418 		printf("deny ");
419 	else
420 		printf("match ");
421 
422 	if (r->quick)
423 		printf("quick ");
424 
425 	if (r->dir == DIR_IN)
426 		printf("from ");
427 	else if (r->dir == DIR_OUT)
428 		printf("to ");
429 	else
430 		printf("eeeeeeeps. ");
431 
432 	if (r->peer.peerid) {
433 		for (p = peer_l; p != NULL && p->conf.id != r->peer.peerid;
434 		    p = p->next)
435 			;	/* nothing */
436 		if (p == NULL)
437 			printf("? ");
438 		else
439 			printf("%s ", log_addr(&p->conf.remote_addr));
440 	} else if (r->peer.groupid) {
441 		for (p = peer_l; p != NULL &&
442 		    p->conf.groupid != r->peer.groupid; p = p->next)
443 			;	/* nothing */
444 		if (p == NULL)
445 			printf("group ? ");
446 		else
447 			printf("group \"%s\" ", p->conf.group);
448 	} else
449 		printf("any ");
450 
451 	if (r->match.prefix.addr.af)
452 		printf("prefix %s/%u ", log_addr(&r->match.prefix.addr),
453 		    r->match.prefix.len);
454 
455 	if (r->match.prefix.addr.af == 0 && r->match.prefixlen.af) {
456 		if (r->match.prefixlen.af == AF_INET)
457 			printf("inet ");
458 		if (r->match.prefixlen.af == AF_INET6)
459 			printf("inet6 ");
460 	}
461 
462 	if (r->match.prefixlen.op) {
463 		if (r->match.prefixlen.op == OP_RANGE ||
464 		    r->match.prefixlen.op == OP_XRANGE) {
465 			printf("prefixlen %u ", r->match.prefixlen.len_min);
466 			print_op(r->match.prefixlen.op);
467 			printf(" %u ", r->match.prefixlen.len_max);
468 		} else {
469 			printf("prefixlen ");
470 			print_op(r->match.prefixlen.op);
471 			printf(" %u ", r->match.prefixlen.len_min);
472 		}
473 	}
474 
475 	if (r->match.as.type) {
476 		if (r->match.as.type == AS_ALL)
477 			printf("AS %s ", log_as(r->match.as.as));
478 		else if (r->match.as.type == AS_SOURCE)
479 			printf("source-as %s ", log_as(r->match.as.as));
480 		else if (r->match.as.type == AS_TRANSIT)
481 			printf("transit-as %s ", log_as(r->match.as.as));
482 		else if (r->match.as.type == AS_PEER)
483 			printf("peer-as %s ", log_as(r->match.as.as));
484 		else
485 			printf("unfluffy-as %s ", log_as(r->match.as.as));
486 	}
487 
488 	if (r->match.community.as != COMMUNITY_UNSET) {
489 		printf("community ");
490 		print_community(r->match.community.as,
491 		    r->match.community.type);
492 	}
493 
494 	print_set(&r->set);
495 
496 	printf("\n");
497 }
498 
499 const char *
500 mrt_type(enum mrt_type t)
501 {
502 	switch (t) {
503 	case MRT_NONE:
504 		break;
505 	case MRT_TABLE_DUMP:
506 		return "table";
507 	case MRT_TABLE_DUMP_MP:
508 		return "table-mp";
509 	case MRT_ALL_IN:
510 		return "all in";
511 	case MRT_ALL_OUT:
512 		return "all out";
513 	case MRT_UPDATE_IN:
514 		return "updates in";
515 	case MRT_UPDATE_OUT:
516 		return "updates out";
517 	}
518 	return "unfluffy MRT";
519 }
520 
521 struct mrt_head	*xmrt_l = NULL;
522 
523 void
524 print_mrt(u_int32_t pid, u_int32_t gid, const char *prep, const char *prep2)
525 {
526 	struct mrt	*m;
527 
528 	if (xmrt_l == NULL)
529 		return;
530 
531 	LIST_FOREACH(m, xmrt_l, entry)
532 		if ((gid != 0 && m->group_id == gid) ||
533 		    (m->peer_id == pid && m->group_id == gid)) {
534 			if (MRT2MC(m)->ReopenTimerInterval == 0)
535 				printf("%s%sdump %s %s\n", prep, prep2,
536 				    mrt_type(m->type), MRT2MC(m)->name);
537 			else
538 				printf("%s%sdump %s %s %d\n", prep, prep2,
539 				    mrt_type(m->type),
540 				    MRT2MC(m)->name,
541 				    MRT2MC(m)->ReopenTimerInterval);
542 		}
543 }
544 
545 void
546 print_groups(struct bgpd_config *conf, struct peer *peer_l)
547 {
548 	struct peer_config	**peerlist;
549 	struct peer		 *p;
550 	u_int			  peer_cnt, i;
551 	u_int32_t		  prev_groupid;
552 	const char		 *tab	= "\t";
553 	const char		 *nada	= "";
554 	const char		 *c;
555 
556 	peer_cnt = 0;
557 	for (p = peer_l; p != NULL; p = p->next)
558 		peer_cnt++;
559 
560 	if ((peerlist = calloc(peer_cnt, sizeof(struct peer_config *))) == NULL)
561 		fatal("print_groups calloc");
562 
563 	i = 0;
564 	for (p = peer_l; p != NULL; p = p->next)
565 		peerlist[i++] = &p->conf;
566 
567 	qsort(peerlist, peer_cnt, sizeof(struct peer_config *), peer_compare);
568 
569 	prev_groupid = 0;
570 	for (i = 0; i < peer_cnt; i++) {
571 		if (peerlist[i]->groupid) {
572 			c = tab;
573 			if (peerlist[i]->groupid != prev_groupid) {
574 				if (prev_groupid)
575 					printf("}\n\n");
576 				printf("group \"%s\" {\n", peerlist[i]->group);
577 				prev_groupid = peerlist[i]->groupid;
578 			}
579 		} else
580 			c = nada;
581 
582 		print_peer(peerlist[i], conf, c);
583 	}
584 
585 	if (prev_groupid)
586 		printf("}\n\n");
587 
588 	free(peerlist);
589 }
590 
591 int
592 peer_compare(const void *aa, const void *bb)
593 {
594 	const struct peer_config * const *a;
595 	const struct peer_config * const *b;
596 
597 	a = aa;
598 	b = bb;
599 
600 	return ((*a)->groupid - (*b)->groupid);
601 }
602 
603 void
604 print_config(struct bgpd_config *conf, struct network_head *net_l,
605     struct peer *peer_l, struct filter_head *rules_l, struct mrt_head *mrt_l)
606 {
607 	struct filter_rule	*r;
608 	struct network		*n;
609 
610 	xmrt_l = mrt_l;
611 	printf("\n");
612 	print_mainconf(conf);
613 	printf("\n");
614 	TAILQ_FOREACH(n, net_l, entry)
615 		print_network(&n->net);
616 	printf("\n");
617 	print_mrt(0, 0, "", "");
618 	printf("\n");
619 	print_groups(conf, peer_l);
620 	printf("\n");
621 	TAILQ_FOREACH(r, rules_l, entry)
622 		print_rule(peer_l, r);
623 }
624