#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 <tcpdump-stdinc.h>
#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 */
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"},
#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, "{ "},
#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
{ 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)
{
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;
/* 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*/
/* 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");
((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;
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
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:
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);
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)
{
const u_char *tptr;
char buf[MAXHOSTNAMELEN + 100];
char tokbuf[TOKBUFSIZE];
+ int as_size;
tptr = pptr;
tlen=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");
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:
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) {
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):
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 {
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):
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));
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:
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",
}
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 ) {
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);
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",
trunc:
printf(" [|BGP]");
}
+
+/*
+ * Local Variables:
+ * c-style: whitesmith
+ * c-basic-offset: 4
+ * End:
+ */