diff options
author | Michael Mann <mmann78@netscape.net> | 2014-11-07 07:47:43 -0500 |
---|---|---|
committer | Michael Mann <mmann78@netscape.net> | 2014-11-08 16:33:50 +0000 |
commit | 421913b721d5b12c1f6c8a09daec35d8bae58bb5 (patch) | |
tree | 1c039d5db023456f106d3bd1d221401463639daf /epan/dissectors/packet-igmp.c | |
parent | bd5384c84a53a88c64fb79094444c063756ca183 (diff) |
Create real subdissectors to the IGMP protocol.
Change-Id: I79ee9413b87722bfe4782342737cff03cfc34495
Reviewed-on: https://code.wireshark.org/review/5179
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
Reviewed-by: Michael Mann <mmann78@netscape.net>
Diffstat (limited to 'epan/dissectors/packet-igmp.c')
-rw-r--r-- | epan/dissectors/packet-igmp.c | 321 |
1 files changed, 139 insertions, 182 deletions
diff --git a/epan/dissectors/packet-igmp.c b/epan/dissectors/packet-igmp.c index 3ce05e6bfa..968aba7f29 100644 --- a/epan/dissectors/packet-igmp.c +++ b/epan/dissectors/packet-igmp.c @@ -112,16 +112,11 @@ #include <glib.h> #include <epan/packet.h> +#include <epan/range.h> #include <epan/to_str.h> #include <epan/ipproto.h> #include <epan/in_cksum.h> #include "packet-igmp.h" -#include "packet-dvmrp.h" -#include "packet-pim.h" -#include "packet-mrdisc.h" -#include "packet-msnip.h" -#include "packet-igap.h" -#include "packet-rgmp.h" void proto_register_igmp(void); void proto_reg_handoff_igmp(void); @@ -176,32 +171,7 @@ static int ett_sqrv_bits = -1; static int ett_max_resp = -1; static int ett_mtrace_block = -1; -#define MC_ALL_ROUTERS 0xe0000002 -#define MC_ALL_IGMPV3_ROUTERS 0xe0000016 -#define MC_RGMP 0xe0000019 - - -#define IGMP_V0_CREATE_GROUP_REQUEST 0x01 -#define IGMP_V0_CREATE_GROUP_REPLY 0x02 -#define IGMP_V0_JOIN_GROUP_REQUEST 0x03 -#define IGMP_V0_JOIN_GROUP_REPLY 0x04 -#define IGMP_V0_LEAVE_GROUP_REQUEST 0x05 -#define IGMP_V0_LEAVE_GROUP_REPLY 0x06 -#define IGMP_V0_CONFIRM_GROUP_REQUEST 0x07 -#define IGMP_V0_CONFIRM_GROUP_REPLY 0x08 -#define IGMP_V1_HOST_MEMBERSHIP_QUERY 0x11 -#define IGMP_V1_HOST_MEMBERSHIP_REPORT 0x12 -#define IGMP_DVMRP 0x13 -#define IGMP_V1_PIM_ROUTING_MESSAGE 0x14 -#define IGMP_V2_MEMBERSHIP_REPORT 0x16 -#define IGMP_V2_LEAVE_GROUP 0x17 -#define IGMP_TRACEROUTE_RESPONSE 0x1e -#define IGMP_TRACEROUTE_QUERY_REQ 0x1f -#define IGMP_V3_MEMBERSHIP_REPORT 0x22 -#define IGMP_TYPE_0x23 0x23 -#define IGMP_TYPE_0x24 0x24 -#define IGMP_TYPE_0x25 0x25 -#define IGMP_TYPE_0x26 0x26 +static dissector_table_t subdissector_table; #define IGMP_TRACEROUTE_HDR_LEN 24 #define IGMP_TRACEROUTE_RSP_LEN 32 @@ -313,20 +283,6 @@ static const value_string mtrace_fwd_code_vals[] = { {0, NULL} }; -#define PRINT_IGMP_VERSION(version) \ - do { \ - proto_item *ti; \ - col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "IGMPv%d",version); \ - col_add_fstr(pinfo->cinfo, COL_INFO, \ - "%s",val_to_str(type, commands, "Unknown Type:0x%02x")); \ - /* version of IGMP protocol */ \ - ti = proto_tree_add_uint(tree, hf_version, tvb, 0, 0, version); \ - PROTO_ITEM_SET_GENERATED(ti); \ - /* type of command */ \ - proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);\ - offset += 1; \ - } while (0); - void igmp_checksum(proto_tree *tree, tvbuff_t *tvb, int hf_index, int hf_index_bad, packet_info *pinfo, guint len) { @@ -368,13 +324,50 @@ void igmp_checksum(proto_tree *tree, tvbuff_t *tvb, int hf_index, return; } +static proto_tree* +dissect_igmp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int* offset, unsigned char* type, int version) +{ + proto_item* ti; + proto_tree* igmp_tree; + + col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "IGMPv%d", version); + col_clear(pinfo->cinfo, COL_INFO); + + ti = proto_tree_add_item(tree, proto_igmp, tvb, 0, -1, ENC_NA); + igmp_tree = proto_item_add_subtree(ti, ett_igmp); + + *type = tvb_get_guint8(tvb, 0); + col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(*type, commands, "Unknown Type:0x%02x")); + + /* version of IGMP protocol */ + ti = proto_tree_add_uint(igmp_tree, hf_version, tvb, 0, 0, version); + PROTO_ITEM_SET_GENERATED(ti); + + /* type of command */ + proto_tree_add_item(igmp_tree, hf_type, tvb, 0, 1, ENC_NA); + *offset = 1; + + return igmp_tree; +} + /* Unknown IGMP message type */ static int -dissect_igmp_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset) +dissect_igmp_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) { + proto_item* ti; + proto_tree* tree; int len; + int offset = 0; + unsigned char type; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "IGMP"); + col_clear(pinfo->cinfo, COL_INFO); + + ti = proto_tree_add_item(parent_tree, proto_igmp, tvb, offset, -1, ENC_NA); + tree = proto_item_add_subtree(ti, ett_igmp); + type = tvb_get_guint8(tvb, offset); col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, commands, "Unknown Type:0x%02x")); @@ -565,11 +558,14 @@ dissect_v3_group_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tr /* dissectors for version 3, rfc3376 */ static int -dissect_igmp_v3_report(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset) +dissect_igmp_v3_report(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_) { + proto_tree* tree; guint16 num; + int offset; + unsigned char type; - PRINT_IGMP_VERSION(3); + tree = dissect_igmp_common(tvb, pinfo, parent_tree, &offset, &type, 3); /* skip reserved field*/ offset += 1; @@ -596,12 +592,15 @@ dissect_igmp_v3_report(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int } static int -dissect_igmp_v3_query(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset) +dissect_igmp_v3_query(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_) { + proto_tree* tree; guint16 num; guint32 maddr; + int offset; + unsigned char type; - PRINT_IGMP_VERSION(3); + tree = dissect_igmp_common(tvb, pinfo, parent_tree, &offset, &type, 3); num = tvb_get_ntohs(tvb, offset+9); /* max resp code */ @@ -648,12 +647,15 @@ dissect_igmp_v3_query(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int t /* dissector for version 2 query and report, rfc2236 */ static int -dissect_igmp_v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset) +dissect_igmp_v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_) { + proto_tree* tree; guint8 tsecs; guint32 maddr; + int offset; + unsigned char type; - PRINT_IGMP_VERSION(2); + tree = dissect_igmp_common(tvb, pinfo, parent_tree, &offset, &type, 2); /* max resp time */ tsecs = tvb_get_guint8(tvb, offset); @@ -672,15 +674,17 @@ dissect_igmp_v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, i if (! maddr) { col_append_str(pinfo->cinfo, COL_INFO, ", general"); } else { - if (type == IGMP_V2_LEAVE_GROUP) { - col_append_fstr(pinfo->cinfo, COL_INFO, - " %s", ip_to_str((guint8*)&maddr)); - } else if (type == IGMP_V1_HOST_MEMBERSHIP_QUERY) { - col_append_fstr(pinfo->cinfo, COL_INFO, - ", specific for group %s", ip_to_str((guint8*)&maddr)); - } else { /* IGMP_V2_MEMBERSHIP_REPORT is the only case left */ - col_append_fstr(pinfo->cinfo, COL_INFO, - " group %s", ip_to_str((guint8*)&maddr)); + switch(type) + { + case IGMP_V2_LEAVE_GROUP: + col_append_fstr(pinfo->cinfo, COL_INFO, " %s", ip_to_str((guint8*)&maddr)); + break; + case IGMP_V1_HOST_MEMBERSHIP_QUERY: + col_append_fstr(pinfo->cinfo, COL_INFO, ", specific for group %s", ip_to_str((guint8*)&maddr)); + break; + default: /* IGMP_V2_MEMBERSHIP_REPORT is the only case left */ + col_append_fstr(pinfo->cinfo, COL_INFO, " group %s", ip_to_str((guint8*)&maddr)); + break; } } offset +=4; @@ -690,9 +694,13 @@ dissect_igmp_v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, i /* dissector for version 1 query and report, rfc1054 */ static int -dissect_igmp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset) +dissect_igmp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_) { - PRINT_IGMP_VERSION(1); + proto_tree* tree; + int offset; + unsigned char type; + + tree = dissect_igmp_common(tvb, pinfo, parent_tree, &offset, &type, 1); /* skip unused byte */ offset += 1; @@ -710,11 +718,14 @@ dissect_igmp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, i /* dissector for version 0, rfc988 */ static int -dissect_igmp_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset) +dissect_igmp_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_) { + proto_tree* tree; unsigned char code; + int offset; + unsigned char type; - PRINT_IGMP_VERSION(0); + tree = dissect_igmp_common(tvb, pinfo, parent_tree, &offset, &type, 0); /* Code */ code = tvb_get_guint8(tvb, offset); @@ -748,13 +759,39 @@ dissect_igmp_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, i return offset; } +static int +dissect_igmp_mquery(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data) +{ + if ( tvb_reported_length(tvb)>=12 ) { + /* version 3 */ + return dissect_igmp_v3_query(tvb, pinfo, parent_tree, data); + } + + /* v1 and v2 differs in second byte of header */ + if (tvb_get_guint8(tvb, 1)) { + return dissect_igmp_v2(tvb, pinfo, parent_tree, data); + } + + return dissect_igmp_v1(tvb, pinfo, parent_tree, data); +} + /* dissector for multicast traceroute, rfc???? */ static int -dissect_igmp_mtrace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset) +dissect_igmp_mtrace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_) { + proto_tree* tree; + proto_item* ti; + int offset = 0; + unsigned char type; const char *typestr, *blocks = NULL; char buf[20]; + ti = proto_tree_add_item(parent_tree, proto_igmp, tvb, offset, -1, ENC_NA); + tree = proto_item_add_subtree(ti, ett_igmp); + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "IGMP"); + col_clear(pinfo->cinfo, COL_INFO); + /* All multicast traceroute packets (Query, Request and * Response) have the same fixed header. Request and Response * have one or more response data blocks following this fixed @@ -763,6 +800,7 @@ dissect_igmp_mtrace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int typ * IGMP packet length. Queries are only * IGMP_TRACEROUTE_HDR_LEN bytes long. */ + type = tvb_get_guint8(tvb, offset); if (type == IGMP_TRACEROUTE_RESPONSE) { int i = (tvb_reported_length_remaining(tvb, offset) - IGMP_TRACEROUTE_HDR_LEN) / IGMP_TRACEROUTE_RSP_LEN; g_snprintf(buf, sizeof buf, ", %d block%s", i, plurality(i, "", "s")); @@ -881,126 +919,15 @@ dissect_igmp_mtrace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int typ static void dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) { - proto_tree *tree; - proto_item *item; int offset = 0; unsigned char type; - guint32 dst; - - item = proto_tree_add_item(parent_tree, proto_igmp, tvb, offset, -1, ENC_NA); - tree = proto_item_add_subtree(item, ett_igmp); - - col_set_str(pinfo->cinfo, COL_PROTOCOL, "IGMP"); - col_clear(pinfo->cinfo, COL_INFO); type = tvb_get_guint8(tvb, offset); - /* version 0 */ - if ((type&0xf0)==0){ - offset = dissect_igmp_v0(tvb, pinfo, tree, type, offset); + if (!dissector_try_uint(subdissector_table, type, tvb, pinfo, parent_tree)) + { + dissect_igmp_unknown(tvb, pinfo, parent_tree); } - - switch (type) { - case IGMP_V1_HOST_MEMBERSHIP_QUERY: /* 0x11 v1/v2/v3 */ - if ( tvb_reported_length(tvb)>=12 ) { - /* version 3 */ - offset = dissect_igmp_v3_query(tvb, pinfo, tree, type, offset); - } else { - /* v1 and v2 differs in second byte of header */ - if (tvb_get_guint8(tvb, offset+1)) { - offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset); - } else { - offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset); - } - } - break; - - case IGMP_V1_HOST_MEMBERSHIP_REPORT: /* 0x12 v1 only */ - offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset); - break; - - case IGMP_DVMRP: - offset = dissect_dvmrp(tvb, pinfo, parent_tree, offset); - break; - - case IGMP_V1_PIM_ROUTING_MESSAGE: - offset = dissect_pimv1(tvb, pinfo, parent_tree, offset); - break; - - case IGMP_V2_MEMBERSHIP_REPORT: - case IGMP_V2_LEAVE_GROUP: - offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset); - break; - - case IGMP_TRACEROUTE_RESPONSE: - case IGMP_TRACEROUTE_QUERY_REQ: - offset = dissect_igmp_mtrace(tvb, pinfo, tree, type, offset); - break; - - case IGMP_V3_MEMBERSHIP_REPORT: - offset = dissect_igmp_v3_report(tvb, pinfo, tree, type, offset); - break; - - case IGMP_TYPE_0x23: - dst = g_htonl(MC_ALL_IGMPV3_ROUTERS); - if (!memcmp(pinfo->dst.data, &dst, 4)) { - offset = dissect_msnip(tvb, pinfo, parent_tree, offset); - } - break; - - case IGMP_TYPE_0x24: - dst = g_htonl(MC_ALL_ROUTERS); - if (!memcmp(pinfo->dst.data, &dst, 4)) { - offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset); - } - dst = g_htonl(MC_ALL_IGMPV3_ROUTERS); - if (!memcmp(pinfo->dst.data, &dst, 4)) { - offset = dissect_msnip(tvb, pinfo, parent_tree, offset); - } - break; - - case IGMP_TYPE_0x25: - if ( tvb_reported_length(tvb)>=8 ) { - /* if len of igmp packet>=8 we assume it is MSNIP */ - offset = dissect_msnip(tvb, pinfo, parent_tree, offset); - } else { - /* ok it's not MSNIP, check if it might be MRDISC */ - dst = g_htonl(MC_ALL_ROUTERS); - if (!memcmp(pinfo->dst.data, &dst, 4)) { - offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset); - } - } - break; - - case IGMP_TYPE_0x26: - dst = g_htonl(MC_ALL_ROUTERS); - if (!memcmp(pinfo->dst.data, &dst, 4)) { - offset = dissect_mrdisc(tvb, pinfo, parent_tree, offset); - } - break; - - case IGMP_IGAP_JOIN: - case IGMP_IGAP_QUERY: - case IGMP_IGAP_LEAVE: - offset = dissect_igap(tvb, pinfo, parent_tree, offset); - break; - - case IGMP_RGMP_HELLO: - case IGMP_RGMP_BYE: - case IGMP_RGMP_JOIN: - case IGMP_RGMP_LEAVE: - dst = g_htonl(MC_RGMP); - if (!memcmp(pinfo->dst.data, &dst, 4)) { - offset = dissect_rgmp(tvb, pinfo, parent_tree, offset); - } - break; - - default: - offset = dissect_igmp_unknown(tvb, pinfo, tree, type, offset); - break; - } - - proto_item_set_len(item, offset); } void @@ -1188,15 +1115,45 @@ proto_register_igmp(void) "IGMP", "igmp"); proto_register_field_array(proto_igmp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); + + subdissector_table = register_dissector_table("igmp.type", "IGMP commands", FT_UINT32, BASE_HEX); + } void proto_reg_handoff_igmp(void) { - dissector_handle_t igmp_handle; + dissector_handle_t igmp_handle, igmpv0_handle, igmpv1_handle, igmpv2_handle, + igmp_mquery_handle, igmp_mtrace_handle, igmp_report_handle; + range_t *igmpv0_range; igmp_handle = create_dissector_handle(dissect_igmp, proto_igmp); dissector_add_uint("ip.proto", IP_PROTO_IGMP, igmp_handle); + + /* IGMP v0 */ + range_convert_str(&igmpv0_range, "0-15", 15); + igmpv0_handle = new_create_dissector_handle(dissect_igmp_v0, proto_igmp); + dissector_add_uint_range("igmp.type", igmpv0_range, igmpv0_handle); + + /* IGMP v1 */ + igmpv1_handle = new_create_dissector_handle(dissect_igmp_v1, proto_igmp); + dissector_add_uint("igmp.type", IGMP_V1_HOST_MEMBERSHIP_REPORT, igmpv1_handle); + + /* IGMP v2 */ + igmpv2_handle = new_create_dissector_handle(dissect_igmp_v2, proto_igmp); + dissector_add_uint("igmp.type", IGMP_V2_MEMBERSHIP_REPORT, igmpv2_handle); + dissector_add_uint("igmp.type", IGMP_V2_LEAVE_GROUP, igmpv2_handle); + + /* IGMP_V1_HOST_MEMBERSHIP_QUERY, all versions */ + igmp_mquery_handle = new_create_dissector_handle(dissect_igmp_mquery, proto_igmp); + dissector_add_uint("igmp.type", IGMP_V1_HOST_MEMBERSHIP_QUERY, igmp_mquery_handle); + + igmp_report_handle = new_create_dissector_handle(dissect_igmp_v3_report, proto_igmp); + dissector_add_uint("igmp.type", IGMP_V3_MEMBERSHIP_REPORT, igmp_report_handle); + + igmp_mtrace_handle = new_create_dissector_handle(dissect_igmp_mtrace, proto_igmp); + dissector_add_uint("igmp.type", IGMP_TRACEROUTE_RESPONSE, igmp_mtrace_handle); + dissector_add_uint("igmp.type", IGMP_TRACEROUTE_QUERY_REQ, igmp_mtrace_handle); } /* |