2 * Routines for BGP packet dissection.
3 * Copyright 1999, Jun-ichiro itojun Hagino <itojun@itojun.org>
5 * $Id: packet-bgp.c,v 1.27 2000/08/20 18:10:12 deniel Exp $
8 * RFC1771 A Border Gateway Protocol 4 (BGP-4)
9 * RFC1965 Autonomous System Confederations for BGP
10 * RFC1966 BGP Route Reflection An alternative to full mesh IBGP
11 * RFC1997 BGP Communities Attribute
12 * RFC2283 Multiprotocol Extensions for BGP-4
15 * Destination Preference Attribute for BGP (work in progress)
16 * RFC1863 A BGP/IDRP Route Server alternative to a full mesh routing
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 HAVE_ARPA_INET_H
53 #include <arpa/inet.h>
59 #ifdef NEED_SNPRINTF_H
60 # include "snprintf.h"
64 #include "packet-bgp.h"
65 #include "packet-ipv6.h"
67 #define TCP_PORT_BGP 179
69 static const value_string bgptypevals[] = {
70 { BGP_OPEN, "OPEN Message" },
71 { BGP_UPDATE, "UPDATE Message" },
72 { BGP_NOTIFICATION, "NOTIFICATION Message" },
73 { BGP_KEEPALIVE, "KEEPALIVE Message" },
77 static const value_string bgpnotify_major[] = {
78 { 1, "Message Header Error" },
79 { 2, "OPEN Message Error" },
80 { 3, "UPDATE Message Error" },
81 { 4, "Hold Timer Expired" },
82 { 5, "Finite State Machine Error" },
87 static const value_string bgpnotify_minor_1[] = {
88 { 1, "Connection Not Synchronized" },
89 { 2, "Bad Message Length" },
90 { 3, "Bad Message Type" },
94 static const value_string bgpnotify_minor_2[] = {
95 { 1, "Unsupported Version Number" },
97 { 3, "Bad BGP Identifier" },
98 { 4, "Unsupported Optional Parameter" },
99 { 5, "Authentication Failure" },
100 { 6, "Unacceptable Hold Time" },
104 static const value_string bgpnotify_minor_3[] = {
105 { 1, "Malformed Attribute List" },
106 { 2, "Unrecognized Well-known Attribute" },
107 { 3, "Missing Well-known Attribute" },
108 { 4, "Attribute Flags Error" },
109 { 5, "Attribute Length Error" },
110 { 6, "Invalid ORIGIN Attribute" },
111 { 7, "AS Routing Loop" },
112 { 8, "Invalid NEXT_HOP Attribute" },
113 { 9, "Optional Attribute Error" },
114 { 10, "Invalid Network Field" },
115 { 11, "Malformed AS_PATH" },
119 static const value_string *bgpnotify_minor[] = {
120 NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
123 static const value_string bgpattr_origin[] = {
130 static const value_string as_segment_type[] = {
132 { 2, "AS_SEQUENCE" },
133 /* This is wrong according to the RFC... in the Zebra code they say that
134 cisco reversed it. Packet traces seem to agree. */
135 { 4, "AS_CONFED_SET" },
136 { 3, "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;
187 static int hf_bgp_type = -1;
189 static gint ett_bgp = -1;
190 static gint ett_bgp_unfeas = -1;
191 static gint ett_bgp_attrs = -1;
192 static gint ett_bgp_attr = -1;
193 static gint ett_bgp_attr_flags = -1;
194 static gint ett_bgp_mp_reach_nlri = -1;
195 static gint ett_bgp_mp_unreach_nlri = -1;
196 static gint ett_bgp_nlri = -1;
197 static gint ett_bgp_open = -1;
198 static gint ett_bgp_update = -1;
199 static gint ett_bgp_notification = -1;
200 static gint ett_bgp_as_paths = -1;
201 static gint ett_bgp_communities = -1;
202 static gint ett_bgp_cluster_list = -1;
205 * Decode an IPv4 prefix.
208 decode_prefix4(const u_char *pd, char *buf, int buflen)
210 guint8 addr[4]; /* IP address */
211 int plen; /* prefix length */
212 int length; /* number of octets needed for prefix */
216 if (plen < 0 || 32 < plen)
218 length = (plen + 7) / 8;
221 memset(addr, 0, sizeof(addr));
222 memcpy(addr, &pd[1], length);
224 addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
226 /* hand back a formatted string */
227 snprintf(buf, buflen, "%s/%d", ip_to_str(addr), plen);
232 * Decode an IPv6 prefix.
235 decode_prefix6(const u_char *pd, char *buf, int buflen)
237 struct e_in6_addr addr; /* IPv6 address */
238 int plen; /* prefix length */
239 int length; /* number of octets needed for prefix */
243 if (plen < 0 || 128 < plen)
245 length = (plen + 7) / 8;
248 memset(&addr, 0, sizeof(addr));
249 memcpy(&addr, &pd[1], length);
251 addr.s6_addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
253 /* hand back a formatted string */
254 snprintf(buf, buflen, "%s/%d", ip6_to_str(&addr), plen);
259 * Dissect a BGP OPEN message.
262 dissect_bgp_open(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
264 struct bgp_open bgpo; /* BGP OPEN message */
265 int hlen; /* message length */
267 /* snarf OPEN message */
268 memcpy(&bgpo, &pd[offset], sizeof(bgpo));
269 hlen = ntohs(bgpo.bgpo_len);
271 proto_tree_add_text(tree, NullTVB,
272 offset + offsetof(struct bgp_open, bgpo_version), 1,
273 "Version: %u", bgpo.bgpo_version);
274 proto_tree_add_text(tree, NullTVB,
275 offset + offsetof(struct bgp_open, bgpo_myas), 2,
276 "My AS: %u", ntohs(bgpo.bgpo_myas));
277 proto_tree_add_text(tree, NullTVB,
278 offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
279 "Hold time: %u", ntohs(bgpo.bgpo_holdtime));
280 proto_tree_add_text(tree, NullTVB,
281 offset + offsetof(struct bgp_open, bgpo_id), 4,
282 "BGP identifier: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
283 proto_tree_add_text(tree, NullTVB,
284 offset + offsetof(struct bgp_open, bgpo_optlen), 1,
285 "Optional parameters length: %u %s", bgpo.bgpo_optlen,
286 (bgpo.bgpo_optlen == 1) ? "byte" : "bytes");
288 if (hlen > sizeof(struct bgp_open)) {
290 openoff = ((char *)&bgpo.bgpo_optlen - (char *)&bgpo) + 1;
291 proto_tree_add_text(tree, NullTVB,
292 offset + openoff, hlen - openoff,
293 "Optional parameters");
298 * Dissect a BGP UPDATE message.
301 dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
304 struct bgp bgp; /* BGP header */
305 struct bgp_attr bgpa; /* path attributes */
306 int hlen; /* message length */
307 const u_char *p; /* packet offset pointer */
308 const u_char *q; /* tmp */
309 const u_char *end; /* message end */
311 proto_item *ti; /* tree item */
312 proto_tree *subtree; /* subtree for attibutes */
313 proto_tree *subtree2; /* subtree for attibutes */
314 proto_tree *subtree3; /* subtree for attibutes */
315 proto_tree *as_paths_tree; /* subtree for AS_PATHs */
316 proto_tree *as_path_tree; /* subtree for AS_PATH */
317 proto_tree *communities_tree; /* subtree for COMMUNITIES */
318 proto_tree *community_tree; /* subtree for a community */
319 proto_tree *cluster_list_tree; /* subtree for CLUSTER_LIST */
321 guint8 length; /* AS_PATH length */
322 guint8 type; /* AS_PATH type */
323 char *as_path_str = NULL; /* AS_PATH string */
324 char *communities_str = NULL; /* COMMUNITIES string */
325 char *cluster_list_str = NULL; /* CLUSTER_LIST string */
326 char junk_buf[256]; /* tmp */
329 /* snarf UPDATE message */
330 memcpy(&bgp, &pd[offset], sizeof(bgp));
331 hlen = ntohs(bgp.bgp_len);
332 p = &pd[offset + BGP_HEADER_SIZE]; /*XXX*/
334 /* check for withdrawals */
336 proto_tree_add_text(tree, NullTVB, p - pd, 2,
337 "Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
340 /* parse unfeasible prefixes */
342 ti = proto_tree_add_text(tree, NullTVB, p - pd, len, "Withdrawn routes:");
343 subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
345 /* parse each prefixes */
348 i = decode_prefix4(p, junk_buf, sizeof(junk_buf));
349 proto_tree_add_text(subtree, NullTVB, p - pd, i, "%s", junk_buf);
357 /* check for advertisements */
359 proto_tree_add_text(tree, NullTVB, p - pd, 2, "Total path attribute length: %u %s",
360 len, (len == 1) ? "byte" : "bytes");
362 /* path attributes */
364 ti = proto_tree_add_text(tree, NullTVB, p - pd + 2, len, "Path attributes");
365 subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
373 memcpy(&bgpa, &p[i], sizeof(bgpa));
374 /* check for the Extended Length bit */
375 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
376 alen = pntohs(&p[i + sizeof(bgpa)]);
377 aoff = sizeof(bgpa) + 2;
379 alen = p[i + sizeof(bgpa)];
380 aoff = sizeof(bgpa) + 1;
383 /* This is kind of ugly - similar code appears twice, but it
384 helps browsing attrs. */
385 /* the first switch prints things in the title of the subtree */
386 switch (bgpa.bgpa_type) {
389 goto default_attribute_top;
390 msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
391 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
393 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
394 msg, alen + aoff, (alen + aoff == 1) ? "byte" :
397 case BGPTYPE_AS_PATH:
399 (p + current attribute + 3 bytes to first tuple) */
400 end = p + alen + i + 3;
402 /* must be freed by second switch! */
403 /* "alen * 6" (5 digits + space) should be a good estimate
404 of how long the AS path string could be */
405 as_path_str = malloc((alen + 1) * 6);
406 if (as_path_str == NULL) break;
407 as_path_str[0] = '\0';
409 /* snarf each AS path */
412 if (type == AS_SET) {
413 snprintf(as_path_str, 2, "{");
415 else if (type == AS_CONFED_SET) {
416 snprintf(as_path_str, 2, "[");
418 else if (type == AS_CONFED_SEQUENCE) {
419 snprintf(as_path_str, 2, "(");
423 /* snarf each value in path */
424 for (j = 0; j < length; j++) {
425 snprintf(junk_buf, sizeof(junk_buf), "%u%s", pntohs(q),
426 (type == AS_SET || type == AS_CONFED_SET)
428 strncat(as_path_str, junk_buf, sizeof(junk_buf));
432 /* cleanup end of string */
433 if (type == AS_SET) {
434 as_path_str[strlen(as_path_str) - 2] = '}';
436 else if (type == AS_CONFED_SET) {
437 as_path_str[strlen(as_path_str) - 2] = ']';
439 else if (type == AS_CONFED_SEQUENCE) {
440 as_path_str[strlen(as_path_str) - 1] = ')';
443 as_path_str[strlen(as_path_str) - 1] = '\0';
447 /* check for empty AS_PATH */
449 strncpy(as_path_str, "empty", 6);
451 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
453 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
454 as_path_str, alen + aoff,
455 (alen + aoff == 1) ? "byte" : "bytes");
457 case BGPTYPE_NEXT_HOP:
459 goto default_attribute_top;
460 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
462 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
463 ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
466 case BGPTYPE_MULTI_EXIT_DISC:
468 goto default_attribute_top;
469 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
471 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
472 pntohl(&p[i + aoff]), alen + aoff,
473 (alen + aoff == 1) ? "byte" : "bytes");
475 case BGPTYPE_LOCAL_PREF:
477 goto default_attribute_top;
478 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
480 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
481 pntohl(&p[i + aoff]), alen + aoff,
482 (alen + aoff == 1) ? "byte" : "bytes");
484 case BGPTYPE_ATOMIC_AGGREGATE:
486 goto default_attribute_top;
487 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
489 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
490 alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
492 case BGPTYPE_AGGREGATOR:
494 goto default_attribute_top;
495 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
496 "%s: AS: %u origin: %s (%u %s)",
497 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
498 pntohs(&p[i + aoff]),
499 ip_to_str(&p[i + aoff + 2]), alen + aoff,
500 (alen + aoff == 1) ? "byte" : "bytes");
502 case BGPTYPE_COMMUNITIES:
504 goto default_attribute_top;
507 (p + current attribute + 3 bytes to first tuple) */
508 end = p + alen + i + 3;
510 /* must be freed by second switch! */
511 /* "alen * 12" (5 digits, a :, 5 digits + space ) should be
512 a good estimate of how long the communities string could
514 communities_str = malloc((alen + 1) * 12);
515 if (communities_str == NULL) break;
516 communities_str[0] = '\0';
517 memset(junk_buf, 0, sizeof(junk_buf));
519 /* snarf each community */
521 /* check for well-known communities */
522 if (pntohl(q) == BGP_COMM_NO_EXPORT)
523 strncpy(junk_buf, "NO_EXPORT ", 10);
524 else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
525 strncpy(junk_buf, "NO_ADVERTISE ", 13);
526 else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
527 strncpy(junk_buf, "NO_EXPORT_SUBCONFED ", 20);
529 snprintf(junk_buf, sizeof(junk_buf), "%u:%u ",
535 strncat(communities_str, junk_buf, sizeof(junk_buf));
537 /* cleanup end of string */
538 communities_str[strlen(communities_str) - 1] = '\0';
540 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
542 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
543 communities_str, alen + aoff,
544 (alen + aoff == 1) ? "byte" : "bytes");
546 case BGPTYPE_ORIGINATOR_ID:
548 goto default_attribute_top;
549 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
551 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
552 ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
555 case BGPTYPE_CLUSTER_LIST:
557 goto default_attribute_top;
560 (p + current attribute + 3 bytes to first tuple) */
561 end = p + alen + i + 3;
563 /* must be freed by second switch! */
564 /* "alen * 16" (12 digits, 3 dots + space ) should be
565 a good estimate of how long the cluster_list string could
567 cluster_list_str = malloc((alen + 1) * 16);
568 if (cluster_list_str == NULL) break;
569 cluster_list_str[0] = '\0';
570 memset(junk_buf, 0, sizeof(junk_buf));
572 /* snarf each cluster list */
574 snprintf(junk_buf, sizeof(junk_buf), "%s ", ip_to_str(q));
575 strncat(cluster_list_str, junk_buf, sizeof(junk_buf));
578 /* cleanup end of string */
579 cluster_list_str[strlen(cluster_list_str) - 1] = '\0';
581 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
583 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
584 cluster_list_str, alen + aoff,
585 (alen + aoff == 1) ? "byte" : "bytes");
588 default_attribute_top:
589 ti = proto_tree_add_text(subtree, NullTVB, p - pd + i, alen + aoff,
591 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
592 alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
593 } /* end of first switch */
594 subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
596 /* figure out flags */
598 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
599 strncat(junk_buf, "Optional, ", 10);
602 strncat(junk_buf, "Well-known, ", 12);
604 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
605 strncat(junk_buf, "Transitive, ", 12);
608 strncat(junk_buf, "Non-transitive, ", 16);
610 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
611 strncat(junk_buf, "Partial, ", 9);
614 strncat(junk_buf, "Complete, ", 10);
616 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
617 strncat(junk_buf, "Extended Length, ", 17);
619 /* stomp last ", " */
620 j = strlen(junk_buf);
621 junk_buf[j - 2] = '\0';
622 ti = proto_tree_add_text(subtree2, NullTVB,
623 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
624 "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_buf);
625 subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
627 /* add flag bitfield subtrees */
628 proto_tree_add_text(subtree3, NullTVB,
629 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
630 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
631 BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
632 proto_tree_add_text(subtree3, NullTVB,
633 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
634 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
635 BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive",
637 proto_tree_add_text(subtree3, NullTVB,
638 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
639 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
640 BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
641 proto_tree_add_text(subtree3, NullTVB,
642 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
643 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
644 BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length",
647 proto_tree_add_text(subtree2, NullTVB,
648 p - pd + i + offsetof(struct bgp_attr, bgpa_type), 1,
649 "Type code: %s (%u)",
650 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
653 proto_tree_add_text(subtree2, NullTVB, p - pd + i + sizeof(bgpa),
654 aoff - sizeof(bgpa), "Length: %d %s", alen,
655 (alen == 1) ? "byte" : "bytes");
657 /* the second switch prints things in the actual subtree of each
659 switch (bgpa.bgpa_type) {
662 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
663 "Origin (invalid): %u %s", alen,
664 (alen == 1) ? "byte" : "bytes");
666 msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
667 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 1,
668 "Origin: %s (%u)", msg, p[i + aoff]);
671 case BGPTYPE_AS_PATH:
672 /* check for empty AS_PATH */
678 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
679 "AS path: %s", as_path_str);
680 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
683 (p + current attribute + 3 bytes to first tuple) */
684 end = p + alen + i + 3;
687 /* snarf each AS path tuple, we have to step through each one
688 again to make a separate subtree so we can't just reuse
689 as_path_str from above */
691 as_path_str[0] = '\0';
693 if (type == AS_SET) {
694 snprintf(as_path_str, 2, "{");
696 else if (type == AS_CONFED_SET) {
697 snprintf(as_path_str, 2, "[");
699 else if (type == AS_CONFED_SEQUENCE) {
700 snprintf(as_path_str, 2, "(");
704 /* snarf each value in path, we're just going to reuse
705 as_path_str since we already have it malloced */
706 for (j = 0; j < length; j++) {
707 snprintf(junk_buf, sizeof(junk_buf), "%u%s", pntohs(q),
708 (type == AS_SET || type == AS_CONFED_SET)
710 strncat(as_path_str, junk_buf, sizeof(junk_buf));
714 /* cleanup end of string */
715 if (type == AS_SET) {
716 as_path_str[strlen(as_path_str) - 2] = '}';
718 else if (type == AS_CONFED_SET) {
719 as_path_str[strlen(as_path_str) - 2] = ']';
721 else if (type == AS_CONFED_SEQUENCE) {
722 as_path_str[strlen(as_path_str) - 1] = ')';
725 as_path_str[strlen(as_path_str) - 1] = '\0';
728 /* length here means number of ASs, ie length * 2 bytes */
729 ti = proto_tree_add_text(as_paths_tree, NullTVB,
730 q - pd - length * 2 - 2,
731 length * 2 + 2, "AS path segment: %s", as_path_str);
732 as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
733 proto_tree_add_text(as_path_tree, NullTVB, q - pd - length * 2 - 2,
734 1, "Path segment type: %s (%u)",
735 val_to_str(type, as_segment_type, "Unknown"), type);
736 proto_tree_add_text(as_path_tree, NullTVB, q - pd - length * 2 - 1,
737 1, "Path segment length: %u %s", length,
738 (length == 1) ? "AS" : "ASs");
740 /* backup and reprint path segment value(s) only */
742 as_path_str[0] = '\0';
743 for (j = 0; j < length; j++) {
744 snprintf(junk_buf, sizeof(junk_buf), "%u ", pntohs(q));
745 strncat(as_path_str, junk_buf, sizeof(junk_buf));
748 as_path_str[strlen(as_path_str) - 1] = '\0';
750 proto_tree_add_text(as_path_tree, NullTVB, q - pd - length * 2,
751 length * 2, "Path segment value: %s", as_path_str);
756 case BGPTYPE_NEXT_HOP:
758 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
759 "Next hop (invalid): %u %s", alen,
760 (alen == 1) ? "byte" : "bytes");
762 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
763 "Next hop: %s", ip_to_str(&p[i + aoff]));
766 case BGPTYPE_MULTI_EXIT_DISC:
768 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
769 "Multiple exit discriminator (invalid): %u %s",
770 alen, (alen == 1) ? "byte" : "bytes");
772 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
773 "Multiple exit discriminator: %u",
774 pntohl(&p[i + aoff]));
777 case BGPTYPE_LOCAL_PREF:
779 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
780 "Local preference (invalid): %u %s", alen,
781 (alen == 1) ? "byte" : "bytes");
783 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
784 "Local preference: %u", pntohl(&p[i + aoff]));
787 case BGPTYPE_ATOMIC_AGGREGATE:
789 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
790 "Atomic aggregate (invalid): %u %s", alen,
791 (alen == 1) ? "byte" : "bytes");
794 case BGPTYPE_AGGREGATOR:
796 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
797 "Aggregator (invalid): %u %s", alen,
798 (alen == 1) ? "byte" : "bytes");
800 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 2,
801 "Aggregator AS: %u", pntohs(&p[i + aoff]));
802 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 2, 4,
803 "Aggregator origin: %s",
804 ip_to_str(&p[i + aoff + 2]));
807 case BGPTYPE_COMMUNITIES:
809 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
810 "Communities (invalid): %u %s", alen,
811 (alen == 1) ? "byte" : "bytes");
812 free(communities_str);
816 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
817 "Communities: %s", communities_str);
818 communities_tree = proto_item_add_subtree(ti,
819 ett_bgp_communities);
822 (p + current attribute + 3 bytes to first tuple) */
823 end = p + alen + i + 3;
826 /* snarf each community */
828 /* check for reserved values */
829 if (pntohs(q) == FOURHEX0 || pntohs(q) == FOURHEXF) {
830 /* check for well-known communities */
831 if (pntohl(q) == BGP_COMM_NO_EXPORT)
832 proto_tree_add_text(communities_tree, NullTVB,
833 q - pd - 3 + aoff, 4,
834 "Community: NO_EXPORT (0x%x)", pntohl(q));
835 else if (pntohl(q) == BGP_COMM_NO_ADVERTISE)
836 proto_tree_add_text(communities_tree, NullTVB,
837 q - pd - 3 + aoff, 4,
838 "Community: NO_ADVERTISE (0x%x)", pntohl(q));
839 else if (pntohl(q) == BGP_COMM_NO_EXPORT_SUBCONFED)
840 proto_tree_add_text(communities_tree, NullTVB,
841 q - pd - 3 + aoff, 4,
842 "Community: NO_EXPORT_SUBCONFED (0x%x)",
845 proto_tree_add_text(communities_tree, NullTVB,
846 q - pd - 3 + aoff, 4,
847 "Community (reserved): 0x%x", pntohl(q));
851 ti = proto_tree_add_text(communities_tree, NullTVB,
852 q - pd - 3 + aoff, 4, "Community: %u:%u",
853 pntohs(q), pntohs(q + 2));
854 community_tree = proto_item_add_subtree(ti,
855 ett_bgp_communities);
856 proto_tree_add_text(community_tree, NullTVB, q - pd - 3 + aoff,
857 2, "Community AS: %u", pntohs(q));
858 proto_tree_add_text(community_tree, NullTVB, q - pd - 1 + aoff,
859 2, "Community value: %u", pntohs(q + 2));
865 free(communities_str);
867 case BGPTYPE_ORIGINATOR_ID:
869 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
870 "Originator identifier (invalid): %u %s", alen,
871 (alen == 1) ? "byte" : "bytes");
873 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
874 "Originator identifier: %s",
875 ip_to_str(&p[i + aoff]));
878 case BGPTYPE_MP_REACH_NLRI:
879 af = pntohs(&p[i + aoff]);
880 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 2,
881 "Address family: %s (%u)",
882 val_to_str(af, afnumber, "Unknown"), af);
883 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 2, 1,
884 "Subsequent address family identifier: %s (%u)",
885 val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
886 p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
888 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 3, 1,
889 "Next hop network address (%d %s)",
890 p[i + aoff + 3], (p[i + aoff + 3] == 1) ? "byte" :
892 if (af == AFNUM_INET || af == AFNUM_INET6) {
896 subtree3 = proto_item_add_subtree(ti,
897 ett_bgp_mp_reach_nlri);
900 while (j < p[i + aoff + 3]) {
901 if (af == AFNUM_INET)
903 else if (af == AFNUM_INET6)
907 if (j + advance > p[i + aoff + 3])
910 if (af == AFNUM_INET)
911 s = ip_to_str(&p[i + aoff + 4 + j]);
913 s = ip6_to_str((struct e_in6_addr *)
914 &p[i + aoff + 4 + j]);
916 proto_tree_add_text(subtree3, NullTVB,
917 p - pd + i + aoff + 4 + j, advance,
923 alen -= (p[i + aoff + 3] + 4);
924 aoff += (p[i + aoff + 3] + 4);
927 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 1,
928 "Subnetwork points of attachment: %u", snpa);
931 subtree3 = proto_item_add_subtree(ti,
932 ett_bgp_mp_reach_nlri);
933 for (/*nothing*/; snpa > 0; snpa--) {
934 proto_tree_add_text(subtree3, NullTVB, p - pd + i + aoff + off, 1,
935 "SNPA length: %u", p[i + aoff + off]);
937 proto_tree_add_text(subtree3, NullTVB, p - pd + i + aoff + off,
938 p[i + aoff + off - 1],
939 "SNPA (%u %s)", p[i + aoff + off - 1],
940 (p[i + aoff + off - 1] == 1) ? "byte" : "bytes");
941 off += p[i + aoff + off - 1];
946 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
947 "Network layer reachability information (%u %s)",
948 alen, (alen == 1) ? "byte" : "bytes");
950 subtree3 = proto_item_add_subtree(ti,
951 ett_bgp_mp_unreach_nlri);
956 if (af == AFNUM_INET) {
957 advance = decode_prefix4(&p[i + aoff], buf,
959 } else if (af == AFNUM_INET6) {
960 advance = decode_prefix6(&p[i + aoff], buf,
968 proto_tree_add_text(subtree3, NullTVB, p - pd + i + aoff, advance,
969 "Network layer reachability information: %s", buf);
976 case BGPTYPE_MP_UNREACH_NLRI:
977 af = pntohs(&p[i + aoff]);
978 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, 2,
979 "Address family: %s (%u)",
980 val_to_str(af, afnumber, "Unknown"), af);
981 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 2, 1,
982 "Subsequent address family identifier: %s (%u)",
983 val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
984 p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
986 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff + 3,
987 alen - 3, "Withdrawn routes (%u %s)", alen - 3,
988 (alen - 3 == 1) ? "byte" : "bytes");
993 subtree3 = proto_item_add_subtree(ti,
994 ett_bgp_mp_unreach_nlri);
999 if (af == AFNUM_INET) {
1000 advance = decode_prefix4(&p[i + aoff], buf,
1002 } else if (af == AFNUM_INET6) {
1003 advance = decode_prefix6(&p[i + aoff], buf,
1011 proto_tree_add_text(subtree3, NullTVB, p - pd + i + aoff, advance,
1012 "Withdrawn route: %s", buf);
1019 case BGPTYPE_CLUSTER_LIST:
1020 if (alen % 4 != 0) {
1021 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
1022 "Cluster list (invalid): %u %s", alen,
1023 (alen == 1) ? "byte" : "bytes");
1024 free(cluster_list_str);
1028 ti = proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
1029 "Cluster list: %s", cluster_list_str);
1030 cluster_list_tree = proto_item_add_subtree(ti,
1031 ett_bgp_cluster_list);
1034 (p + current attribute + 3 bytes to first tuple) */
1035 end = p + alen + i + 3;
1038 /* snarf each cluster identifier */
1040 ti = proto_tree_add_text(cluster_list_tree, NullTVB,
1041 q - pd - 3 + aoff, 4, "Cluster identifier: %s",
1047 free(cluster_list_str);
1050 proto_tree_add_text(subtree2, NullTVB, p - pd + i + aoff, alen,
1051 "Unknown (%d %s)", alen, (alen == 1) ? "byte" :
1054 } /* end of second switch */
1061 len = hlen - (p - &pd[offset]);
1063 /* parse prefixes */
1065 ti = proto_tree_add_text(tree, NullTVB, p - pd, len,
1066 "Network layer reachability information: %u %s", len,
1067 (len == 1) ? "byte" : "bytes");
1068 subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
1071 i = decode_prefix4(p, junk_buf, sizeof(junk_buf));
1072 proto_tree_add_text(subtree, NullTVB, p - pd, i, "%s", junk_buf);
1080 * Dissect a BGP NOTIFICATION message.
1083 dissect_bgp_notification(const u_char *pd, int offset, frame_data *fd,
1086 struct bgp_notification bgpn; /* BGP NOTIFICATION message */
1087 int hlen; /* message length */
1088 char *p; /* string pointer */
1091 memcpy(&bgpn, &pd[offset], sizeof(bgpn));
1092 hlen = ntohs(bgpn.bgpn_len);
1094 /* print error code */
1095 proto_tree_add_text(tree, NullTVB,
1096 offset + offsetof(struct bgp_notification, bgpn_major), 1,
1097 "Error code: %s (%u)",
1098 val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
1101 /* print error subcode */
1102 if (bgpn.bgpn_major < array_length(bgpnotify_minor)
1103 && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
1104 p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
1106 } else if (bgpn.bgpn_minor == 0)
1110 proto_tree_add_text(tree, NullTVB,
1111 offset + offsetof(struct bgp_notification, bgpn_minor), 1,
1112 "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
1114 /* only print if there is optional data */
1115 if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
1116 proto_tree_add_text(tree, NullTVB, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
1117 hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
1122 * Dissect a BGP packet.
1125 dissect_bgp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
1127 proto_item *ti; /* tree item */
1128 proto_tree *bgp_tree; /* BGP packet tree */
1129 proto_tree *bgp1_tree; /* BGP message tree */
1130 const u_char *p; /* packet offset pointer */
1132 int found; /* number of BGP messages in packet */
1133 static u_char marker[] = { /* BGP message marker */
1134 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1135 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1137 struct bgp bgp; /* BGP header */
1138 int hlen; /* BGP header length */
1139 char *typ; /* BGP message type */
1141 OLD_CHECK_DISPLAY_AS_DATA(proto_bgp, pd, offset, fd, tree);
1143 if (check_col(fd, COL_PROTOCOL))
1144 col_add_str(fd, COL_PROTOCOL, "BGP");
1150 /* run through the TCP packet looking for BGP headers */
1151 /* this is done twice, but this way each message type can be
1152 printed in the COL_INFO field */
1154 /* look for bgp header */
1159 CHECK_SIZE(i, sizeof(marker), l);
1160 if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
1165 memcpy(&bgp, &p[i], sizeof(bgp));
1167 hlen = ntohs(bgp.bgp_len);
1168 typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1170 if (check_col(fd, COL_INFO)) {
1172 col_add_fstr(fd, COL_INFO, "%s", typ);
1174 col_append_fstr(fd, COL_INFO, ", %s", typ);
1181 ti = proto_tree_add_item(tree, proto_bgp, NullTVB, offset,
1182 END_OF_FRAME, FALSE);
1183 bgp_tree = proto_item_add_subtree(ti, ett_bgp);
1188 /* now, run through the TCP packet again, this time dissect */
1189 /* each message that we find */
1191 /* look for bgp header */
1196 CHECK_SIZE(i, sizeof(marker), l);
1197 if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
1202 memcpy(&bgp, &p[i], sizeof(bgp));
1203 hlen = ntohs(bgp.bgp_len);
1204 typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1205 if (END_OF_FRAME < hlen) {
1206 ti = proto_tree_add_text(bgp_tree, NullTVB, offset + i, END_OF_FRAME,
1207 "%s (truncated)", typ);
1209 ti = proto_tree_add_text(bgp_tree, NullTVB, offset + i, hlen,
1212 /* add a different tree for each message type */
1213 switch (bgp.bgp_type) {
1215 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
1218 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
1220 case BGP_NOTIFICATION:
1221 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
1224 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1227 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1231 proto_tree_add_text(bgp1_tree, NullTVB, offset + i, BGP_MARKER_SIZE,
1232 "Marker: 16 bytes");
1234 if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
1235 proto_tree_add_text(bgp1_tree, NullTVB,
1236 offset + i + offsetof(struct bgp, bgp_len), 2,
1237 "Length (invalid): %u %s", hlen,
1238 (hlen == 1) ? "byte" : "bytes");
1240 proto_tree_add_text(bgp1_tree, NullTVB,
1241 offset + i + offsetof(struct bgp, bgp_len), 2,
1242 "Length: %u %s", hlen,
1243 (hlen == 1) ? "byte" : "bytes");
1246 proto_tree_add_uint_format(bgp1_tree, hf_bgp_type, NullTVB,
1248 offsetof(struct bgp, bgp_type), 1,
1250 "Type: %s (%u)", typ, bgp.bgp_type);
1252 CHECK_SIZE(i, hlen, l);
1254 /* handle each message type */
1255 switch (bgp.bgp_type) {
1257 dissect_bgp_open(pd, offset + i, fd, bgp1_tree);
1260 dissect_bgp_update(pd, offset + i, fd, bgp1_tree);
1262 case BGP_NOTIFICATION:
1263 dissect_bgp_notification(pd, offset + i, fd, bgp1_tree);
1266 /* no data in KEEPALIVE messages */
1278 * Register ourselves.
1281 proto_register_bgp(void)
1284 static hf_register_info hf[] = {
1286 { "BGP message type", "bgp.type", FT_UINT8, BASE_HEX,
1287 VALS(bgptypevals), 0x0, "BGP message type" }},
1290 static gint *ett[] = {
1295 &ett_bgp_attr_flags,
1296 &ett_bgp_mp_reach_nlri,
1297 &ett_bgp_mp_unreach_nlri,
1301 &ett_bgp_notification,
1303 &ett_bgp_communities,
1304 &ett_bgp_cluster_list,
1307 proto_bgp = proto_register_protocol("Border Gateway Protocol", "bgp");
1308 proto_register_field_array(proto_bgp, hf, array_length(hf));
1309 proto_register_subtree_array(ett, array_length(ett));
1313 proto_reg_handoff_bgp(void)
1315 old_dissector_add("tcp.port", TCP_PORT_BGP, dissect_bgp);