forked from osmocom/wireshark
udp_dissect_pdus follow-up
Add heuristic support Better documentation Change-Id: I236c1f4d3613aa58d608aee0e5edc40c3b158d25 Reviewed-on: https://code.wireshark.org/review/10120 Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
parent
69e61db3ae
commit
ad1b785fe8
|
@ -3147,7 +3147,92 @@ will then be added to the protocol tree. Note that there may be more
|
|||
than one complete C string in the tvbuff, so the dissection is done in a
|
||||
loop.
|
||||
|
||||
2.8 ptvcursors.
|
||||
2.8 Using udp_dissect_pdus().
|
||||
|
||||
As noted in section 2.7.1, TCP has an API to dissect its PDU that can handle
|
||||
a PDU spread across multiple packets or multiple PDUs spread across a single
|
||||
packet. This section describes a similar mechanism for UDP, but is only
|
||||
applicable for one or more PDUs in a single packet. If a protocol runs on top
|
||||
of TCP as well as UDP, a common PDU dissection function can be created for both.
|
||||
|
||||
To register the distinct dissector functions, consider the following
|
||||
example using UDP and TCP dissection, stolen from packet-dnp.c:
|
||||
|
||||
#include "packet-tcp.h"
|
||||
#include "packet-udp.h"
|
||||
|
||||
dissector_handle_t dnp3_tcp_handle;
|
||||
dissector_handle_t dnp3_udp_handle;
|
||||
|
||||
dnp3_tcp_handle = new_create_dissector_handle(dissect_dnp3_tcp, proto_dnp3);
|
||||
dnp3_udp_handle = new_create_dissector_handle(dissect_dnp3_udp, proto_dnp3);
|
||||
|
||||
dissector_add_uint("tcp.port", TCP_PORT_DNP, dnp3_tcp_handle);
|
||||
dissector_add_uint("udp.port", UDP_PORT_DNP, dnp3_udp_handle);
|
||||
|
||||
Both dissect_dnp3_tcp and dissect_dnp3_udp call tcp_dissect_pdus and
|
||||
udp_dissect_pdus respectively, with a reference to the same callbacks which
|
||||
are called to handle PDU data.
|
||||
|
||||
static int
|
||||
dissect_dnp3_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
{
|
||||
return udp_dissect_pdus(tvb, pinfo, tree, DNP_HDR_LEN, dnp3_udp_check_header,
|
||||
get_dnp3_message_len, dissect_dnp3_message, data);
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_dnp3_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
{
|
||||
if (!check_dnp3_header(tvb, FALSE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, DNP_HDR_LEN,
|
||||
get_dnp3_message_len, dissect_dnp3_message, data);
|
||||
|
||||
return tvb_captured_length(tvb);
|
||||
}
|
||||
|
||||
(udp_dissect_pdus has an option of a heuristic check function within it while
|
||||
tcp_dissect_pdus does not, so it's done outside)
|
||||
|
||||
The arguments to udp_dissect_pdus are:
|
||||
|
||||
the tvbuff pointer, packet_info pointer, and proto_tree pointer
|
||||
passed to the dissector;
|
||||
|
||||
the number of bytes of PDU data required to determine the length
|
||||
of the PDU;
|
||||
|
||||
an optional routine (passing NULL is okay) 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 TRUE if the packet belongs to the dissector.
|
||||
The routine must not throw exceptions (it is guaranteed that the
|
||||
number of bytes specified by the previous argument to
|
||||
udp_dissect_pdus is available, but more data might not be available,
|
||||
so don't refer to any data past that);
|
||||
|
||||
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 the total length of the PDU in bytes. If return value is 0,
|
||||
it's treated the same as a failed heuristic.
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
a void pointer to user data that is passed to the length-determining
|
||||
routine, and the dissector routine referenced in the previous parameter.
|
||||
|
||||
2.9 ptvcursors.
|
||||
|
||||
The ptvcursor API allows a simpler approach to writing dissectors for
|
||||
simple protocols. The ptvcursor API works best for protocols whose fields
|
||||
|
@ -3180,7 +3265,7 @@ To use the ptvcursor API, include the "ptvcursor.h" file. The PGM dissector
|
|||
is an example of how to use it. You don't need to look at it as a guide;
|
||||
instead, the API description here should be good enough.
|
||||
|
||||
2.8.1 ptvcursor API.
|
||||
2.9.1 ptvcursor API.
|
||||
|
||||
ptvcursor_t*
|
||||
ptvcursor_new(proto_tree* tree, tvbuff_t* tvb, gint offset)
|
||||
|
@ -3236,7 +3321,7 @@ If the length is unknown, length may be defined as SUBTREE_UNDEFINED_LENGTH.
|
|||
In this case, at the next pop, the item length will be equal to the advancement
|
||||
of the cursor since the creation of the subtree.
|
||||
|
||||
2.8.2 Miscellaneous functions.
|
||||
2.9.2 Miscellaneous functions.
|
||||
|
||||
tvbuff_t*
|
||||
ptvcursor_tvbuff(ptvcursor_t* ptvc)
|
||||
|
@ -3259,7 +3344,7 @@ ptvcursor_set_subtree(ptvcursor_t* ptvc, proto_item* it, gint ett_subtree);
|
|||
Creates a subtree and adds it to the cursor as the working tree but does
|
||||
not save the old working tree.
|
||||
|
||||
2.9 Optimizations
|
||||
2.10 Optimizations
|
||||
|
||||
A protocol dissector may be called in 2 different ways - with, or
|
||||
without a non-null "tree" argument.
|
||||
|
|
|
@ -103,7 +103,7 @@ Heuristic Code Example
|
|||
----------------------
|
||||
You can find a lot of code examples in the Wireshark sources, e.g.:
|
||||
grep -l heur_dissector_add epan/dissectors/*.c
|
||||
returns 163 files (November 2014).
|
||||
returns 177 files (October 2015).
|
||||
|
||||
For the above example criteria, the following code example might do the work
|
||||
(combine this with the dissector skeleton in README.developer):
|
||||
|
@ -118,7 +118,7 @@ static dissector_handle_t PROTOABBREV_pdu_handle;
|
|||
|
||||
/* Heuristics test */
|
||||
static gboolean
|
||||
test_PROTOABBREV(tvbuff_t *tvb)
|
||||
test_PROTOABBREV(packet_info *pinfo _U_, tvbuff_t *tvb, int offset _U_, void *data _U_)
|
||||
{
|
||||
/* 0) Verify needed bytes available in tvb so tvb_get...() doesn't cause exception.
|
||||
if (tvb_captured_length(tvb) < 5)
|
||||
|
@ -172,7 +172,7 @@ dissect_PROTOABBREV_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
|
|||
static gboolean
|
||||
dissect_PROTOABBREV_heur_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
{
|
||||
if (!test_PROTOABBREV(tvb))
|
||||
if (!test_PROTOABBREV(pinfo, tvb, 0, data))
|
||||
return FALSE;
|
||||
|
||||
/* specify that dissect_PROTOABBREV is to be called directly from now on for
|
||||
|
@ -190,26 +190,21 @@ dissect_PROTOABBREV_heur_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
|
|||
return (TRUE);
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_PROTOABBREV_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
{
|
||||
udp_dissect_pdus(tvb, pinfo, tree, TRUE, 5, NULL,
|
||||
get_PROTOABBREV_len, dissect_PROTOABBREV_pdu, data);
|
||||
return tvb_reported_length(tvb);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dissect_PROTOABBREV_heur_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
{
|
||||
...
|
||||
If (!test_PROTOABBREV(tvb))
|
||||
return FALSE;
|
||||
|
||||
/* specify that dissect_PROTOABBREV is to be called directly from now on for
|
||||
* packets for this "connection" ... but only do this if your heuristic sits directly
|
||||
* on top of (was called by) a dissector which established a conversation for the
|
||||
* protocol "port type". In other words: only directly over TCP, UDP, DCCP, ...
|
||||
* otherwise you'll be overriding the dissector that called your heuristic dissector.
|
||||
*/
|
||||
conversation = find_or_create_conversation(pinfo);
|
||||
conversation_set_dissector(conversation, PROTOABBREV_pdu_handle);
|
||||
|
||||
/* and do the dissection */
|
||||
dissect_PROTOABBREV_pdu(tvb, pinfo, tree, data);
|
||||
|
||||
return (TRUE);
|
||||
return (udp_dissect_pdus(tvb, pinfo, tree, TRUE, 5, test_PROTOABBREV,
|
||||
get_PROTOABBREV_len, dissect_PROTOABBREV_pdu, data) != 0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -221,9 +216,9 @@ proto_reg_handoff_PROTOABBREV(void)
|
|||
proto_PROTOABBREV);
|
||||
|
||||
/* register as heuristic dissector for both TCP and UDP */
|
||||
heur_dissector_add("tcp", dissect_PROTOABBREV_tcp_heur, "PROTOABBREV over TCP",
|
||||
heur_dissector_add("tcp", dissect_PROTOABBREV_heur_tcp, "PROTOABBREV over TCP",
|
||||
"PROTOABBREV_tcp", proto_PROTOABBREV, HEURISTIC_ENABLE);
|
||||
heur_dissector_add("udp", dissect_PROTOABBREV_udp_heur, "PROTOABBREV over UDP",
|
||||
heur_dissector_add("udp", dissect_PROTOABBREV_heur_udp, "PROTOABBREV over UDP",
|
||||
"PROTOABBREV_udp", proto_PROTOABBREV, HEURISTIC_ENABLE);
|
||||
|
||||
#ifdef OPTIONAL
|
||||
|
|
|
@ -3521,30 +3521,31 @@ dissect_dnp3_tcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dnp3_udp_check_header(packet_info *pinfo _U_, tvbuff_t *tvb, int offset _U_, void *data _U_)
|
||||
{
|
||||
return check_dnp3_header(tvb, FALSE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dnp3_udp_check_header_heur(packet_info *pinfo _U_, tvbuff_t *tvb, int offset _U_, void *data _U_)
|
||||
{
|
||||
return check_dnp3_header(tvb, TRUE);
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_dnp3_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
{
|
||||
if (!check_dnp3_header(tvb, FALSE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
udp_dissect_pdus(tvb, pinfo, tree, DNP_HDR_LEN,
|
||||
return udp_dissect_pdus(tvb, pinfo, tree, DNP_HDR_LEN, dnp3_udp_check_header,
|
||||
get_dnp3_message_len, dissect_dnp3_message, data);
|
||||
|
||||
return tvb_captured_length(tvb);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dissect_dnp3_udp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
{
|
||||
if (!check_dnp3_header(tvb, FALSE)) {
|
||||
return FALSE;
|
||||
}
|
||||
return (udp_dissect_pdus(tvb, pinfo, tree, DNP_HDR_LEN, dnp3_udp_check_header_heur,
|
||||
get_dnp3_message_len, dissect_dnp3_message, data) != 0);
|
||||
|
||||
udp_dissect_pdus(tvb, pinfo, tree, DNP_HDR_LEN,
|
||||
get_dnp3_message_len, dissect_dnp3_message, data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -549,9 +549,10 @@ decode_udp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
|
|||
call_dissector(data_handle,next_tvb, pinfo, tree);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
udp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
||||
guint fixed_len, guint (*get_pdu_len)(packet_info *, tvbuff_t *, int, void*),
|
||||
guint fixed_len, gboolean (*heuristic_check)(packet_info *, tvbuff_t *, int, void*),
|
||||
guint (*get_pdu_len)(packet_info *, tvbuff_t *, int, void*),
|
||||
new_dissector_t dissect_pdu, void* dissector_data)
|
||||
{
|
||||
volatile int offset = 0;
|
||||
|
@ -579,10 +580,26 @@ udp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
|||
*/
|
||||
captured_length_remaining = tvb_ensure_captured_length_remaining(tvb, offset);
|
||||
|
||||
/*
|
||||
* If there is a heuristic function, check it
|
||||
*/
|
||||
if ((heuristic_check != NULL) &&
|
||||
((*heuristic_check)(pinfo, tvb, offset, dissector_data) == FALSE)) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the length of the PDU.
|
||||
*/
|
||||
plen = (*get_pdu_len)(pinfo, tvb, offset, dissector_data);
|
||||
if (plen == 0) {
|
||||
/*
|
||||
* Either protocol has variable length (which isn't supposed by UDP)
|
||||
* or packet doesn't belong to protocol
|
||||
*/
|
||||
return offset;
|
||||
}
|
||||
|
||||
if (plen < fixed_len) {
|
||||
/*
|
||||
* Either:
|
||||
|
@ -600,7 +617,7 @@ udp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
|||
* Report this as a bounds error.
|
||||
*/
|
||||
show_reported_bounds_error(tvb, pinfo, tree);
|
||||
return;
|
||||
return offset;
|
||||
}
|
||||
|
||||
curr_layer_num = pinfo->curr_layer_num-1;
|
||||
|
@ -668,6 +685,8 @@ udp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
|||
if (offset <= offset_before)
|
||||
break;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -115,20 +115,22 @@ WS_DLL_PUBLIC struct udp_analysis *get_udp_conversation_data(conversation_t *,
|
|||
* 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.
|
||||
*
|
||||
* "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
|
||||
* @param tvb the tvbuff with the (remaining) packet data passed to dissector
|
||||
* @param pinfo the packet info of this packet (additional info) passed to dissector
|
||||
* @param tree the protocol tree to be build or NULL passed to dissector
|
||||
* @param fixed_len is the length of the fixed-length part of the PDU.
|
||||
* @param heuristic_check is the optional routine called to see if dissection
|
||||
* should be done; it's passed "pinfo", "tvb", "offset" and "dissector_data".
|
||||
* @param 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", "offset" and
|
||||
* "dissector_data".
|
||||
*
|
||||
* "dissect_pdu()" is the routine to dissect a PDU.
|
||||
* @param dissect_pdu the sub-dissector to be called
|
||||
* @param dissector_data parameter to pass to subdissector
|
||||
*/
|
||||
WS_DLL_PUBLIC void
|
||||
WS_DLL_PUBLIC int
|
||||
udp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
||||
guint fixed_len, guint (*get_pdu_len)(packet_info *, tvbuff_t *, int, void*),
|
||||
guint fixed_len, gboolean (*heuristic_check)(packet_info *, tvbuff_t *, int, void*),
|
||||
guint (*get_pdu_len)(packet_info *, tvbuff_t *, int, void*),
|
||||
new_dissector_t dissect_pdu, void* dissector_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
Loading…
Reference in New Issue