forked from osmocom/wireshark
DNP3: Fix reassembly of out of order fragments
Rework Application Layer fragment reassembly to handle out of order fragments (seen over UDP). Change-Id: Ifd2bffba30f0a419a5f82ea6b9d2d221f7d6d276 Reviewed-on: https://code.wireshark.org/review/19947 Petri-Dish: Graham Bloice <graham.bloice@trihedral.com> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Graham Bloice <graham.bloice@trihedral.com>
This commit is contained in:
parent
fd2bd2b154
commit
a8ceeca444
|
@ -602,6 +602,7 @@ static int hf_dnp3_data_chunk = -1;
|
|||
static int hf_dnp3_data_chunk_len = -1;
|
||||
static int hf_dnp3_data_chunk_crc = -1;
|
||||
static int hf_dnp3_data_chunk_crc_status = -1;
|
||||
|
||||
/* Added for Application Layer Decoding */
|
||||
static int hf_dnp3_al_ctl = -1;
|
||||
static int hf_dnp3_al_fir = -1;
|
||||
|
@ -1301,48 +1302,11 @@ static expert_field ei_dnp3_buffering_user_data_until_final_frame_is_received =
|
|||
|
||||
/* Tables for reassembly of fragments. */
|
||||
static reassembly_table al_reassembly_table;
|
||||
static wmem_map_t *dl_conversation_table = NULL;
|
||||
|
||||
/* Data-Link-Layer Conversation Key Structure */
|
||||
typedef struct _dl_conversation_key
|
||||
{
|
||||
guint32 conversation; /* TCP / UDP conversation index */
|
||||
guint16 src; /* DNP3.0 Source Address */
|
||||
guint16 dst; /* DNP3.0 Destination Address */
|
||||
} dl_conversation_key_t;
|
||||
|
||||
/* Data-Link-Layer conversation key equality function */
|
||||
static gboolean
|
||||
dl_conversation_equal(gconstpointer v, gconstpointer w)
|
||||
{
|
||||
const dl_conversation_key_t* v1 = (const dl_conversation_key_t*)v;
|
||||
const dl_conversation_key_t* v2 = (const dl_conversation_key_t*)w;
|
||||
|
||||
if ((v1->conversation == v2->conversation) &&
|
||||
(v1->src == v2->src) &&
|
||||
(v1->dst == v2->dst))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Data-Link-Layer conversation key hash function */
|
||||
static guint
|
||||
dl_conversation_hash(gconstpointer v)
|
||||
{
|
||||
const dl_conversation_key_t *key = (const dl_conversation_key_t*)v;
|
||||
guint val;
|
||||
|
||||
val = key->conversation + (key->src << 16) + key->dst;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
/* Header values for reassembly */
|
||||
/* ************************************************************************* */
|
||||
static int hf_al_frag_data = -1;
|
||||
static int hf_dnp3_fragment = -1;
|
||||
static int hf_dnp3_fragments = -1;
|
||||
static int hf_dnp3_fragment_overlap = -1;
|
||||
|
@ -1374,18 +1338,6 @@ static const fragment_items dnp3_frag_items = {
|
|||
"DNP 3.0 fragments"
|
||||
};
|
||||
|
||||
/* Conversation stuff, used for tracking application message fragments */
|
||||
/* the number of entries in the memory chunk array */
|
||||
#define dnp3_conv_init_count 50
|
||||
|
||||
/* Conversation structure */
|
||||
typedef struct {
|
||||
guint conv_seq_number;
|
||||
} dnp3_conv_t;
|
||||
|
||||
/* The conversation sequence number */
|
||||
static guint seq_number = 0;
|
||||
|
||||
/* desegmentation of DNP3 over TCP */
|
||||
static gboolean dnp3_desegment = TRUE;
|
||||
|
||||
|
@ -3302,82 +3254,56 @@ dissect_dnp3_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
|
|||
|
||||
/* Check for fragmented packet */
|
||||
save_fragmented = pinfo->fragmented;
|
||||
if (! (tr_fir && tr_fin))
|
||||
|
||||
/* Reassemble AL fragments */
|
||||
static guint al_max_fragments = 60;
|
||||
static guint al_fragment_aging = 64; /* sequence numbers only 6 bit */
|
||||
fragment_head *frag_al = NULL;
|
||||
pinfo->fragmented = TRUE;
|
||||
if (!pinfo->fd->flags.visited)
|
||||
{
|
||||
guint conv_seq_number;
|
||||
fragment_head *frag_msg;
|
||||
conversation_t *conversation;
|
||||
dnp3_conv_t *conv_data_ptr;
|
||||
dl_conversation_key_t dl_conversation_key;
|
||||
|
||||
/* A fragmented packet */
|
||||
pinfo->fragmented = TRUE;
|
||||
|
||||
/* Look up the conversation to get the fragment reassembly id */
|
||||
conversation = find_or_create_conversation(pinfo);
|
||||
|
||||
/*
|
||||
* The TCP/UDP conversation is not sufficient to identify a conversation
|
||||
* on a multi-drop DNP network. Lookup conversation data based on TCP/UDP
|
||||
* conversation and the DNP src and dst addresses
|
||||
*/
|
||||
|
||||
dl_conversation_key.conversation = conversation->conv_index;
|
||||
dl_conversation_key.src = dl_src;
|
||||
dl_conversation_key.dst = dl_dst;
|
||||
|
||||
conv_data_ptr = (dnp3_conv_t*)wmem_map_lookup(dl_conversation_table, &dl_conversation_key);
|
||||
|
||||
if (!pinfo->fd->flags.visited && conv_data_ptr == NULL)
|
||||
{
|
||||
dl_conversation_key_t* new_dl_conversation_key = NULL;
|
||||
new_dl_conversation_key = wmem_new(wmem_file_scope(), dl_conversation_key_t);
|
||||
*new_dl_conversation_key = dl_conversation_key;
|
||||
|
||||
conv_data_ptr = wmem_new(wmem_file_scope(), dnp3_conv_t);
|
||||
|
||||
/*** Increment static global fragment reassembly id ***/
|
||||
conv_data_ptr->conv_seq_number = seq_number++;
|
||||
|
||||
wmem_map_insert(dl_conversation_table, new_dl_conversation_key, conv_data_ptr);
|
||||
}
|
||||
|
||||
conv_seq_number = conv_data_ptr->conv_seq_number;
|
||||
|
||||
/*
|
||||
* Add the frame to
|
||||
* whatever reassembly is in progress, if any, and see
|
||||
* if it's done.
|
||||
*/
|
||||
|
||||
frag_msg = fragment_add_seq_next(&al_reassembly_table,
|
||||
al_tvb, 0, pinfo, conv_seq_number, NULL,
|
||||
frag_al = fragment_add_seq_single_aging(&al_reassembly_table,
|
||||
al_tvb, 0, pinfo, tr_seq, NULL,
|
||||
tvb_reported_length(al_tvb), /* As this is a constructed tvb, all of it is ok */
|
||||
!tr_fin);
|
||||
|
||||
next_tvb = process_reassembled_data(al_tvb, 0, pinfo,
|
||||
"Reassembled DNP 3.0 Application Layer message", frag_msg, &dnp3_frag_items,
|
||||
NULL, dnp3_tree);
|
||||
|
||||
if (next_tvb) /* Reassembled */
|
||||
{
|
||||
/* We have the complete payload, zap the info column as the AL info takes precedence */
|
||||
col_clear(pinfo->cinfo, COL_INFO);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We don't have the complete reassembled payload. */
|
||||
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "TL fragment %u ", tr_seq);
|
||||
}
|
||||
|
||||
tr_fir, tr_fin,
|
||||
al_max_fragments, al_fragment_aging);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No reassembly required */
|
||||
next_tvb = al_tvb;
|
||||
add_new_data_source(pinfo, next_tvb, "DNP 3.0 Application Layer message");
|
||||
col_clear(pinfo->cinfo, COL_INFO);
|
||||
frag_al = fragment_get_reassembled_id(&al_reassembly_table, pinfo, tr_seq);
|
||||
}
|
||||
next_tvb = process_reassembled_data(al_tvb, 0, pinfo,
|
||||
"Reassembled DNP 3.0 Application Layer message", frag_al, &dnp3_frag_items,
|
||||
NULL, dnp3_tree);
|
||||
|
||||
if (frag_al)
|
||||
{
|
||||
if (pinfo->num == frag_al->reassembled_in)
|
||||
{
|
||||
/* As a complete AL message will have cleared the info column,
|
||||
make sure source and dest are always in the info column */
|
||||
//col_append_fstr(pinfo->cinfo, COL_INFO, "from %u to %u", dl_src, dl_dst);
|
||||
//col_set_fence(pinfo->cinfo, COL_INFO);
|
||||
dissect_dnp3_al(next_tvb, pinfo, dnp3_tree);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Lock any column info set by the DL and TL */
|
||||
col_set_fence(pinfo->cinfo, COL_INFO);
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO,
|
||||
" (Application Layer fragment %u, reassembled in packet %u)",
|
||||
tr_seq, frag_al->reassembled_in);
|
||||
proto_tree_add_item(dnp3_tree, hf_al_frag_data, al_tvb, 0, -1, ENC_NA);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO,
|
||||
" (Application Layer Unreassembled fragment %u)",
|
||||
tr_seq);
|
||||
proto_tree_add_item(dnp3_tree, hf_al_frag_data, al_tvb, 0, -1, ENC_NA);
|
||||
}
|
||||
|
||||
pinfo->fragmented = save_fragmented;
|
||||
}
|
||||
else
|
||||
|
@ -3385,21 +3311,6 @@ dissect_dnp3_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*
|
|||
/* CRC error - throw away the data. */
|
||||
next_tvb = NULL;
|
||||
}
|
||||
|
||||
/* Dissect any completed Application Layer message */
|
||||
if (next_tvb && tr_fin)
|
||||
{
|
||||
/* As a complete AL message will have cleared the info column,
|
||||
make sure source and dest are always in the info column */
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "from %u to %u", dl_src, dl_dst);
|
||||
col_set_fence(pinfo->cinfo, COL_INFO);
|
||||
dissect_dnp3_al(next_tvb, pinfo, dnp3_tree);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Lock any column info set by the DL and TL */
|
||||
col_set_fence(pinfo->cinfo, COL_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the length of the message */
|
||||
|
@ -4428,6 +4339,11 @@ proto_register_dnp3(void)
|
|||
NULL, HFILL }
|
||||
},
|
||||
|
||||
{ &hf_al_frag_data,
|
||||
{"DNP3.0 AL Fragment Data", "dnp3.al.frag_data",
|
||||
FT_BYTES, BASE_NONE, NULL, 0x00,
|
||||
"DNP 3.0 Application Layer Fragment Data", HFILL }},
|
||||
|
||||
{ &hf_dnp3_fragment,
|
||||
{ "DNP 3.0 AL Fragment", "dnp3.al.fragment",
|
||||
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
|
||||
|
@ -4539,7 +4455,6 @@ proto_register_dnp3(void)
|
|||
module_t *dnp3_module;
|
||||
expert_module_t* expert_dnp3;
|
||||
|
||||
dl_conversation_table = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), dl_conversation_hash, dl_conversation_equal);
|
||||
reassembly_table_register(&al_reassembly_table,
|
||||
&addresses_reassembly_table_functions);
|
||||
|
||||
|
|
Loading…
Reference in New Issue