Ethereal-users: Re: [Ethereal-users] TDS unreassembled packets diagnosis

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Guy Harris <guy@xxxxxxxxxxxx>
Date: Fri, 22 Aug 2003 20:41:39 -0700
On Friday, August 22, 2003, at 8:30 PM, Guy Harris wrote:


On Friday, August 22, 2003, at 2:48 PM, Tom Jordan wrote:

Attached is a capture of a TDS stream that I had posted to the list.

Note to self: next time, if I put in a comment saying "do XXX and then return", don't forget to put the "return;" statement in.

I.e., the problem is that there's a bug in Ethereal (which I put in), so don't trust what it displays to reflect reality.

I've attached a patch that puts the missing "return;" statement into the TDS dissector, so that it correctly dissects Netlib messages that cross TCP segment boundaries, like the ones in your capture. It also makes an attempt to dissect part of the "remote procedure call" packets (there appears to be a counted string at the beginning; I don't know what's in the rest of the packet), and cleans up some other stuff.

Note to self: next time, if I say "I've attached a patch" in a mail message, attach the patch.

Here's the patch:

Index: packet-tds.c
===================================================================
RCS file: /cvsroot/ethereal/packet-tds.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -c -r1.12 -r1.13
*** packet-tds.c	20 Apr 2003 11:36:16 -0000	1.12
--- packet-tds.c	23 Aug 2003 02:34:09 -0000	1.13
***************
*** 308,313 ****
--- 308,314 ----
  static const value_string packet_type_names[] = {
  	{TDS_QUERY_PKT,  "Query Packet"},
  	{TDS_LOGIN_PKT,  "Login Packet"},
+ 	{TDS_RPC_PKT,    "Remote Procedure Call Packet"},
  	{TDS_RESP_PKT,   "Response Packet"},
  	{TDS_CANCEL_PKT, "Cancel Packet"},
  	{TDS_QUERY5_PKT, "TDS5 Query Packet"},
***************
*** 424,432 ****
  dissect_tds7_login(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  {
  	guint offset, i, offset2, len;
- 	guint16 bc;
  	gboolean is_unicode = TRUE;
! 	const char *val;
  
  	proto_item *login_hdr;
  	proto_tree *login_tree;
--- 425,432 ----
  dissect_tds7_login(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  {
  	guint offset, i, offset2, len;
  	gboolean is_unicode = TRUE;
! 	char *val;
  
  	proto_item *login_hdr;
  	proto_tree *login_tree;
***************
*** 456,470 ****
  			val_to_str(i, login_field_names, "Unknown"),
  			len);
  		if (len != 0) {
! 			if (is_unicode == TRUE)
  				len *= 2;
! 			val = get_unicode_or_ascii_string(tvb, &offset2,
! 				is_unicode, &len, TRUE, TRUE, &bc);
! 			if (val != NULL)
! 				proto_tree_add_text(login_tree, tvb, offset2, len,
! 					"%s: %s",
! 					val_to_str(i, login_field_names, "Unknown"),
! 					val);
  		}
  	}
  
--- 456,472 ----
  			val_to_str(i, login_field_names, "Unknown"),
  			len);
  		if (len != 0) {
! 			if (is_unicode == TRUE) {
! 				val = tvb_fake_unicode(tvb, offset2, len,
! 				    TRUE);
  				len *= 2;
! 			} else
! 				val = tvb_get_string(tvb, offset2, len);
! 			proto_tree_add_text(login_tree, tvb, offset2, len,
! 				"%s: %s",
! 				val_to_str(i, login_field_names, "Unknown"),
! 				val);
! 			g_free(val);
  		}
  	}
  
***************
*** 689,697 ****
  {
  	guint8 env_type;
  	guint old_len, new_len, old_len_offset;
! 	const char *new_val = NULL, *old_val = NULL;
  	guint32 string_offset;
- 	guint16 bc;
  	gboolean is_unicode = FALSE;
  
  	env_type = tvb_get_guint8(tvb, offset);
--- 691,698 ----
  {
  	guint8 env_type;
  	guint old_len, new_len, old_len_offset;
! 	char *new_val = NULL, *old_val = NULL;
  	guint32 string_offset;
  	gboolean is_unicode = FALSE;
  
  	env_type = tvb_get_guint8(tvb, offset);
***************
*** 715,749 ****
  	proto_tree_add_text(tree, tvb, offset + 1, 1, "New Value Length: %u",
  	    new_len);
  	if (new_len) {
  		if (is_unicode == TRUE) {
  			new_len *= 2;
! 		}
! 		string_offset = offset + 2;
! 		new_val = get_unicode_or_ascii_string(tvb, &string_offset,
! 		                            is_unicode, &new_len,
! 		                            TRUE, TRUE, &bc);
! 
  		proto_tree_add_text(tree, tvb, string_offset, new_len,
  		    "New Value: %s", new_val);
  	}
  
  	proto_tree_add_text(tree, tvb, old_len_offset, 1, "Old Value Length: %u",
  	    old_len);
  	if (old_len) {
  		if (is_unicode == TRUE) {
  			old_len *= 2;
! 		}
! 		string_offset = old_len_offset + 1;
! 		old_val = get_unicode_or_ascii_string(tvb, &string_offset,
! 		                            is_unicode, &old_len,
! 		                            TRUE, TRUE, &bc);
! 
  		proto_tree_add_text(tree, tvb, string_offset, old_len,
  		    "Old Value: %s", old_val);
  	 }
  }
  
  static void
  dissect_tds_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  {
  	int offset = 0;
--- 716,774 ----
  	proto_tree_add_text(tree, tvb, offset + 1, 1, "New Value Length: %u",
  	    new_len);
  	if (new_len) {
+ 		string_offset = offset + 2;
  		if (is_unicode == TRUE) {
+ 			new_val = tvb_fake_unicode(tvb, string_offset,
+ 			    new_len, TRUE);
  			new_len *= 2;
! 		} else
! 			new_val = tvb_get_string(tvb, string_offset, new_len);
  		proto_tree_add_text(tree, tvb, string_offset, new_len,
  		    "New Value: %s", new_val);
+ 		g_free(new_val);
  	}
  
  	proto_tree_add_text(tree, tvb, old_len_offset, 1, "Old Value Length: %u",
  	    old_len);
  	if (old_len) {
+ 		string_offset = old_len_offset + 1;
  		if (is_unicode == TRUE) {
+ 			old_val = tvb_fake_unicode(tvb, string_offset,
+ 			    old_len, TRUE);
  			old_len *= 2;
! 		} else
! 			old_val = tvb_get_string(tvb, string_offset, old_len);
  		proto_tree_add_text(tree, tvb, string_offset, old_len,
  		    "Old Value: %s", old_val);
+ 		g_free(old_val);
  	 }
  }
  
  static void
+ dissect_tds_rpc(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
+ {
+ 	int offset = 0;
+ 	guint len;
+ 	const char *val;
+ 
+ 	/*
+ 	 * This appears to start with a little-endian string length,
+ 	 * followed by a little-endian Unicode string (or perhaps
+ 	 * it's Unicode-or-ASCII).
+ 	 */
+ 	len = tvb_get_letohs(tvb, offset);
+ 	proto_tree_add_text(tree, tvb, offset, 2, "String Length: %u", len);
+ 	offset += 2;
+ 	if (len != 0) {
+ 		val = tvb_fake_unicode(tvb, offset, len, TRUE);
+ 		len *= 2;
+ 		proto_tree_add_text(tree, tvb, offset, len, "String: %s", val);
+ 		offset += len;
+ 	}
+ 	proto_tree_add_text(tree, tvb, offset, -1, "Unknown data");
+ }
+ 
+ static void
  dissect_tds_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
  {
  	int offset = 0;
***************
*** 916,921 ****
--- 941,950 ----
  	if (next_tvb != NULL) {
  		switch (type) {
  
+ 		case TDS_RPC_PKT:
+ 			dissect_tds_rpc(next_tvb, pinfo, tds_tree);
+ 			break;
+ 
  		case TDS_RESP_PKT:
  			dissect_tds_resp(next_tvb, pinfo, tds_tree);
  			break;
***************
*** 1023,1028 ****
--- 1052,1058 ----
  				 */
  				pinfo->desegment_offset = offset;
  				pinfo->desegment_len = plen - length_remaining;
+ 				return;
  			}
  		}