fix tcp reassembly to work again for
authorsahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 14 Jun 2006 11:51:25 +0000 (11:51 +0000)
committersahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 14 Jun 2006 11:51:25 +0000 (11:51 +0000)
ldap   and ldap+sasl

remove a recent ber length validation in packet-ber.c that cant work and breaks reassembly  and also makes all ber pacvket sspanning multiple segments show up as malformed packets.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@18465 f5534014-38df-0310-8fa8-9805f1628bb7

asn1/ldap/packet-ldap-template.c
epan/dissectors/packet-ber.c
epan/dissectors/packet-ldap.c

index ab6c2ee541a5015961c5ccc7758b7c0c2dbef9b5..8cdfbfb2250163592122e5d842896db54cfc85cd 100644 (file)
@@ -489,27 +489,6 @@ dissect_ldap_payload(tvbuff_t *tvb, packet_info *pinfo,
 
     if (rest_is_pad && length_remaining < 6) return;
 
-    /*
-     * The frame begins
-     * with a "Sequence Of" header.
-     * Can we do reassembly?
-     */
-    if (ldap_desegment && pinfo->can_desegment) {
-        /*
-         * Yes - is the "Sequence Of" header split across segment
-         * boundaries?  We require at least 6 bytes for the header
-         * which allows for a 4 byte length (ASN.1 BER).
-         */
-        if (length_remaining < 6) {
-         /* stop if the caller says that we are given all data and the rest is padding
-          * this is for the SASL GSSAPI case when the data is only signed and not sealed
-          */
-          pinfo->desegment_offset = offset;
-          pinfo->desegment_len = 6 - length_remaining;
-          return;
-        }
-    }
-
     /*
      * OK, try to read the "Sequence Of" header; this gets the total
      * length of the LDAP message.
@@ -544,29 +523,6 @@ dissect_ldap_payload(tvbuff_t *tvb, packet_info *pinfo,
        msg_len = length_remaining;
     }
 
-    /*
-     * Is the message split across segment boundaries?
-     */
-    if (length_remaining < msg_len) {
-        /* provide a hint to TCP where the next PDU starts */
-        pinfo->want_pdu_tracking=2;
-        pinfo->bytes_until_next_pdu= msg_len - length_remaining;
-        /*
-         * Can we do reassembly?
-         */
-        if (ldap_desegment && pinfo->can_desegment) {
-           /*
-            * Yes.  Tell the TCP dissector where the data for this message
-            * starts in the data it handed us, and how many more bytes
-            * we need, and return.
-            */
-           pinfo->desegment_offset = offset;
-           pinfo->desegment_len = msg_len - length_remaining;
-
-           return;
-        }
-    }
-
     /*
      * Construct a tvbuff containing the amount of the payload we have
      * available.  Make its reported length the amount of data in the
@@ -674,27 +630,6 @@ dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean i
      */
     length_remaining = tvb_ensure_length_remaining(tvb, offset);
 
-    /*
-     * Try to find out if we have a plain LDAP buffer
-     * with a "Sequence Of" header or a SASL buffer with
-     * Can we do reassembly?
-     */
-    if (ldap_desegment && pinfo->can_desegment) {
-        /*
-         * Yes - is the "Sequence Of" header split across segment
-         * boundaries?  We require at least 6 bytes for the header
-         * which allows for a 4 byte length (ASN.1 BER).
-        * For the SASL case we need at least 4 bytes, so this is
-        * no problem here because we check for 6 bytes ans sasl buffers
-        * with less than 2 bytes should not exist...
-         */
-        if (length_remaining < 6) {
-           pinfo->desegment_offset = offset;
-           pinfo->desegment_len = 6 - length_remaining;
-           return;
-        }
-    }
-
     /* It might still be a packet containing a SASL security layer
      * but its just that we never saw the BIND packet.
      * check if it looks like it could be a SASL blob here
@@ -767,28 +702,6 @@ dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean i
         return;
       }
 
-      /*
-       * Is the buffer split across segment boundaries?
-       */
-      if (length_remaining < sasl_msg_len) {
-        /* provide a hint to TCP where the next PDU starts */
-        pinfo->want_pdu_tracking = 2;
-        pinfo->bytes_until_next_pdu= sasl_msg_len - length_remaining;
-        /*
-         * Can we do reassembly?
-         */
-        if (ldap_desegment && pinfo->can_desegment) {
-          /*
-           * Yes.  Tell the TCP dissector where the data for this message
-           * starts in the data it handed us, and how many more bytes we
-           * need, and return.
-           */
-          pinfo->desegment_offset = offset;
-          pinfo->desegment_len = sasl_msg_len - length_remaining;
-          return;
-        }
-      }
-
       /*
        * Construct a tvbuff containing the amount of the payload we have
        * available.  Make its reported length the amount of data in the PDU.
@@ -1157,9 +1070,106 @@ static void dissect_NetLogon_PDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
 }
 
 
+static guint 
+get_sasl_ldap_pdu_len(tvbuff_t *tvb, int offset)
+{
+       /* sasl encapsulated ldap is 4 bytes plus the length in size */
+       return tvb_get_ntohl(tvb, offset)+4;
+}
+
+static void 
+dissect_sasl_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
+       return;
+}
+
+static guint 
+get_normal_ldap_pdu_len(tvbuff_t *tvb, int offset)
+{
+       guint32 len;
+       gboolean ind;
+       int data_offset;
+
+       /* normal ldap is tag+len bytes plus the length
+        * offset==0 is where the tag is 
+        * offset==1 is where length starts
+        */
+       data_offset=get_ber_length(NULL, tvb, 1, &len, &ind);
+       return len+data_offset;
+}
+
+static void 
+dissect_normal_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
+       return;
+}
+
+
 static void
 dissect_ldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
+       /* Here we must take care of reassembly but this is tricky since
+        * depending on whether SASL is present or not, the heuristics
+        * will be very different.
+        */
+       if(ldap_desegment && (tvb_length(tvb)==tvb_reported_length(tvb))){
+               guint32 len;
+
+               /* check for a SASL header, i.e. four byte integer where the
+                * first two bytes are 0x00 and the value is <64k and >2
+                * (>2 to fight false positives, 0x00000000 is a common
+                *     "random" tcp payload)
+                * (no SASL ldap PDUs are ever going to be >64k in size?)
+                *
+                * Following the SASL header is a GSSAPI blob so the next byte
+                * is always 0x60. (only true for MS SASL LDAP, there are other
+                * blobs that may follow in real-world)
+                */
+               len=tvb_get_ntohl(tvb, 0);
+               if( (len<65535)
+               &&  (len>2)
+               &&  (tvb_get_guint8(tvb, 4)==0x60)){
+                       if(len<=tvb_length_remaining(tvb, 4)){
+                               /* we have a full ldap pdu */
+                               dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
+                               return;
+                       } else {
+                               /* we have to do reassembly */
+                               tcp_dissect_pdus(tvb, pinfo, tree, ldap_desegment, 4, get_sasl_ldap_pdu_len, dissect_sasl_ldap_pdu);
+                               return;
+                       }
+               }
+               /* check if it is a normal BER encoded LDAP packet
+                * i.e. first byte is 0x30 followed by a length that is 
+                * <64k
+                * (no ldap PDUs are ever >64kb? )
+                */
+               if(tvb_get_guint8(tvb, 0)==0x30){
+                       gboolean ind;
+                       int data_offset;
+
+                       /* check that length makes sense */
+                       data_offset=get_ber_length(NULL, tvb, 1, &len, &ind);
+
+                       /* dont check ind since indefinite length is never used for ldap (famous last words)*/
+                       if(len<2 || len>65535){
+                               return;
+                       }
+
+                       if(len<=tvb_length_remaining(tvb, data_offset)){
+                               /* we have a full ldap pdu */
+                               dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
+                               return;
+                       } else {
+                               /* we have to do reassembly */
+                               tcp_dissect_pdus(tvb, pinfo, tree, ldap_desegment, 4, get_normal_ldap_pdu_len, dissect_normal_ldap_pdu);
+                               return;
+                       }
+               }
+       }
+
        dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
        return;
 }
index c07fb54601ac4e6dca31bada3df43cca6c4e20c4..d4f4777358aaa532d64464899f8f23693263e8a2 100644 (file)
@@ -106,7 +106,6 @@ static gint ett_ber_unknown = -1;
 static gint ett_ber_SEQUENCE = -1;
 
 static gboolean show_internal_ber_fields = FALSE;
-static gboolean verify_ber_length_field = TRUE;
 
 proto_item *ber_last_created_item=NULL;
 
@@ -530,16 +529,6 @@ get_ber_length(proto_tree *tree, tvbuff_t *tvb, int offset, guint32 *length, gbo
                }
        }
 
-       if(verify_ber_length_field){
-         /* check that the length is sane */
-         if(tmp_length>(guint32)tvb_reported_length_remaining(tvb,offset)){
-           proto_tree_add_text(tree, tvb, old_offset, offset-old_offset, "BER: Error length:%u longer than tvb_reported_length_remaining:%d",tmp_length, tvb_reported_length_remaining(tvb, offset));
-           /* force the appropriate exception */
-           tvb_ensure_bytes_exist(tvb, offset, tmp_length);
-           /*tmp_length = (guint32)tvb_reported_length_remaining(tvb,offset);*/
-         }
-       }
-
        if (length)
                *length = tmp_length;
        if (ind)
@@ -2398,10 +2387,6 @@ proto_register_ber(void)
        "Whether the dissector should also display internal"
        " ASN.1 BER details such as Identifier and Length fields", &show_internal_ber_fields);
 
-    prefs_register_bool_preference(ber_module, "verify_length",
-       "Verify length",
-       "Verify that the current packet contains (at least) the number of bytes indicated by the length field", &verify_ber_length_field);
-
     ber_oid_dissector_table = register_dissector_table("ber.oid", "BER OID Dissectors", FT_STRING, BASE_NONE);
 }
 
index 5cecc00503af3c8c66ae971e22445e5447e4af8f..8304e86b175b223e13be3044ce699990890054f2 100644 (file)
@@ -2675,27 +2675,6 @@ dissect_ldap_payload(tvbuff_t *tvb, packet_info *pinfo,
 
     if (rest_is_pad && length_remaining < 6) return;
 
-    /*
-     * The frame begins
-     * with a "Sequence Of" header.
-     * Can we do reassembly?
-     */
-    if (ldap_desegment && pinfo->can_desegment) {
-        /*
-         * Yes - is the "Sequence Of" header split across segment
-         * boundaries?  We require at least 6 bytes for the header
-         * which allows for a 4 byte length (ASN.1 BER).
-         */
-        if (length_remaining < 6) {
-         /* stop if the caller says that we are given all data and the rest is padding
-          * this is for the SASL GSSAPI case when the data is only signed and not sealed
-          */
-          pinfo->desegment_offset = offset;
-          pinfo->desegment_len = 6 - length_remaining;
-          return;
-        }
-    }
-
     /*
      * OK, try to read the "Sequence Of" header; this gets the total
      * length of the LDAP message.
@@ -2730,29 +2709,6 @@ dissect_ldap_payload(tvbuff_t *tvb, packet_info *pinfo,
        msg_len = length_remaining;
     }
 
-    /*
-     * Is the message split across segment boundaries?
-     */
-    if (length_remaining < msg_len) {
-        /* provide a hint to TCP where the next PDU starts */
-        pinfo->want_pdu_tracking=2;
-        pinfo->bytes_until_next_pdu= msg_len - length_remaining;
-        /*
-         * Can we do reassembly?
-         */
-        if (ldap_desegment && pinfo->can_desegment) {
-           /*
-            * Yes.  Tell the TCP dissector where the data for this message
-            * starts in the data it handed us, and how many more bytes
-            * we need, and return.
-            */
-           pinfo->desegment_offset = offset;
-           pinfo->desegment_len = msg_len - length_remaining;
-
-           return;
-        }
-    }
-
     /*
      * Construct a tvbuff containing the amount of the payload we have
      * available.  Make its reported length the amount of data in the
@@ -2860,27 +2816,6 @@ dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean i
      */
     length_remaining = tvb_ensure_length_remaining(tvb, offset);
 
-    /*
-     * Try to find out if we have a plain LDAP buffer
-     * with a "Sequence Of" header or a SASL buffer with
-     * Can we do reassembly?
-     */
-    if (ldap_desegment && pinfo->can_desegment) {
-        /*
-         * Yes - is the "Sequence Of" header split across segment
-         * boundaries?  We require at least 6 bytes for the header
-         * which allows for a 4 byte length (ASN.1 BER).
-        * For the SASL case we need at least 4 bytes, so this is
-        * no problem here because we check for 6 bytes ans sasl buffers
-        * with less than 2 bytes should not exist...
-         */
-        if (length_remaining < 6) {
-           pinfo->desegment_offset = offset;
-           pinfo->desegment_len = 6 - length_remaining;
-           return;
-        }
-    }
-
     /* It might still be a packet containing a SASL security layer
      * but its just that we never saw the BIND packet.
      * check if it looks like it could be a SASL blob here
@@ -2953,28 +2888,6 @@ dissect_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean i
         return;
       }
 
-      /*
-       * Is the buffer split across segment boundaries?
-       */
-      if (length_remaining < sasl_msg_len) {
-        /* provide a hint to TCP where the next PDU starts */
-        pinfo->want_pdu_tracking = 2;
-        pinfo->bytes_until_next_pdu= sasl_msg_len - length_remaining;
-        /*
-         * Can we do reassembly?
-         */
-        if (ldap_desegment && pinfo->can_desegment) {
-          /*
-           * Yes.  Tell the TCP dissector where the data for this message
-           * starts in the data it handed us, and how many more bytes we
-           * need, and return.
-           */
-          pinfo->desegment_offset = offset;
-          pinfo->desegment_len = sasl_msg_len - length_remaining;
-          return;
-        }
-      }
-
       /*
        * Construct a tvbuff containing the amount of the payload we have
        * available.  Make its reported length the amount of data in the PDU.
@@ -3343,9 +3256,106 @@ static void dissect_NetLogon_PDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
 }
 
 
+static guint 
+get_sasl_ldap_pdu_len(tvbuff_t *tvb, int offset)
+{
+       /* sasl encapsulated ldap is 4 bytes plus the length in size */
+       return tvb_get_ntohl(tvb, offset)+4;
+}
+
+static void 
+dissect_sasl_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
+       return;
+}
+
+static guint 
+get_normal_ldap_pdu_len(tvbuff_t *tvb, int offset)
+{
+       guint32 len;
+       gboolean ind;
+       int data_offset;
+
+       /* normal ldap is tag+len bytes plus the length
+        * offset==0 is where the tag is 
+        * offset==1 is where length starts
+        */
+       data_offset=get_ber_length(NULL, tvb, 1, &len, &ind);
+       return len+data_offset;
+}
+
+static void 
+dissect_normal_ldap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+       dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
+       return;
+}
+
+
 static void
 dissect_ldap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
+       /* Here we must take care of reassembly but this is tricky since
+        * depending on whether SASL is present or not, the heuristics
+        * will be very different.
+        */
+       if(ldap_desegment && (tvb_length(tvb)==tvb_reported_length(tvb))){
+               guint32 len;
+
+               /* check for a SASL header, i.e. four byte integer where the
+                * first two bytes are 0x00 and the value is <64k and >2
+                * (>2 to fight false positives, 0x00000000 is a common
+                *     "random" tcp payload)
+                * (no SASL ldap PDUs are ever going to be >64k in size?)
+                *
+                * Following the SASL header is a GSSAPI blob so the next byte
+                * is always 0x60. (only true for MS SASL LDAP, there are other
+                * blobs that may follow in real-world)
+                */
+               len=tvb_get_ntohl(tvb, 0);
+               if( (len<65535)
+               &&  (len>2)
+               &&  (tvb_get_guint8(tvb, 4)==0x60)){
+                       if(len<=tvb_length_remaining(tvb, 4)){
+                               /* we have a full ldap pdu */
+                               dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
+                               return;
+                       } else {
+                               /* we have to do reassembly */
+                               tcp_dissect_pdus(tvb, pinfo, tree, ldap_desegment, 4, get_sasl_ldap_pdu_len, dissect_sasl_ldap_pdu);
+                               return;
+                       }
+               }
+               /* check if it is a normal BER encoded LDAP packet
+                * i.e. first byte is 0x30 followed by a length that is 
+                * <64k
+                * (no ldap PDUs are ever >64kb? )
+                */
+               if(tvb_get_guint8(tvb, 0)==0x30){
+                       gboolean ind;
+                       int data_offset;
+
+                       /* check that length makes sense */
+                       data_offset=get_ber_length(NULL, tvb, 1, &len, &ind);
+
+                       /* dont check ind since indefinite length is never used for ldap (famous last words)*/
+                       if(len<2 || len>65535){
+                               return;
+                       }
+
+                       if(len<=tvb_length_remaining(tvb, data_offset)){
+                               /* we have a full ldap pdu */
+                               dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
+                               return;
+                       } else {
+                               /* we have to do reassembly */
+                               tcp_dissect_pdus(tvb, pinfo, tree, ldap_desegment, 4, get_normal_ldap_pdu_len, dissect_normal_ldap_pdu);
+                               return;
+                       }
+               }
+       }
+
        dissect_ldap_pdu(tvb, pinfo, tree, FALSE);
        return;
 }
@@ -3922,7 +3932,7 @@ void proto_register_ldap(void) {
         "ExtendedResponse/response", HFILL }},
 
 /*--- End of included file: packet-ldap-hfarr.c ---*/
-#line 1347 "packet-ldap-template.c"
+#line 1357 "packet-ldap-template.c"
   };
 
   /* List of subtrees */
@@ -3975,7 +3985,7 @@ void proto_register_ldap(void) {
     &ett_ldap_ExtendedResponse,
 
 /*--- End of included file: packet-ldap-ettarr.c ---*/
-#line 1358 "packet-ldap-template.c"
+#line 1368 "packet-ldap-template.c"
   };
 
     module_t *ldap_module;