Reassembly: add helper macros

Add REASSEMBLE_ITEMS_DEFINE, REASSEMBLE_INIT_HF_ITEMS
 and REASSEMBLE_INIT_ETT_ITEMS helper macros to define and
 initialize hf and ett items of reassembly much easier.

Make packet-http.c to use these macros.
This commit is contained in:
Huang Qiangxiong 2023-06-12 23:39:20 +08:00 committed by Pascal Quantin
parent d7eedba8e2
commit cd3275c1b5
2 changed files with 257 additions and 96 deletions

View File

@ -137,18 +137,6 @@ static int hf_http_unknown_header = -1;
static int hf_http_http2_settings_uri = -1;
static int hf_http_path_segment = -1;
static int hf_http_path_sub_segment = -1;
static int hf_http_body_fragments = -1;
static int hf_http_body_fragment = -1;
static int hf_http_body_fragment_overlap = -1;
static int hf_http_body_fragment_overlap_conflicts = -1;
static int hf_http_body_fragment_multiple_tails = -1;
static int hf_http_body_fragment_too_long_fragment = -1;
static int hf_http_body_fragment_error = -1;
static int hf_http_body_fragment_count = -1;
static int hf_http_body_reassembled_in = -1;
static int hf_http_body_reassembled_length = -1;
static int hf_http_body_reassembled_data = -1;
static int hf_http_body_segment = -1;
static gint ett_http = -1;
static gint ett_http_ntlmssp = -1;
@ -162,8 +150,6 @@ static gint ett_http_encoded_entity = -1;
static gint ett_http_header_item = -1;
static gint ett_http_http2_settings_item = -1;
static gint ett_http_path = -1;
static gint ett_http_body_fragment = -1;
static gint ett_http_body_fragments = -1;
static expert_field ei_http_chat = EI_INIT;
static expert_field ei_http_te_and_length = EI_INIT;
@ -194,24 +180,7 @@ static ws_mempbrk_pattern pbrk_sub_delims;
/* reassembly table for streaming chunk mode */
static reassembly_table http_streaming_reassembly_table;
static const fragment_items http_body_fragment_items = {
/* Fragment subtrees */
&ett_http_body_fragment,
&ett_http_body_fragments,
/* Fragment fields */
&hf_http_body_fragments,
&hf_http_body_fragment,
&hf_http_body_fragment_overlap,
&hf_http_body_fragment_overlap_conflicts,
&hf_http_body_fragment_multiple_tails,
&hf_http_body_fragment_too_long_fragment,
&hf_http_body_fragment_error,
&hf_http_body_fragment_count,
&hf_http_body_reassembled_in,
&hf_http_body_reassembled_length,
&hf_http_body_reassembled_data,
"Reassembled HTTP Chunked Body fragments"
};
REASSEMBLE_ITEMS_DEFINE(http_body, "HTTP Chunked Body");
/* HTTP chunk virtual frame number (similar to HTTP2 frame num) */
#define get_http_chunk_frame_num get_virtual_frame_num64
@ -4433,66 +4402,7 @@ proto_register_http(void)
NULL, HFILL } },
/* Body fragments */
{ &hf_http_body_fragments,
{ "Reassembled HTTP Chunked Body fragments", "http.body.fragments",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_http_body_fragment,
{ "Body fragment", "http.body.fragment",
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_http_body_fragment_overlap,
{ "Body fragment overlap", "http.body.fragment.overlap",
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_http_body_fragment_overlap_conflicts,
{ "Body fragment overlapping with conflicting data", "http.body.fragment.overlap.conflicts",
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_http_body_fragment_multiple_tails,
{ "Body has multiple tail fragments", "http.body.fragment.multiple_tails",
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_http_body_fragment_too_long_fragment,
{ "Body fragment too long", "http.body.fragment.too_long_fragment",
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_http_body_fragment_error,
{ "Body defragment error", "http.body.fragment.error",
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_http_body_fragment_count,
{ "Body fragment count", "http.body.fragment.count",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_http_body_reassembled_in,
{ "Reassembled body in frame", "http.body.reassembled.in",
FT_FRAMENUM, BASE_NONE, NULL, 0x0,
"Reassembled body in frame number", HFILL }
},
{ &hf_http_body_reassembled_length,
{ "Reassembled body length", "http.body.reassembled.length",
FT_UINT32, BASE_DEC, NULL, 0x0,
"Reassembled body in frame number", HFILL }
},
{ &hf_http_body_reassembled_data,
{ "Reassembled body data", "http.body.reassembled.data",
FT_BYTES, BASE_NONE, NULL, 0x0,
"Reassembled body data for multisegment PDU spanning across DATAs", HFILL }
},
{ &hf_http_body_segment,
{ "Body segment", "http.body.segment",
FT_BYTES, BASE_NONE, NULL, 0x0,
"A body segment used in reassembly", HFILL}
},
REASSEMBLE_INIT_HF_ITEMS(http_body, "HTTP Chunked Body", "http.body"),
};
static gint *ett[] = {
&ett_http,
@ -4506,8 +4416,7 @@ proto_register_http(void)
&ett_http_encoded_entity,
&ett_http_header_item,
&ett_http_http2_settings_item,
&ett_http_body_fragment,
&ett_http_body_fragments,
REASSEMBLE_INIT_ETT_ITEMS(http_body),
&ett_http_path
};

View File

@ -531,6 +531,196 @@ extern void
reassembly_table_cleanup(void);
/* ===================== Streaming data reassembly helper ===================== */
/**
* Macro to help to define ett or hf items variables for reassembly (especially for streaming reassembly).
* The statement:
*
* REASSEMBLE_ITEMS_DEFINE(foo_body, "Foo Body"); // in global scope
*
* will create global variables:
*
* static gint ett_foo_body_fragment = -1;
* static gint ett_foo_body_fragments = -1;
* static int hf_foo_body_fragment = -1;
* static int hf_foo_body_fragments = -1;
* static int hf_foo_body_fragment_overlap = -1;
* ...
* static int hf_foo_body_segment = -1;
*
* static const fragment_items foo_body_fragment_items = {
* &ett_foo_body_fragment,
* &ett_foo_body_fragments,
* &hf_foo_body_fragments,
* &hf_foo_body_fragment,
* &hf_foo_body_fragment_overlap,
* ...
* "Foo Body fragments"
* };
*/
#define REASSEMBLE_ITEMS_DEFINE(var_prefix, name_prefix) \
static gint ett_##var_prefix##_fragment = -1; \
static gint ett_##var_prefix##_fragments = -1; \
static int hf_##var_prefix##_fragments = -1; \
static int hf_##var_prefix##_fragment = -1; \
static int hf_##var_prefix##_fragment_overlap = -1; \
static int hf_##var_prefix##_fragment_overlap_conflicts = -1; \
static int hf_##var_prefix##_fragment_multiple_tails = -1; \
static int hf_##var_prefix##_fragment_too_long_fragment = -1; \
static int hf_##var_prefix##_fragment_error = -1; \
static int hf_##var_prefix##_fragment_count = -1; \
static int hf_##var_prefix##_reassembled_in = -1; \
static int hf_##var_prefix##_reassembled_length = -1; \
static int hf_##var_prefix##_reassembled_data = -1; \
static int hf_##var_prefix##_segment = -1; \
static const fragment_items var_prefix##_fragment_items = { \
&ett_##var_prefix##_fragment, \
&ett_##var_prefix##_fragments, \
&hf_##var_prefix##_fragments, \
&hf_##var_prefix##_fragment, \
&hf_##var_prefix##_fragment_overlap, \
&hf_##var_prefix##_fragment_overlap_conflicts, \
&hf_##var_prefix##_fragment_multiple_tails, \
&hf_##var_prefix##_fragment_too_long_fragment, \
&hf_##var_prefix##_fragment_error, \
&hf_##var_prefix##_fragment_count, \
&hf_##var_prefix##_reassembled_in, \
&hf_##var_prefix##_reassembled_length, \
&hf_##var_prefix##_reassembled_data, \
name_prefix " fragments" \
}
/**
* Macro to help to initialize hf (head field) items for reassembly.
* The statement:
*
* void proto_register_foo(void) {
* static hf_register_info hf[] = {
* ...
* { &hf_proto_foo_payload,
* { "Payload", "foo.payload",
* FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
* },
*
* // Add fragments items
* REASSEMBLE_INIT_HF_ITEMS(foo_body, "Foo Body", "foo.body"),
* ...
* };
* ...
* }
*
* will expand like:
*
* void proto_register_foo(void) {
* static hf_register_info hf[] = {
* ...
* { &hf_proto_foo_payload,
* { "Payload", "foo.payload",
* FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }
* },
*
* // Add fragments items
* { &hf_foo_body_fragments, \
* { "Reassembled Foo Body fragments", "foo.body.fragments", \
* FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } \
* },
* { &hf_foo_body_fragment, \
* { "Foo Body fragment", "foo.body.fragment", \
* FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } \
* },
* { &hf_foo_body_fragment_overlap, \
* { "Foo Body fragment overlap", "foo.body.fragment.overlap", \
* FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } \
* },
* ...
* };
* ...
* }
*/
#define REASSEMBLE_INIT_HF_ITEMS(var_prefix, name_prefix, abbrev_prefix) \
{ &hf_##var_prefix##_fragments, \
{ "Reassembled " name_prefix " fragments", abbrev_prefix ".fragments", \
FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } \
}, \
{ &hf_##var_prefix##_fragment, \
{ name_prefix " fragment", abbrev_prefix ".fragment", \
FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } \
}, \
{ &hf_##var_prefix##_fragment_overlap, \
{ name_prefix " fragment overlap", abbrev_prefix ".fragment.overlap", \
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } \
}, \
{ &hf_##var_prefix##_fragment_overlap_conflicts, \
{ name_prefix " fragment overlapping with conflicting data", abbrev_prefix ".fragment.overlap.conflicts", \
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } \
}, \
{ &hf_##var_prefix##_fragment_multiple_tails, \
{ name_prefix " has multiple tail fragments", abbrev_prefix ".fragment.multiple_tails", \
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } \
}, \
{ &hf_##var_prefix##_fragment_too_long_fragment, \
{ name_prefix " fragment too long", abbrev_prefix ".fragment.too_long_fragment", \
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL } \
}, \
{ &hf_##var_prefix##_fragment_error, \
{ name_prefix " defragment error", abbrev_prefix ".fragment.error", \
FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } \
}, \
{ &hf_##var_prefix##_fragment_count, \
{ name_prefix " fragment count", abbrev_prefix ".fragment.count", \
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } \
}, \
{ &hf_##var_prefix##_reassembled_in, \
{ "Reassembled in", abbrev_prefix ".reassembled.in", \
FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } \
}, \
{ &hf_##var_prefix##_reassembled_length, \
{ "Reassembled length", abbrev_prefix ".reassembled.length", \
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } \
}, \
{ &hf_##var_prefix##_reassembled_data, \
{ "Reassembled data", abbrev_prefix ".reassembled.data", \
FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } \
}, \
{ &hf_##var_prefix##_segment, \
{ name_prefix " segment", abbrev_prefix ".segment", \
FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL} \
}
/**
* Macro to help to initialize protocol subtree (ett) items for reassembly.
* The statement:
*
* void proto_register_foo(void) {
* ...
* static gint* ett[] = {
* &ett_foo_abc,
* ...
* // Add ett items
* REASSEMBLE_INIT_ETT_ITEMS(foo_body),
* ...
* };
* ...
* }
*
* will expand like:
*
* void proto_register_foo(void) {
* ...
* static gint* ett[] = {
* &ett_foo_abc,
* ...
* // Add ett items
* &ett_foo_body_fragment,
* &ett_foo_body_fragments,
* ...
* };
* ...
* }
*/
#define REASSEMBLE_INIT_ETT_ITEMS(var_prefix) \
&ett_##var_prefix##_fragment, \
&ett_##var_prefix##_fragments
/** a private structure for keeping streaming reassembly information */
typedef struct streaming_reassembly_info_t streaming_reassembly_info_t;
@ -643,7 +833,7 @@ streaming_reassembly_info_new(void);
* pinfo->desegment_offset = offset;
* // calculate how many additional bytes needed to parse head of a ProtoB message
* pinfo->desegment_len = PROTO_B_MESSAGE_HEAD_LEN - (tvb_len - offset);
* return tvb_len;
* return offset; // return the length handled by ProtoB
* }
* ...
* }
@ -657,12 +847,13 @@ streaming_reassembly_info_new(void);
* pinfo->desegment_offset = offset;
* // caculate how many additional bytes need to parsing body of a ProtoB message
* pinfo->desegment_len = body_len - (tvb_len - offset - PROTO_B_MESSAGE_HEAD_LEN);
* return tvb_len;
* return offset;
* }
* ...
* }
* ...
* }
* return tvb_len; // all bytes of this tvb are parsed
* }
* </code>
*
@ -792,6 +983,67 @@ streaming_reassembly_info_new(void);
* }
* </code>
*
* Alternatively, the code of ProtoA (packet-proto-a.c) can be made simpler with helper macros:
* <code>
* // file packet-proto-a.c
* ...
* // reassembly table for streaming chunk mode
* static reassembly_table proto_a_streaming_reassembly_table;
* // reassembly head field items definition
* REASSEMBLE_ITEMS_DEFINE(proto_a_body, "ProtoA Body");
* ...
* static int
* dissect_proto_a(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data)
* {
* ...
* streaming_reassembly_info_t* streaming_reassembly_info = NULL;
* ...
* proto_a_tree = proto_item_add_subtree(ti, ett_proto_a);
* ...
* if (!PINFO_FD_VISITED(pinfo)) {
* streaming_reassembly_info = streaming_reassembly_info_new();
* // save streaming reassembly info in the stream conversation or something like that
* save_reassembly_info(pinfo, stream_id, flow_dir, streaming_reassembly_info);
* } else {
* streaming_reassembly_info = get_reassembly_info(pinfo, stream_id, flow_dir);
* }
* ...
* while (offset < tvb_len)
* {
* ...
* payload_len = xxx;
* ...
* if (dissecting_in_streaming_mode) {
* // reassemble and call subdissector
* reassemble_streaming_data_and_call_subdissector(tvb, pinfo, offset,
* payload_len, proto_a_tree, proto_tree_get_parent_tree(proto_a_tree),
* proto_a_streaming_reassembly_table, streaming_reassembly_info,
* get_virtual_frame_num64(tvb, pinfo, offset), subdissector_handle,
* proto_tree_get_parent_tree(tree), NULL, "ProtoA Body",
* &proto_a_body_fragment_items, hf_proto_a_body_segment);
* ...
* }
* }
*
* ...
* void proto_register_proto_a(void) {
* ...
* static hf_register_info hf[] = {
* ...
* REASSEMBLE_INIT_HF_ITEMS(proto_a_body, "ProtoA Body", "protoa.body")
* }
* ...
* static gint *ett[] = {
* ...
* REASSEMBLE_INIT_ETT_ITEMS(proto_a_body)
* }
* ...
* reassembly_table_register(&proto_a_streaming_reassembly_table,
* &addresses_ports_reassembly_table_functions);
* ...
* }
* </code>
*
* @param tvb TVB contains (ProtoA) payload which will be passed to subdissector.
* @param pinfo Packet information.
* @param offset The beginning offset of payload in TVB.