]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-bgp.c
Fix the pointer tests in the non-ndoified TTEST2() macro as well.
[tcpdump] / print-bgp.c
index 0bbdb40abb6e5d2d445c8dcf89d15b3102b9b541..d77802dd734b14476744479aac1589de73a9ad36 100644 (file)
@@ -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 <tcpdump-stdinc.h>
@@ -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:
+ */