aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/dissectors/packet-bgp.c204
1 files changed, 189 insertions, 15 deletions
diff --git a/epan/dissectors/packet-bgp.c b/epan/dissectors/packet-bgp.c
index 96a8aecf62..744eb69d1d 100644
--- a/epan/dissectors/packet-bgp.c
+++ b/epan/dissectors/packet-bgp.c
@@ -37,6 +37,7 @@
* draft-ietf-idr-bgp-ext-communities-05
* draft-knoll-idr-qos-attribute-03
* draft-nalawade-kapoor-tunnel-safi-05
+ * draft-ietf-idr-add-paths-04 Additional-Path for BGP-4
*
* TODO:
* Destination Preference Attribute for BGP (work in progress)
@@ -316,6 +317,7 @@ static const value_string capability_vals[] = {
{ BGP_CAPABILITY_GRACEFUL_RESTART, "Graceful Restart capability" },
{ BGP_CAPABILITY_4_OCTET_AS_NUMBER, "Support for 4-octet AS number capability" },
{ BGP_CAPABILITY_DYNAMIC_CAPABILITY, "Support for Dynamic capability" },
+ { BGP_CAPABILITY_ADDITIONAL_PATHS, "Support for Additional Paths" },
{ BGP_CAPABILITY_ROUTE_REFRESH_CISCO, "Route refresh capability" },
{ BGP_CAPABILITY_ORF_CISCO, "Cooperative route filtering capability" },
{ 0, NULL }
@@ -361,6 +363,7 @@ static int hf_bgp_mp_unreach_nlri_ipv4_prefix = -1;
static int hf_bgp_mp_nlri_tnl_id = -1;
static int hf_bgp_withdrawn_prefix = -1;
static int hf_bgp_nlri_prefix = -1;
+static int hf_bgp_nlri_path_id = -1;
static gint ett_bgp = -1;
static gint ett_bgp_prefix = -1;
@@ -397,6 +400,108 @@ static gboolean bgp_desegment = TRUE;
static gint bgp_asn_len = 0;
/*
+ * Detect IPv4 prefixes conform to BGP Additional Path but NOT conform to standard BGP
+ *
+ * A real BGP speaker would rely on the BGP Additional Path in the BGP Open messages.
+ * But it is not suitable for a packet analyse because the BGP sessions are not supposed to
+ * restart very often, and Open messages from both sides of the session would be needed
+ * to determine the result of the capability negociation.
+ * Code inspired from the decode_prefix4 function
+ */
+static int
+detect_add_path_prefix4(tvbuff_t *tvb, gint offset, gint end) {
+ guint32 addr_len;
+ guint8 prefix_len;
+ gint o;
+ /* Must be compatible with BGP Additional Path */
+ for (o = offset + 4; o < end; o += 4) {
+ prefix_len = tvb_get_guint8(tvb, o);
+ if( prefix_len > 32) {
+ return 0; /* invalid prefix lenght - not BGP add-path */
+ }
+ addr_len = (prefix_len + 7) / 8;
+ o += 1 + addr_len;
+ if( o > end ) {
+ return 0; /* invalid offset - not BGP add-path */
+ }
+ if (prefix_len % 8) {
+ /* detect bits set after the end of the prefix */
+ if( tvb_get_guint8(tvb, o - 1 ) & (0xFF >> (prefix_len % 8)) ) {
+ return 0; /* invalid prefix content - not BGP add-path */
+ }
+ }
+ }
+ /* Must NOT be compatible with standard BGP */
+ for (o = offset; o < end; ) {
+ prefix_len = tvb_get_guint8(tvb, o);
+ if( prefix_len > 32) {
+ return 1; /* invalid prefix lenght - may be BGP add-path */
+ }
+ addr_len = (prefix_len + 7) / 8;
+ o += 1 + addr_len;
+ if( o > end ) {
+ return 1; /* invalid offset - may be BGP add-path */
+ }
+ if (prefix_len % 8) {
+ /* detect bits set after the end of the prefix */
+ if( tvb_get_guint8(tvb, o - 1 ) & (0xFF >> (prefix_len % 8)) ) {
+ return 1; /* invalid prefix content - may be BGP add-path (or a bug) */
+ }
+ }
+ }
+ return 0; /* valid - do not assume Additional Path */
+}
+/*
+ * Decode an IPv4 prefix with Path Identifier
+ * Code inspired from the decode_prefix4 function
+ */
+static int
+decode_path_prefix4(proto_tree *tree, int hf_path_id, int hf_addr, tvbuff_t *tvb, gint offset,
+ const char *tag)
+{
+ proto_item *ti;
+ proto_tree *prefix_tree;
+ union {
+ guint8 addr_bytes[4];
+ guint32 addr;
+ } ip_addr; /* IP address */
+ guint8 plen; /* prefix length */
+ int length; /* number of octets needed for prefix */
+ guint32 path_identifier;
+ /* snarf path identifier length and prefix */
+ path_identifier = tvb_get_ntohl(tvb, offset);
+ plen = tvb_get_guint8(tvb, offset + 4);
+ length = ipv4_addr_and_mask(tvb, offset + 4 + 1, ip_addr.addr_bytes, plen);
+ if (length < 0) {
+ proto_tree_add_text(tree, tvb, offset + 4 , 1, "%s length %u invalid (> 32)",
+ tag, plen);
+ return -1;
+ }
+ /* put prefix into protocol tree */
+ ti = proto_tree_add_text(tree, tvb, offset,
+ 4 + 1 + length, "%s/%u PathId %u ",
+ ip_to_str(ip_addr.addr_bytes), plen, path_identifier);
+ prefix_tree = proto_item_add_subtree(ti, ett_bgp_prefix);
+ if (hf_path_id != -1) {
+ proto_tree_add_uint(prefix_tree, hf_path_id, tvb, offset, 4,
+ path_identifier);
+ } else {
+ proto_tree_add_text(prefix_tree, tvb, offset, 4,
+ "%s Path Id: %u", tag, path_identifier);
+ }
+ proto_tree_add_text(prefix_tree, tvb, offset + 4, 1, "%s prefix length: %u",
+ tag, plen);
+ if (hf_addr != -1) {
+ proto_tree_add_ipv4(prefix_tree, hf_addr, tvb, offset + 4 + 1, length,
+ ip_addr.addr);
+ } else {
+ proto_tree_add_text(prefix_tree, tvb, offset + 4 + 1, length,
+ "%s prefix: %s", tag, ip_to_str(ip_addr.addr_bytes));
+ }
+ return(4 + 1 + length);
+}
+
+/*
* Decode an IPv4 prefix.
*/
static int
@@ -1377,6 +1482,48 @@ dissect_bgp_capability_item(tvbuff_t *tvb, int *p, proto_tree *tree, int ctype,
}
}
break;
+ case BGP_CAPABILITY_ADDITIONAL_PATHS:
+ proto_tree_add_text(tree, tvb, *p - 2, 1,
+ "Capability code: %s (%d)", val_to_str(ctype,
+ capability_vals, "Unknown capability"), ctype);
+ if (clen != 4) {
+ proto_tree_add_text(tree, tvb, *p,
+ clen, "Capability value: Invalid");
+ proto_tree_add_text(tree, tvb, *p,
+ clen, "Capability value: Unknown");
+ }
+ else { /* AFI SAFI Send-receive*/
+ proto_tree_add_text(tree, tvb, *p - 1,
+ 1, "Capability length: %u byte%s", clen,
+ plurality(clen, "", "s"));
+ ti = proto_tree_add_text(tree, tvb, *p, clen, "Capability value");
+ subtree = proto_item_add_subtree(ti, ett_bgp_option);
+ /* AFI */
+ i = tvb_get_ntohs(tvb, *p);
+ proto_tree_add_text(subtree, tvb, *p,
+ 2, "Address family identifier: %s (%u)",
+ val_to_str(i, afn_vals, "Unknown"), i);
+ *p += 2;
+ /* SAFI */
+ i = tvb_get_guint8(tvb, *p);
+ proto_tree_add_text(subtree, tvb, *p,
+ 1, "Subsequent address family identifier: %s (%u)",
+ val_to_str(i, bgpattr_nlri_safi,
+ i >= 128 ? "Vendor specific" : "Unknown"), i);
+ (*p)++;
+ /* Send-Receive */
+ i = tvb_get_guint8(tvb, *p);
+ proto_tree_add_text(subtree, tvb, *p, 1,
+ "Flags: 0x%02x (%sSend,%sReceive)", i,
+ ((i&BGP_ADDPATH_SEND)? "":"Dont"),
+ ((i&BGP_ADDPATH_RECEIVE)? "":"Dont"));
+ /* Note: flags may be provided as a bitfield subtree */
+ (*p)++;
+
+ }
+ *p += clen;
+ break;
+
case BGP_CAPABILITY_ROUTE_REFRESH_CISCO:
case BGP_CAPABILITY_ROUTE_REFRESH:
proto_tree_add_text(tree, tvb, *p - 2, 1,
@@ -1630,17 +1777,28 @@ dissect_bgp_update(tvbuff_t *tvb, proto_tree *tree)
if (len > 0) {
ti = proto_tree_add_text(tree, tvb, o, len, "Withdrawn routes:");
subtree = proto_item_add_subtree(ti, ett_bgp_unfeas);
-
/* parse each prefix */
- end = o + len;
- while (o < end) {
- i = decode_prefix4(subtree, hf_bgp_withdrawn_prefix, tvb, o, len,
- "Withdrawn route");
- if (i < 0)
- return;
- o += i;
+ end = o + len;
+ /* Heuristic to detect if IPv4 prefix are using Path Identifiers */
+ if( detect_add_path_prefix4(tvb, o, end) ) {
+ /* IPv4 prefixes with Path Id */
+ while (o < end) {
+ i = decode_path_prefix4(subtree, hf_bgp_nlri_path_id, hf_bgp_withdrawn_prefix, tvb, o,
+ "Withdrawn route");
+ if (i < 0)
+ return;
+ o += i;
+ }
+ } else {
+ while (o < end) {
+ i = decode_prefix4(subtree, hf_bgp_withdrawn_prefix, tvb, o, len,
+ "Withdrawn route");
+ if (i < 0)
+ return;
+ o += i;
+ }
}
- }
+ }
/* check for advertisements */
len = tvb_get_ntohs(tvb, o);
@@ -2655,12 +2813,25 @@ dissect_bgp_update(tvbuff_t *tvb, proto_tree *tree)
plurality(len, "", "s"));
subtree = proto_item_add_subtree(ti, ett_bgp_nlri);
end = o + len;
- while (o < end) {
- i = decode_prefix4(subtree, hf_bgp_nlri_prefix, tvb, o, 0,
- "NLRI");
- if (i < 0)
- return;
- o += i;
+ /* Heuristic to detect if IPv4 prefix are using Path Identifiers */
+ if( detect_add_path_prefix4(tvb, o, end) ) {
+ /* IPv4 prefixes with Path Id */
+ while (o < end) {
+ i = decode_path_prefix4(subtree, hf_bgp_nlri_path_id, hf_bgp_nlri_prefix, tvb, o,
+ "NLRI");
+ if (i < 0)
+ return;
+ o += i;
+ }
+ } else {
+ /* Standard prefixes */
+ while (o < end) {
+ i = decode_prefix4(subtree, hf_bgp_nlri_prefix, tvb, o, 0,
+ "NLRI");
+ if (i < 0)
+ return;
+ o += i;
+ }
}
}
}
@@ -3212,6 +3383,9 @@ proto_register_bgp(void)
{ &hf_bgp_nlri_prefix,
{ "NLRI prefix", "bgp.nlri_prefix", FT_IPv4, BASE_NONE,
NULL, 0x0, NULL, HFILL}},
+ { &hf_bgp_nlri_path_id,
+ { "NLRI path id", "bgp.nlri_path_id", FT_UINT32, BASE_DEC,
+ NULL, 0x0, NULL, HFILL}},
{ &hf_bgp_origin,
{ "Origin", "bgp.origin", FT_UINT8, BASE_DEC,
VALS(bgpattr_origin), 0x0, NULL, HFILL}},