]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-isoclns.c
add boundary, infinite loop checks
[tcpdump] / print-isoclns.c
index 6df82300f35d6d8a4c0b646de57b8e58b2fbb117..90299860cfda077f77390ccda1c4bab8dcb7a0a1 100644 (file)
@@ -26,7 +26,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.129 2005-03-09 18:42:51 hannes Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/tcpdump/print-isoclns.c,v 1.138 2005-04-26 07:14:07 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -210,6 +210,83 @@ static struct tok clnp_option_values[] = {
     { 0, NULL }
 };
 
+static struct tok clnp_option_rfd_class_values[] = {
+    { 0x0, "General"},
+    { 0x8, "Address"},
+    { 0x9, "Source Routeing"},
+    { 0xa, "Lifetime"},
+    { 0xb, "PDU Discarded"},
+    { 0xc, "Reassembly"},
+    { 0, NULL }
+};
+
+static struct tok clnp_option_rfd_general_values[] = {
+    { 0x0, "Reason not specified"},
+    { 0x1, "Protocol procedure error"},
+    { 0x2, "Incorrect checksum"},
+    { 0x3, "PDU discarded due to congestion"},
+    { 0x4, "Header syntax error (cannot be parsed)"},
+    { 0x5, "Segmentation needed but not permitted"},
+    { 0x6, "Incomplete PDU received"},
+    { 0x7, "Duplicate option"},
+    { 0, NULL }
+};
+
+static struct tok clnp_option_rfd_address_values[] = {
+    { 0x0, "Destination address unreachable"},
+    { 0x1, "Destination address unknown"},
+    { 0, NULL }
+};
+
+static struct tok clnp_option_rfd_source_routeing_values[] = {
+    { 0x0, "Unspecified source routeing error"},
+    { 0x1, "Syntax error in source routeing field"},
+    { 0x2, "Unknown address in source routeing field"},
+    { 0x3, "Path not acceptable"},
+    { 0, NULL }
+};
+
+static struct tok clnp_option_rfd_lifetime_values[] = {
+    { 0x0, "Lifetime expired while data unit in transit"},
+    { 0x1, "Lifetime expired during reassembly"},
+    { 0, NULL }
+};
+
+static struct tok clnp_option_rfd_pdu_discard_values[] = {
+    { 0x0, "Unsupported option not specified"},
+    { 0x1, "Unsupported protocol version"},
+    { 0x2, "Unsupported security option"},
+    { 0x3, "Unsupported source routeing option"},
+    { 0x4, "Unsupported recording of route option"},
+    { 0, NULL }
+};
+
+static struct tok clnp_option_rfd_reassembly_values[] = {
+    { 0x0, "Reassembly interference"},
+    { 0, NULL }
+};
+
+/* array of 16 error-classes */
+static struct tok *clnp_option_rfd_error_class[] = {
+    clnp_option_rfd_general_values,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    clnp_option_rfd_address_values,
+    clnp_option_rfd_source_routeing_values,
+    clnp_option_rfd_lifetime_values,
+    clnp_option_rfd_pdu_discard_values,
+    clnp_option_rfd_reassembly_values,
+    NULL,
+    NULL,
+    NULL
+};
+
+
 #define ISIS_SUBTLV_EXT_IS_REACH_ADMIN_GROUP           3 /* draft-ietf-isis-traffic-05 */
 #define ISIS_SUBTLV_EXT_IS_REACH_LINK_LOCAL_REMOTE_ID  4 /* draft-ietf-isis-gmpls-extensions */
 #define ISIS_SUBTLV_EXT_IS_REACH_LINK_REMOTE_ID        5 /* draft-ietf-isis-traffic-05 */
@@ -509,7 +586,9 @@ void isoclns_print(const u_int8_t *p, u_int length, u_int caplen)
                break;
 
        case NLPID_NULLNS:
-               (void)printf(", length: %u", length);
+               (void)printf("%slength: %u",
+                            eflag ? "" : ", ",
+                             length);
                break;
 
         case NLPID_Q933:
@@ -517,7 +596,7 @@ void isoclns_print(const u_int8_t *p, u_int length, u_int caplen)
                 break;
 
         case NLPID_IP:
-                ip_print(p+1, length-1);
+               ip_print(gndo, p+1, length-1);
                 break;
 
 #ifdef INET6
@@ -533,7 +612,9 @@ void isoclns_print(const u_int8_t *p, u_int length, u_int caplen)
        default:
                 if (!eflag)
                     printf("OSI NLPID 0x%02x unknown",*p);
-               (void)printf(", length: %u", length);
+               (void)printf("%slength: %u",
+                            eflag ? "" : ", ",
+                             length);
                if (caplen > 1)
                         print_unknown_data(p,"\n\t",caplen);
                break;
@@ -582,6 +663,7 @@ static int clnp_print (const u_int8_t *pptr, u_int length)
         u_int li,source_address_length,dest_address_length, clnp_pdu_type, clnp_flags;
        const struct clnp_header_t *clnp_header;
        const struct clnp_segment_header_t *clnp_segment_header;
+        u_int8_t rfd_error_major,rfd_error_minor;
 
        clnp_header = (const struct clnp_header_t *) pptr;
         TCHECK(*clnp_header);
@@ -668,8 +750,7 @@ static int clnp_print (const u_int8_t *pptr, u_int length)
             u_int op, opli;
             const u_int8_t *tptr;
             
-            if (snapend - pptr < 2)
-                return (0);
+            TCHECK2(*pptr, 2);
             if (li < 2) {
                 printf(", bad opts/li");
                 return (0);
@@ -677,6 +758,7 @@ static int clnp_print (const u_int8_t *pptr, u_int length)
             op = *pptr++;
             opli = *pptr++;
             li -= 2;
+            TCHECK2(*pptr, opli);
             if (opli > li) {
                 printf(", opt (%d) too long", op);
                 return (0);
@@ -684,9 +766,6 @@ static int clnp_print (const u_int8_t *pptr, u_int length)
             li -= opli;
             tptr = pptr;
             
-            if (snapend < pptr)
-                return(0);
-            
             printf("\n\t  %s Option #%u, length %u, value: ",
                    tok2str(clnp_option_values,"Unknown",op),
                    op,
@@ -698,13 +777,21 @@ static int clnp_print (const u_int8_t *pptr, u_int length)
                 printf("%u", *tptr);
                 break;
 
+            case CLNP_OPTION_DISCARD_REASON:
+                rfd_error_major = (*tptr&0xf0) >> 4;
+                rfd_error_minor = *tptr&0x0f;
+                printf("\n\t    Class: %s Error (0x%01x), %s (0x%01x)",
+                       tok2str(clnp_option_rfd_class_values,"Unknown",rfd_error_major),
+                       rfd_error_major,
+                       tok2str(clnp_option_rfd_error_class[rfd_error_major],"Unknown",rfd_error_minor),
+                       rfd_error_minor);
+                break;
+
                 /*
                  * FIXME those are the defined Options that lack a decoder
                  * you are welcome to contribute code ;-)
                  */
 
-            case CLNP_OPTION_DISCARD_REASON:
-
             default:
                 print_unknown_data(tptr,"\n\t  ",opli);
                 break;
@@ -716,24 +803,26 @@ static int clnp_print (const u_int8_t *pptr, u_int length)
 
         switch (clnp_pdu_type) {
 
+        case    CLNP_PDU_ER: /* fall through */
         case   CLNP_PDU_ERP:
+            TCHECK(*pptr);
             if (*(pptr) == NLPID_CLNP) {
-                printf("\n\t-----request packet-----\n\t");
+                printf("\n\t-----original packet-----\n\t");
                 /* FIXME recursion protection */
                 clnp_print(pptr, length-clnp_header->length_indicator);
                 break;
             } 
 
-        case   CLNP_PDU_ER:
         case   CLNP_PDU_DT:
         case   CLNP_PDU_MD:
         case   CLNP_PDU_ERQ:
             
         default:
             /* dump the PDU specific data */
-            printf("\n\t  undecoded non-header data, length %u",length-clnp_header->length_indicator);
-            print_unknown_data(pptr,"\n\t  ",length-(pptr-optr));
-
+            if (length-(pptr-optr) > 0) {
+                printf("\n\t  undecoded non-header data, length %u",length-clnp_header->length_indicator);
+                print_unknown_data(pptr,"\n\t  ",length-(pptr-optr));
+            }
         }
 
         return (1);
@@ -785,6 +874,7 @@ esis_print(const u_int8_t *pptr, u_int length)
        }
 
        esis_header = (const struct esis_header_t *) pptr;
+        TCHECK(*esis_header);
         li = esis_header->length_indicator;
         optr = pptr;
 
@@ -834,7 +924,8 @@ esis_print(const u_int8_t *pptr, u_int length)
         /* do not attempt to verify the checksum if it is zero */
         if (EXTRACT_16BITS(esis_header->cksum) == 0)
                 printf("(unverified)");
-            else printf("(%s)", osi_cksum(pptr, li) ? "incorrect" : "correct");
+        else
+                printf("(%s)", osi_cksum(pptr, li) ? "incorrect" : "correct");
 
         printf(", holding time: %us, length indicator: %u",EXTRACT_16BITS(esis_header->holdtime),li);
 
@@ -846,25 +937,72 @@ esis_print(const u_int8_t *pptr, u_int length)
 
        switch (esis_pdu_type) {
        case ESIS_PDU_REDIRECT: {
-               const u_int8_t *dst, *snpa, *tptr;
+               const u_int8_t *dst, *snpa, *neta;
+               u_int dstl, snpal, netal;
 
-               dst = pptr; pptr += *pptr + 1;
-               if (pptr > snapend)
+               TCHECK(*pptr);
+               if (li < 1) {
+                       printf(", bad redirect/li");
                        return;
-               printf("\n\t  %s", isonsap_string(dst+1,*dst));
-               snpa = pptr; pptr += *pptr + 1;
-               tptr = pptr;   pptr += *pptr + 1;
-               if (pptr > snapend)
+               }
+               dstl = *pptr;
+               pptr++;
+               li--;
+               TCHECK2(*pptr, dstl);
+               if (li < dstl) {
+                       printf(", bad redirect/li");
+                       return;
+               }
+               dst = pptr;
+               pptr += dstl;
+                li -= dstl;
+               printf("\n\t  %s", isonsap_string(dst,dstl));
+
+               TCHECK(*pptr);
+               if (li < 1) {
+                       printf(", bad redirect/li");
+                       return;
+               }
+               snpal = *pptr;
+               pptr++;
+               li--;
+               TCHECK2(*pptr, snpal);
+               if (li < snpal) {
+                       printf(", bad redirect/li");
+                       return;
+               }
+               snpa = pptr;
+               pptr += snpal;
+                li -= snpal;
+               TCHECK(*pptr);
+               if (li < 1) {
+                       printf(", bad redirect/li");
+                       return;
+               }
+               netal = *pptr;
+               pptr++;
+               TCHECK2(*pptr, netal);
+               if (li < netal) {
+                       printf(", bad redirect/li");
                        return;
+               }
+               neta = pptr;
+               pptr += netal;
+                li -= netal;
 
-               if (tptr[0] == 0)
-                       printf("\n\t  %s", etheraddr_string(&snpa[1]));
+               if (netal == 0)
+                       printf("\n\t  %s", etheraddr_string(snpa));
                else
-                       printf("\n\t  %s", isonsap_string(tptr+1,*tptr));
+                       printf("\n\t  %s", isonsap_string(neta,netal));
                break;
        }
 
        case ESIS_PDU_ESH:
+            TCHECK(*pptr);
+            if (li < 1) {
+                printf(", bad esh/li");
+                return;
+            }
             source_address_number = *pptr;
             pptr++;
             li--;
@@ -872,23 +1010,47 @@ esis_print(const u_int8_t *pptr, u_int length)
             printf("\n\t  Number of Source Addresses: %u", source_address_number);
            
             while (source_address_number > 0) {
+                TCHECK(*pptr);
+               if (li < 1) {
+                    printf(", bad esh/li");
+                   return;
+               }
                 source_address_length = *pptr;
+                pptr++;
+               li--;
+
+                TCHECK2(*pptr, source_address_length);
+               if (li < source_address_length) {
+                    printf(", bad esh/li");
+                   return;
+               }
                 printf("\n\t  NET (length: %u): %s",
                        source_address_length,
-                       isonsap_string(pptr+1,source_address_length));
-
-                pptr += source_address_length+1;
-                li -= source_address_length+1;
+                       isonsap_string(pptr,source_address_length));
+                pptr += source_address_length;
+                li -= source_address_length;
                 source_address_number--;
             }
 
             break;
 
        case ESIS_PDU_ISH: {
+            TCHECK(*pptr);
+            if (li < 1) {
+                printf(", bad ish/li");
+                return;
+            }
             source_address_length = *pptr;
-            printf("\n\t  NET (length: %u): %s", source_address_length, isonsap_string(pptr+1, source_address_length));
-            pptr += source_address_length+1;
-            li -= source_address_length +1;
+            pptr++;
+            li--;
+            TCHECK2(*pptr, source_address_length);
+            if (li < source_address_length) {
+                printf(", bad ish/li");
+                return;
+            }
+            printf("\n\t  NET (length: %u): %s", source_address_length, isonsap_string(pptr, source_address_length));
+            pptr += source_address_length;
+            li -= source_address_length;
             break;
        }
 
@@ -905,8 +1067,7 @@ esis_print(const u_int8_t *pptr, u_int length)
             u_int op, opli;
             const u_int8_t *tptr;
             
-            if (snapend - pptr < 2)
-                return;
+            TCHECK2(*pptr, 2);
             if (li < 2) {
                 printf(", bad opts/li");
                 return;
@@ -921,9 +1082,6 @@ esis_print(const u_int8_t *pptr, u_int length)
             li -= opli;
             tptr = pptr;
             
-            if (snapend < pptr)
-                return;
-            
             printf("\n\t  %s Option #%u, length %u, value: ",
                    tok2str(esis_option_values,"Unknown",op),
                    op,
@@ -932,12 +1090,13 @@ esis_print(const u_int8_t *pptr, u_int length)
             switch (op) {
 
             case ESIS_OPTION_ES_CONF_TIME:
+                TCHECK2(*pptr, 2);
                 printf("%us", EXTRACT_16BITS(tptr));
                 break;
-                
 
             case ESIS_OPTION_PROTOCOLS:
                 while (opli>0) {
+                    TCHECK(*pptr);
                     printf("%s (0x%02x)",
                            tok2str(nlpid_values,
                                    "unknown",
@@ -969,6 +1128,8 @@ esis_print(const u_int8_t *pptr, u_int length)
                 print_unknown_data(pptr,"\n\t  ",opli);
             pptr += opli;
         }
+trunc:
+       return;
 }   
 
 /* shared routine for printing system, node and lsp-ids */
@@ -1818,6 +1979,9 @@ static int isis_print (const u_int8_t *p, u_int length)
                tlv_type,
                tlv_len);
 
+        if (tlv_len == 0) /* something is malformed */
+            break;
+
         /* now check if we have a decoder otherwise do a hexdump at the end*/
        switch (tlv_type) {
        case ISIS_TLV_AREA_ADDR:
@@ -1848,9 +2012,13 @@ static int isis_print (const u_int8_t *p, u_int length)
            break;
 
         case ISIS_TLV_ISNEIGH_VARLEN:
-            if (!TTEST2(*tptr, 1))
+            if (!TTEST2(*tptr, 1) || tmp < 3) /* min. TLV length */
                goto trunctlv;
-           lan_alen = *tptr++; /* LAN adress length */
+           lan_alen = *tptr++; /* LAN address length */
+           if (lan_alen == 0) {
+                printf("\n\t      LAN address length 0 bytes (invalid)");
+                break;
+            }
             tmp --;
             printf("\n\t      LAN address length %u bytes ",lan_alen);
            while (tmp >= lan_alen) {
@@ -2261,6 +2429,10 @@ static int isis_print (const u_int8_t *p, u_int length)
                 if (!TTEST2(*tptr, 1))
                     goto trunctlv;
                 prefix_len=*tptr++; /* read out prefix length in semioctets*/
+                if (prefix_len < 2) {
+                    printf("\n\t\tAddress: prefix length %u < 2", prefix_len);
+                    break;
+                }
                 tmp--;
                 if (!TTEST2(*tptr, prefix_len/2))
                     goto trunctlv;
@@ -2350,3 +2522,11 @@ osi_cksum(const u_int8_t *tptr, u_int len)
        }
        return (c0 | c1);
 }
+
+
+/*
+ * Local Variables:
+ * c-style: whitesmith
+ * c-basic-offset: 8
+ * End:
+ */