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@unicom.net>
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"
66 #include <arpa/inet.h>
68 static const value_string bgptypevals[] = {
69 { BGP_OPEN, "OPEN Message" },
70 { BGP_UPDATE, "UPDATE Message" },
71 { BGP_NOTIFICATION, "NOTIFICATION Message" },
72 { BGP_KEEPALIVE, "KEEPALIVE Message" },
76 static const value_string bgpnotify_major[] = {
77 { 1, "Message Header Error" },
78 { 2, "OPEN Message Error" },
79 { 3, "UPDATE Message Error" },
80 { 4, "Hold Timer Expired" },
81 { 5, "Finite State Machine Error" },
86 static const value_string bgpnotify_minor_1[] = {
87 { 1, "Connection Not Synchronized" },
88 { 2, "Bad Message Length" },
89 { 3, "Bad Message Type" },
93 static const value_string bgpnotify_minor_2[] = {
94 { 1, "Unsupported Version Number" },
96 { 3, "Bad BGP Identifier" },
97 { 4, "Unsupported Optional Parameter" },
98 { 5, "Authentication Failure" },
99 { 6, "Unacceptable Hold Time" },
103 static const value_string bgpnotify_minor_3[] = {
104 { 1, "Malformed Attribute List" },
105 { 2, "Unrecognized Well-known Attribute" },
106 { 3, "Missing Well-known Attribute" },
107 { 4, "Attribute Flags Error" },
108 { 5, "Attribute Length Error" },
109 { 6, "Invalid ORIGIN Attribute" },
110 { 7, "AS Routing Loop" },
111 { 8, "Invalid NEXT_HOP Attribute" },
112 { 9, "Optional Attribute Error" },
113 { 10, "Invalid Network Field" },
114 { 11, "Malformed AS_PATH" },
118 static const value_string *bgpnotify_minor[] = {
119 NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3,
122 static const value_string bgpattr_origin[] = {
129 static const value_string as_segment_type[] = {
131 { 2, "AS_SEQUENCE" },
132 { 3, "AS_CONFED_SET" },
133 { 4, "AS_CONFED_SEQUENCE" },
137 static const value_string bgpattr_type[] = {
138 { BGPTYPE_ORIGIN, "ORIGIN" },
139 { BGPTYPE_AS_PATH, "AS_PATH" },
140 { BGPTYPE_NEXT_HOP, "NEXT_HOP" },
141 { BGPTYPE_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
142 { BGPTYPE_LOCAL_PREF, "LOCAL_PREF" },
143 { BGPTYPE_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
144 { BGPTYPE_AGGREGATOR, "AGGREGATOR" },
145 { BGPTYPE_COMMUNITIES, "COMMUNITIES" },
146 { BGPTYPE_ORIGINATOR_ID, "ORIGINATOR_ID" },
147 { BGPTYPE_CLUSTER_LIST, "CLUSTER_LIST" },
148 { BGPTYPE_MP_REACH_NLRI, "MP_REACH_NLRI" },
149 { BGPTYPE_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
153 /* Subsequent address family identifier, RFC2283 section 7 */
154 static const value_string bgpattr_nlri_safi[] = {
158 { 3, "Unicast+Multicast" },
162 static const value_string afnumber[] = {
164 { AFNUM_INET, "IPv4" },
165 { AFNUM_INET6, "IPv6" },
166 { AFNUM_NSAP, "NSAP" },
167 { AFNUM_HDLC, "HDLC" },
168 { AFNUM_BBN1822, "BBN 1822" },
169 { AFNUM_802, "802" },
170 { AFNUM_E163, "E.163" },
171 { AFNUM_E164, "E.164" },
172 { AFNUM_F69, "F.69" },
173 { AFNUM_X121, "X.121" },
174 { AFNUM_IPX, "IPX" },
175 { AFNUM_ATALK, "Appletalk" },
176 { AFNUM_DECNET, "Decnet IV" },
177 { AFNUM_BANYAN, "Banyan Vines" },
178 { AFNUM_E164NSAP, "E.164 with NSAP subaddress" },
179 { 65535, "Reserved" },
183 static int proto_bgp = -1;
185 static gint ett_bgp = -1;
186 static gint ett_bgp_unfeas = -1;
187 static gint ett_bgp_attrs = -1;
188 static gint ett_bgp_attr = -1;
189 static gint ett_bgp_attr_flags = -1;
190 static gint ett_bgp_mp_reach_nlri = -1;
191 static gint ett_bgp_mp_unreach_nlri = -1;
192 static gint ett_bgp_nlri = -1;
193 static gint ett_bgp_open = -1;
194 static gint ett_bgp_update = -1;
195 static gint ett_bgp_notification = -1;
196 static gint ett_bgp_as_paths = -1;
199 * Decode an IPv4 prefix.
202 decode_prefix4(const u_char *pd, char *buf, int buflen)
204 guint8 addr[4]; /* IP address */
205 int plen; /* prefix length */
206 int length; /* number of octets needed for prefix */
210 if (plen < 0 || 32 < plen)
212 length = (plen + 7) / 8;
215 memset(addr, 0, sizeof(addr));
216 memcpy(addr, &pd[1], length);
218 addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
220 /* hand back a formatted string */
221 snprintf(buf, buflen, "%s/%d", ip_to_str(addr), plen);
226 * Decode an IPv6 prefix.
229 decode_prefix6(const u_char *pd, char *buf, int buflen)
231 struct e_in6_addr addr; /* IPv6 address */
232 int plen; /* prefix length */
233 int length; /* number of octets needed for prefix */
237 if (plen < 0 || 128 < plen)
239 length = (plen + 7) / 8;
242 memset(&addr, 0, sizeof(addr));
243 memcpy(&addr, &pd[1], length);
245 addr.s6_addr[length - 1] &= ((0xff00 >> (plen % 8)) & 0xff);
247 /* hand back a formatted string */
248 snprintf(buf, buflen, "%s/%d", ip6_to_str(&addr), plen);
253 * Dissect a BGP OPEN message.
256 dissect_bgp_open(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
258 struct bgp_open bgpo; /* BGP OPEN message */
259 int hlen; /* message length */
261 /* snarf OPEN message */
262 memcpy(&bgpo, &pd[offset], sizeof(bgpo));
263 hlen = ntohs(bgpo.bgpo_len);
265 proto_tree_add_text(tree,
266 offset + offsetof(struct bgp_open, bgpo_version), 1,
267 "Version: %u", bgpo.bgpo_version);
268 proto_tree_add_text(tree,
269 offset + offsetof(struct bgp_open, bgpo_myas), 2,
270 "My AS: %u", ntohs(bgpo.bgpo_myas));
271 proto_tree_add_text(tree,
272 offset + offsetof(struct bgp_open, bgpo_holdtime), 2,
273 "Hold time: %u", ntohs(bgpo.bgpo_holdtime));
274 proto_tree_add_text(tree,
275 offset + offsetof(struct bgp_open, bgpo_id), 4,
276 "BGP identifier: %s", ip_to_str((guint8 *)&bgpo.bgpo_id));
277 proto_tree_add_text(tree,
278 offset + offsetof(struct bgp_open, bgpo_optlen), 1,
279 "Optional parameters length: %u %s", bgpo.bgpo_optlen,
280 (bgpo.bgpo_optlen == 1) ? "byte" : "bytes");
282 if (hlen > sizeof(struct bgp_open)) {
284 openoff = ((char *)&bgpo.bgpo_optlen - (char *)&bgpo) + 1;
285 proto_tree_add_text(tree,
286 offset + openoff, hlen - openoff,
287 "Optional parameters");
292 * Dissect a BGP UPDATE message.
295 dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
298 struct bgp bgp; /* BGP header */
299 struct bgp_attr bgpa; /* path attributes */
300 int hlen; /* message length */
301 const u_char *p; /* packet offset pointer */
302 const u_char *q; /* tmp */
303 const u_char *end; /* message end */
305 proto_item *ti; /* tree item */
306 proto_tree *subtree; /* subtree for attibutes */
307 proto_tree *subtree2; /* subtree for attibutes */
308 proto_tree *subtree3; /* subtree for attibutes */
309 proto_tree *as_paths_tree; /* subtree for AS_PATHs */
310 proto_tree *as_path_tree; /* subtree for AS_PATH */
312 guint8 length; /* AS_PATH length */
313 guint8 type; /* AS_PATH type */
314 char *as_path_str = NULL; /* AS_PATH string */
315 char junk_buf[256]; /* tmp */
318 /* snarf UPDATE message */
319 memcpy(&bgp, &pd[offset], sizeof(bgp));
320 hlen = ntohs(bgp.bgp_len);
321 p = &pd[offset + BGP_HEADER_SIZE]; /*XXX*/
323 /* check for withdrawals */
324 len = ntohs(*(guint16 *)p);
325 proto_tree_add_text(tree, p - pd, 2,
326 "Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
329 /* parse unfeasible prefixes */
331 ti = proto_tree_add_text(tree, p - pd, len, "Withdrawn routes:");
332 subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
334 /* parse each prefixes */
337 i = decode_prefix4(p, junk_buf, sizeof(junk_buf));
338 proto_tree_add_text(subtree, p - pd, i, "%s", junk_buf);
346 /* check for advertisements */
347 len = ntohs(*(guint16 *)p);
348 proto_tree_add_text(tree, p - pd, 2, "Total path attribute length: %u %s",
349 len, (len == 1) ? "byte" : "bytes");
351 /* path attributes */
354 ti = proto_tree_add_text(tree, p - pd + 2, len, "Path attributes");
355 subtree = proto_item_add_subtree(ti, ett_bgp_attrs);
363 memcpy(&bgpa, &p[i], sizeof(bgpa));
364 /* check for the Extended Length bit */
365 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
366 alen = ntohs(*(guint16 *)&p[i + sizeof(bgpa)]);
367 aoff = sizeof(bgpa) + 2;
369 alen = p[i + sizeof(bgpa)];
370 aoff = sizeof(bgpa) + 1;
373 /* This is kind of ugly - similar code appears twice, but it
374 helps browsing attrs. */
375 /* the first switch prints things in the title of the subtree */
376 switch (bgpa.bgpa_type) {
379 goto default_attribute_top;
380 msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
381 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
383 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
384 msg, alen + aoff, (alen + aoff == 1) ? "byte" :
387 case BGPTYPE_AS_PATH:
389 (p + current attribute + 3 bytes to first tuple) */
390 end = p + alen + i + 3;
392 /* must be freed by second switch! */
393 /* "alen * 6" (5 digits + space) should be a good estimate
394 of how long the AS path string could be */
395 as_path_str = malloc((alen + 1) * 6);
396 if (as_path_str == NULL) break;
397 as_path_str[0] = '\0';
399 /* snarf each AS path */
402 if (type == AS_SET) {
403 snprintf(as_path_str, 2, "{");
407 /* ignore confederation types until we support them */
408 if (type == AS_CONFED_SET || type == AS_CONFED_SEQUENCE) {
413 /* snarf each value in path */
414 for (j = 0; j < length; j++) {
415 snprintf(junk_buf, sizeof(junk_buf), "%u%s", pntohs(q),
416 (type == AS_SET) ? ", " : " ");
417 strncat(as_path_str, junk_buf, sizeof(junk_buf));
421 /* cleanup end of string */
422 if (type == AS_SET) {
423 as_path_str[strlen(as_path_str) - 2] = '}';
426 as_path_str[strlen(as_path_str) - 1] = '\0';
430 /* check for empty AS_PATH */
432 strncpy(as_path_str, "empty", 6);
434 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
436 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
437 as_path_str, alen + aoff,
438 (alen + aoff == 1) ? "byte" : "bytes");
440 case BGPTYPE_NEXT_HOP:
442 goto default_attribute_top;
443 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
445 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
446 ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
449 case BGPTYPE_MULTI_EXIT_DISC:
451 goto default_attribute_top;
452 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
454 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
455 ntohl(*(guint32 *)&p[i + aoff]), alen + aoff,
456 (alen + aoff == 1) ? "byte" : "bytes");
458 case BGPTYPE_LOCAL_PREF:
460 goto default_attribute_top;
461 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
463 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
464 ntohl(*(guint32 *)&p[i + aoff]), alen + aoff,
465 (alen + aoff == 1) ? "byte" : "bytes");
467 case BGPTYPE_ATOMIC_AGGREGATE:
469 goto default_attribute_top;
470 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
472 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
473 alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
475 case BGPTYPE_AGGREGATOR:
477 goto default_attribute_top;
478 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
479 "%s: AS: %u origin: %s (%u %s)",
480 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
481 ntohs(*(guint16 *)&p[i + aoff]),
482 ip_to_str(&p[i + aoff + 2]), alen + aoff,
483 (alen + aoff == 1) ? "byte" : "bytes");
485 case BGPTYPE_COMMUNITIES:
487 goto default_attribute_top;
489 /* check for well-known communities */
490 if (ntohl(*(guint32 *)&p[i + aoff]) == BGP_COMM_NO_EXPORT)
491 strncpy(junk_buf, "NO_EXPORT", 10);
492 else if (ntohl(*(guint32 *)&p[i + aoff]) ==
493 BGP_COMM_NO_ADVERTISE)
494 strncpy(junk_buf, "NO_ADVERTISE", 13);
495 else if (ntohl(*(guint32 *)&p[i + aoff]) ==
496 BGP_COMM_NO_EXPORT_SUBCONFED)
497 strncpy(junk_buf, "NO_EXPORT_SUBCONFED", 20);
499 snprintf(junk_buf, sizeof(junk_buf), "%u:%u",
500 ntohs(*(guint16 *)&p[i + aoff]),
501 ntohs(*(guint16 *)&p[i + aoff + 2]));
504 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
506 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
507 junk_buf, alen + aoff,
508 (alen + aoff == 1) ? "byte" : "bytes");
510 case BGPTYPE_ORIGINATOR_ID:
512 goto default_attribute_top;
513 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
515 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
516 ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
519 case BGPTYPE_CLUSTER_LIST:
521 default_attribute_top:
522 ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
524 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
525 alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
527 subtree2 = proto_item_add_subtree(ti, ett_bgp_attr);
529 /* figure out flags */
531 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_OPTIONAL) {
532 strncat(junk_buf, "Optional, ", 10);
535 strncat(junk_buf, "Well-known, ", 12);
537 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_TRANSITIVE) {
538 strncat(junk_buf, "Transitive, ", 12);
541 strncat(junk_buf, "Non-transitive, ", 16);
543 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_PARTIAL) {
544 strncat(junk_buf, "Partial, ", 9);
547 strncat(junk_buf, "Complete, ", 10);
549 if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
550 strncat(junk_buf, "Extended Length, ", 17);
552 /* stomp last ", " */
553 j = strlen(junk_buf);
554 junk_buf[j - 2] = '\0';
555 ti = proto_tree_add_text(subtree2,
556 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
557 "Flags: 0x%02x (%s)", bgpa.bgpa_flags, junk_buf);
558 subtree3 = proto_item_add_subtree(ti, ett_bgp_attr_flags);
560 /* add flag bitfield subtrees */
561 proto_tree_add_text(subtree3,
562 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
563 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
564 BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
565 proto_tree_add_text(subtree3,
566 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
567 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
568 BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive",
570 proto_tree_add_text(subtree3,
571 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
572 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
573 BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
574 proto_tree_add_text(subtree3,
575 p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
576 "%s", decode_boolean_bitfield(bgpa.bgpa_flags,
577 BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length",
580 proto_tree_add_text(subtree2,
581 p - pd + i + offsetof(struct bgp_attr, bgpa_type), 1,
582 "Type code: %s (%u)",
583 val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
586 proto_tree_add_text(subtree2, p - pd + i + sizeof(bgpa),
587 aoff - sizeof(bgpa), "Length: %d %s", alen,
588 (alen == 1) ? "byte" : "bytes");
590 /* the second switch prints things in the actual subtree of each
592 switch (bgpa.bgpa_type) {
595 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
596 "Origin (invalid): %u %s", alen,
597 (alen == 1) ? "byte" : "bytes");
599 msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
600 proto_tree_add_text(subtree2, p - pd + i + aoff, 1,
601 "Origin: %s (%u)", msg, p[i + aoff]);
604 case BGPTYPE_AS_PATH:
605 /* check for empty AS_PATH */
611 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
612 "AS path: %s", as_path_str);
613 as_paths_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
616 (p + current attribute + 3 bytes to first tuple) */
617 end = p + alen + i + 3;
620 /* snarf each AS path tuple */
622 as_path_str[0] = '\0';
624 if (type == AS_SET) {
625 snprintf(as_path_str, 2, "{");
629 /* ignore confederation types until we support them */
630 if (type == AS_CONFED_SET || type == AS_CONFED_SEQUENCE) {
635 /* snarf each value in path, we're just going to reuse
636 as_path_str since we already have it malloced */
637 for (j = 0; j < length; j++) {
638 snprintf(junk_buf, sizeof(junk_buf), "%u%s", pntohs(q),
639 (type == AS_SET) ? ", " : " ");
640 strncat(as_path_str, junk_buf, sizeof(junk_buf));
644 /* cleanup end of string */
645 if (type == AS_SET) {
646 as_path_str[strlen(as_path_str) - 2] = '}';
649 as_path_str[strlen(as_path_str) - 1] = '\0';
652 /* length here means number of ASs, ie length * 2 bytes */
653 ti = proto_tree_add_text(as_paths_tree,
654 q - pd - length * 2 - 2,
655 length * 2 + 2, "AS path segment: %s", as_path_str);
656 as_path_tree = proto_item_add_subtree(ti, ett_bgp_as_paths);
657 proto_tree_add_text(as_path_tree, q - pd - length * 2 - 2,
658 1, "Path segment type: %s (%u)",
659 val_to_str(type, as_segment_type, "Unknown"), type);
660 proto_tree_add_text(as_path_tree, q - pd - length * 2 - 1,
661 1, "Path segment length: %u %s", length,
662 (length == 1) ? "AS" : "ASs");
663 proto_tree_add_text(as_path_tree, q - pd - length * 2,
664 length * 2, "Path segment value: %s", as_path_str);
669 case BGPTYPE_NEXT_HOP:
671 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
672 "Next hop (invalid): %u %s", alen,
673 (alen == 1) ? "byte" : "bytes");
675 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
676 "Next hop: %s", ip_to_str(&p[i + aoff]));
679 case BGPTYPE_MULTI_EXIT_DISC:
681 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
682 "Multi exit discriminator (invalid): %u %s",
683 alen, (alen == 1) ? "byte" : "bytes");
685 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
686 "Multi exit discriminator: %u",
687 ntohl(*(guint32 *)&p[i + aoff]));
690 case BGPTYPE_LOCAL_PREF:
692 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
693 "Local preference (invalid): %u %s", alen,
694 (alen == 1) ? "byte" : "bytes");
696 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
697 "Local preference: %u",
698 ntohl(*(guint32 *)&p[i + aoff]));
701 case BGPTYPE_ATOMIC_AGGREGATE:
703 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
704 "Atomic aggregate (invalid): %u %s", alen,
705 (alen == 1) ? "byte" : "bytes");
708 case BGPTYPE_AGGREGATOR:
710 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
711 "Aggregator (invalid): %u %s", alen,
712 (alen == 1) ? "byte" : "bytes");
714 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
716 ntohs(*(guint16 *)&p[i + aoff]));
717 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 4,
718 "Aggregator origin: %s",
719 ip_to_str(&p[i + aoff + 2]));
722 case BGPTYPE_COMMUNITIES:
724 proto_tree_add_text(subtree2, p - pd + i + aoff, 4,
725 "Communities (invalid): %u %s", alen,
726 (alen == 1) ? "byte" : "bytes");
728 /* check for reserved values */
729 else if (ntohs(*(guint16 *)&p[i + aoff]) == FOURHEX0 ||
730 ntohs(*(guint16 *)&p[i + aoff]) == FOURHEXF) {
731 /* check for well-known communities */
732 if (ntohl(*(guint32 *)&p[i + aoff]) == BGP_COMM_NO_EXPORT)
733 proto_tree_add_text(subtree2, p - pd + i + aoff, 4,
734 "Communities: NO_EXPORT (0x%x)",
735 ntohl(*(guint32 *)&p[i + aoff]));
736 else if (ntohl(*(guint32 *)&p[i + aoff]) ==
737 BGP_COMM_NO_ADVERTISE)
738 proto_tree_add_text(subtree2, p - pd + i + aoff, 4,
739 "Communities: NO_ADVERTISE (0x%x)",
740 ntohl(*(guint32 *)&p[i + aoff]));
741 else if (ntohl(*(guint32 *)&p[i + aoff]) ==
742 BGP_COMM_NO_EXPORT_SUBCONFED)
743 proto_tree_add_text(subtree2, p - pd + i + aoff, 4,
744 "Communities: NO_EXPORT_SUBCONFED (0x%x)",
745 ntohl(*(guint32 *)&p[i + aoff]));
747 proto_tree_add_text(subtree2, p - pd + i + aoff, 4,
748 "Communities (reserved): 0x%x",
749 ntohl(*(guint32 *)&p[i + aoff]));
753 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
754 "Communities AS: %u",
755 ntohs(*(guint16 *)&p[i + aoff]));
756 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 2,
757 "Communities value: %u",
758 ntohs(*(guint16 *)&p[i + aoff + 2]));
761 case BGPTYPE_ORIGINATOR_ID:
763 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
764 "Originator identifier (invalid): %u %s", alen,
765 (alen == 1) ? "byte" : "bytes");
767 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
768 "Originator identifier: %s",
769 ip_to_str(&p[i + aoff]));
772 case BGPTYPE_MP_REACH_NLRI:
773 af = ntohs(*(guint16 *)&p[i + aoff]);
774 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
775 "Address family: %s (%u)",
776 val_to_str(af, afnumber, "Unknown"), af);
777 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 1,
778 "Subsequent address family identifier: %s (%u)",
779 val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
780 p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
782 ti = proto_tree_add_text(subtree2, p - pd + i + aoff + 3, 1,
783 "Next hop network address (%d %s)",
784 p[i + aoff + 3], (p[i + aoff + 3] == 1) ? "byte" :
786 if (af == AFNUM_INET || af == AFNUM_INET6) {
790 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_reach_nlri);
793 while (j < p[i + aoff + 3]) {
794 if (af == AFNUM_INET)
796 else if (af == AFNUM_INET6)
800 if (j + advance > p[i + aoff + 3])
803 if (af == AFNUM_INET)
804 s = ip_to_str(&p[i + aoff + 4 + j]);
806 s = ip6_to_str((struct e_in6_addr *)
807 &p[i + aoff + 4 + j]);
809 proto_tree_add_text(subtree3,
810 p - pd + i + aoff + 4 + j, advance,
816 alen -= (p[i + aoff + 3] + 4);
817 aoff += (p[i + aoff + 3] + 4);
820 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, 1,
821 "Subnetwork points of attachment: %u", snpa);
824 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_reach_nlri);
825 for (/*nothing*/; snpa > 0; snpa--) {
826 proto_tree_add_text(subtree3, p - pd + i + aoff + off, 1,
827 "SNPA length: ", p[i + aoff + off]);
829 proto_tree_add_text(subtree3, p - pd + i + aoff + off,
830 p[i + aoff + off - 1],
831 "SNPA (%u %s)", p[i + aoff + off - 1],
832 (p[i + aoff + off - 1] == 1) ? "byte" : "bytes");
833 off += p[i + aoff + off - 1];
838 ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
839 "Network layer reachability information (%u %s)",
840 alen, (alen == 1) ? "byte" : "bytes");
842 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_unreach_nlri);
847 if (af == AFNUM_INET) {
848 advance = decode_prefix4(&p[i + aoff], buf,
850 } else if (af == AFNUM_INET6) {
851 advance = decode_prefix6(&p[i + aoff], buf,
859 proto_tree_add_text(subtree3, p - pd + i + aoff, advance,
860 "Network layer reachability information: %s", buf);
867 case BGPTYPE_MP_UNREACH_NLRI:
868 af = ntohs(*(guint16 *)&p[i + aoff]);
869 proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
870 "Address family: %s (%u)",
871 val_to_str(af, afnumber, "Unknown"), af);
872 proto_tree_add_text(subtree2, p - pd + i + aoff + 2, 1,
873 "Subsequent address family identifier: %s (%u)",
874 val_to_str(p[i + aoff + 2], bgpattr_nlri_safi,
875 p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
877 ti = proto_tree_add_text(subtree2, p - pd + i + aoff + 3,
878 alen - 3, "Withdrawn routes (%u %s)", alen - 3,
879 (alen - 3 == 1) ? "byte" : "bytes");
884 subtree3 = proto_item_add_subtree(ti, ett_bgp_mp_unreach_nlri);
889 if (af == AFNUM_INET) {
890 advance = decode_prefix4(&p[i + aoff], buf,
892 } else if (af == AFNUM_INET6) {
893 advance = decode_prefix6(&p[i + aoff], buf,
901 proto_tree_add_text(subtree3, p - pd + i + aoff, advance,
902 "Withdrawn route: %s", buf);
909 case BGPTYPE_CLUSTER_LIST:
911 proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
912 "Unknown (%d %s)", alen, (alen == 1) ? "byte" :
923 len = hlen - (p - &pd[offset]);
927 ti = proto_tree_add_text(tree, p - pd, len,
928 "Network layer reachability information: %u %s", len,
929 (len == 1) ? "byte" : "bytes");
930 subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
933 i = decode_prefix4(p, junk_buf, sizeof(junk_buf));
934 proto_tree_add_text(subtree, p - pd, i, "%s", junk_buf);
942 * Dissect a BGP NOTIFICATION message.
945 dissect_bgp_notification(const u_char *pd, int offset, frame_data *fd,
948 struct bgp_notification bgpn; /* BGP NOTIFICATION message */
949 int hlen; /* message length */
950 char *p; /* string pointer */
953 memcpy(&bgpn, &pd[offset], sizeof(bgpn));
954 hlen = ntohs(bgpn.bgpn_len);
956 /* print error code */
957 proto_tree_add_text(tree,
958 offset + offsetof(struct bgp_notification, bgpn_major), 1,
959 "Error code: %s (%u)",
960 val_to_str(bgpn.bgpn_major, bgpnotify_major, "Unknown"),
963 /* print error subcode */
964 if (bgpn.bgpn_major < array_length(bgpnotify_minor)
965 && bgpnotify_minor[bgpn.bgpn_major] != NULL) {
966 p = val_to_str(bgpn.bgpn_minor, bgpnotify_minor[bgpn.bgpn_major],
968 } else if (bgpn.bgpn_minor == 0)
972 proto_tree_add_text(tree,
973 offset + offsetof(struct bgp_notification, bgpn_minor), 1,
974 "Error subcode: %s (%u)", p, bgpn.bgpn_minor);
976 /* only print if there is optional data */
977 if (hlen > BGP_MIN_NOTIFICATION_MSG_SIZE) {
978 proto_tree_add_text(tree, offset + BGP_MIN_NOTIFICATION_MSG_SIZE,
979 hlen - BGP_MIN_NOTIFICATION_MSG_SIZE, "Data");
984 * Dissect a BGP packet.
987 dissect_bgp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
989 proto_item *ti; /* tree item */
990 proto_tree *bgp_tree; /* BGP packet tree */
991 proto_tree *bgp1_tree; /* BGP message tree */
992 const u_char *p; /* packet offset pointer */
994 int found; /* number of BGP messages in packet */
995 static u_char marker[] = { /* BGP message marker */
996 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
997 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
999 struct bgp bgp; /* BGP header */
1000 int hlen; /* BGP header length */
1001 char *typ; /* BGP message type */
1003 if (check_col(fd, COL_PROTOCOL))
1004 col_add_str(fd, COL_PROTOCOL, "BGP");
1010 /* run through the TCP packet looking for BGP headers */
1011 /* this is done twice, but this way each message type can be
1012 printed in the COL_INFO field */
1014 /* look for bgp header */
1019 CHECK_SIZE(i, sizeof(marker), l);
1020 if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
1025 memcpy(&bgp, &p[i], sizeof(bgp));
1027 hlen = ntohs(bgp.bgp_len);
1028 typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1030 if (check_col(fd, COL_INFO)) {
1032 col_add_fstr(fd, COL_INFO, "%s", typ);
1034 col_append_fstr(fd, COL_INFO, ", %s", typ);
1041 ti = proto_tree_add_text(tree, offset, END_OF_FRAME,
1042 "Border Gateway Protocol");
1043 bgp_tree = proto_item_add_subtree(ti, ett_bgp);
1048 /* now, run through the TCP packet again, this time dissect */
1049 /* each message that we find */
1051 /* look for bgp header */
1056 CHECK_SIZE(i, sizeof(marker), l);
1057 if (memcmp(&p[i], marker, sizeof(marker)) != 0) {
1062 memcpy(&bgp, &p[i], sizeof(bgp));
1063 hlen = ntohs(bgp.bgp_len);
1064 typ = val_to_str(bgp.bgp_type, bgptypevals, "Unknown Message");
1065 if (END_OF_FRAME < hlen) {
1066 ti = proto_tree_add_text(bgp_tree, offset + i, END_OF_FRAME,
1067 "%s (truncated)", typ);
1069 ti = proto_tree_add_text(bgp_tree, offset + i, hlen,
1072 /* add a different tree for each message type */
1073 switch (bgp.bgp_type) {
1075 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_open);
1078 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_update);
1080 case BGP_NOTIFICATION:
1081 bgp1_tree = proto_item_add_subtree(ti, ett_bgp_notification);
1084 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1087 bgp1_tree = proto_item_add_subtree(ti, ett_bgp);
1091 proto_tree_add_text(bgp1_tree, offset + i, BGP_MARKER_SIZE,
1094 if (hlen < BGP_HEADER_SIZE || hlen > BGP_MAX_PACKET_SIZE) {
1095 proto_tree_add_text(bgp1_tree,
1096 offset + i + offsetof(struct bgp, bgp_len), 2,
1097 "Length (invalid): %u %s", hlen,
1098 (hlen == 1) ? "byte" : "bytes");
1100 proto_tree_add_text(bgp1_tree,
1101 offset + i + offsetof(struct bgp, bgp_len), 2,
1102 "Length: %u %s", hlen,
1103 (hlen == 1) ? "byte" : "bytes");
1106 proto_tree_add_text(bgp1_tree,
1107 offset + i + offsetof(struct bgp, bgp_type), 1,
1108 "Type: %s (%u)", typ, bgp.bgp_type);
1110 CHECK_SIZE(i, hlen, l);
1112 /* handle each message type */
1113 switch (bgp.bgp_type) {
1115 dissect_bgp_open(pd, offset + i, fd, bgp1_tree);
1118 dissect_bgp_update(pd, offset + i, fd, bgp1_tree);
1120 case BGP_NOTIFICATION:
1121 dissect_bgp_notification(pd, offset + i, fd, bgp1_tree);
1124 /* no data in KEEPALIVE messages */
1136 * Register ourselves.
1139 proto_register_bgp(void)
1141 static gint *ett[] = {
1146 &ett_bgp_attr_flags,
1147 &ett_bgp_mp_reach_nlri,
1148 &ett_bgp_mp_unreach_nlri,
1152 &ett_bgp_notification,
1156 proto_bgp = proto_register_protocol("Border Gateway Protocol", "bgp");
1157 proto_register_subtree_array(ett, array_length(ett));