fix tcp reassembly to work again for

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.



svn path=/trunk/; revision=18465
This commit is contained in:
Ronnie Sahlberg 2006-06-14 11:51:25 +00:00
parent 59c8c8065d
commit 2f95f76a1e
3 changed files with 196 additions and 191 deletions

View 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;
}

View 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);
}

View 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;