2 * Routines for IGMP packet disassembly
5 * <See AUTHORS for emails>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
14 IGMP is defined in the following RFCs
15 RFC988 Version 0 Obsolete
17 RFC1112 Version 1 (same as RFC1054 as far as we are concerned)
21 Size in bytes for each packet
22 type RFC988 RFC1054 RFC2236 RFC3376 DVMRP MRDISC MSNIP IGAP RGMP
50 * Differs in second byte of protocol. Always 0 in V1
53 Multicast traceroute was taken from
54 draft-ietf-idmr-traceroute-ipm-07.txt
56 Size in bytes for each packet
57 type draft-ietf-idmr-traceroute-ipm-07.ps
59 0x1f 24 + n*32 (n == 0 for Query)
61 x DVMRP Protocol see packet-dvmrp.c
63 DVMRP is defined in the following RFCs
65 draft-ietf-idmr-dvmrp-v3-10.txt Version 3
67 V1 and V3 can be distinguished by looking at bytes 6 and 7 in the
69 If header[6]==0xff and header[7]==0x03 we have version 3.
71 a MRDISC Protocol see packet-mrdisc.c
73 MRDISC : IGMP Multicast Router DISCovery
74 draft-ietf-idmr-igmp-mrdisc-06.txt
75 TTL == 1 and IP.DST==224.0.0.2 for all packets
77 b MSNIP Protocol see packet-msnip.c
79 MSNIP : Multicast Source Notification of Interest Protocol
80 draft-ietf-idmr-msnip-00.txt
81 0x23, 0x24 are sent with ip.dst==224.0.0.22
82 0x25 is sent as unicast.
84 c IGAP Protocol see packet-igap.c
86 IGAP : Internet Group membership Authentication Protocol
87 draft-hayashi-igap-03.txt
89 d RGMP Protocol see packet-rgmp.c
91 RGMP : Router-port Group Management Protocol
93 TTL == 1 and IP.DST==224.0.0.25 for all packets
99 #include <epan/packet.h>
100 #include <epan/expert.h>
101 #include <epan/range.h>
102 #include <epan/to_str.h>
103 #include <epan/ipproto.h>
104 #include <epan/in_cksum.h>
105 #include <epan/tfs.h>
106 #include <wsutil/array.h>
108 #include <wsutil/str_util.h>
109 #include "packet-igmp.h"
111 void proto_register_igmp(void);
112 void proto_reg_handoff_igmp(void);
114 static dissector_handle_t igmp_handle
, igmpv0_handle
, igmpv1_handle
, igmpv2_handle
;
116 static int proto_igmp
;
118 static int hf_reserved
;
119 static int hf_version
;
120 static int hf_group_type
;
121 static int hf_reply_code
;
122 static int hf_reply_pending
;
123 static int hf_checksum
;
124 static int hf_checksum_status
;
125 static int hf_identifier
;
126 static int hf_access_key
;
127 static int hf_max_resp
;
128 static int hf_max_resp_exp
;
129 static int hf_max_resp_mant
;
130 static int hf_suppress
;
133 static int hf_num_src
;
135 static int hf_num_grp_recs
;
136 static int hf_record_type
;
137 static int hf_aux_data_len
;
139 static int hf_aux_data
;
141 static int hf_mtrace_max_hops
;
142 static int hf_mtrace_saddr
;
143 static int hf_mtrace_raddr
;
144 static int hf_mtrace_rspaddr
;
145 static int hf_mtrace_resp_ttl
;
146 static int hf_mtrace_q_id
;
147 static int hf_mtrace_q_arrival
;
148 static int hf_mtrace_q_inaddr
;
149 static int hf_mtrace_q_outaddr
;
150 static int hf_mtrace_q_prevrtr
;
151 static int hf_mtrace_q_inpkt
;
152 static int hf_mtrace_q_outpkt
;
153 static int hf_mtrace_q_total
;
154 static int hf_mtrace_q_rtg_proto
;
155 static int hf_mtrace_q_fwd_ttl
;
156 static int hf_mtrace_q_mbz
;
157 static int hf_mtrace_q_s
;
158 static int hf_mtrace_q_src_mask
;
159 static int hf_mtrace_q_fwd_code
;
162 static int ett_group_record
;
163 static int ett_max_resp
;
164 static int ett_mtrace_block
;
166 static expert_field ei_checksum
;
168 static dissector_table_t subdissector_table
;
170 #define IGMP_TRACEROUTE_HDR_LEN 24
171 #define IGMP_TRACEROUTE_RSP_LEN 32
173 static const value_string commands
[] = {
174 {IGMP_V0_CREATE_GROUP_REQUEST
, "Create Group Request" },
175 {IGMP_V0_CREATE_GROUP_REPLY
, "Create Group Reply" },
176 {IGMP_V0_JOIN_GROUP_REQUEST
, "Join Group Request" },
177 {IGMP_V0_JOIN_GROUP_REPLY
, "Join Group Reply" },
178 {IGMP_V0_LEAVE_GROUP_REQUEST
, "Leave Group Request" },
179 {IGMP_V0_LEAVE_GROUP_REPLY
, "Leave Group Reply" },
180 {IGMP_V0_CONFIRM_GROUP_REQUEST
, "Confirm Group Request" },
181 {IGMP_V0_CONFIRM_GROUP_REPLY
, "Confirm Group Reply" },
182 {IGMP_V1_HOST_MEMBERSHIP_QUERY
, "Membership Query" },
183 {IGMP_V1_HOST_MEMBERSHIP_REPORT
,"Membership Report" },
184 {IGMP_DVMRP
, "DVMRP Protocol" },
185 {IGMP_V1_PIM_ROUTING_MESSAGE
, "PIM Routing Message" },
186 {IGMP_V2_MEMBERSHIP_REPORT
, "Membership Report" },
187 {IGMP_V2_LEAVE_GROUP
, "Leave Group" },
188 {IGMP_TRACEROUTE_RESPONSE
, "Traceroute Response" },
189 {IGMP_TRACEROUTE_QUERY_REQ
, "Traceroute Query or Request" },
190 {IGMP_V3_MEMBERSHIP_REPORT
, "Membership Report" },
194 #define IGMP_V3_S 0x08
195 #define IGMP_V3_QRV_MASK 0x07
197 #define IGMP_MAX_RESP_EXP 0x70
198 #define IGMP_MAX_RESP_MANT 0x0f
200 #define IGMP_V0_GROUP_PUBLIC 0x00
201 #define IGMP_V0_GROUP_PRIVATE 0x01
203 static const value_string vs_group_type
[] = {
204 {IGMP_V0_GROUP_PUBLIC
, "Public Group" },
205 {IGMP_V0_GROUP_PRIVATE
, "Private Group" },
209 #define IGMP_V0_REPLY_GRANTED 0x00
210 #define IGMP_V0_REPLY_NO_RESOURCES 0x01
211 #define IGMP_V0_REPLY_INVALID_CODE 0x02
212 #define IGMP_V0_REPLY_INVALID_GROUP 0x03
213 #define IGMP_V0_REPLY_INVALID_KEY 0x04
215 static const value_string vs_reply_code
[] = {
216 {IGMP_V0_REPLY_GRANTED
, "Request Granted" },
217 {IGMP_V0_REPLY_NO_RESOURCES
, "Request Denied, No Resources" },
218 {IGMP_V0_REPLY_INVALID_CODE
, "Request Denied, Invalid Code" },
219 {IGMP_V0_REPLY_INVALID_GROUP
, "Request Denied, Invalid Group" },
220 {IGMP_V0_REPLY_INVALID_KEY
, "Request Denied, Invalid Key" },
224 static const true_false_string tfs_s
= {
225 "SUPPRESS router side processing",
226 "Do not suppress router side processing"
229 #define IGMP_V3_MODE_IS_INCLUDE 1
230 #define IGMP_V3_MODE_IS_EXCLUDE 2
231 #define IGMP_V3_CHANGE_TO_INCLUDE_MODE 3
232 #define IGMP_V3_CHANGE_TO_EXCLUDE_MODE 4
233 #define IGMP_V3_ALLOW_NEW_SOURCES 5
234 #define IGMP_V3_BLOCK_OLD_SOURCES 6
236 static const value_string vs_record_type
[] = {
237 {IGMP_V3_MODE_IS_INCLUDE
, "Mode Is Include" },
238 {IGMP_V3_MODE_IS_EXCLUDE
, "Mode Is Exclude" },
239 {IGMP_V3_CHANGE_TO_INCLUDE_MODE
,"Change To Include Mode" },
240 {IGMP_V3_CHANGE_TO_EXCLUDE_MODE
,"Change To Exclude Mode" },
241 {IGMP_V3_ALLOW_NEW_SOURCES
, "Allow New Sources" },
242 {IGMP_V3_BLOCK_OLD_SOURCES
, "Block Old Sources" },
246 static const value_string mtrace_rtg_vals
[] = {
251 {5, "PIM using special routing table" },
252 {6, "PIM using a static route" },
253 {7, "DVMRP using a static route" },
254 {8, "PIM using MBGP (aka BGP4+) route" },
255 {9, "CBT using special routing table" },
256 {10, "CBT using a static route" },
257 {11, "PIM using state created by Assert processing" },
261 static const value_string mtrace_fwd_code_vals
[] = {
264 {0x02, "PRUNE_SENT" },
265 {0x03, "PRUNE_RCVD" },
268 {0x06, "WRONG_LAST_HOP" },
269 {0x07, "NOT_FORWARDING" },
270 {0x08, "REACHED_RP" },
272 {0x0A, "NO_MULTICAST" },
273 {0x0B, "INFO_HIDDEN" },
275 {0x82, "OLD_ROUTER" },
276 {0x83, "ADMIN_PROHIB" },
280 void igmp_checksum(proto_tree
*tree
, tvbuff_t
*tvb
, int hf_index
,
281 int hf_index_status
, expert_field
* ei_index
, packet_info
*pinfo
, unsigned len
)
287 * Checksum the entire IGMP packet.
289 len
= tvb_reported_length(tvb
);
292 if (!pinfo
->fragmented
&& tvb_captured_length(tvb
) >= len
) {
294 * The packet isn't part of a fragmented datagram and isn't
295 * truncated, so we can checksum it.
297 SET_CKSUM_VEC_TVB(cksum_vec
[0], tvb
, 0, len
);
298 proto_tree_add_checksum(tree
, tvb
, 2, hf_index
, hf_index_status
, ei_index
, pinfo
, in_cksum(&cksum_vec
[0], 1),
299 ENC_BIG_ENDIAN
, PROTO_CHECKSUM_VERIFY
|PROTO_CHECKSUM_IN_CKSUM
);
301 proto_tree_add_checksum(tree
, tvb
, 2, hf_index
, hf_index_status
, ei_index
, pinfo
, 0, ENC_BIG_ENDIAN
, PROTO_CHECKSUM_NO_FLAGS
);
307 dissect_igmp_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int* offset
, unsigned char* type
, int version
)
310 proto_tree
* igmp_tree
;
312 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "IGMPv%d", version
);
313 col_clear(pinfo
->cinfo
, COL_INFO
);
315 ti
= proto_tree_add_item(tree
, proto_igmp
, tvb
, 0, -1, ENC_NA
);
316 igmp_tree
= proto_item_add_subtree(ti
, ett_igmp
);
318 *type
= tvb_get_uint8(tvb
, 0);
319 col_add_str(pinfo
->cinfo
, COL_INFO
, val_to_str(*type
, commands
, "Unknown Type:0x%02x"));
321 /* version of IGMP protocol */
322 ti
= proto_tree_add_uint(igmp_tree
, hf_version
, tvb
, 0, 0, version
);
323 proto_item_set_generated(ti
);
325 /* type of command */
326 proto_tree_add_item(igmp_tree
, hf_type
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
333 /* Unknown IGMP message type */
335 dissect_igmp_unknown(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
)
343 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IGMP");
344 col_clear(pinfo
->cinfo
, COL_INFO
);
346 ti
= proto_tree_add_item(parent_tree
, proto_igmp
, tvb
, offset
, -1, ENC_NA
);
347 tree
= proto_item_add_subtree(ti
, ett_igmp
);
349 type
= tvb_get_uint8(tvb
, offset
);
350 col_add_str(pinfo
->cinfo
, COL_INFO
,
351 val_to_str(type
, commands
, "Unknown Type:0x%02x"));
353 /* type of command */
354 proto_tree_add_uint(tree
, hf_type
, tvb
, offset
, 1, type
);
357 /* Just call the rest of it "data" */
358 len
= tvb_captured_length_remaining(tvb
, offset
);
359 proto_tree_add_item(tree
, hf_data
, tvb
, offset
, -1, ENC_NA
);
367 /*************************************************************
368 * IGMP Protocol dissectors
369 *************************************************************/
371 dissect_v3_max_resp(tvbuff_t
*tvb
, proto_tree
*parent_tree
, int offset
)
378 bits
= tvb_get_uint8(tvb
, offset
);
380 tsecs
= ((bits
&IGMP_MAX_RESP_MANT
)|0x10);
381 tsecs
= tsecs
<< ( ((bits
&IGMP_MAX_RESP_EXP
)>>4) + 3);
386 item
= proto_tree_add_uint_format_value(parent_tree
, hf_max_resp
, tvb
,
387 offset
, 1, tsecs
, "%.1f sec (0x%02x)",tsecs
*0.1,bits
);
390 tree
= proto_item_add_subtree(item
, ett_max_resp
);
392 proto_tree_add_uint(tree
, hf_max_resp_exp
, tvb
, offset
, 1,
394 proto_tree_add_uint(tree
, hf_max_resp_mant
, tvb
, offset
, 1,
404 dissect_v3_sqrv_bits(tvbuff_t
*tvb
, proto_tree
*parent_tree
, int offset
)
406 static int * const bits
[] = {
412 proto_tree_add_bitmask_list(parent_tree
, tvb
, offset
, 1, bits
, ENC_NA
);
419 dissect_v3_group_record(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, int offset
)
423 int old_offset
= offset
;
426 const char *maddr_str
;
429 tree
= proto_tree_add_subtree_format(parent_tree
, tvb
, offset
, -1,
430 ett_group_record
, &item
, "Group Record : %s %s",
431 tvb_ip_to_str(pinfo
->pool
, tvb
, offset
+4),
432 val_to_str_const(tvb_get_uint8(tvb
, offset
), vs_record_type
,"")
436 record_type
= tvb_get_uint8(tvb
, offset
);
437 proto_tree_add_item(tree
, hf_record_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
441 adl
= tvb_get_uint8(tvb
, offset
);
442 proto_tree_add_uint(tree
, hf_aux_data_len
, tvb
, offset
, 1, adl
);
445 /*number of sources*/
446 num
= tvb_get_ntohs(tvb
, offset
);
447 proto_tree_add_uint(tree
, hf_num_src
, tvb
, offset
, 2, num
);
450 /* multicast address */
451 proto_tree_add_item(tree
, hf_maddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
452 maddr_str
= tvb_ip_to_str(pinfo
->pool
, tvb
, offset
);
456 switch(record_type
) {
457 case IGMP_V3_MODE_IS_INCLUDE
:
458 case IGMP_V3_CHANGE_TO_INCLUDE_MODE
:
459 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " / Leave group %s", maddr_str
);
461 case IGMP_V3_MODE_IS_EXCLUDE
:
462 case IGMP_V3_CHANGE_TO_EXCLUDE_MODE
:
463 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
464 " / Join group %s for any sources", maddr_str
);
466 case IGMP_V3_ALLOW_NEW_SOURCES
:
467 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
468 " / Group %s, ALLOW_NEW_SOURCES but no source specified (?)",
471 case IGMP_V3_BLOCK_OLD_SOURCES
:
472 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
473 " / Group %s, BLOCK_OLD_SOURCES but no source specified (?)",
477 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
478 " / Group %s, unknown record type (?)", maddr_str
);
482 switch(record_type
) {
483 case IGMP_V3_MODE_IS_INCLUDE
:
484 case IGMP_V3_CHANGE_TO_INCLUDE_MODE
:
485 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
486 " / Join group %s for source%s {",
487 maddr_str
, (num
>1) ? "s in" : "");
489 case IGMP_V3_MODE_IS_EXCLUDE
:
490 case IGMP_V3_CHANGE_TO_EXCLUDE_MODE
:
491 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
492 " / Join group %s, for source%s {",
493 maddr_str
, (num
>1) ? "s not in" : " not");
495 case IGMP_V3_ALLOW_NEW_SOURCES
:
496 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
497 " / Group %s, new source%s {",
498 maddr_str
, (num
>1) ? "s" : "");
500 case IGMP_V3_BLOCK_OLD_SOURCES
:
501 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
502 " / Group %s, block source%s {",
503 maddr_str
, (num
>1) ? "s" : "");
506 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
507 " / Group %s, unknown record type (?), sources {",
513 /* source addresses */
515 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s%s",
516 tvb_ip_to_str(pinfo
->pool
, tvb
, offset
), (num
?", ":"}"));
518 proto_tree_add_item(tree
, hf_saddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
524 proto_tree_add_item(tree
, hf_aux_data
, tvb
, offset
, adl
*4, ENC_NA
);
528 proto_item_set_len(item
, offset
-old_offset
);
532 /* dissectors for version 3, rfc3376 */
534 dissect_igmp_v3_report(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
541 tree
= dissect_igmp_common(tvb
, pinfo
, parent_tree
, &offset
, &type
, 3);
543 proto_tree_add_item(tree
, hf_reserved
, tvb
, offset
, 1, ENC_NA
);
547 igmp_checksum(tree
, tvb
, hf_checksum
, hf_checksum_status
, &ei_checksum
, pinfo
, 0);
550 proto_tree_add_item(tree
, hf_reserved
, tvb
, offset
, 2, ENC_NA
);
553 /* number of group records */
554 num
= tvb_get_ntohs(tvb
, offset
);
556 col_append_str(pinfo
->cinfo
, COL_INFO
, " - General query");
558 proto_tree_add_uint(tree
, hf_num_grp_recs
, tvb
, offset
, 2, num
);
562 offset
= dissect_v3_group_record(tvb
, pinfo
, tree
, offset
);
568 dissect_igmp_v3_query(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
575 tree
= dissect_igmp_common(tvb
, pinfo
, parent_tree
, &offset
, &type
, 3);
577 num
= tvb_get_ntohs(tvb
, offset
+9);
579 offset
= dissect_v3_max_resp(tvb
, tree
, offset
);
582 igmp_checksum(tree
, tvb
, hf_checksum
, hf_checksum_status
, &ei_checksum
, pinfo
, 0);
586 proto_tree_add_item(tree
, hf_maddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
588 if (!tvb_get_ipv4(tvb
, offset
)) {
589 col_append_str(pinfo
->cinfo
, COL_INFO
, ", general");
591 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", specific for group %s",
592 tvb_ip_to_str(pinfo
->pool
, tvb
, offset
));
596 /* bitmask for S and QRV */
597 offset
= dissect_v3_sqrv_bits(tvb
, tree
, offset
);
600 proto_tree_add_item(tree
, hf_qqic
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
603 /*number of sources*/
604 proto_tree_add_uint(tree
, hf_num_src
, tvb
, offset
, 2, num
);
606 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", source%s {", (num
>1)?"s":"");
611 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s%s", tvb_ip_to_str(pinfo
->pool
, tvb
, offset
), (num
?", ":"}"));
612 proto_tree_add_item(tree
, hf_saddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
619 /* dissector for version 2 query and report, rfc2236 */
621 dissect_igmp_v2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
628 tree
= dissect_igmp_common(tvb
, pinfo
, parent_tree
, &offset
, &type
, 2);
631 tsecs
= tvb_get_uint8(tvb
, offset
);
632 proto_tree_add_uint_format_value(tree
, hf_max_resp
, tvb
,
633 offset
, 1, tsecs
, "%.1f sec (0x%02x)", tsecs
*0.1,tsecs
);
637 igmp_checksum(tree
, tvb
, hf_checksum
, hf_checksum_status
, &ei_checksum
, pinfo
, 8);
641 proto_tree_add_item(tree
, hf_maddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
643 if (! tvb_get_ipv4(tvb
, offset
)) {
644 col_append_str(pinfo
->cinfo
, COL_INFO
, ", general");
648 case IGMP_V2_LEAVE_GROUP
:
649 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " %s", tvb_ip_to_str(pinfo
->pool
, tvb
, offset
));
651 case IGMP_V1_HOST_MEMBERSHIP_QUERY
:
652 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", specific for group %s", tvb_ip_to_str(pinfo
->pool
, tvb
, offset
));
654 default: /* IGMP_V2_MEMBERSHIP_REPORT is the only case left */
655 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " group %s", tvb_ip_to_str(pinfo
->pool
, tvb
, offset
));
664 /* dissector for version 1 query and report, rfc1054 */
666 dissect_igmp_v1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
672 tree
= dissect_igmp_common(tvb
, pinfo
, parent_tree
, &offset
, &type
, 1);
674 /* skip unused byte */
675 proto_tree_add_item(tree
, hf_reserved
, tvb
, offset
, 1, ENC_NA
);
679 igmp_checksum(tree
, tvb
, hf_checksum
, hf_checksum_status
, &ei_checksum
, pinfo
, 8);
683 proto_tree_add_item(tree
, hf_maddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
689 /* dissector for version 0, rfc988 */
691 dissect_igmp_v0(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
698 tree
= dissect_igmp_common(tvb
, pinfo
, parent_tree
, &offset
, &type
, 0);
701 code
= tvb_get_uint8(tvb
, offset
);
702 if (type
==IGMP_V0_CREATE_GROUP_REQUEST
) {
703 proto_tree_add_uint(tree
, hf_group_type
, tvb
, offset
, 1, code
);
704 } else if (!(type
&0x01)) {
706 proto_tree_add_uint(tree
, hf_reply_code
, tvb
, offset
, 1, code
);
708 proto_tree_add_uint(tree
, hf_reply_pending
, tvb
, offset
, 1, code
);
714 igmp_checksum(tree
, tvb
, hf_checksum
, hf_checksum_status
, &ei_checksum
, pinfo
, 20);
718 proto_tree_add_item(tree
, hf_identifier
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
722 proto_tree_add_item(tree
, hf_maddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
726 proto_tree_add_item(tree
, hf_access_key
, tvb
, offset
, 8, ENC_NA
);
733 dissect_igmp_mquery(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data
)
735 if ( tvb_reported_length(tvb
)>=12 ) {
737 return dissect_igmp_v3_query(tvb
, pinfo
, parent_tree
, data
);
740 /* v1 and v2 differs in second byte of header */
741 if (tvb_get_uint8(tvb
, 1)) {
742 return dissect_igmp_v2(tvb
, pinfo
, parent_tree
, data
);
745 return dissect_igmp_v1(tvb
, pinfo
, parent_tree
, data
);
748 /* dissector for multicast traceroute, rfc???? */
750 dissect_igmp_mtrace(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
756 const char *typestr
, *blocks
= NULL
;
759 ti
= proto_tree_add_item(parent_tree
, proto_igmp
, tvb
, offset
, -1, ENC_NA
);
760 tree
= proto_item_add_subtree(ti
, ett_igmp
);
762 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IGMP");
763 col_clear(pinfo
->cinfo
, COL_INFO
);
765 /* All multicast traceroute packets (Query, Request and
766 * Response) have the same fixed header. Request and Response
767 * have one or more response data blocks following this fixed
768 * header. Since Query and Request share the same IGMP type,
769 * the method to differentiate between them is to check the
770 * IGMP packet length. Queries are only
771 * IGMP_TRACEROUTE_HDR_LEN bytes long.
773 type
= tvb_get_uint8(tvb
, offset
);
774 if (type
== IGMP_TRACEROUTE_RESPONSE
) {
775 int i
= (tvb_reported_length_remaining(tvb
, offset
) - IGMP_TRACEROUTE_HDR_LEN
) / IGMP_TRACEROUTE_RSP_LEN
;
776 snprintf(buf
, sizeof buf
, ", %d block%s", i
, plurality(i
, "", "s"));
777 typestr
= "Traceroute Response";
779 } else if (tvb_reported_length_remaining(tvb
, offset
) == IGMP_TRACEROUTE_HDR_LEN
)
780 typestr
= "Traceroute Query";
782 typestr
= "Traceroute Request";
784 col_set_str(pinfo
->cinfo
, COL_INFO
, typestr
);
786 col_append_str(pinfo
->cinfo
, COL_INFO
, blocks
);
788 proto_tree_add_uint_format_value(tree
, hf_type
, tvb
, offset
, 1, type
,
789 "%s (0x%02x)", typestr
, type
);
792 /* maximum number of hops that the requester wants to trace */
793 proto_tree_add_item(tree
, hf_mtrace_max_hops
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
797 igmp_checksum(tree
, tvb
, hf_checksum
, hf_checksum_status
, &ei_checksum
, pinfo
, 0);
800 /* group address to be traced */
801 proto_tree_add_item(tree
, hf_maddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
804 /* address of multicast source for the path being traced */
805 proto_tree_add_item(tree
, hf_mtrace_saddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
808 /* address of multicast receiver for the path being traced */
809 proto_tree_add_item(tree
, hf_mtrace_raddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
812 /* address where the completed traceroute response packet gets sent */
813 proto_tree_add_item(tree
, hf_mtrace_rspaddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
816 /* for multicasted responses, TTL at which to multicast the response */
817 proto_tree_add_item(tree
, hf_mtrace_resp_ttl
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
820 /* unique identifier for this traceroute request (for e.g. duplicate/delay detection) */
821 proto_tree_add_item(tree
, hf_mtrace_q_id
, tvb
, offset
, 3, ENC_BIG_ENDIAN
);
824 /* If this was Query, we only had the fixed header */
825 if (tvb_reported_length_remaining(tvb
, offset
) == 0)
828 /* Loop through the response data blocks */
829 while (tvb_reported_length_remaining(tvb
, offset
) >= IGMP_TRACEROUTE_RSP_LEN
) {
830 proto_tree
*block_tree
;
832 block_tree
= proto_tree_add_subtree_format(tree
, tvb
, offset
, IGMP_TRACEROUTE_RSP_LEN
,
833 ett_mtrace_block
, NULL
, "Response data block: %s -> %s, Proto: %s, Forwarding Code: %s",
834 tvb_ip_to_str(pinfo
->pool
, tvb
, offset
+ 4),
835 tvb_ip_to_str(pinfo
->pool
, tvb
, offset
+ 8),
836 val_to_str_const(tvb_get_uint8(tvb
, offset
+ 28), mtrace_rtg_vals
, "Unknown"),
837 val_to_str_const(tvb_get_uint8(tvb
, offset
+ 31), mtrace_fwd_code_vals
, "Unknown"));
839 /* Query Arrival Time */
840 proto_tree_add_item(block_tree
, hf_mtrace_q_arrival
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
843 /* Incoming Interface Address */
844 proto_tree_add_item(block_tree
, hf_mtrace_q_inaddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
847 /* Outgoing Interface Address */
848 proto_tree_add_item(block_tree
, hf_mtrace_q_outaddr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
851 /* Previous-Hop Router Address */
852 proto_tree_add_item(block_tree
, hf_mtrace_q_prevrtr
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
855 /* Input packet count on incoming interface */
856 proto_tree_add_item(block_tree
, hf_mtrace_q_inpkt
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
859 /* Output packet count on outgoing interface */
860 proto_tree_add_item(block_tree
, hf_mtrace_q_outpkt
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
863 /* Total number of packets for this source-group pair */
864 proto_tree_add_item(block_tree
, hf_mtrace_q_total
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
867 /* Routing protocol in use between this and previous-hop router */
868 proto_tree_add_item(block_tree
, hf_mtrace_q_rtg_proto
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
871 /* TTL that a packet is required to be forwarded */
872 proto_tree_add_item(block_tree
, hf_mtrace_q_fwd_ttl
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
875 /* Must be zeroed and ignored bit, S bit and src network mask length */
876 proto_tree_add_item(block_tree
, hf_mtrace_q_mbz
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
877 proto_tree_add_item(block_tree
, hf_mtrace_q_s
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
878 proto_tree_add_item(block_tree
, hf_mtrace_q_src_mask
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
881 /* Forwarding information/error code */
882 proto_tree_add_item(block_tree
, hf_mtrace_q_fwd_code
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
890 dissect_igmp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
895 type
= tvb_get_uint8(tvb
, offset
);
897 if (!dissector_try_uint(subdissector_table
, type
, tvb
, pinfo
, parent_tree
))
899 dissect_igmp_unknown(tvb
, pinfo
, parent_tree
);
901 return tvb_captured_length(tvb
);
905 proto_register_igmp(void)
907 static hf_register_info hf
[] = {
909 { "Type", "igmp.type", FT_UINT8
, BASE_HEX
,
910 VALS(commands
), 0, "IGMP Packet Type", HFILL
}},
913 { "Reserved", "igmp.reserved", FT_BYTES
, BASE_NONE
,
914 NULL
, 0, "IGMP Reserved", HFILL
}},
917 { "IGMP Version", "igmp.version", FT_UINT8
, BASE_DEC
,
918 NULL
, 0, NULL
, HFILL
}},
921 { "Type Of Group", "igmp.group_type", FT_UINT8
, BASE_DEC
,
922 VALS(vs_group_type
), 0, "IGMP V0 Type Of Group", HFILL
}},
925 { "Reply", "igmp.reply", FT_UINT8
, BASE_DEC
,
926 VALS(vs_reply_code
), 0, "IGMP V0 Reply", HFILL
}},
929 { "Reply Pending", "igmp.reply.pending", FT_UINT8
, BASE_DEC
,
930 NULL
, 0, "IGMP V0 Reply Pending, Retry in this many seconds", HFILL
}},
933 { "Checksum", "igmp.checksum", FT_UINT16
, BASE_HEX
,
934 NULL
, 0, "IGMP Checksum", HFILL
}},
936 { &hf_checksum_status
,
937 { "Checksum Status", "igmp.checksum.status", FT_UINT8
, BASE_NONE
,
938 VALS(proto_checksum_vals
), 0x0, NULL
, HFILL
}},
941 { "Identifier", "igmp.identifier", FT_UINT32
, BASE_DEC
,
942 NULL
, 0, "IGMP V0 Identifier", HFILL
}},
945 { "Access Key", "igmp.access_key", FT_BYTES
, BASE_NONE
,
946 NULL
, 0, "IGMP V0 Access Key", HFILL
}},
949 { "Max Resp Time", "igmp.max_resp", FT_UINT8
, BASE_DEC
,
950 NULL
, 0, "Max Response Time", HFILL
}},
953 { "S", "igmp.s", FT_BOOLEAN
, 8,
954 TFS(&tfs_s
), IGMP_V3_S
, "Suppress Router Side Processing", HFILL
}},
957 { "QRV", "igmp.qrv", FT_UINT8
, BASE_DEC
,
958 NULL
, IGMP_V3_QRV_MASK
, "Querier's Robustness Value", HFILL
}},
961 { "QQIC", "igmp.qqic", FT_UINT8
, BASE_DEC
,
962 NULL
, 0, "Querier's Query Interval Code", HFILL
}},
965 { "Num Src", "igmp.num_src", FT_UINT16
, BASE_DEC
,
966 NULL
, 0, "Number Of Sources", HFILL
}},
969 { "Source Address", "igmp.saddr", FT_IPv4
, BASE_NONE
,
970 NULL
, 0, NULL
, HFILL
}},
973 { "Num Group Records", "igmp.num_grp_recs", FT_UINT16
, BASE_DEC
,
974 NULL
, 0, "Number Of Group Records", HFILL
}},
977 { "Record Type", "igmp.record_type", FT_UINT8
, BASE_DEC
,
978 VALS(vs_record_type
), 0, NULL
, HFILL
}},
981 { "Aux Data Len", "igmp.aux_data_len", FT_UINT8
, BASE_DEC
,
982 NULL
, 0, "Aux Data Len, In units of 32bit words", HFILL
}},
985 { "Multicast Address", "igmp.maddr", FT_IPv4
, BASE_NONE
,
986 NULL
, 0, NULL
, HFILL
}},
989 { "Aux Data", "igmp.aux_data", FT_BYTES
, BASE_NONE
,
990 NULL
, 0, "IGMP V3 Auxiliary Data", HFILL
}},
993 { "Data", "igmp.data", FT_BYTES
, BASE_NONE
,
994 NULL
, 0, NULL
, HFILL
}},
997 { "Exponent", "igmp.max_resp.exp", FT_UINT8
, BASE_HEX
,
998 NULL
, IGMP_MAX_RESP_EXP
, "Maximum Response Time, Exponent", HFILL
}},
1000 { &hf_max_resp_mant
,
1001 { "Mantissa", "igmp.max_resp.mant", FT_UINT8
, BASE_HEX
,
1002 NULL
, IGMP_MAX_RESP_MANT
, "Maximum Response Time, Mantissa", HFILL
}},
1004 { &hf_mtrace_max_hops
,
1005 { "# hops", "igmp.mtrace.max_hops", FT_UINT8
, BASE_DEC
,
1006 NULL
, 0, "Maximum Number of Hops to Trace", HFILL
}},
1009 { "Source Address", "igmp.mtrace.saddr", FT_IPv4
, BASE_NONE
,
1010 NULL
, 0, "Multicast Source for the Path Being Traced", HFILL
}},
1013 { "Receiver Address", "igmp.mtrace.raddr", FT_IPv4
, BASE_NONE
,
1014 NULL
, 0, "Multicast Receiver for the Path Being Traced", HFILL
}},
1016 { &hf_mtrace_rspaddr
,
1017 { "Response Address", "igmp.mtrace.rspaddr", FT_IPv4
, BASE_NONE
,
1018 NULL
, 0, "Destination of Completed Traceroute Response", HFILL
}},
1020 { &hf_mtrace_resp_ttl
,
1021 { "Response TTL", "igmp.mtrace.resp_ttl", FT_UINT8
, BASE_DEC
,
1022 NULL
, 0, "TTL for Multicasted Responses", HFILL
}},
1025 { "Query ID", "igmp.mtrace.q_id", FT_UINT24
, BASE_DEC
,
1026 NULL
, 0, "Identifier for this Traceroute Request", HFILL
}},
1028 { &hf_mtrace_q_arrival
,
1029 { "Query Arrival", "igmp.mtrace.q_arrival", FT_UINT32
, BASE_DEC
,
1030 NULL
, 0, "Query Arrival Time", HFILL
}},
1032 { &hf_mtrace_q_inaddr
,
1033 { "In itf addr", "igmp.mtrace.q_inaddr", FT_IPv4
, BASE_NONE
,
1034 NULL
, 0, "Incoming Interface Address", HFILL
}},
1036 { &hf_mtrace_q_outaddr
,
1037 { "Out itf addr", "igmp.mtrace.q_outaddr", FT_IPv4
, BASE_NONE
,
1038 NULL
, 0, "Outgoing Interface Address", HFILL
}},
1040 { &hf_mtrace_q_prevrtr
,
1041 { "Previous rtr addr", "igmp.mtrace.q_prevrtr", FT_IPv4
, BASE_NONE
,
1042 NULL
, 0, "Previous-Hop Router Address", HFILL
}},
1044 { &hf_mtrace_q_inpkt
,
1045 { "In pkts", "igmp.mtrace.q_inpkt", FT_UINT32
, BASE_DEC
,
1046 NULL
, 0, "Input packet count on incoming interface", HFILL
}},
1048 { &hf_mtrace_q_outpkt
,
1049 { "Out pkts", "igmp.mtrace.q_outpkt", FT_UINT32
, BASE_DEC
,
1050 NULL
, 0, "Output packet count on outgoing interface", HFILL
}},
1052 { &hf_mtrace_q_total
,
1053 { "S,G pkt count", "igmp.mtrace.q_total", FT_UINT32
, BASE_DEC
,
1054 NULL
, 0, "Total number of packets for this source-group pair", HFILL
}},
1056 { &hf_mtrace_q_rtg_proto
,
1057 { "Rtg Protocol", "igmp.mtrace.q_rtg_proto", FT_UINT8
, BASE_DEC
,
1058 VALS(mtrace_rtg_vals
), 0, "Routing protocol between this and previous hop rtr", HFILL
}},
1060 { &hf_mtrace_q_fwd_ttl
,
1061 { "FwdTTL", "igmp.mtrace.q_fwd_ttl", FT_UINT8
, BASE_DEC
,
1062 NULL
, 0, "TTL required for forwarding", HFILL
}},
1065 { "MBZ", "igmp.mtrace.q_mbz", FT_UINT8
, BASE_HEX
,
1066 NULL
, 0x80, "Must be zeroed on transmission and ignored on reception", HFILL
}},
1069 { "S", "igmp.mtrace.q_s", FT_UINT8
, BASE_HEX
,
1070 NULL
, 0x40, "Set if S,G packet count is for source network", HFILL
}},
1072 { &hf_mtrace_q_src_mask
,
1073 { "Src Mask", "igmp.mtrace.q_src_mask", FT_UINT8
, BASE_HEX
,
1074 NULL
, 0x3F, "Source mask length. 63 when forwarding on group state", HFILL
}},
1076 { &hf_mtrace_q_fwd_code
,
1077 { "Forwarding Code", "igmp.mtrace.q_fwd_code", FT_UINT8
, BASE_HEX
,
1078 VALS(mtrace_fwd_code_vals
), 0, "Forwarding information/error code", HFILL
}},
1081 static int *ett
[] = {
1088 static ei_register_info ei
[] = {
1089 { &ei_checksum
, { "igmp.bad_checksum", PI_CHECKSUM
, PI_ERROR
, "Bad checksum", EXPFILL
}},
1092 expert_module_t
* expert_igmp
;
1094 proto_igmp
= proto_register_protocol("Internet Group Management Protocol", "IGMP", "igmp");
1095 proto_register_field_array(proto_igmp
, hf
, array_length(hf
));
1096 proto_register_subtree_array(ett
, array_length(ett
));
1097 expert_igmp
= expert_register_protocol(proto_igmp
);
1098 expert_register_field_array(expert_igmp
, ei
, array_length(ei
));
1100 subdissector_table
= register_dissector_table("igmp.type", "IGMP commands", proto_igmp
, FT_UINT32
, BASE_HEX
);
1102 igmp_handle
= register_dissector("igmp", dissect_igmp
, proto_igmp
);
1103 igmpv0_handle
= register_dissector("igmp_v0", dissect_igmp_v0
, proto_igmp
);
1104 igmpv1_handle
= register_dissector("igmp_v1", dissect_igmp_v1
, proto_igmp
);
1105 igmpv2_handle
= register_dissector("igmp_v2", dissect_igmp_v2
, proto_igmp
);
1109 proto_reg_handoff_igmp(void)
1111 dissector_handle_t igmp_mquery_handle
, igmp_mtrace_handle
, igmp_report_handle
;
1112 range_t
*igmpv0_range
= NULL
;
1114 dissector_add_uint("ip.proto", IP_PROTO_IGMP
, igmp_handle
);
1117 range_convert_str(NULL
, &igmpv0_range
, "0-15", 15);
1118 dissector_add_uint_range("igmp.type", igmpv0_range
, igmpv0_handle
);
1119 wmem_free(NULL
, igmpv0_range
);
1122 dissector_add_uint("igmp.type", IGMP_V1_HOST_MEMBERSHIP_REPORT
, igmpv1_handle
);
1125 dissector_add_uint("igmp.type", IGMP_V2_MEMBERSHIP_REPORT
, igmpv2_handle
);
1126 dissector_add_uint("igmp.type", IGMP_V2_LEAVE_GROUP
, igmpv2_handle
);
1128 /* IGMP_V1_HOST_MEMBERSHIP_QUERY, all versions */
1129 igmp_mquery_handle
= create_dissector_handle(dissect_igmp_mquery
, proto_igmp
);
1130 dissector_add_uint("igmp.type", IGMP_V1_HOST_MEMBERSHIP_QUERY
, igmp_mquery_handle
);
1132 igmp_report_handle
= create_dissector_handle(dissect_igmp_v3_report
, proto_igmp
);
1133 dissector_add_uint("igmp.type", IGMP_V3_MEMBERSHIP_REPORT
, igmp_report_handle
);
1135 igmp_mtrace_handle
= create_dissector_handle(dissect_igmp_mtrace
, proto_igmp
);
1136 dissector_add_uint("igmp.type", IGMP_TRACEROUTE_RESPONSE
, igmp_mtrace_handle
);
1137 dissector_add_uint("igmp.type", IGMP_TRACEROUTE_QUERY_REQ
, igmp_mtrace_handle
);
1141 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1146 * indent-tabs-mode: t
1149 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1150 * :indentSize=8:tabSize=8:noTabs=false: