On 2015/10/13 18:21, Kevin Reay wrote:
> Fix a segfault when printing a malformed BGP AS_PATH update due to ASN
> extraction.
There are line-wrapping and whitespace issues in this patch.
> Better AS size extraction from AS paths: better heuristics (see
> bgp_attr_get_as_size).
That makes sense though the English in the comments relating to
this change is very awkward.
> Also fixes output support for 4-byte ASNs. For example;
> (AS_PATH[T] {500.500 513.65211})
> becomes:
> (AS_PATH[T] {500 500} 65211)
This example seems very wrong. I think what the diff is doing in this
area is switching from ASDOT to ASPLAIN which is alright (though it
should be a separate diff - one change, one diff - and I don't regard
it as "fix" but "change to the more common format") ... but that
doesn't match this example at all, which appears to be doing
something strange with as-sets.
> Collapses bgp_attr_print switch 2-byte and 4-byte path cases.
>
> bgp_attr_get_as_size function copied from tcpdump Git repo master.
The formatting of this function doesn't match style(9) or the code
in the rest of this file.
> This brings behavior in-line with newer versions on Linux.
>
> Finally, minor output tweak: add a space after BGP update attribute
> ORIGINATOR_ID's flags to make consistent with other attributes.
>
>
> Index: print-bgp.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/tcpdump/print-bgp.c,v
> retrieving revision 1.17
> diff -u -p -r1.17 print-bgp.c
> --- print-bgp.c 16 Jan 2015 06:40:21 -0000 1.17
> +++ print-bgp.c 14 Oct 2015 00:15:13 -0000
> @@ -140,6 +140,9 @@ struct bgp_attr {
> #define BGP_CONFED_AS_SEQUENCE 3 /* draft-ietf-idr-rfc3065bis-01 */
> #define BGP_CONFED_AS_SET 4 /* draft-ietf-idr-rfc3065bis-01 */
>
> +#define BGP_AS_SEG_TYPE_MIN BGP_AS_SET
> +#define BGP_AS_SEG_TYPE_MAX BGP_CONFED_AS_SET
> +
> static struct tok bgp_as_path_segment_open_values[] = {
> { BGP_AS_SET, " {" },
> { BGP_AS_SEQUENCE, " " },
> @@ -400,6 +403,63 @@ trunc:
> }
> #endif
>
> +/*
> + * bgp_attr_get_as_size
> + *
> + * Try to find the size of the ASs encoded in an as-path. It is not obvious,
> as
> + * both Old speakers that do not support 4 byte AS, and the new speakers
> that do
> + * support, exchange AS-Path with the same path-attribute type value 0x02.
> + */
> +static int
> +bgp_attr_get_as_size (u_int8_t bgpa_type, const u_char *pptr, int len)
> +{
> + const u_char *tptr = pptr;
> +
> + /*
> + * If the path attribute is the optional AS4 path type, then we already
> + * know, that ASs must be encoded in 4 byte format.
> + */
> + if (bgpa_type == BGPTYPE_AS4_PATH) {
> + return 4;
> + }
> +
> + /*
> + * Let us assume that ASs are of 2 bytes in size, and check if the
> AS-Path
> + * TLV is good. If not, ask the caller to try with AS encoded as 4 bytes
> + * each.
> + */
> + while (tptr < pptr + len) {
> + TCHECK(tptr[0]);
> +
> + /*
> + * If we do not find a valid segment type, our guess might be wrong.
> + */
> + if (tptr[0] < BGP_AS_SEG_TYPE_MIN || tptr[0] > BGP_AS_SEG_TYPE_MAX) {
> + goto trunc;
> + }
> + TCHECK(tptr[1]);
> + tptr += 2 + tptr[1] * 2;
> + }
> +
> + /*
> + * If we correctly reached end of the AS path attribute data content,
> + * then most likely ASs were indeed encoded as 2 bytes.
> + */
> + if (tptr == pptr + len) {
> + return 2;
> + }
> +
> +trunc:
> +
> + /*
> + * We can come here, either we did not have enough data, or if we
> + * try to decode 4 byte ASs in 2 byte format. Either way, return 4,
> + * so that calller can try to decode each AS as of 4 bytes. If indeed
> + * there was not enough data, it will crib and end the parse anyways.
> + */
> + return 4;
> +}
> +
> static int
> bgp_attr_print(const struct bgp_attr *attr, const u_char *dat, int len)
> {
> @@ -413,7 +473,6 @@ bgp_attr_print(const struct bgp_attr *at
>
> p = dat;
> tlen = len;
> - asn_bytes = 0;
>
> switch (attr->bgpa_type) {
> case BGPTYPE_ORIGIN:
> @@ -425,17 +484,8 @@ bgp_attr_print(const struct bgp_attr *at
> }
> break;
> case BGPTYPE_AS4_PATH:
> - asn_bytes = 4;
> /* FALLTHROUGH */
> case BGPTYPE_AS_PATH:
> - /*
> - * 2-byte speakers will receive AS4_PATH as well AS_PATH (2-byte).
> - * 4-byte speakers will only receive AS_PATH but it will be 4-byte.
> - * To identify which is the case, compare the length of the path
> - * segment value in bytes, with the path segment length from the
> - * message (counted in # of AS)
> - */
> -
> if (len % 2) {
> printf(" invalid len");
> break;
> @@ -444,11 +494,19 @@ bgp_attr_print(const struct bgp_attr *at
> printf(" empty");
> break;
> }
> +
> + /*
> + * BGP updates exchanged between New speakers that support 4
> + * byte AS, ASs are always encoded in 4 bytes. There is no
> + * definitive way to find this, just by the packet's
> + * contents. So, check for packet's TLV's sanity assuming
> + * 2 bytes first, and it does not pass, assume that ASs are
> + * encoded in 4 bytes format and move on.
> + */
> + asn_bytes = bgp_attr_get_as_size(attr->bgpa_type, dat, len);
> +
> while (p < dat + len) {
> TCHECK(p[0]);
> - if (asn_bytes == 0) {
> - asn_bytes = (len-2)/p[1];
> - }
> printf("%s",
> tok2str(bgp_as_path_segment_open_values,
> "?", p[0]));
> @@ -456,13 +514,10 @@ bgp_attr_print(const struct bgp_attr *at
> for (i = 0; i < p[1] * asn_bytes; i += asn_bytes) {
> TCHECK2(p[2 + i], asn_bytes);
> printf("%s", i == 0 ? "" : " ");
> - if (asn_bytes == 2 || EXTRACT_16BITS(&p[2 + i]))
> - printf("%u%s",
> - EXTRACT_16BITS(&p[2 + i]),
> - asn_bytes == 4 ? "." : "");
> - if (asn_bytes == 4)
> - printf("%u",
> - EXTRACT_16BITS(&p[2 + i + 2]));
> + printf("%u",
> + asn_bytes == 2 ?
> + EXTRACT_16BITS(&p[2 + i]) :
> + EXTRACT_32BITS(&p[2 + i]));
> }
> TCHECK(p[0]);
> printf("%s",
> @@ -549,7 +604,7 @@ bgp_attr_print(const struct bgp_attr *at
> break;
> }
> TCHECK2(p[0], 4);
> - printf("%s",getname(p));
> + printf(" %s", getname(p));
> break;
> case BGPTYPE_CLUSTER_LIST:
> if (len % 4) {
>