tcp: support variable-length tcp_dissect_pdus

Originally suggested by Bill Meier for the MQTT protocol[1], but the
Websocket protocol can also benefit from this. Since
DESEGMENT_ONE_MORE_SEGMENT is a valid packet length, use the zero length
instead as an indicator that the length is not yet known.

Updated documentation too and remove the function documentation from
packet-tcp.c since it is duplicated in packet-tcp.h.

A noteworthy WSDG change is that the get_pdu_len parameter of
tcp_dissect_pdus gained another void pointer since
v1.99.2rc0-890-gceb8d95 ("Lua: Expose tcp_dissect_pdus() to Lua").

 [1]: https://www.wireshark.org/lists/wireshark-dev/201405/msg00044.html

Change-Id: I4eba380e00cd757635eb5639c2857356dae3171e
Reviewed-on: https://code.wireshark.org/review/7279
Reviewed-by: Guy Harris <guy@alum.mit.edu>
Reviewed-by: Michael Mann <mmann78@netscape.net>
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Evan Huus <eapache@gmail.com>
This commit is contained in:
Peter Wu 2015-02-20 19:33:16 +01:00 committed by Evan Huus
parent 554c8fd7ca
commit 4ca3dbae94
4 changed files with 34 additions and 33 deletions

View File

@ -2972,16 +2972,17 @@ The arguments to tcp_dissect_pdus are:
a routine that takes as arguments a packet_info pointer, a tvbuff
pointer and an offset value representing the offset into the tvbuff
at which a PDU begins, and a void pointer for user data, and should
return - *without* throwing an exception (it is guaranteed that the
return the total length of the PDU in bytes (or 0 if more bytes are
needed to determine the message length).
The routine must not throw exceptions (it is guaranteed that the
number of bytes specified by the previous argument to
tcp_dissect_pdus is available, but more data might not be available,
so don't refer to any data past that) - the total length of the PDU,
in bytes;
so don't refer to any data past that);
a new_dissector_t routine to dissect the pdu that's passed a tvbuff
pointer, packet_info pointer, proto_tree pointer and a void pointer for
user data, with the tvbuff containing a possibly-reassembled PDU. (The
"reported_length" of the tvbuff will be the length of the PDU).
"reported_length" of the tvbuff will be the length of the PDU);
a void pointer to user data that is passed to the length-determining
routine, and the dissector routine referenced in the previous parameter.

View File

@ -594,7 +594,7 @@ effect.
guchar *decompressed_buffer = (guchar*)g_malloc(orig_size);
offset += 2;
decompress_packet(tvb_get_ptr(tvb, offset, -1),
tvb_length_remaining(tvb, offset),
tvb_captured_length_remaining(tvb, offset),
decompressed_buffer, orig_size);
/* Now re-setup the tvb buffer to have the new data */
next_tvb = tvb_new_child_real_data(tvb, decompressed_buffer, orig_size, orig_size);
@ -618,7 +618,7 @@ So armed with the size, a buffer is allocated to receive the uncompressed data
using +g_malloc()+, and the packet is decompressed into it. The +tvb_get_ptr()+
function is useful to get a pointer to the raw data of the packet from the
offset onwards. In this case the decompression routine also needs to know the
length, which is given by the +tvb_length_remaining()+ function.
length, which is given by the +tvb_captured_length_remaining()+ function.
Next we build a new tvb buffer from this data, using the
+tvb_new_child_real_data()+ call. This data is a child of our original data, so
@ -700,7 +700,7 @@ if (flags & FL_FRAGMENT) { /* fragmented */
msg_fragment_table, /* list of message fragments */
msg_reassembled_table, /* list of reassembled messages */
msg_num, /* fragment sequence number */
tvb_length_remaining(tvb, offset), /* fragment length - to the end */
tvb_captured_length_remaining(tvb, offset), /* fragment length - to the end */
flags & FL_FRAG_LAST); /* More fragments? */
----
====
@ -922,25 +922,28 @@ This function is implemented in 'epan/dissectors/packet-tcp.h'.
#define FRAME_HEADER_LEN 8
/* This method dissects fully reassembled messages */
static int dissect_foo_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
static int
dissect_foo_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
/* TODO: implement your dissecting code */
return tvb_length(tvb);
return tvb_captured_length(tvb);
}
/* determine PDU length of protocol foo */
static guint get_foo_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset)
static guint
get_foo_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
{
/* TODO: change this to your needs */
return (guint)tvb_get_ntohl(tvb, offset+4); /* e.g. length is at offset 4 */
}
/* The main dissecting routine */
static int dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
static int
dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, FRAME_HEADER_LEN,
get_foo_message_len, dissect_foo_message, data);
return tvb_length(tvb);
return tvb_captured_length(tvb);
}
...
@ -951,16 +954,20 @@ As you can see this is really simple. Just call +tcp_dissect_pdus()+ in your
main dissection routine and move you message parsing code into another function.
This function gets called whenever a message has been reassembled.
The parameters tvb, pinfo, treeand dataare just handed over to
The parameters tvb, pinfo, tree and data are just handed over to
+tcp_dissect_pdus()+. The 4th parameter is a flag to indicate if the data should
be reassembled or not. This could be set according to a dissector preference as
well. Parameter 5 indicates how much data has at least to be available to be
able to determine the length of the foo message. Parameter 6 is a function
pointer to a method that returns this length. It gets called when at least the
number of bytes given in the previous parameter is available. Parameter 7 is a
function pointer to your real message dissector. Parameter 8 is a the data
function pointer to your real message dissector. Parameter 8 is the data
passed in from parent dissector.
Protocols which need more data before the message length can be determined can
return zero. Other values smaller than the fixed length will result in an
exception.
[[ChDissectTap]]
=== How to tap protocols

View File

@ -2306,24 +2306,6 @@ again:
}
}
/*
* Loop for dissecting PDUs within a TCP stream; assumes that a PDU
* consists of a fixed-length chunk of data that contains enough information
* to determine the length of the PDU, followed by rest of the PDU.
*
* The first three arguments are the arguments passed to the dissector
* that calls this routine.
*
* "proto_desegment" is the dissector's flag controlling whether it should
* desegment PDUs that cross TCP segment boundaries.
*
* "fixed_len" is the length of the fixed-length part of the PDU.
*
* "get_pdu_len()" is a routine called to get the length of the PDU from
* the fixed-length part of the PDU; it's passed "pinfo", "tvb" and "offset".
*
* "dissect_pdu()" is the routine to dissect a PDU.
*/
void
tcp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
gboolean proto_desegment, guint fixed_len,
@ -2379,6 +2361,16 @@ tcp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
* Get the length of the PDU.
*/
plen = (*get_pdu_len)(pinfo, tvb, offset, dissector_data);
if (plen == 0) {
/*
* Support protocols which have a variable length which cannot
* always be determined within the given fixed_len.
*/
DISSECTOR_ASSERT(proto_desegment && pinfo->can_desegment);
pinfo->desegment_offset = offset;
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
return;
}
if (plen < fixed_len) {
/*
* Either:

View File

@ -99,7 +99,8 @@ struct tcpinfo {
* "fixed_len" is the length of the fixed-length part of the PDU.
*
* "get_pdu_len()" is a routine called to get the length of the PDU from
* the fixed-length part of the PDU; it's passed "pinfo", "tvb" and "offset".
* the fixed-length part of the PDU; it's passed "pinfo", "tvb", "offset" and
* "dissector_data".
*
* "dissect_pdu()" is the routine to dissect a PDU.
*/