2 * Routines for BGP packet dissection.
3 * Copyright 1999, Jun-ichiro itojun Hagino <itojun@itojun.org>
8 * RFC1771 A Border Gateway Protocol 4 (BGP-4)
9 * RFC1997 BGP Communities Attribute
10 * RFC2283 Multiprotocol Extensions for BGP-4
13 * RFC1966 BGP Route Reflection An alternative to full mesh IBGP
14 * RFC1863 A BGP/IDRP Route Server alternative to a full mesh routing
15 * RFC1965 Autonomous System Confederations for BGP
16 * Destination Preference Attribute for BGP (work in progress)
18 * Ethereal - Network traffic analyzer
19 * By Gerald Combs <gerald@zing.org>
20 * Copyright 1998 Gerald Combs
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * as published by the Free Software Foundation; either version 2
25 * of the License, or (at your option) any later version.
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
44 #ifdef HAVE_SYS_TYPES_H
45 # include <sys/types.h>
48 #ifdef HAVE_NETINET_IN_H
49 # include <netinet/in.h>
52 #ifdef NEED_SNPRINTF_H
58 # include "snprintf.h"
64 #include "packet-bgp.h"
65 #include "packet-ipv6.h"
67 #ifdef HAVE_ARPA_INET_H
68 #include <arpa/inet.h>
71 static const value_string bgptypevals[] = {
72 { BGP_OPEN, "OPEN Message" },
73 { BGP_UPDATE, "UPDATE Message" },
74 { BGP_NOTIFICATION, "NOTIFICATION Message" },
75 { BGP_KEEPALIVE, "KEEPALIVE Message" },
79 static const value_string bgpnotify_major[] = {
80 { 1, "Message Header Error" },
81 { 2, "OPEN Message Error" },
82 { 3, "UPDATE Message Error" },
83 { 4, "Hold Timer Expired" },
84 { 5, "Finite State Machine Error" },
89 static const value_string bgpnotify_minor_1[] = {
90 { 1, "Connection Not Synchronized" },
91 { 2, "Bad Message Length" },
92 { 3, "Bad Message Type" },
96 static const value_string bgpnotify_minor_2[] = {
97 { 1, "Unsupported Version Number" },
99 { 3, "Bad BGP Identifier" },
100 { 4, "Unsupported Optional Parameter" },
101 { 5, "Authentication Failure" },
102 { 6, "Unacceptable Hold Time" },
106 static const value_string bgpnotify_minor_3[] = {
107 { 1, "Malformed Attribute List" },
108 { 2, "Unrecognized Well-known Attribute" },
109 { 3, "Missing Well-known Attribute" },
110 { 4, "Attribute Flags Error" },
111 { 5, "Attribute Length Error" },
112 { 6, "Invalid ORIGIN Attribute" },
113 { 7, "AS Routing Loop" },
114 { 8, "Invalid NEXT_HOP Attribute" },
115 { 9, "Optional Attribute Error" },
116 { 10, "Invalid Network Field" },
117 { 11, "Malformed AS_PATH" },
121 static const value_string *bgpnotify_minor[] = {
122 NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
125 static const value_string bgpattr_origin[] = {
132 static const value_string as_segment_type[] = {
134 { 2, "AS_SEQUENCE" },
135 { 3, "AS_CONFED_SET" },
136 { 4, "AS_CONFED_SEQUENCE" },
140 static const value_string bgpattr_type[] = {
141 { BGPTYPE_ORIGIN, "ORIGIN" },
142 { BGPTYPE_AS_PATH, "AS_PATH" },
143 { BGPTYPE_NEXT_HOP, "NEXT_HOP" },
144 { BGPTYPE_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
145 { BGPTYPE_LOCAL_PREF, "LOCAL_PREF" },
146 { BGPTYPE_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
147 { BGPTYPE_AGGREGATOR, "AGGREGATOR" },
148 { BGPTYPE_COMMUNITIES, "COMMUNITIES" },
149 { BGPTYPE_ORIGINATOR_ID, "ORIGINATOR_ID" },
150 { BGPTYPE_CLUSTER_LIST, "CLUSTER_LIST" },
151 { BGPTYPE_MP_REACH_NLRI, "MP_REACH_NLRI" },
152 { BGPTYPE_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
156 /* Subsequent address family identifier, RFC2283 section 7 */
157 static const value_string bgpattr_nlri_safi[] = {
161 { 3, "Unicast+Multicast" },
165 static const value_string afnumber[] = {
167 { AFNUM_INET, "IPv4" },
168 { AFNUM_INET6, "IPv6" },
169 { AFNUM_NSAP, "NSAP" },
170 { AFNUM_HDLC, "HDLC" },
171 { AFNUM_BBN1822, "BBN 1822" },
172 { AFNUM_802, "802" },
173 { AFNUM_E163, "E.163" },
174 { AFNUM_E164, "E.164" },
175 { AFNUM_F69, "F.69" },
176 { AFNUM_X121, "X.121" },
177 { AFNUM_IPX, "IPX" },
178 { AFNUM_ATALK, "Appletalk" },
179 { AFNUM_DECNET, "Decnet IV" },
180 { AFNUM_BANYAN, "Banyan Vines" },
181 { AFNUM_E164NSAP, "E.164 with NSAP subaddress" },
182 { 65535, "Reserved" },
186 static int proto_bgp = -1;
188 static gint ett_bgp = -1;
189 static gint ett_bgp_unfeas = -1;
190 static gint ett_bgp_attrs = -1;
191 static gint ett_bgp_attr = -1;
192 static gint ett_bgp_attr_flags = -1;
193 static gint ett_bgp_mp_reach_nlri = -1;
194 static gint ett_bgp_mp_unreach_nlri = -1;
195 static gint ett_bgp_nlri = -1;
196 static gint ett_bgp_open = -1;
197 static gint ett_bgp_update = -1;
198 static gint ett_bgp_notification = -1;
199 static gint ett_bgp_as_paths = -1;
200 static gint ett_bgp_communities = -1;
203 * Decode an IPv4 prefix.
206 decode_prefix4(const u_char *pd, char *buf, int buflen)
208 guint8 addr[4]; /* IP address */
209 int plen; /* prefix length */
210 int length; /* number of octets needed for prefix */
214 if (plen < 0 || 32 < plen)
216 length = (plen + 7) / 8;
219 memset(addr, 0, sizeof(addr));
220 memcpy(addr, &pd[1], length);
222 addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
224 /* hand back a formatted string */
225 snprintf(buf, buflen, "%s/%d", ip_to_str(addr), plen);
230 * Decode an IPv6 prefix.
233 decode_prefix6(const u_char *pd, char *buf, int buflen)
235 struct e_in6_addr addr; /* IPv6 address */
236 int plen; /* prefix length */
237 int length; /* number of octets needed for prefix */
241 if (plen < 0 || 128 < plen)
243 length = (plen + 7) / 8;
246 memset(&addr, 0, sizeof(addr));
247 memcpy(&addr, &pd[1], length);
249 addr.s6_addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
251 /* hand back a formatted string */
252 snprintf(buf, buflen, "%s/%d", ip6_to_str(&addr), plen);
257 * Dissect a BGP OPEN message.
260 dissect_bgp_open(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
262 struct bgp_open bgpo; /* BGP OPEN message */
263 int hlen; /* message length */
265 /* snarf OPEN message */
266 memcpy(&bgpo, &pd[offset], sizeof(bgpo));
267 hlen = ntohs(bgpo.bgpo_len);
269 proto_tree_add_text(tree,
270 offset + offsetof(struct bgp_open, bgpo_version), 1,
271 "Version: %u", bgpo.bgpo_version);
272 proto_tree_add_text(tree,
273 offset + offsetof(struct bgp_open, bgpo_myas), 2,
274 "My AS: %u", ntohs(bgpo.bgpo_myas));
275 proto_tree_add_text(tree,
276 offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
277 "Hold time: %u", ntohs(bgpo.bgpo_holdtime));
278 proto_tree_add_text(tree,
279 offset + offsetof(struct bgp_open, bgpo_id), 4,
280 "BGP identifier: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
281 proto_tree_add_text(tree,
282 offset + offsetof(struct bgp_open, bgpo_optlen), 1,
283 "Optional parameters length: %u %s", bgpo.bgpo_optlen,
284 (bgpo.bgpo_optlen == 1) ? "byte" : "bytes");
286 if (hlen > sizeof(struct bgp_open)) {
288 openoff = ((char *)&bgpo.bgpo_optlen - (char *)&bgpo) + 1;
289 proto_tree_add_text(tree,
290 offset + openoff, hlen - openoff,
291 "Optional parameters");
296 * Dissect a BGP UPDATE message.
299 dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
302 struct bgp bgp; /* BGP header */
303 struct bgp_attr bgpa; /* path attributes */
304 int hlen; /* message length */
305 const u_char *p; /* packet offset pointer */
306 const u_char *q; /* tmp */
307 const u_char *end; /* message end */
309 proto_item *ti; /* tree item */
310 proto_tree *subtree; /* subtree for attibutes */
311 proto_tree *subtree2; /* subtree for attibutes */
312 proto_tree *subtree3; /* subtree for attibutes */
313 proto_tree *as_paths_tree; /* subtree for AS_PATHs */
314 proto_tree *as_path_tree; /* subtree for AS_PATH */
315 proto_tree *communities_tree; /* subtree for COMMUNITIES */
316 proto_tree *community_tree; /* subtree for a community */
318 guint8 length; /* AS_PATH length */
319 guint8 type; /* AS_PATH type */
320 char *as_path_str = NULL; /* AS_PATH string */
321 char *communities_str = NULL; /* COMMUNITIES string */
322 char junk_buf[256]; /* tmp */
325 /* snarf UPDATE message */
326 memcpy(&bgp, &pd[offset], sizeof(bgp));
327 hlen = ntohs(bgp.bgp_len);
328 p = &pd[offset + BGP_HEADER_SIZE]; /*XXX*/
330 /* check for withdrawals */
332 proto_tree_add_text(tree, p - pd, 2,
333 "Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
336 /* parse unfeasible prefixes */
338 ti = proto_tree_add_text(tree, p - pd, len, "Withdrawn routes:");
339 subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
341 /* parse each prefixes */
344 i = decode_prefix4(p, junk_buf, sizeof(junk_buf));
345 proto_tree_add_text(subtree, p - pd, i, "%s", junk_buf);
353 /* check for advertisements */
355 proto_tree_add_text(tree, p - pd, 2, "Total path attribute length: %u %s",
356 len, (len == 1) ? "byte" : "bytes");
358 /* path attributes */
361 ti = proto_tree_add_text(tree, p - pd + 2, len, "Path attributes");
362 subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
370 memcpy(&bgpa, &p[i], sizeof(bgpa));
371 /* check for the Extended Length bit */
372 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
373 alen = pntohs(&p[i + sizeof(bgpa)]);
374 aoff = sizeof(bgpa) + 2;
376 alen = p[i + sizeof(bgpa)];
377 aoff = sizeof(bgpa) + 1;
380 /* This is kind of ugly - similar code appears twice, but it
381 helps browsing attrs. */
382 /* the first switch prints things in the title of the subtree */
383 switch (bgpa.bgpa_type) {
386 goto default_attribute_top;
387 msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
388 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
390 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
391 msg, alen + aoff, (alen + aoff == 1) ? "byte" :
394 case BGPTYPE_AS_PATH:
396 (p + current attribute + 3 bytes to first tuple) */
397 end = p + alen + i + 3;
399 /* must be freed by second switch! */
400 /* "alen * 6" (5 digits + space) should be a good estimate
401 of how long the AS path string could be */
402 as_path_str = malloc((alen + 1) * 6);
403 if (as_path_str == NULL) break;
404 as_path_str[0] = '\0';
406 /* snarf each AS path */
409 if (type == AS_SET) {
410 snprintf(as_path_str, 2, "{");
414 /* ignore confederation types until we support them */
415 if (type == AS_CONFED_SET || type == AS_CONFED_SEQUENCE) {
420 /* snarf each value in path */
421 for (j = 0; j < length; j++) {
422 snprintf(junk_buf, sizeof(junk_buf), "%u%s", pntohs(q),
423 (type == AS_SET) ? ", " : " ");
424 strncat(as_path_str, junk_buf, sizeof(junk_buf));
428 /* cleanup end of string */
429 if (type == AS_SET) {
430 as_path_str[strlen(as_path_str) - 2] = '}';
433 as_path_str[strlen(as_path_str) - 1] = '\0';
437 /* check for empty AS_PATH */
439 strncpy(as_path_str, "empty", 6);
441 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
443 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
444 as_path_str, alen + aoff,
445 (alen + aoff == 1) ? "byte" : "bytes");
447 case BGPTYPE_NEXT_HOP:
449 goto default_attribute_top;
450 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
452 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
453 ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
456 case BGPTYPE_MULTI_EXIT_DISC:
458 goto default_attribute_top;
459 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
461 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
462 pntohl(&p[i + aoff]), alen + aoff,
463 (alen + aoff == 1) ? "byte" : "bytes");
465 case BGPTYPE_LOCAL_PREF:
467 goto default_attribute_top;
468 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
470 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
471 pntohl(&p[i + aoff]), alen + aoff,
472 (alen + aoff == 1) ? "byte" : "bytes");
474 case BGPTYPE_ATOMIC_AGGREGATE:
476 goto default_attribute_top;
477 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
479 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
480 alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
482 case BGPTYPE_AGGREGATOR:
484 goto default_attribute_top;
485 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
486 "%s: AS: %u origin: %s (%u %s)",
487 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
488 pntohs(&p[i + aoff]),
489 ip_to_str(&p[i + aoff + 2]), alen + aoff,
490 (alen + aoff == 1) ? "byte" : "bytes");
492 case BGPTYPE_COMMUNITIES:
494 goto default_attribute_top;
497 (p + current attribute + 3 bytes to first tuple) */
498 end = p + alen + i + 3;
500 /* must be freed by second switch! */
501 /* "alen * 12" (5 digits, a :, 5 digits + space ) should be
502 a good estimate of how long the communities string could
504 communities_str = malloc((alen + 1) * 12);
505 if (communities_str == NULL) break;
506 communities_str[0] = '\0';
507 memset(junk_buf, 0, sizeof(junk_buf));
509 /* snarf each community */
511 /* check for well-known communities */
512 if (pntohl(q) == BGP_COMM_NO_EXPORT)
513 strncpy(junk_buf, "NO_EXPORT ", 10);
514 else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
515 strncpy(junk_buf, "NO_ADVERTISE ", 13);
516 else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
517 strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
519 snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
525 strncat(communities_str, junk_buf, sizeof(junk_buf));
527 /* cleanup end of string */
528 communities_str[strlen(communities_str) - 1] = '\0';
530 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
532 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
533 communities_str, alen + aoff,
534 (alen + aoff == 1) ? "byte" : "bytes");
536 case BGPTYPE_ORIGINATOR_ID:
538 goto default_attribute_top;
539 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
541 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
542 ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
545 case BGPTYPE_CLUSTER_LIST:
547 default_attribute_top:
548 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
550 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
551 alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
553 subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
555 /* figure out flags */
557 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
558 strncat(junk_buf, "Optional, ", 10);
561 strncat(junk_buf, "Well-known, ", 12);
563 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
564 strncat(junk_buf, "Transitive, ", 12);
567 strncat(junk_buf, "Non-transitive, ", 16);
569 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
570 strncat(junk_buf, "Partial, ", 9);
573 strncat(junk_buf, "Complete, ", 10);
575 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
576 strncat(junk_buf, "Extended Length, ", 17);
578 /* stomp last ", " */
579 j = strlen(junk_buf);
580 junk_buf[j - 2] = '\0';
581 ti = proto_tree_add_text(subtree2,
582 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
583 "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_buf);
584 subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
586 /* add flag bitfield subtrees */
587 proto_tree_add_text(subtree3,
588 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
589 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
590 BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
591 proto_tree_add_text(subtree3,
592 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
593 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
594 BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive",
596 proto_tree_add_text(subtree3,
597 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
598 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
599 BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
600 proto_tree_add_text(subtree3,
601 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
602 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
603 BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length",
606 proto_tree_add_text(subtree2,
607 p - pd + i + offsetof(struct bgp_attr, bgpa_type), 1,
608 "Type code: %s (%u)",
609 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
612 proto_tree_add_text(subtree2, p - pd + i + sizeof(bgpa),
613 aoff - sizeof(bgpa), "Length: %d %s", alen,
614 (alen == 1) ? "byte" : "bytes");
616 /* the second switch prints things in the actual subtree of each
618 switch (bgpa.bgpa_type) {
621 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
622 "Origin (invalid): %u %s", alen,
623 (alen == 1) ? "byte" : "bytes");
625 msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
626 proto_tree_add_text(subtree2, p - pd + i + aoff, 1,
627 "Origin: %s (%u)", msg, p[i + aoff]);
630 case BGPTYPE_AS_PATH:
631 /* check for empty AS_PATH */
637 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
638 "AS path: %s", as_path_str);
639 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
642 (p + current attribute + 3 bytes to first tuple) */
643 end = p + alen + i + 3;
646 /* snarf each AS path tuple */
648 as_path_str[0] = '\0';
650 if (type == AS_SET) {
651 snprintf(as_path_str, 2, "{");
655 /* ignore confederation types until we support them */
656 if (type == AS_CONFED_SET || type == AS_CONFED_SEQUENCE) {
661 /* snarf each value in path, we're just going to reuse
662 as_path_str since we already have it malloced */
663 for (j = 0; j < length; j++) {
664 snprintf(junk_buf, sizeof(junk_buf), "%u%s", pntohs(q),
665 (type == AS_SET) ? ", " : " ");
666 strncat(as_path_str, junk_buf, sizeof(junk_buf));
670 /* cleanup end of string */
671 if (type == AS_SET) {
672 as_path_str[strlen(as_path_str) - 2] = '}';
675 as_path_str[strlen(as_path_str) - 1] = '\0';
678 /* length here means number of ASs, ie length * 2 bytes */
679 ti = proto_tree_add_text(as_paths_tree,
680 q - pd - length * 2 - 2,
681 length * 2 + 2, "AS path segment: %s", as_path_str);
682 as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
683 proto_tree_add_text(as_path_tree, q - pd - length * 2 - 2,
684 1, "Path segment type: %s (%u)",
685 val_to_str(type, as_segment_type, "Unknown"), type);
686 proto_tree_add_text(as_path_tree, q - pd - length * 2 - 1,
687 1, "Path segment length: %u %s", length,
688 (length == 1) ? "AS" : "ASs");
689 proto_tree_add_text(as_path_tree, q - pd - length * 2,
690 length * 2, "Path segment value: %s", as_path_str);
695 case BGPTYPE_NEXT_HOP:
697 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
698 "Next hop (invalid): %u %s", alen,
699 (alen == 1) ? "byte" : "bytes");
701 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
702 "Next hop: %s", ip_to_str(&p[i + aoff]));
705 case BGPTYPE_MULTI_EXIT_DISC:
707 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
708 "Multi exit discriminator (invalid): %u %s",
709 alen, (alen == 1) ? "byte" : "bytes");
711 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
712 "Multi exit discriminator: %u",
713 pntohl(&p[i + aoff]));
716 case BGPTYPE_LOCAL_PREF:
718 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
719 "Local preference (invalid): %u %s", alen,
720 (alen == 1) ? "byte" : "bytes");
722 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
723 "Local preference: %u",
724 pntohl(&p[i + aoff]));
727 case BGPTYPE_ATOMIC_AGGREGATE:
729 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
730 "Atomic aggregate (invalid): %u %s", alen,
731 (alen == 1) ? "byte" : "bytes");
734 case BGPTYPE_AGGREGATOR:
736 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
737 "Aggregator (invalid): %u %s", alen,
738 (alen == 1) ? "byte" : "bytes");
740 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
742 pntohs(&p[i + aoff]));
743 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 4,
744 "Aggregator origin: %s",
745 ip_to_str(&p[i + aoff + 2]));
748 case BGPTYPE_COMMUNITIES:
750 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
751 "Communities (invalid): %u %s", alen,
752 (alen == 1) ? "byte" : "bytes");
755 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
756 "Communities: %s", communities_str);
757 communities_tree = proto_item_add_subtree(ti,
758 ett_bgp_communities);
761 (p + current attribute + 3 bytes to first tuple) */
762 end = p + alen + i + 3;
765 /* snarf each community */
767 /* check for reserved values */
768 if (pntohs(q) == FOURHEX0 || pntohs(q) == FOURHEXF) {
769 /* check for well-known communities */
770 if (pntohl(q) == BGP_COMM_NO_EXPORT)
771 proto_tree_add_text(communities_tree,
772 q - pd - 3 + aoff, 4,
773 "Community: NO_EXPORT (0x%x)", pntohl(q));
774 else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
775 proto_tree_add_text(communities_tree,
776 q - pd - 3 + aoff, 4,
777 "Community: NO_ADVERTISE (0x%x)", pntohl(q));
778 else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
779 proto_tree_add_text(communities_tree,
780 q - pd - 3 + aoff, 4,
781 "Community: NO_EXPORT_SUBCONFED (0x%x)",
784 proto_tree_add_text(communities_tree,
785 q - pd - 3 + aoff, 4,
786 "Community (reserved): 0x%x", pntohl(q));
790 ti = proto_tree_add_text(communities_tree,
791 q - pd - 3 + aoff, 4, "Community: %u:%u",
792 pntohs(q), pntohs(q + 2));
793 community_tree = proto_item_add_subtree(ti,
794 ett_bgp_communities);
795 proto_tree_add_text(community_tree, q - pd - 3 + aoff,
796 2, "Community AS: %u", pntohs(q));
797 proto_tree_add_text(community_tree, q - pd - 1 + aoff,
798 2, "Community value: %u", pntohs(q + 2));
804 free(communities_str);
806 case BGPTYPE_ORIGINATOR_ID:
808 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
809 "Originator identifier (invalid): %u %s", alen,
810 (alen == 1) ? "byte" : "bytes");
812 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
813 "Originator identifier: %s",
814 ip_to_str(&p[i + aoff]));
817 case BGPTYPE_MP_REACH_NLRI:
818 af = pntohs(&p[i + aoff]);
819 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
820 "Address family: %s (%u)",
821 val_to_str(af, afnumber, "Unknown"), af);
822 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 1,
823 "Subsequent address family identifier: %s (%u)",
824 val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
825 p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
827 ti = proto_tree_add_text(subtree2, p - pd + i + aoff + 3, 1,
828 "Next hop network address (%d %s)",
829 p[i + aoff + 3], (p[i + aoff + 3] == 1) ? "byte" :
831 if (af == AFNUM_INET || af == AFNUM_INET6) {
835 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_reach_nlri);
838 while (j < p[i + aoff + 3]) {
839 if (af == AFNUM_INET)
841 else if (af == AFNUM_INET6)
845 if (j + advance > p[i + aoff + 3])
848 if (af == AFNUM_INET)
849 s = ip_to_str(&p[i + aoff + 4 + j]);
851 s = ip6_to_str((struct e_in6_addr *)
852 &p[i + aoff + 4 + j]);
854 proto_tree_add_text(subtree3,
855 p - pd + i + aoff + 4 + j, advance,
861 alen -= (p[i + aoff + 3] + 4);
862 aoff += (p[i + aoff + 3] + 4);
865 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, 1,
866 "Subnetwork points of attachment: %u", snpa);
869 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_reach_nlri);
870 for (/*nothing*/; snpa > 0; snpa--) {
871 proto_tree_add_text(subtree3, p - pd + i + aoff + off, 1,
872 "SNPA length: ", p[i + aoff + off]);
874 proto_tree_add_text(subtree3, p - pd + i + aoff + off,
875 p[i + aoff + off - 1],
876 "SNPA (%u %s)", p[i + aoff + off - 1],
877 (p[i + aoff + off - 1] == 1) ? "byte" : "bytes");
878 off += p[i + aoff + off - 1];
883 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
884 "Network layer reachability information (%u %s)",
885 alen, (alen == 1) ? "byte" : "bytes");
887 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_unreach_nlri);
892 if (af == AFNUM_INET) {
893 advance = decode_prefix4(&p[i + aoff], buf,
895 } else if (af == AFNUM_INET6) {
896 advance = decode_prefix6(&p[i + aoff], buf,
904 proto_tree_add_text(subtree3, p - pd + i + aoff, advance,
905 "Network layer reachability information: %s", buf);
912 case BGPTYPE_MP_UNREACH_NLRI:
913 af = pntohs(&p[i + aoff]);
914 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
915 "Address family: %s (%u)",
916 val_to_str(af, afnumber, "Unknown"), af);
917 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 1,
918 "Subsequent address family identifier: %s (%u)",
919 val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
920 p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
922 ti = proto_tree_add_text(subtree2, p - pd + i + aoff + 3,
923 alen - 3, "Withdrawn routes (%u %s)", alen - 3,
924 (alen - 3 == 1) ? "byte" : "bytes");
929 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_unreach_nlri);
934 if (af == AFNUM_INET) {
935 advance = decode_prefix4(&p[i + aoff], buf,
937 } else if (af == AFNUM_INET6) {
938 advance = decode_prefix6(&p[i + aoff], buf,
946 proto_tree_add_text(subtree3, p - pd + i + aoff, advance,
947 "Withdrawn route: %s", buf);
954 case BGPTYPE_CLUSTER_LIST:
956 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
957 "Unknown (%d %s)", alen, (alen == 1) ? "byte" :
968 len = hlen - (p - &pd[offset]);
972 ti = proto_tree_add_text(tree, p - pd, len,
973 "Network layer reachability information: %u %s", len,
974 (len == 1) ? "byte" : "bytes");
975 subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
978 i = decode_prefix4(p, junk_buf, sizeof(junk_buf));
979 proto_tree_add_text(subtree, p - pd, i, "%s", junk_buf);
987 * Dissect a BGP NOTIFICATION message.
990 dissect_bgp_notification(const u_char *pd, int offset, frame_data *fd,
993 struct bgp_notification bgpn; /* BGP NOTIFICATION message */
994 int hlen; /* message length */
995 char *p; /* string pointer */
998 memcpy(&bgpn, &pd[offset], sizeof(bgpn));
999 hlen = ntohs(bgpn.bgpn_len);
1001 /* print error code */
1002 proto_tree_add_text(tree,
1003 offset + offsetof(struct bgp_notification, bgpn_major), 1,
1004 "Error code: %s (%u)",
1005 val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
1008 /* print error subcode */
1009 if (bgpn.bgpn_major < array_length(bgpnotify_minor)
1010 && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
1011 p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
1013 } else if (bgpn.bgpn_minor == 0)
1017 proto_tree_add_text(tree,
1018 offset + offsetof(struct bgp_notification, bgpn_minor), 1,
1019 "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
1021 /* only print if there is optional data */
1022 if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
1023 proto_tree_add_text(tree, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
1024 hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
1029 * Dissect a BGP packet.
1032 dissect_bgp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1034 proto_item *ti; /* tree item */
1035 proto_tree *bgp_tree; /* BGP packet tree */
1036 proto_tree *bgp1_tree; /* BGP message tree */
1037 const u_char *p; /* packet offset pointer */
1039 int found; /* number of BGP messages in packet */
1040 static u_char marker[] = { /* BGP message marker */
1041 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1042 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1044 struct bgp bgp; /* BGP header */
1045 int hlen; /* BGP header length */
1046 char *typ; /* BGP message type */
1048 if (check_col(fd, COL_PROTOCOL))
1049 col_add_str(fd, COL_PROTOCOL, "BGP");
1055 /* run through the TCP packet looking for BGP headers */
1056 /* this is done twice, but this way each message type can be
1057 printed in the COL_INFO field */
1059 /* look for bgp header */
1064 CHECK_SIZE(i, sizeof(marker), l);
1065 if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
1070 memcpy(&bgp, &p[i], sizeof(bgp));
1072 hlen = ntohs(bgp.bgp_len);
1073 typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1075 if (check_col(fd, COL_INFO)) {
1077 col_add_fstr(fd, COL_INFO, "%s", typ);
1079 col_append_fstr(fd, COL_INFO, ", %s", typ);
1086 ti = proto_tree_add_text(tree, offset, END_OF_FRAME,
1087 "Border Gateway Protocol");
1088 bgp_tree = proto_item_add_subtree(ti, ett_bgp);
1093 /* now, run through the TCP packet again, this time dissect */
1094 /* each message that we find */
1096 /* look for bgp header */
1101 CHECK_SIZE(i, sizeof(marker), l);
1102 if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
1107 memcpy(&bgp, &p[i], sizeof(bgp));
1108 hlen = ntohs(bgp.bgp_len);
1109 typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1110 if (END_OF_FRAME < hlen) {
1111 ti = proto_tree_add_text(bgp_tree, offset + i, END_OF_FRAME,
1112 "%s (truncated)", typ);
1114 ti = proto_tree_add_text(bgp_tree, offset + i, hlen,
1117 /* add a different tree for each message type */
1118 switch (bgp.bgp_type) {
1120 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
1123 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
1125 case BGP_NOTIFICATION:
1126 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
1129 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1132 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1136 proto_tree_add_text(bgp1_tree, offset + i, BGP_MARKER_SIZE,
1139 if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
1140 proto_tree_add_text(bgp1_tree,
1141 offset + i + offsetof(struct bgp, bgp_len), 2,
1142 "Length (invalid): %u %s", hlen,
1143 (hlen == 1) ? "byte" : "bytes");
1145 proto_tree_add_text(bgp1_tree,
1146 offset + i + offsetof(struct bgp, bgp_len), 2,
1147 "Length: %u %s", hlen,
1148 (hlen == 1) ? "byte" : "bytes");
1151 proto_tree_add_text(bgp1_tree,
1152 offset + i + offsetof(struct bgp, bgp_type), 1,
1153 "Type: %s (%u)", typ, bgp.bgp_type);
1155 CHECK_SIZE(i, hlen, l);
1157 /* handle each message type */
1158 switch (bgp.bgp_type) {
1160 dissect_bgp_open(pd, offset + i, fd, bgp1_tree);
1163 dissect_bgp_update(pd, offset + i, fd, bgp1_tree);
1165 case BGP_NOTIFICATION:
1166 dissect_bgp_notification(pd, offset + i, fd, bgp1_tree);
1169 /* no data in KEEPALIVE messages */
1181 * Register ourselves.
1184 proto_register_bgp(void)
1186 static gint *ett[] = {
1191 &ett_bgp_attr_flags,
1192 &ett_bgp_mp_reach_nlri,
1193 &ett_bgp_mp_unreach_nlri,
1197 &ett_bgp_notification,
1199 &ett_bgp_communities,
1202 proto_bgp = proto_register_protocol("Border Gateway Protocol", "bgp");
1203 proto_register_subtree_array(ett, array_length(ett));