xref: /openbsd-src/usr.sbin/tcpdump/print-bgp.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: print-bgp.c,v 1.11 2009/01/29 09:46:32 bluhm Exp $	*/
2 
3 /*
4  * Copyright (C) 1999 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #ifndef lint
33 static const char rcsid[] =
34      "@(#) $Id: print-bgp.c,v 1.11 2009/01/29 09:46:32 bluhm Exp $";
35 #endif
36 
37 #include <sys/param.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 
42 #include <netinet/in.h>
43 
44 #include <errno.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <netdb.h>
48 
49 #include "interface.h"
50 #include "addrtoname.h"
51 #include "extract.h"
52 #include "afnum.h"
53 
54 struct bgp {
55 	u_int8_t bgp_marker[16];
56 	u_int16_t bgp_len;
57 	u_int8_t bgp_type;
58 };
59 #define BGP_SIZE		19	/* unaligned */
60 
61 #define BGP_OPEN		1
62 #define BGP_UPDATE		2
63 #define BGP_NOTIFICATION	3
64 #define BGP_KEEPALIVE		4
65 
66 struct bgp_open {
67 	u_int8_t bgpo_marker[16];
68 	u_int16_t bgpo_len;
69 	u_int8_t bgpo_type;
70 	u_int8_t bgpo_version;
71 	u_int16_t bgpo_myas;
72 	u_int16_t bgpo_holdtime;
73 	u_int32_t bgpo_id;
74 	u_int8_t bgpo_optlen;
75 	/* options should follow */
76 };
77 #define BGP_OPEN_SIZE		29	/* unaligned */
78 
79 struct bgp_opt {
80 	u_int8_t bgpopt_type;
81 	u_int8_t bgpopt_len;
82 	/* variable length */
83 };
84 #define BGP_OPT_SIZE		2	/* some compilers may pad to 4 bytes */
85 
86 struct bgp_notification {
87 	u_int8_t bgpn_marker[16];
88 	u_int16_t bgpn_len;
89 	u_int8_t bgpn_type;
90 	u_int8_t bgpn_major;
91 	u_int8_t bgpn_minor;
92 	/* data should follow */
93 };
94 #define BGP_NOTIFICATION_SIZE		21	/* unaligned */
95 
96 struct bgp_attr {
97 	u_int8_t bgpa_flags;
98 	u_int8_t bgpa_type;
99 	union {
100 		u_int8_t len;
101 		u_int16_t elen;
102 	} bgpa_len;
103 #define bgp_attr_len(p) \
104 	(((p)->bgpa_flags & 0x10) ? \
105 		ntohs((p)->bgpa_len.elen) : (p)->bgpa_len.len)
106 #define bgp_attr_off(p) \
107 	(((p)->bgpa_flags & 0x10) ? 4 : 3)
108 };
109 
110 #define BGPTYPE_ORIGIN			1
111 #define BGPTYPE_AS_PATH			2
112 #define BGPTYPE_NEXT_HOP		3
113 #define BGPTYPE_MULTI_EXIT_DISC		4
114 #define BGPTYPE_LOCAL_PREF		5
115 #define BGPTYPE_ATOMIC_AGGREGATE	6
116 #define BGPTYPE_AGGREGATOR		7
117 #define	BGPTYPE_COMMUNITIES		8	/* RFC1997 */
118 #define	BGPTYPE_ORIGINATOR_ID		9	/* RFC1998 */
119 #define	BGPTYPE_CLUSTER_LIST		10	/* RFC1998 */
120 #define	BGPTYPE_DPA			11	/* draft-ietf-idr-bgp-dpa */
121 #define	BGPTYPE_ADVERTISERS		12	/* RFC1863 */
122 #define	BGPTYPE_RCID_PATH		13	/* RFC1863 */
123 #define BGPTYPE_MP_REACH_NLRI		14	/* RFC2283 */
124 #define BGPTYPE_MP_UNREACH_NLRI		15	/* RFC2283 */
125 
126 #define BGP_MP_NLRI_MINSIZE		3
127 
128 static const char *bgptype[] = {
129 	NULL, "OPEN", "UPDATE", "NOTIFICATION", "KEEPALIVE",
130 };
131 #define bgp_type(x) num_or_str(bgptype, sizeof(bgptype)/sizeof(bgptype[0]), (x))
132 
133 static const char *bgpopt_type[] = {
134 	NULL, "Authentication Information", "Capabilities Advertisement",
135 };
136 #define bgp_opttype(x) \
137 	num_or_str(bgpopt_type, sizeof(bgpopt_type)/sizeof(bgpopt_type[0]), (x))
138 
139 static const char *bgpnotify_major[] = {
140 	NULL, "Message Header Error",
141 	"OPEN Message Error", "UPDATE Message Error",
142 	"Hold Timer Expired", "Finite State Machine Error",
143 	"Cease",
144 };
145 #define bgp_notify_major(x) \
146 	num_or_str(bgpnotify_major, \
147 		sizeof(bgpnotify_major)/sizeof(bgpnotify_major[0]), (x))
148 
149 static const char *bgpnotify_minor_1[] = {
150 	NULL, "Connection Not Synchronized",
151 	"Bad Message Length", "Bad Message Type",
152 };
153 
154 static const char *bgpnotify_minor_2[] = {
155 	NULL, "Unsupported Version Number",
156 	"Bad Peer AS", "Bad BGP Identifier",
157 	"Unsupported Optional Parameter", "Authentication Failure",
158 	"Unacceptable Hold Time",
159 };
160 
161 static const char *bgpnotify_minor_3[] = {
162 	NULL, "Malformed Attribute List",
163 	"Unrecognized Well-known Attribute", "Missing Well-known Attribute",
164 	"Attribute Flags Error", "Attribute Length Error",
165 	"Invalid ORIGIN Attribute", "AS Routing Loop",
166 	"Invalid NEXT_HOP Attribute", "Optional Attribute Error",
167 	"Invalid Network Field", "Malformed AS_PATH",
168 };
169 
170 static const char **bgpnotify_minor[] = {
171 	NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
172 };
173 static const int bgpnotify_minor_siz[] = {
174 	0, sizeof(bgpnotify_minor_1)/sizeof(bgpnotify_minor_1[0]),
175 	sizeof(bgpnotify_minor_2)/sizeof(bgpnotify_minor_2[0]),
176 	sizeof(bgpnotify_minor_3)/sizeof(bgpnotify_minor_3[0]),
177 };
178 
179 static const char *bgpattr_origin[] = {
180 	"IGP", "EGP", "INCOMPLETE",
181 };
182 #define bgp_attr_origin(x) \
183 	num_or_str(bgpattr_origin, \
184 		sizeof(bgpattr_origin)/sizeof(bgpattr_origin[0]), (x))
185 
186 static const char *bgpattr_type[] = {
187 	NULL, "ORIGIN", "AS_PATH", "NEXT_HOP",
188 	"MULTI_EXIT_DISC", "LOCAL_PREF", "ATOMIC_AGGREGATE", "AGGREGATOR",
189 	"COMMUNITIES", "ORIGINATOR_ID", "CLUSTER_LIST", "DPA",
190 	"ADVERTISERS", "RCID_PATH", "MP_REACH_NLRI", "MP_UNREACH_NLRI",
191 };
192 #define bgp_attr_type(x) \
193 	num_or_str(bgpattr_type, \
194 		sizeof(bgpattr_type)/sizeof(bgpattr_type[0]), (x))
195 
196 /* Subsequent address family identifier, RFC2283 section 7 */
197 static const char *bgpattr_nlri_safi[] = {
198 	"Reserved", "Unicast", "Multicast", "Unicast+Multicast",
199 };
200 #define bgp_attr_nlri_safi(x) \
201 	num_or_str(bgpattr_nlri_safi, \
202 		sizeof(bgpattr_nlri_safi)/sizeof(bgpattr_nlri_safi[0]), (x))
203 
204 /* well-known community */
205 #define BGP_COMMUNITY_NO_EXPORT			0xffffff01
206 #define BGP_COMMUNITY_NO_ADVERT			0xffffff02
207 #define BGP_COMMUNITY_NO_EXPORT_SUBCONFED	0xffffff03
208 #define BGP_COMMUNITY_NO_PEER			0xffffff04
209 
210 static const char *afnumber[] = AFNUM_NAME_STR;
211 #define af_name(x) \
212 	(((x) == 65535) ? afnumber[0] : \
213 		num_or_str(afnumber, \
214 			sizeof(afnumber)/sizeof(afnumber[0]), (x)))
215 
216 
217 static const char *
218 num_or_str(const char **table, size_t siz, int value)
219 {
220 	static char buf[20];
221 	if (value < 0 || siz <= value || table[value] == NULL) {
222 		snprintf(buf, sizeof(buf), "#%d", value);
223 		return buf;
224 	} else
225 		return table[value];
226 }
227 
228 static const char *
229 bgp_notify_minor(int major, int minor)
230 {
231 	static const char **table;
232 	int siz;
233 	static char buf[20];
234 	const char *p;
235 
236 	if (0 <= major
237 	 && major < sizeof(bgpnotify_minor)/sizeof(bgpnotify_minor[0])
238 	 && bgpnotify_minor[major]) {
239 		table = bgpnotify_minor[major];
240 		siz = bgpnotify_minor_siz[major];
241 		if (0 <= minor && minor < siz && table[minor])
242 			p = table[minor];
243 		else
244 			p = NULL;
245 	} else
246 		p = NULL;
247 	if (p == NULL) {
248 		snprintf(buf, sizeof(buf), "#%d", minor);
249 		return buf;
250 	} else
251 		return p;
252 }
253 
254 static int
255 decode_prefix4(const u_char *pd, char *buf, u_int buflen)
256 {
257 	struct in_addr addr;
258 	u_int plen;
259 	int n;
260 
261 	TCHECK(pd[0]);
262 	plen = pd[0]; /*
263 		       * prefix length is in bits; packet only contains
264 		       * enough bytes of address to contain this many bits
265 		       */
266 	if (plen < 0 || 32 < plen)
267 		return -1;
268 	memset(&addr, 0, sizeof(addr));
269 	TCHECK2(pd[1], (plen + 7) / 8);
270 	memcpy(&addr, &pd[1], (plen + 7) / 8);
271 	if (plen % 8) {
272 		((u_char *)&addr)[(plen + 7) / 8 - 1] &=
273 			((0xff00 >> (plen % 8)) & 0xff);
274 	}
275 	n = snprintf(buf, buflen, "%s/%d", getname((u_char *)&addr), plen);
276 	if (n == -1 || n >= buflen)
277 		return -1;
278 
279 	return 1 + (plen + 7) / 8;
280 
281 trunc:
282 	return -2;
283 }
284 
285 #ifdef INET6
286 static int
287 decode_prefix6(const u_char *pd, char *buf, u_int buflen)
288 {
289 	struct in6_addr addr;
290 	u_int plen;
291 	int n;
292 
293 	TCHECK(pd[0]);
294 	plen = pd[0];
295 	if (plen < 0 || 128 < plen)
296 		return -1;
297 
298 	memset(&addr, 0, sizeof(addr));
299 	TCHECK2(pd[1], (plen + 7) / 8);
300 	memcpy(&addr, &pd[1], (plen + 7) / 8);
301 	if (plen % 8) {
302 		addr.s6_addr[(plen + 7) / 8 - 1] &=
303 			((0xff00 >> (plen % 8)) & 0xff);
304 	}
305 
306 	n = snprintf(buf, buflen, "%s/%d", getname6((u_char *)&addr), plen);
307 	if (n == -1 || n >= buflen)
308 		return -1;
309 
310 	return 1 + (plen + 7) / 8;
311 
312 trunc:
313 	return -2;
314 }
315 #endif
316 
317 static int
318 bgp_attr_print(const struct bgp_attr *attr, const u_char *dat, int len)
319 {
320 	int i;
321 	u_int16_t af;
322 	u_int8_t safi, snpa;
323 	int advance;
324 	int tlen;
325 	const u_char *p;
326 	char buf[MAXHOSTNAMELEN + 100];
327 
328 	p = dat;
329 
330 	switch (attr->bgpa_type) {
331 	case BGPTYPE_ORIGIN:
332 		if (len != 1)
333 			printf(" invalid len");
334 		else {
335 			TCHECK(p[0]);
336 			printf(" %s", bgp_attr_origin(p[0]));
337 		}
338 		break;
339 	case BGPTYPE_AS_PATH:
340 		if (len % 2) {
341 			printf(" invalid len");
342 			break;
343 		}
344 		if (!len) {
345 			printf(" empty");
346 			break;
347 		}
348 		while (p < dat + len) {
349 			/*
350 			 * under RFC1965, p[0] means:
351 			 * 1: AS_SET 2: AS_SEQUENCE
352 			 * 3: AS_CONFED_SET 4: AS_CONFED_SEQUENCE
353 			 */
354 			printf(" ");
355 			TCHECK(p[1]);
356 			if (p[0] == 3 || p[0] == 4)
357 				printf("confed");
358 			printf("%s", (p[0] & 1) ? "{" : "");
359 			for (i = 0; i < p[1] * 2; i += 2) {
360 				TCHECK2(p[2 + i], 2); /* ASN is 2-bytes */
361 				printf("%s%u", i == 0 ? "" : " ",
362 					EXTRACT_16BITS(&p[2 + i]));
363 			}
364 			printf("%s", (p[0] & 1) ? "}" : "");
365 			/*
366 			 * 1 byte for attr type, 1 byte for path length,
367 			 * plus size of ASN (2-bytes for now) * no of ASN
368 			 *
369 			 */
370 			p += 2 + p[1] * 2;
371 		}
372 		break;
373 	case BGPTYPE_NEXT_HOP:
374 		if (len != 4)
375 			printf(" invalid len");
376 		else {
377 			TCHECK2(p[0], 4);
378 			printf(" %s", getname(p));
379 		}
380 		break;
381 	case BGPTYPE_MULTI_EXIT_DISC:
382 	case BGPTYPE_LOCAL_PREF:
383 		if (len != 4)
384 			printf(" invalid len");
385 		else {
386 			TCHECK2(p[0], 4);
387 			printf(" %u", EXTRACT_32BITS(p));
388 		}
389 		break;
390 	case BGPTYPE_ATOMIC_AGGREGATE:
391 		if (len != 0)
392 			printf(" invalid len");
393 		break;
394 	case BGPTYPE_AGGREGATOR:
395 		if (len != 6) {
396 			printf(" invalid len");
397 			break;
398 		}
399 		TCHECK2(p[0], 6);
400 		printf(" AS #%u, origin %s", EXTRACT_16BITS(p),
401 			getname(p + 2));
402 		break;
403 	case BGPTYPE_COMMUNITIES:
404 		if (len % 4) {
405 			printf(" invalid len");
406 			break;
407 		}
408 		for (i = 0; i < len; i += 4) {
409 			u_int32_t comm;
410 			TCHECK2(p[i], 4);
411 			comm = EXTRACT_32BITS(&p[i]);
412 			switch (comm) {
413 			case BGP_COMMUNITY_NO_EXPORT:
414 				printf(" NO_EXPORT");
415 				break;
416 			case BGP_COMMUNITY_NO_ADVERT:
417 				printf(" NO_ADVERTISE");
418 				break;
419 			case BGP_COMMUNITY_NO_EXPORT_SUBCONFED:
420 				printf(" NO_EXPORT_SUBCONFED");
421 				break;
422 			case BGP_COMMUNITY_NO_PEER:
423 				printf(" NO_PEER");
424 				break;
425 			default:
426 				printf(" %d:%d",
427 					(comm >> 16) & 0xffff, comm & 0xffff);
428 				break;
429 			}
430 		}
431 		break;
432 	case BGPTYPE_MP_REACH_NLRI:
433 		TCHECK2(p[0], BGP_MP_NLRI_MINSIZE);
434 		af = EXTRACT_16BITS(p);
435 		safi = p[2];
436 		if (safi >= 128)
437 			printf(" %s vendor specific,", af_name(af));
438 		else {
439 			printf(" %s %s,", af_name(af),
440 				bgp_attr_nlri_safi(safi));
441 		}
442 		p += 3;
443 
444 		if (af == AFNUM_INET)
445 			;
446 #ifdef INET6
447 		else if (af == AFNUM_INET6)
448 			;
449 #endif
450 		else
451 			break;
452 
453 		TCHECK(p[0]);
454 		tlen = p[0];
455 		if (tlen) {
456 			printf(" nexthop");
457 			i = 0;
458 			while (i < tlen) {
459 				switch (af) {
460 				case AFNUM_INET:
461 					TCHECK2(p[1+i], sizeof(struct in_addr));
462 					printf(" %s", getname(p + 1 + i));
463 					i += sizeof(struct in_addr);
464 					break;
465 #ifdef INET6
466 				case AFNUM_INET6:
467 					TCHECK2(p[1+i], sizeof(struct in6_addr));
468 					printf(" %s", getname6(p + 1 + i));
469 					i += sizeof(struct in6_addr);
470 					break;
471 #endif
472 				default:
473 					printf(" (unknown af)");
474 					i = tlen;	/*exit loop*/
475 					break;
476 				}
477 			}
478 			printf(",");
479 		}
480 		p += 1 + tlen;
481 
482 		TCHECK(p[0]);
483 		snpa = p[0];
484 		p++;
485 		if (snpa) {
486 			printf(" %u snpa", snpa);
487 			for (/*nothing*/; snpa > 0; snpa--) {
488 				TCHECK(p[0]);
489 				printf("(%d bytes)", p[0]);
490 				p += p[0] + 1;
491 			}
492 			printf(",");
493 		}
494 
495 		printf(" NLRI");
496 		while (len - (p - dat) > 0) {
497 			switch (af) {
498 			case AFNUM_INET:
499 				advance = decode_prefix4(p, buf, sizeof(buf));
500 				break;
501 #ifdef INET6
502 			case AFNUM_INET6:
503 				advance = decode_prefix6(p, buf, sizeof(buf));
504 				break;
505 #endif
506 			default:
507 				printf(" (unknown af)");
508 				advance = 0;
509 				p = dat + len;
510 				break;
511 			}
512 
513 			if (advance <= 0)
514 				break;
515 
516 			printf(" %s", buf);
517 			p += advance;
518 		}
519 
520 		break;
521 
522 	case BGPTYPE_MP_UNREACH_NLRI:
523 		TCHECK2(p[0], BGP_MP_NLRI_MINSIZE);
524 		af = EXTRACT_16BITS(p);
525 		safi = p[2];
526 		if (safi >= 128)
527 			printf(" %s vendor specific,", af_name(af));
528 		else {
529 			printf(" %s %s,", af_name(af),
530 				bgp_attr_nlri_safi(safi));
531 		}
532 		p += 3;
533 
534 		printf(" Withdraw");
535 		while (len - (p - dat) > 0) {
536 			switch (af) {
537 			case AFNUM_INET:
538 				advance = decode_prefix4(p, buf, sizeof(buf));
539 				break;
540 #ifdef INET6
541 			case AFNUM_INET6:
542 				advance = decode_prefix6(p, buf, sizeof(buf));
543 				break;
544 #endif
545 			default:
546 				printf(" (unknown af)");
547 				advance = 0;
548 				p = dat + len;
549 				break;
550 			}
551 
552 			if (advance <= 0)
553 				break;
554 
555 			printf(" %s", buf);
556 			p += advance;
557 		}
558 		break;
559 	default:
560 		break;
561 	}
562 	return 1;
563 
564 trunc:
565 	return 0;
566 }
567 
568 static void
569 bgp_open_print(const u_char *dat, int length)
570 {
571 	struct bgp_open bgpo;
572 	struct bgp_opt bgpopt;
573 	const u_char *opt;
574 	int i;
575 
576 	TCHECK2(dat[0], BGP_OPEN_SIZE);
577 	memcpy(&bgpo, dat, BGP_OPEN_SIZE);
578 
579 	printf(": Version %d,", bgpo.bgpo_version);
580 	printf(" AS #%u,", ntohs(bgpo.bgpo_myas));
581 	printf(" Holdtime %u,", ntohs(bgpo.bgpo_holdtime));
582 	printf(" ID %s,", getname((u_char *)&bgpo.bgpo_id));
583 	printf(" Option length %u", bgpo.bgpo_optlen);
584 
585 	/* ugly! */
586 	opt = &((const struct bgp_open *)dat)->bgpo_optlen;
587 	opt++;
588 
589 	i = 0;
590 	while (i < bgpo.bgpo_optlen) {
591 		TCHECK2(opt[i], BGP_OPT_SIZE);
592 		memcpy(&bgpopt, &opt[i], BGP_OPT_SIZE);
593 		if (i + 2 + bgpopt.bgpopt_len > bgpo.bgpo_optlen) {
594 			printf(" [|opt %d %d]", bgpopt.bgpopt_len, bgpopt.bgpopt_type);
595 			break;
596 		}
597 
598 		printf(" (option %s, len=%d)", bgp_opttype(bgpopt.bgpopt_type),
599 			bgpopt.bgpopt_len);
600 		i += BGP_OPT_SIZE + bgpopt.bgpopt_len;
601 	}
602 	return;
603 trunc:
604 	printf("[|BGP]");
605 }
606 
607 static void
608 bgp_update_print(const u_char *dat, int length)
609 {
610 	struct bgp bgp;
611 	struct bgp_attr bgpa;
612 	const u_char *p;
613 	int len;
614 	int i;
615 	int newline;
616 
617 	TCHECK2(dat[0], BGP_SIZE);
618 	memcpy(&bgp, dat, BGP_SIZE);
619 	p = dat + BGP_SIZE;	/*XXX*/
620 	printf(":");
621 
622 	/* Unfeasible routes */
623 	len = EXTRACT_16BITS(p);
624 	if (len) {
625 		/*
626 		 * Without keeping state from the original NLRI message,
627 		 * it's not possible to tell if this a v4 or v6 route,
628 		 * so only try to decode it if we're not v6 enabled.
629 	         */
630 #ifdef INET6
631 		printf(" (Withdrawn routes: %d bytes)", len);
632 #else
633 		char buf[MAXHOSTNAMELEN + 100];
634 		int wpfx;
635 
636 		TCHECK2(p[2], len);
637  		i = 2;
638 
639 		printf(" (Withdrawn routes:");
640 
641 		while(i < 2 + len) {
642 			wpfx = decode_prefix4(&p[i], buf, sizeof(buf));
643 			if (wpfx == -2)
644 				goto trunc;
645 			else if (wpfx < 0) {
646 				printf(" (illegal prefix length)");
647 				break;
648 			}
649 			i += wpfx;
650 			printf(" %s", buf);
651 		}
652 		printf(")");
653 #endif
654 	}
655 	p += 2 + len;
656 
657 	TCHECK2(p[0], 2);
658 	len = EXTRACT_16BITS(p);
659 
660 	if (len) {
661 		/* do something more useful!*/
662 		i = 2;
663 		printf(" (Path attributes:");	/* ) */
664 		newline = 0;
665 		while (i < 2 + len) {
666 			int alen, aoff;
667 
668 			TCHECK2(p[i], sizeof(bgpa));
669 			memcpy(&bgpa, &p[i], sizeof(bgpa));
670 			alen = bgp_attr_len(&bgpa);
671 			aoff = bgp_attr_off(&bgpa);
672 
673 			if (vflag && newline)
674 				printf("\n\t\t");
675 			else
676 				printf(" ");
677 			printf("(");		/* ) */
678 			printf("%s", bgp_attr_type(bgpa.bgpa_type));
679 			if (bgpa.bgpa_flags) {
680 				printf("[%s%s%s%s",
681 					bgpa.bgpa_flags & 0x80 ? "O" : "",
682 					bgpa.bgpa_flags & 0x40 ? "T" : "",
683 					bgpa.bgpa_flags & 0x20 ? "P" : "",
684 					bgpa.bgpa_flags & 0x10 ? "E" : "");
685 				if (bgpa.bgpa_flags & 0xf)
686 					printf("+%x", bgpa.bgpa_flags & 0xf);
687 				printf("]");
688 			}
689 
690 			if (!bgp_attr_print(&bgpa, &p[i + aoff], alen))
691 				goto trunc;
692 			newline = 1;
693 
694 			/* ( */
695 			printf(")");
696 
697 			i += aoff + alen;
698 		}
699 
700 		/* ( */
701 		printf(")");
702 	}
703 	p += 2 + len;
704 
705 	if (len && dat + length > p)
706 		printf("\n\t\t");
707 	if (dat + length > p) {
708 		printf("(NLRI:");	/* ) */
709 		while (dat + length > p) {
710 			char buf[MAXHOSTNAMELEN + 100];
711 			i = decode_prefix4(p, buf, sizeof(buf));
712 			if (i == -2)
713 				goto trunc;
714 			else if (i < 0) {
715 				printf(" (illegal prefix length)");
716 				break;
717 			}
718 			printf(" %s", buf);
719 			p += i;
720 		}
721 
722 		/* ( */
723 		printf(")");
724 	}
725 	return;
726 trunc:
727 	printf("[|BGP]");
728 }
729 
730 static void
731 bgp_notification_print(const u_char *dat, int length)
732 {
733 	struct bgp_notification bgpn;
734 
735 	TCHECK2(dat[0], BGP_NOTIFICATION_SIZE);
736 	memcpy(&bgpn, dat, BGP_NOTIFICATION_SIZE);
737 
738 	printf(": error %s,", bgp_notify_major(bgpn.bgpn_major));
739 	printf(" subcode %s",
740 		bgp_notify_minor(bgpn.bgpn_major, bgpn.bgpn_minor));
741 	return;
742 trunc:
743 	printf("[|BGP]");
744 }
745 
746 static int
747 bgp_header_print(const u_char *dat, int length)
748 {
749 	struct bgp bgp;
750 
751 	TCHECK2(dat[0], BGP_SIZE);
752 	memcpy(&bgp, dat, BGP_SIZE);
753 	printf("(%s", bgp_type(bgp.bgp_type));		/* ) */
754 
755 	switch (bgp.bgp_type) {
756 	case BGP_OPEN:
757 		bgp_open_print(dat, length);
758 		break;
759 	case BGP_UPDATE:
760 		bgp_update_print(dat, length);
761 		break;
762 	case BGP_NOTIFICATION:
763 		bgp_notification_print(dat, length);
764 		break;
765 	}
766 
767 	/* ( */
768 	printf(")");
769 	return 1;
770 trunc:
771 	printf("[|BGP]");
772 	return 0;
773 }
774 
775 void
776 bgp_print(const u_char *dat, int length)
777 {
778 	const u_char *p;
779 	const u_char *ep;
780 	const u_char *start;
781 	const u_char marker[] = {
782 		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
783 		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
784 	};
785 	struct bgp bgp;
786 	u_int16_t hlen;
787 	int newline;
788 
789 	ep = dat + length;
790 	if (snapend < dat + length)
791 		ep = snapend;
792 
793 	printf(": BGP");
794 
795 	p = dat;
796 	newline = 0;
797 	start = p;
798 	while (p < ep) {
799 		if (!TTEST2(p[0], 1))
800 			break;
801 		if (p[0] != 0xff) {
802 			p++;
803 			continue;
804 		}
805 
806 		if (!TTEST2(p[0], sizeof(marker)))
807 			break;
808 		if (memcmp(p, marker, sizeof(marker)) != 0) {
809 			p++;
810 			continue;
811 		}
812 
813 		/* found BGP header */
814 		TCHECK2(p[0], BGP_SIZE);	/*XXX*/
815 		memcpy(&bgp, p, BGP_SIZE);
816 
817 		if (start != p)
818 			printf(" [|BGP]");
819 
820 		hlen = ntohs(bgp.bgp_len);
821 		if (vflag && newline)
822 			printf("\n\t");
823 		else
824 			printf(" ");
825 		if (TTEST2(p[0], hlen)) {
826 			if (!bgp_header_print(p, hlen))
827 				return;
828 			newline = 1;
829 			p += hlen;
830 			start = p;
831 		} else {
832 			printf("[|BGP %s]", bgp_type(bgp.bgp_type));
833 			break;
834 		}
835 	}
836 
837 	return;
838 
839 trunc:
840 	printf(" [|BGP]");
841 }
842