X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/1c617b856ce38d5b1fbf72a181f6f69afa9e12df..refs/heads/tcpdump-4.1:/print-bgp.c diff --git a/print-bgp.c b/print-bgp.c index 0bbdb40a..d77802dd 100644 --- a/print-bgp.c +++ b/print-bgp.c @@ -36,7 +36,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/tcpdump/print-bgp.c,v 1.114 2007-07-14 22:24:54 guy Exp $"; + "@(#) $Header: /tcpdump/master/tcpdump/print-bgp.c,v 1.118 2007-12-07 15:54:52 hannes Exp $"; #endif #include @@ -145,6 +145,8 @@ struct bgp_attr { #define BGPTYPE_MP_REACH_NLRI 14 /* RFC2283 */ #define BGPTYPE_MP_UNREACH_NLRI 15 /* RFC2283 */ #define BGPTYPE_EXTD_COMMUNITIES 16 /* draft-ietf-idr-bgp-ext-communities */ +#define BGPTYPE_AS4_PATH 17 /* RFC4893 */ +#define BGPTYPE_AGGREGATOR4 18 /* RFC4893 */ #define BGPTYPE_PMSI_TUNNEL 22 /* draft-ietf-l3vpn-2547bis-mcast-bgp-02.txt */ #define BGPTYPE_ATTR_SET 128 /* draft-marques-ppvpn-ibgp */ @@ -153,11 +155,13 @@ struct bgp_attr { static struct tok bgp_attr_values[] = { { BGPTYPE_ORIGIN, "Origin"}, { BGPTYPE_AS_PATH, "AS Path"}, + { BGPTYPE_AS4_PATH, "AS4 Path"}, { BGPTYPE_NEXT_HOP, "Next Hop"}, { BGPTYPE_MULTI_EXIT_DISC, "Multi Exit Discriminator"}, { BGPTYPE_LOCAL_PREF, "Local Preference"}, { BGPTYPE_ATOMIC_AGGREGATE, "Atomic Aggregate"}, { BGPTYPE_AGGREGATOR, "Aggregator"}, + { BGPTYPE_AGGREGATOR4, "Aggregator4"}, { BGPTYPE_COMMUNITIES, "Community"}, { BGPTYPE_ORIGINATOR_ID, "Originator ID"}, { BGPTYPE_CLUSTER_LIST, "Cluster List"}, @@ -178,6 +182,9 @@ static struct tok bgp_attr_values[] = { #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_SEQUENCE, ""}, { BGP_AS_SET, "{ "}, @@ -339,7 +346,8 @@ static struct tok bgp_pmsi_flag_values[] = { #define SAFNUM_MULTICAST_VPN 5 #define SAFNUM_TUNNEL 64 /* XXX */ #define SAFNUM_VPLS 65 /* XXX */ -#define SAFNUM_MDT 66 /* XXX */ +/* draft-nalawade-idr-mdt-safi-03 */ +#define SAFNUM_MDT 66 /* Section 4.3.4 of draft-rosen-rfc2547bis-03.txt */ #define SAFNUM_VPNUNICAST 128 #define SAFNUM_VPNMULTICAST 129 @@ -457,6 +465,29 @@ static struct tok bgp_extd_comm_ospf_rtype_values[] = { { 0, NULL }, }; +#define TOKBUFSIZE 128 +static char astostr[20]; + +/* + * as_printf + * + * Convert an AS number into a string and return string pointer. + * + * Bepending on bflag is set or not, AS number is converted into ASDOT notation + * or plain number notation. + * + */ +static char * +as_printf (char *str, int size, u_int asnum) +{ + if (!bflag || asnum <= 0xFFFF) { + snprintf(str, size, "%u", asnum); + } else { + snprintf(str, size, "%u.%u", asnum >> 16, asnum & 0xFFFF); + } + return str; +} + int decode_prefix4(const u_char *pptr, char *buf, u_int buflen) { @@ -544,10 +575,12 @@ bgp_vpn_ip_print (const u_char *pptr, u_int addr_length) { TCHECK2(pptr[0], sizeof(struct in_addr)); snprintf(pos, sizeof(addr), "%s", ipaddr_string(pptr)); break; +#ifdef INET6 case (sizeof(struct in6_addr) << 3): /* 128 */ TCHECK2(pptr[0], sizeof(struct in6_addr)); snprintf(pos, sizeof(addr), "%s", ip6addr_string(pptr)); break; +#endif default: snprintf(pos, sizeof(addr), "bogus address length %u", addr_length); break; @@ -631,10 +664,12 @@ bgp_vpn_rd_print (const u_char *pptr) { /* ok lets load the RD format */ switch (EXTRACT_16BITS(pptr)) { - /* AS:IP-address fmt*/ + /* 2-byte-AS:number fmt*/ case 0: - snprintf(pos, sizeof(rd) - (pos - rd), "%u:%u.%u.%u.%u", - EXTRACT_16BITS(pptr+2), *(pptr+4), *(pptr+5), *(pptr+6), *(pptr+7)); + snprintf(pos, sizeof(rd) - (pos - rd), "%u:%u (= %u.%u.%u.%u)", + EXTRACT_16BITS(pptr+2), + EXTRACT_32BITS(pptr+4), + *(pptr+4), *(pptr+5), *(pptr+6), *(pptr+7)); break; /* IP-address:AS fmt*/ @@ -645,9 +680,10 @@ bgp_vpn_rd_print (const u_char *pptr) { /* 4-byte-AS:number fmt*/ case 2: - snprintf(pos, sizeof(rd) - (pos - rd), "%u:%u (%u.%u.%u.%u:%u)", - EXTRACT_32BITS(pptr+2), EXTRACT_16BITS(pptr+6), - *(pptr+2), *(pptr+3), *(pptr+4), *(pptr+5), EXTRACT_16BITS(pptr+6)); + snprintf(pos, sizeof(rd) - (pos - rd), "%s:%u (%u.%u.%u.%u:%u)", + as_printf(astostr, sizeof(astostr), EXTRACT_32BITS(pptr+2)), + EXTRACT_16BITS(pptr+6), *(pptr+2), *(pptr+3), *(pptr+4), + *(pptr+5), EXTRACT_16BITS(pptr+6)); break; default: snprintf(pos, sizeof(rd) - (pos - rd), "unknown RD format"); @@ -685,9 +721,9 @@ decode_rt_routing_info(const u_char *pptr, char *buf, u_int buflen) ((u_char *)&route_target)[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff); } - snprintf(buf, buflen, "origin AS: %u, route target %s", - EXTRACT_32BITS(pptr+1), - bgp_vpn_rd_print((u_char *)&route_target)); + snprintf(buf, buflen, "origin AS: %s, route target %s", + as_printf(astostr, sizeof(astostr), EXTRACT_32BITS(pptr+1)), + bgp_vpn_rd_print((u_char *)&route_target)); return 5 + (plen + 7) / 8; @@ -733,6 +769,55 @@ trunc: return -2; } +/* + * +-------------------------------+ + * | | + * | RD:IPv4-address (12 octets) | + * | | + * +-------------------------------+ + * | MDT Group-address (4 octets) | + * +-------------------------------+ + */ + +#define MDT_VPN_NLRI_LEN 16 + +static int +decode_mdt_vpn_nlri(const u_char *pptr, char *buf, u_int buflen) +{ + + const u_char *rd; + const u_char *vpn_ip; + + TCHECK(pptr[0]); + + /* if the NLRI is not predefined length, quit.*/ + if (*pptr != MDT_VPN_NLRI_LEN * NBBY) + return -1; + pptr++; + + /* RD */ + TCHECK2(pptr[0], 8); + rd = pptr; + pptr+=8; + + /* IPv4 address */ + TCHECK2(pptr[0], sizeof(struct in_addr)); + vpn_ip = pptr; + pptr+=sizeof(struct in_addr); + + /* MDT Group Address */ + TCHECK2(pptr[0], sizeof(struct in_addr)); + + snprintf(buf, buflen, "RD: %s, VPN IP Address: %s, MC Group Address: %s", + bgp_vpn_rd_print(rd), ipaddr_string(vpn_ip), ipaddr_string(pptr)); + + return MDT_VPN_NLRI_LEN + 1; + + trunc: + +return -2; +} + #define BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI 1 #define BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI 2 #define BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI 3 @@ -778,9 +863,10 @@ decode_multicast_vpn(const u_char *pptr, char *buf, u_int buflen) case BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI: TCHECK2(pptr[0], BGP_VPN_RD_LEN + 4); offset = strlen(buf); - snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %u", - bgp_vpn_rd_print(pptr), - EXTRACT_32BITS(pptr + BGP_VPN_RD_LEN)); + snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s", + bgp_vpn_rd_print(pptr), + as_printf(astostr, sizeof(astostr), + EXTRACT_32BITS(pptr + BGP_VPN_RD_LEN))); break; case BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI: @@ -813,9 +899,10 @@ decode_multicast_vpn(const u_char *pptr, char *buf, u_int buflen) case BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN: TCHECK2(pptr[0], BGP_VPN_RD_LEN); offset = strlen(buf); - snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %u", - bgp_vpn_rd_print(pptr), - EXTRACT_32BITS(pptr + BGP_VPN_RD_LEN)); + snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s", + bgp_vpn_rd_print(pptr), + as_printf(astostr, sizeof(astostr), + EXTRACT_32BITS(pptr + BGP_VPN_RD_LEN))); pptr += BGP_VPN_RD_LEN; bgp_vpn_sg_print(pptr, buf, buflen); @@ -1089,6 +1176,63 @@ trunc: return -2; } +/* + * 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 *pptr, int len) { @@ -1104,6 +1248,7 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *pptr, int len) const u_char *tptr; char buf[MAXHOSTNAMELEN + 100]; char tokbuf[TOKBUFSIZE]; + int as_size; tptr = pptr; tlen=len; @@ -1121,6 +1266,11 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *pptr, int len) } break; + + /* + * Process AS4 byte path and AS2 byte path attributes here. + */ + case BGPTYPE_AS4_PATH: case BGPTYPE_AS_PATH: if (len % 2) { printf("invalid len"); @@ -1131,21 +1281,35 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *pptr, int len) 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. + */ + as_size = bgp_attr_get_as_size(attr->bgpa_type, pptr, len); + while (tptr < pptr + len) { TCHECK(tptr[0]); printf("%s", tok2strbuf(bgp_as_path_segment_open_values, "?", tptr[0], tokbuf, sizeof(tokbuf))); - for (i = 0; i < tptr[1] * 2; i += 2) { - TCHECK2(tptr[2 + i], 2); - printf("%u ", EXTRACT_16BITS(&tptr[2 + i])); + for (i = 0; i < tptr[1] * as_size; i += as_size) { + TCHECK2(tptr[2 + i], as_size); + printf("%s ", + as_printf(astostr, sizeof(astostr), + as_size == 2 ? + EXTRACT_16BITS(&tptr[2 + i]) : + EXTRACT_32BITS(&tptr[2 + i]))); } TCHECK(tptr[0]); printf("%s", tok2strbuf(bgp_as_path_segment_close_values, "?", tptr[0], tokbuf, sizeof(tokbuf))); TCHECK(tptr[1]); - tptr += 2 + tptr[1] * 2; + tptr += 2 + tptr[1] * as_size; } break; case BGPTYPE_NEXT_HOP: @@ -1169,14 +1333,36 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *pptr, int len) if (len != 0) printf("invalid len"); break; - case BGPTYPE_AGGREGATOR: - if (len != 6) { + case BGPTYPE_AGGREGATOR: + + /* + * Depending on the AS encoded is of 2 bytes or of 4 bytes, + * the length of this PA can be either 6 bytes or 8 bytes. + */ + if (len != 6 && len != 8) { + printf("invalid len"); + break; + } + TCHECK2(tptr[0], len); + if (len == 6) { + printf(" AS #%s, origin %s", + as_printf(astostr, sizeof(astostr), EXTRACT_16BITS(tptr)), + getname(tptr + 2)); + } else { + printf(" AS #%s, origin %s", + as_printf(astostr, sizeof(astostr), + EXTRACT_32BITS(tptr)), getname(tptr + 4)); + } + break; + case BGPTYPE_AGGREGATOR4: + if (len != 8) { printf("invalid len"); break; } - TCHECK2(tptr[0], 6); - printf(" AS #%u, origin %s", EXTRACT_16BITS(tptr), - getname(tptr + 2)); + TCHECK2(tptr[0], 8); + printf(" AS #%s, origin %s", + as_printf(astostr, sizeof(astostr), EXTRACT_32BITS(tptr)), + getname(tptr + 4)); break; case BGPTYPE_COMMUNITIES: if (len % 4) { @@ -1254,6 +1440,7 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *pptr, int len) case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST): case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST): case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): + case (AFNUM_INET<<8 | SAFNUM_MDT): #ifdef INET6 case (AFNUM_INET6<<8 | SAFNUM_UNICAST): case (AFNUM_INET6<<8 | SAFNUM_MULTICAST): @@ -1300,7 +1487,8 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *pptr, int len) case (AFNUM_INET<<8 | SAFNUM_LABUNICAST): case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO): case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): - if (tlen < (int)sizeof(struct in_addr)) { + case (AFNUM_INET<<8 | SAFNUM_MDT): + if (tlen < (int)sizeof(struct in_addr)) { printf("invalid len"); tlen = 0; } else { @@ -1484,6 +1672,16 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *pptr, int len) else printf("\n\t %s", buf); break; + + case (AFNUM_INET<<8 | SAFNUM_MDT): + advance = decode_mdt_vpn_nlri(tptr, buf, sizeof(buf)); + if (advance == -1) + printf("\n\t (illegal prefix length)"); + else if (advance == -2) + goto trunc; + else + printf("\n\t %s", buf); + break; #ifdef INET6 case (AFNUM_INET6<<8 | SAFNUM_UNICAST): case (AFNUM_INET6<<8 | SAFNUM_MULTICAST): @@ -1686,6 +1884,15 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *pptr, int len) else printf("\n\t %s", buf); break; + case (AFNUM_INET<<8 | SAFNUM_MDT): + advance = decode_mdt_vpn_nlri(tptr, buf, sizeof(buf)); + if (advance == -1) + printf("\n\t (illegal prefix length)"); + else if (advance == -2) + goto trunc; + else + printf("\n\t %s", buf); + break; case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): /* fall through */ case (AFNUM_INET6<<8 | SAFNUM_MULTICAST_VPN): advance = decode_multicast_vpn(tptr, buf, sizeof(buf)); @@ -1732,8 +1939,9 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *pptr, int len) switch(extd_comm) { case BGP_EXT_COM_RT_0: case BGP_EXT_COM_RO_0: - printf(": %u:%s", + printf(": %u:%u (= %s)", EXTRACT_16BITS(tptr+2), + EXTRACT_32BITS(tptr+4), getname(tptr+4)); break; case BGP_EXT_COM_RT_1: @@ -1745,10 +1953,10 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *pptr, int len) break; case BGP_EXT_COM_RT_2: case BGP_EXT_COM_RO_2: - printf(": %u:%u", - EXTRACT_32BITS(tptr+2), - EXTRACT_16BITS(tptr+6)); - break; + printf(": %s:%u", + as_printf(astostr, sizeof(astostr), + EXTRACT_32BITS(tptr+2)), EXTRACT_16BITS(tptr+6)); + break; case BGP_EXT_COM_LINKBAND: bw.i = EXTRACT_32BITS(tptr+2); printf(": bandwidth: %.3f Mbps", @@ -1855,8 +2063,9 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *pptr, int len) } case BGPTYPE_ATTR_SET: TCHECK2(tptr[0], 4); - printf("\n\t Origin AS: %u", EXTRACT_32BITS(tptr)); - tptr+=4; + printf("\n\t Origin AS: %s", + as_printf(astostr, sizeof(astostr), EXTRACT_32BITS(tptr))); + tptr+=4; len -=4; while (len >= 2 ) { @@ -1926,7 +2135,8 @@ bgp_open_print(const u_char *dat, int length) memcpy(&bgpo, dat, BGP_OPEN_SIZE); printf("\n\t Version %d, ", bgpo.bgpo_version); - printf("my AS %u, ", ntohs(bgpo.bgpo_myas)); + printf("my AS %s, ", + as_printf(astostr, sizeof(astostr), ntohs(bgpo.bgpo_myas))); printf("Holdtime %us, ", ntohs(bgpo.bgpo_holdtime)); printf("ID %s", getname((u_char *)&bgpo.bgpo_id)); printf("\n\t Optional parameters, length: %u", bgpo.bgpo_optlen); @@ -2002,6 +2212,18 @@ bgp_open_print(const u_char *dat, int length) case BGP_CAPCODE_RR: case BGP_CAPCODE_RR_CISCO: break; + case BGP_CAPCODE_AS_NEW: + + /* + * Extract the 4 byte AS number encoded. + */ + TCHECK2(opt[i + BGP_OPT_SIZE + 2], cap_len); + if (cap_len == 4) { + printf("\n\t\t 4 Byte AS %s", + as_printf(astostr, sizeof(astostr), + EXTRACT_32BITS(opt + i + BGP_OPT_SIZE + 2))); + } + break; default: TCHECK2(opt[i+BGP_OPT_SIZE+2],cap_len); printf("\n\t\tno decoder for Capability %u", @@ -2371,3 +2593,10 @@ bgp_print(const u_char *dat, int length) trunc: printf(" [|BGP]"); } + +/* + * Local Variables: + * c-style: whitesmith + * c-basic-offset: 4 + * End: + */