Add support for IPv6 heuristic dissectors.

This adds limited support for heuristic subdissectors with IPv6.
The initial motivation is STT but it should transparently work
for other protocols using IP heuristic dissectors in a manner
similar to the non-heuristic dissectors.

The limitation is in regards to IPv6 extension headers. IPv6 has
multiple checks against the next protocol table when determining
when the protocol is an unknown extension header or not. This
assumes that the check is cheap and has no side effects, neither
of which is true for heuristic dissectors. As a compromise, this
assumes that the next protocol is registered as protocol, even
if is not the one that is ultimately dissected. Although not
strictly correct, in practice this is true for existing protocols
and likely future ones because the heuristic dissectors are
overriding non-heuristic ones.

Change-Id: Iff8cfc148ced5ca16191cc2b1879ad87e38d23cd
Reviewed-on: https://code.wireshark.org/review/8197
Petri-Dish: Pascal Quantin <pascal.quantin@gmail.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com>
This commit is contained in:
Jesse Gross 2015-04-25 20:29:30 -07:00 committed by Pascal Quantin
parent 812d31122a
commit 26a3573f90
3 changed files with 43 additions and 14 deletions

View File

@ -1950,6 +1950,31 @@ static const true_false_string flags_sf_set_evil = {
"Not evil"
};
gboolean
ip_try_dissect(gboolean heur_first, tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, ws_ip *iph)
{
heur_dtbl_entry_t *hdtbl_entry;
if ((heur_first) && (dissector_try_heuristic(heur_subdissector_list, tvb,
pinfo, tree, &hdtbl_entry, iph))) {
return TRUE;
}
if (dissector_try_uint_new(ip_dissector_table, iph->ip_p, tvb, pinfo,
tree, TRUE, iph)) {
return TRUE;
}
if ((!heur_first) && (!dissector_try_heuristic(heur_subdissector_list, tvb,
pinfo, tree, &hdtbl_entry,
iph))) {
return TRUE;
}
return FALSE;
}
static void
dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
{
@ -1959,7 +1984,6 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
int offset = 0, dst_off;
guint hlen, optlen;
guint16 flags;
guint8 nxt;
guint16 ipsum;
guint16 expected_cksum;
fragment_head *ipfd_head = NULL;
@ -1972,7 +1996,6 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
proto_item *item = NULL, *ttl_item;
proto_tree *checksum_tree;
guint16 ttl;
heur_dtbl_entry_t *hdtbl_entry;
tree = parent_tree;
iph = (ws_ip *)wmem_alloc(wmem_packet_scope(), sizeof(ws_ip));
@ -2349,7 +2372,6 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
/* Skip over header + options */
offset += hlen;
nxt = iph->ip_p; /* XXX - what if this isn't the same for all fragments? */
/* If ip_defragment is on, this is a fragment, we have all the data
* in the fragment, and the header checksum is valid, then just add
@ -2420,18 +2442,13 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
even be labeled as an IP frame; ideally, if a frame being dissected
throws an exception, it'll be labeled as a mangled frame of the
type in question. */
if ((try_heuristic_first) && (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, parent_tree, &hdtbl_entry, iph))) {
/* We're good */
} else if (!dissector_try_uint_new(ip_dissector_table, nxt, next_tvb, pinfo,
parent_tree, TRUE, iph)) {
if ((!try_heuristic_first) && (!dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, parent_tree, &hdtbl_entry, iph))) {
/* Unknown protocol */
if (update_col_info) {
col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%u)",
if (!ip_try_dissect(try_heuristic_first, next_tvb, pinfo, parent_tree, iph)) {
/* Unknown protocol */
if (update_col_info) {
col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%u)",
ipprotostr(iph->ip_p), iph->ip_p);
}
call_dissector(data_handle,next_tvb, pinfo, parent_tree);
}
call_dissector(data_handle,next_tvb, pinfo, parent_tree);
}
pinfo->fragmented = save_fragmented;
}

View File

@ -43,6 +43,8 @@ typedef struct _ws_ip
} ws_ip;
void capture_ip(const guchar *, int, int, packet_counts *);
gboolean ip_try_dissect(gboolean heur_first, tvbuff_t *tvb,
packet_info *pinfo, proto_tree *tree, ws_ip *iph);
/* Export the DSCP extended value-string table for other protocols */
WS_DLL_PUBLIC value_string_ext dscp_vals_ext;

View File

@ -472,6 +472,9 @@ static gboolean ipv6_use_geoip = TRUE;
/* Perform strict RFC adherence checking */
static gboolean g_ipv6_rpl_srh_strict_rfc_checking = FALSE;
/* Use heuristics to determine subdissector */
static gboolean try_heuristic_first = FALSE;
#ifndef offsetof
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
#endif
@ -2199,8 +2202,10 @@ again:
else
pinfo->fragmented = FALSE;
iph.ip_p = nxt;
/* do lookup with the subdissector table */
if (!dissector_try_uint_new(ip_dissector_table, nxt, next_tvb, pinfo, tree, TRUE, &iph)) {
if (!ip_try_dissect(try_heuristic_first, next_tvb, pinfo, tree, &iph)) {
/* Unknown protocol.
Handle "no next header" specially. */
if (nxt != IP_PROTO_NONE) {
@ -3018,6 +3023,11 @@ proto_register_ipv6(void)
"Whether to check that all RPL Source Routing Headers adhere to RFC 6554",
&g_ipv6_rpl_srh_strict_rfc_checking);
prefs_register_bool_preference(ipv6_module, "try_heuristic_first",
"Try heuristic sub-dissectors first",
"Try to decode a packet using an heuristic sub-dissector before using a sub-dissector registered to a specific port",
&try_heuristic_first);
register_dissector("ipv6", dissect_ipv6, proto_ipv6);
register_init_routine(ipv6_reassemble_init);
ipv6_tap = register_tap("ipv6");