BGP: Heuristic for IPv6 NLRI path identifier

NLRIs can contain path identifiers as defined in RFC7911.

This commit adopts the IPv4 heuristic to IPv6 to detect usage
of additional path identifier.

Bug: 14241
Change-Id: I6b99c079b12d1f9a3e05b152a5540a621076e965
Reviewed-on: https://code.wireshark.org/review/26157
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
This commit is contained in:
Uli Heilmeier 2018-02-27 22:56:29 +01:00 committed by Alexis La Goutte
parent faf6ee9ada
commit eb15a1ed19
1 changed files with 61 additions and 9 deletions

View File

@ -2178,7 +2178,7 @@ load_link_state_data(packet_info *pinfo) {
}
/*
* Detect IPv4 prefixes conform to BGP Additional Path but NOT conform to standard BGP
* Detect IPv4/IPv6 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
@ -2187,14 +2187,14 @@ load_link_state_data(packet_info *pinfo) {
* Code inspired from the decode_prefix4 function
*/
static int
detect_add_path_prefix4(tvbuff_t *tvb, gint offset, gint end) {
detect_add_path_prefix46(tvbuff_t *tvb, gint offset, gint end, gint max_bit_length) {
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) {
if( prefix_len > max_bit_length) {
return 0; /* invalid prefix length - not BGP add-path */
}
addr_len = (prefix_len + 7) / 8;
@ -2215,7 +2215,7 @@ detect_add_path_prefix4(tvbuff_t *tvb, gint offset, gint end) {
if( prefix_len == 0 && end - offset > 1 ) {
return 1; /* prefix length is zero (i.e. matching all IP prefixes) and remaining bytes within the NLRI is greater than or equal to 1 - may be BGP add-path */
}
if( prefix_len > 32) {
if( prefix_len > max_bit_length) {
return 1; /* invalid prefix length - may be BGP add-path */
}
addr_len = (prefix_len + 7) / 8;
@ -2232,6 +2232,14 @@ detect_add_path_prefix4(tvbuff_t *tvb, gint offset, gint end) {
}
return 0; /* valid - do not assume Additional Path */
}
static int
detect_add_path_prefix4(tvbuff_t *tvb, gint offset, gint end) {
return detect_add_path_prefix46(tvb, offset, end, 32);
}
static int
detect_add_path_prefix6(tvbuff_t *tvb, gint offset, gint end) {
return detect_add_path_prefix46(tvb, offset, end, 128);
}
/*
* Decode an IPv4 prefix with Path Identifier
* Code inspired from the decode_prefix4 function
@ -2312,7 +2320,7 @@ decode_prefix4(proto_tree *tree, packet_info *pinfo, proto_item *parent_item, in
}
/*
* Decode an IPv6 prefix.
* Decode an IPv6 prefix with path ID.
*/
static int
decode_path_prefix6(proto_tree *tree, packet_info *pinfo, int hf_path_id, int hf_addr, tvbuff_t *tvb, gint offset,
@ -2349,6 +2357,39 @@ decode_path_prefix6(proto_tree *tree, packet_info *pinfo, int hf_path_id, int hf
return(4 + 1 + length);
}
/*
* Decode an IPv6 prefix.
*/
static int
decode_prefix6(proto_tree *tree, packet_info *pinfo, int hf_addr, tvbuff_t *tvb, gint offset,
guint16 tlen, const char *tag)
{
proto_tree *prefix_tree;
ws_in6_addr addr; /* IPv6 address */
address addr_str;
int plen; /* prefix length */
int length; /* number of octets needed for prefix */
/* snarf length and prefix */
plen = tvb_get_guint8(tvb, offset);
length = tvb_get_ipv6_addr_with_prefix_len(tvb, offset + 1, &addr, plen);
if (length < 0) {
proto_tree_add_expert_format(tree, pinfo, &ei_bgp_length_invalid, tvb, offset, 1, "%s length %u invalid",
tag, plen);
return -1;
}
/* put prefix into protocol tree */
set_address(&addr_str, AT_IPv6, 16, addr.bytes);
prefix_tree = proto_tree_add_subtree_format(tree, tvb, offset,
tlen != 0 ? tlen : 1 + length, ett_bgp_prefix, NULL, "%s/%u",
address_to_str(wmem_packet_scope(), &addr_str), plen);
proto_tree_add_uint_format(prefix_tree, hf_bgp_prefix_length, tvb, offset, 1, plen, "%s prefix length: %u",
tag, plen);
proto_tree_add_ipv6(prefix_tree, hf_addr, tvb, offset + 1, length, &addr);
return(1 + length);
}
static int
decode_fspec_match_prefix6(proto_tree *tree, proto_item *parent_item, int hf_addr,
tvbuff_t *tvb, gint offset, guint16 tlen, packet_info *pinfo)
@ -4870,7 +4911,7 @@ static int decode_evpn_nlri(proto_tree *tree, tvbuff_t *tvb, gint offset, packet
*/
static int
decode_prefix_MP(proto_tree *tree, int hf_path_id, int hf_addr4, int hf_addr6,
guint16 afi, guint8 safi, tvbuff_t *tvb, gint offset,
guint16 afi, guint8 safi, gint tlen, tvbuff_t *tvb, gint offset,
const char *tag, packet_info *pinfo)
{
int start_offset = offset;
@ -4896,6 +4937,7 @@ decode_prefix_MP(proto_tree *tree, int hf_path_id, int hf_addr4, int hf_addr6,
guint16 rd_type; /* Route Distinguisher type */
guint16 nlri_type; /* NLRI Type */
guint16 tmp16;
gint end=0; /* Message End */
wmem_strbuf_t *stack_strbuf; /* label stack */
wmem_strbuf_t *comm_strbuf;
@ -5121,7 +5163,17 @@ decode_prefix_MP(proto_tree *tree, int hf_path_id, int hf_addr4, int hf_addr6,
case SAFNUM_UNICAST:
case SAFNUM_MULCAST:
case SAFNUM_UNIMULC:
total_length = decode_path_prefix6(tree, pinfo, hf_path_id, hf_addr6, tvb, offset, tag);
/* parse each prefix */
end = offset + tlen;
/* Heuristic to detect if IPv6 prefix are using Path Identifiers */
if( detect_add_path_prefix6(tvb, offset, end) ) {
/* IPv4 prefixes with Path Id */
total_length = decode_path_prefix6(tree, pinfo, hf_path_id, hf_addr6, tvb, offset, tag);
} else {
total_length = decode_prefix6(tree, pinfo, hf_addr6, tvb, offset, 0, tag);
}
if (total_length < 0)
return -1;
break;
@ -7208,7 +7260,7 @@ dissect_bgp_path_attr(proto_tree *subtree, tvbuff_t *tvb, guint16 path_attr_len,
hf_bgp_nlri_path_id,
hf_bgp_mp_reach_nlri_ipv4_prefix,
hf_bgp_mp_reach_nlri_ipv6_prefix,
af, saf,
af, saf, tlen,
tvb, o + i + aoff, "MP Reach NLRI", pinfo);
if (advance < 0)
break;
@ -7241,7 +7293,7 @@ dissect_bgp_path_attr(proto_tree *subtree, tvbuff_t *tvb, guint16 path_attr_len,
hf_bgp_nlri_path_id,
hf_bgp_mp_unreach_nlri_ipv4_prefix,
hf_bgp_mp_unreach_nlri_ipv6_prefix,
af, saf,
af, saf, tlen,
tvb, o + i + aoff, "MP Unreach NLRI", pinfo);
if (advance < 0)
break;