2 * Routines for ICMP - Internet Control Message Protocol
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * Monday, June 27, 2005
11 * Support for the ICMP extensions for MPLS
12 * (http://www.ietf.org/proceedings/01aug/I-D/draft-ietf-mpls-icmp-02.txt
13 * which has been replaced by rfcs 4884 and 4950)
14 * by Maria-Luiza Crivat <luizacri@gmail.com>
15 * & Brice Augustin <bricecotte@gmail.com>
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 * Added support for ICMP extensions RFC 4884 and RFC 5837
32 * (c) 2011 Gaurav Tungatkar <gstungat@ncsu.edu>
40 #include <epan/packet.h>
41 #include <epan/ipproto.h>
42 #include <epan/prefs.h>
43 #include <epan/in_cksum.h>
45 #include "packet-ip.h"
46 #include "packet-icmp.h"
47 #include <epan/conversation.h>
48 #include <epan/wmem/wmem.h>
51 static int icmp_tap
= -1;
53 /* Conversation related data */
54 static int hf_icmp_resp_in
= -1;
55 static int hf_icmp_resp_to
= -1;
56 static int hf_icmp_resptime
= -1;
57 static int hf_icmp_data_time
= -1;
58 static int hf_icmp_data_time_relative
= -1;
60 typedef struct _icmp_conv_info_t
{
61 wmem_tree_t
*unmatched_pdus
;
62 wmem_tree_t
*matched_pdus
;
65 static icmp_transaction_t
*transaction_start(packet_info
* pinfo
,
68 static icmp_transaction_t
*transaction_end(packet_info
* pinfo
,
72 /* Decode the end of the ICMP payload as ICMP MPLS extensions
73 if the packet in the payload has more than 128 bytes */
74 static gboolean favor_icmp_mpls_ext
= FALSE
;
77 static int hf_icmp_type
= -1;
78 static int hf_icmp_code
= -1;
79 static int hf_icmp_checksum
= -1;
80 static int hf_icmp_checksum_bad
= -1;
81 static int hf_icmp_ident
= -1;
82 static int hf_icmp_ident_le
= -1;
83 static int hf_icmp_seq_num
= -1;
84 static int hf_icmp_seq_num_le
= -1;
85 static int hf_icmp_mtu
= -1;
86 static int hf_icmp_redir_gw
= -1;
87 static int hf_icmp_length
= -1;
90 static int hf_icmp_mip_type
= -1;
91 static int hf_icmp_mip_length
= -1;
92 static int hf_icmp_mip_prefix_length
= -1;
93 static int hf_icmp_mip_seq
= -1;
94 static int hf_icmp_mip_life
= -1;
95 static int hf_icmp_mip_flags
= -1;
96 static int hf_icmp_mip_r
= -1;
97 static int hf_icmp_mip_b
= -1;
98 static int hf_icmp_mip_h
= -1;
99 static int hf_icmp_mip_f
= -1;
100 static int hf_icmp_mip_m
= -1;
101 static int hf_icmp_mip_g
= -1;
102 static int hf_icmp_mip_v
= -1;
103 static int hf_icmp_mip_rt
= -1;
104 static int hf_icmp_mip_u
= -1;
105 static int hf_icmp_mip_x
= -1;
106 static int hf_icmp_mip_reserved
= -1;
107 static int hf_icmp_mip_coa
= -1;
108 static int hf_icmp_mip_challenge
= -1;
110 /* extensions RFC 4884*/
111 static int hf_icmp_ext
= -1;
112 static int hf_icmp_ext_version
= -1;
113 static int hf_icmp_ext_reserved
= -1;
114 static int hf_icmp_ext_checksum
= -1;
115 static int hf_icmp_ext_checksum_bad
= -1;
116 static int hf_icmp_ext_length
= -1;
117 static int hf_icmp_ext_class
= -1;
118 static int hf_icmp_ext_c_type
= -1;
120 /* Interface information extension RFC 5837 */
121 static int hf_icmp_int_info_ifindex
= -1;
122 static int hf_icmp_int_info_ipaddr
= -1;
123 static int hf_icmp_int_info_name
= -1;
124 static int hf_icmp_int_info_mtu
= -1;
125 static int hf_icmp_int_info_afi
= -1;
126 static int hf_icmp_int_info_ipv4
= -1;
127 static int hf_icmp_int_info_ipv6
= -1;
128 static int hf_icmp_int_info_role
= -1;
129 static int hf_icmp_int_info_reserved
= -1;
130 static gint ett_icmp_interface_info_object
= -1;
131 static gint ett_icmp_interface_ipaddr
= -1;
132 static gint ett_icmp_interface_name
= -1;
133 /* MPLS extension object*/
134 static int hf_icmp_mpls_label
= -1;
135 static int hf_icmp_mpls_exp
= -1;
136 static int hf_icmp_mpls_s
= -1;
137 static int hf_icmp_mpls_ttl
= -1;
139 static gint ett_icmp
= -1;
140 static gint ett_icmp_mip
= -1;
141 static gint ett_icmp_mip_flags
= -1;
144 static gint ett_icmp_ext
= -1;
145 static gint ett_icmp_ext_object
= -1;
147 /* MPLS extensions */
148 static gint ett_icmp_mpls_stack_object
= -1;
150 /* ICMP definitions */
151 #define ICMP_ECHOREPLY 0
152 #define ICMP_UNREACH 3
153 #define ICMP_SOURCEQUENCH 4
154 #define ICMP_REDIRECT 5
155 #define ICMP_ALTHOST 6
157 #define ICMP_RTRADVERT 9
158 #define ICMP_RTRSOLICIT 10
159 #define ICMP_TIMXCEED 11
160 #define ICMP_PARAMPROB 12
161 #define ICMP_TSTAMP 13
162 #define ICMP_TSTAMPREPLY 14
164 #define ICMP_IREQREPLY 16
165 #define ICMP_MASKREQ 17
166 #define ICMP_MASKREPLY 18
167 #define ICMP_PHOTURIS 40
169 /* ICMP UNREACHABLE */
170 #define ICMP_NET_UNREACH 0 /* Network Unreachable */
171 #define ICMP_HOST_UNREACH 1 /* Host Unreachable */
172 #define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */
173 #define ICMP_PORT_UNREACH 3 /* Port Unreachable */
174 #define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */
175 #define ICMP_SR_FAILED 5 /* Source Route failed */
176 #define ICMP_NET_UNKNOWN 6
177 #define ICMP_HOST_UNKNOWN 7
178 #define ICMP_HOST_ISOLATED 8
179 #define ICMP_NET_ANO 9
180 #define ICMP_HOST_ANO 10
181 #define ICMP_NET_UNR_TOS 11
182 #define ICMP_HOST_UNR_TOS 12
183 #define ICMP_PKT_FILTERED 13 /* Packet filtered */
184 #define ICMP_PREC_VIOLATION 14 /* Precedence violation */
185 #define ICMP_PREC_CUTOFF 15 /* Precedence cut off */
187 #define ICMP_MIP_EXTENSION_PAD 0
188 #define ICMP_MIP_MOB_AGENT_ADV 16
189 #define ICMP_MIP_PREFIX_LENGTHS 19
190 #define ICMP_MIP_CHALLENGE 24
192 static dissector_handle_t ip_handle
;
193 static dissector_handle_t data_handle
;
195 static const value_string icmp_type_str
[] = {
196 {ICMP_ECHOREPLY
, "Echo (ping) reply"},
199 {ICMP_UNREACH
, "Destination unreachable"},
200 {ICMP_SOURCEQUENCH
, "Source quench (flow control)"},
201 {ICMP_REDIRECT
, "Redirect"},
202 {ICMP_ALTHOST
, "Alternate host address"},
203 {ICMP_ECHO
, "Echo (ping) request"},
204 {ICMP_RTRADVERT
, "Router advertisement"},
205 {ICMP_RTRSOLICIT
, "Router solicitation"},
206 {ICMP_TIMXCEED
, "Time-to-live exceeded"},
207 {ICMP_PARAMPROB
, "Parameter problem"},
208 {ICMP_TSTAMP
, "Timestamp request"},
209 {ICMP_TSTAMPREPLY
, "Timestamp reply"},
210 {ICMP_IREQ
, "Information request"},
211 {ICMP_IREQREPLY
, "Information reply"},
212 {ICMP_MASKREQ
, "Address mask request"},
213 {ICMP_MASKREPLY
, "Address mask reply"},
214 {19, "Reserved (for security)"},
216 {31, "Datagram Conversion Error"},
217 {32, "Mobile Host Redirect"},
218 {33, "IPv6 Where-Are-You"},
219 {34, "IPv6 I-Am-Here"},
220 {35, "Mobile Registration Request"},
221 {36, "Mobile Registration Reply"},
222 {37, "Domain Name Request"},
223 {38, "Domain Name Reply"},
225 {ICMP_PHOTURIS
, "Photuris"},
226 {41, "Experimental mobility protocols"},
230 static const value_string unreach_code_str
[] = {
231 {ICMP_NET_UNREACH
, "Network unreachable"},
232 {ICMP_HOST_UNREACH
, "Host unreachable"},
233 {ICMP_PROT_UNREACH
, "Protocol unreachable"},
234 {ICMP_PORT_UNREACH
, "Port unreachable"},
235 {ICMP_FRAG_NEEDED
, "Fragmentation needed"},
236 {ICMP_SR_FAILED
, "Source route failed"},
237 {ICMP_NET_UNKNOWN
, "Destination network unknown"},
238 {ICMP_HOST_UNKNOWN
, "Destination host unknown"},
239 {ICMP_HOST_ISOLATED
, "Source host isolated"},
240 {ICMP_NET_ANO
, "Network administratively prohibited"},
241 {ICMP_HOST_ANO
, "Host administratively prohibited"},
242 {ICMP_NET_UNR_TOS
, "Network unreachable for TOS"},
243 {ICMP_HOST_UNR_TOS
, "Host unreachable for TOS"},
244 {ICMP_PKT_FILTERED
, "Communication administratively filtered"},
245 {ICMP_PREC_VIOLATION
, "Host precedence violation"},
246 {ICMP_PREC_CUTOFF
, "Precedence cutoff in effect"},
250 static const value_string redir_code_str
[] = {
251 {0, "Redirect for network"},
252 {1, "Redirect for host"},
253 {2, "Redirect for TOS and network"},
254 {3, "Redirect for TOS and host"},
258 static const value_string alt_host_code_str
[] = {
259 {0, "Alternate address for host"},
263 static const value_string rtradvert_code_str
[] = {
264 {0, "Normal router advertisement"},
265 {16, "Does not route common traffic"},
269 static const value_string ttl_code_str
[] = {
270 {0, "Time to live exceeded in transit"},
271 {1, "Fragment reassembly time exceeded"},
275 static const value_string par_code_str
[] = {
276 {0, "Pointer indicates the error"},
277 {1, "Required option missing"},
282 static const value_string photuris_code_str
[] = {
284 {1, "Authentication Failed"},
285 {2, "Decompression Failed"},
286 {3, "Decryption Failed"},
287 {4, "Need Authentication"},
288 {5, "Need Authorization"},
292 static const value_string mip_extensions
[] = {
293 {ICMP_MIP_EXTENSION_PAD
, "One byte padding extension"}, /* RFC 2002 */
294 {ICMP_MIP_MOB_AGENT_ADV
, "Mobility Agent Advertisement Extension"},
296 {ICMP_MIP_PREFIX_LENGTHS
, "Prefix Lengths Extension"}, /* RFC 2002 */
297 {ICMP_MIP_CHALLENGE
, "Challenge Extension"}, /* RFC 3012 */
301 /* RFC 5837 ICMP extension - Interface Information Object
304 static const value_string interface_role_str
[] = {
305 {0, "IP interface upon which datagram arrived"},
307 "sub-IP component of an IP interface upon which datagram arrived"},
308 {2, "IP interface through which datagram would be forwarded"},
309 {3, "IP next-hop to which datagram would be forwarded"},
313 #define INT_INFO_INTERFACE_ROLE 0xc0
314 #define INT_INFO_RESERVED 0x30
315 #define INT_INFO_IFINDEX 0x08
316 #define INT_INFO_IPADDR 0x04
317 #define INT_INFO_NAME 0x02
318 #define INT_INFO_MTU 0x01
320 #define INTERFACE_INFORMATION_OBJECT_CLASS 2
322 #define MPLS_STACK_ENTRY_OBJECT_CLASS 1
323 #define MPLS_EXTENDED_PAYLOAD_OBJECT_CLASS 0
325 #define MPLS_STACK_ENTRY_C_TYPE 1
326 #define MPLS_EXTENDED_PAYLOAD_C_TYPE 1
328 #define INET6_ADDRLEN 16
330 static conversation_t
*_find_or_create_conversation(packet_info
* pinfo
)
332 conversation_t
*conv
= NULL
;
334 /* Have we seen this conversation before? */
336 find_conversation(pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
,
337 pinfo
->ptype
, 0, 0, 0);
339 /* No, this is a new conversation. */
341 conversation_new(pinfo
->fd
->num
, &pinfo
->src
,
342 &pinfo
->dst
, pinfo
->ptype
, 0, 0, 0);
348 * Dissect the mobile ip advertisement extensions.
351 dissect_mip_extensions(tvbuff_t
* tvb
, int offset
, proto_tree
* tree
)
357 proto_tree
*mip_tree
= NULL
;
358 proto_tree
*flags_tree
= NULL
;
362 /* Not much to do if we're not parsing everything */
366 while (tvb_reported_length_remaining(tvb
, offset
) > 0) {
367 type
= tvb_get_guint8(tvb
, offset
+ 0);
369 length
= tvb_get_guint8(tvb
, offset
+ 1);
374 ti
= proto_tree_add_text(tree
, tvb
, offset
,
375 type
? (length
+ 2) : 1,
376 "Ext: %s", val_to_str(type
,
379 mip_tree
= proto_item_add_subtree(ti
, ett_icmp_mip
);
382 case ICMP_MIP_EXTENSION_PAD
:
383 /* One byte padding extension */
386 proto_tree_add_item(mip_tree
, hf_icmp_mip_type
,
391 case ICMP_MIP_MOB_AGENT_ADV
:
392 /* Mobility Agent Advertisement Extension (RFC 2002) */
395 proto_tree_add_item(mip_tree
, hf_icmp_mip_type
,
400 proto_tree_add_item(mip_tree
, hf_icmp_mip_length
,
404 /* sequence number */
405 proto_tree_add_item(mip_tree
, hf_icmp_mip_seq
, tvb
,
406 offset
, 2, ENC_BIG_ENDIAN
);
408 /* Registration Lifetime */
409 proto_tree_add_item(mip_tree
, hf_icmp_mip_life
,
414 flags
= tvb_get_ntohs(tvb
, offset
);
415 ti
= proto_tree_add_uint(mip_tree
,
416 hf_icmp_mip_flags
, tvb
,
419 proto_item_add_subtree(ti
, ett_icmp_mip_flags
);
420 proto_tree_add_boolean(flags_tree
, hf_icmp_mip_r
,
421 tvb
, offset
, 2, flags
);
422 proto_tree_add_boolean(flags_tree
, hf_icmp_mip_b
,
423 tvb
, offset
, 2, flags
);
424 proto_tree_add_boolean(flags_tree
, hf_icmp_mip_h
,
425 tvb
, offset
, 2, flags
);
426 proto_tree_add_boolean(flags_tree
, hf_icmp_mip_f
,
427 tvb
, offset
, 2, flags
);
428 proto_tree_add_boolean(flags_tree
, hf_icmp_mip_m
,
429 tvb
, offset
, 2, flags
);
430 proto_tree_add_boolean(flags_tree
, hf_icmp_mip_g
,
431 tvb
, offset
, 2, flags
);
432 proto_tree_add_boolean(flags_tree
, hf_icmp_mip_v
,
433 tvb
, offset
, 2, flags
);
434 proto_tree_add_boolean(flags_tree
, hf_icmp_mip_rt
,
435 tvb
, offset
, 2, flags
);
436 proto_tree_add_boolean(flags_tree
, hf_icmp_mip_u
,
437 tvb
, offset
, 2, flags
);
438 proto_tree_add_boolean(flags_tree
, hf_icmp_mip_x
,
439 tvb
, offset
, 2, flags
);
442 proto_tree_add_uint(flags_tree
,
443 hf_icmp_mip_reserved
, tvb
,
448 numCOAs
= (length
- 6) / 4;
449 for (i
= 0; i
< numCOAs
; i
++) {
450 proto_tree_add_item(mip_tree
,
451 hf_icmp_mip_coa
, tvb
,
457 case ICMP_MIP_PREFIX_LENGTHS
:
458 /* Prefix-Lengths Extension (RFC 2002) */
461 proto_tree_add_item(mip_tree
, hf_icmp_mip_type
,
466 proto_tree_add_item(mip_tree
, hf_icmp_mip_length
,
472 for (i
= 0; i
< length
; i
++) {
473 proto_tree_add_item(mip_tree
,
474 hf_icmp_mip_prefix_length
,
480 case ICMP_MIP_CHALLENGE
:
481 /* Challenge Extension (RFC 3012) */
483 proto_tree_add_item(mip_tree
, hf_icmp_mip_type
,
488 proto_tree_add_item(mip_tree
, hf_icmp_mip_length
,
493 proto_tree_add_item(mip_tree
,
494 hf_icmp_mip_challenge
, tvb
,
495 offset
, length
, ENC_NA
);
501 proto_tree_add_item(mip_tree
, hf_icmp_mip_type
,
506 proto_tree_add_item(mip_tree
, hf_icmp_mip_length
,
512 proto_tree_add_text(mip_tree
, tvb
, offset
,
521 } /* dissect_mip_extensions */
524 dissect_mpls_extended_payload_object(tvbuff_t
* tvb
, gint offset
,
525 proto_tree
* ext_object_tree
,
526 proto_item
* tf_object
)
529 guint16 obj_length
, obj_trunc_length
;
530 gboolean unknown_object
;
532 unknown_object
= FALSE
;
534 obj_length
= tvb_get_ntohs(tvb
, offset
);
537 MIN(obj_length
, tvb_reported_length_remaining(tvb
, offset
));
540 c_type
= tvb_get_guint8(tvb
, offset
+ 3);
541 proto_tree_add_uint(ext_object_tree
, hf_icmp_ext_c_type
, tvb
,
542 offset
+ 3, 1, c_type
);
544 /* skip the object header */
548 case MPLS_EXTENDED_PAYLOAD_C_TYPE
:
549 proto_item_set_text(tf_object
, "Extended Payload");
551 /* This object contains some portion of the original packet
552 that could not fit in the 128 bytes of the ICMP payload */
553 if (obj_trunc_length
> 4) {
554 proto_tree_add_text(ext_object_tree
, tvb
,
555 offset
, obj_trunc_length
- 4,
557 obj_trunc_length
- 4);
561 unknown_object
= TRUE
;
562 } /* end switch c_type */
563 return unknown_object
;
567 dissect_mpls_stack_entry_object(tvbuff_t
* tvb
, gint offset
,
568 proto_tree
* ext_object_tree
,
569 proto_item
* tf_object
)
572 proto_item
*tf_entry
;
573 proto_tree
*mpls_stack_object_tree
;
574 guint16 obj_length
, obj_trunc_length
;
579 gboolean unknown_object
;
581 unknown_object
= FALSE
;
583 obj_length
= tvb_get_ntohs(tvb
, offset
);
586 MIN(obj_length
, tvb_reported_length_remaining(tvb
, offset
));
587 obj_end_offset
= offset
+ obj_trunc_length
;
589 c_type
= tvb_get_guint8(tvb
, offset
+ 3);
590 proto_tree_add_uint(ext_object_tree
, hf_icmp_ext_c_type
, tvb
,
591 offset
+ 3, 1, c_type
);
593 /* skip the object header */
597 case MPLS_STACK_ENTRY_C_TYPE
:
598 proto_item_set_text(tf_object
, "MPLS Stack Entry");
600 while (offset
+ 4 <= obj_end_offset
) {
601 if (tvb_reported_length_remaining(tvb
, offset
) < 4) {
602 /* Not enough room in the packet ! */
605 /* Create a subtree for each entry (the text will be set later) */
606 tf_entry
= proto_tree_add_text(ext_object_tree
,
609 mpls_stack_object_tree
=
610 proto_item_add_subtree(tf_entry
,
611 ett_icmp_mpls_stack_object
);
614 label
= (guint
) tvb_get_ntohs(tvb
, offset
);
615 tmp
= tvb_get_guint8(tvb
, offset
+ 2);
616 label
= (label
<< 4) + (tmp
>> 4);
618 proto_tree_add_uint(mpls_stack_object_tree
,
619 hf_icmp_mpls_label
, tvb
,
620 offset
, 3, label
<< 4);
622 proto_item_set_text(tf_entry
, "Label: %u", label
);
624 /* Experimental field (also called "CoS") */
625 proto_tree_add_uint(mpls_stack_object_tree
,
626 hf_icmp_mpls_exp
, tvb
,
629 proto_item_append_text(tf_entry
, ", Exp: %u",
633 proto_tree_add_boolean(mpls_stack_object_tree
,
637 proto_item_append_text(tf_entry
, ", S: %u",
641 ttl
= tvb_get_guint8(tvb
, offset
+ 3);
643 proto_tree_add_item(mpls_stack_object_tree
,
644 hf_icmp_mpls_ttl
, tvb
,
645 offset
+ 3, 1, ENC_BIG_ENDIAN
);
647 proto_item_append_text(tf_entry
, ", TTL: %u", ttl
);
653 if (offset
< obj_end_offset
) {
654 proto_tree_add_text(ext_object_tree
, tvb
, offset
,
655 obj_end_offset
- offset
,
657 obj_end_offset
- offset
);
663 unknown_object
= TRUE
;
666 } /* end switch c_type */
667 return unknown_object
;
669 } /* end dissect_mpls_stack_entry_object */
671 /* Dissect Interface Information Object RFC 5837*/
673 dissect_interface_information_object(tvbuff_t
* tvb
, gint offset
,
674 proto_tree
* ext_object_tree
,
675 proto_item
* tf_object
)
678 proto_tree
*int_name_object_tree
= NULL
;
679 proto_tree
*int_ipaddr_object_tree
;
680 guint16 obj_length
, obj_trunc_length
;
683 gboolean unknown_object
;
684 guint8 if_index_flag
;
689 struct e_in6_addr ipaddr_v6
;
690 guint8 int_name_length
= 0;
692 unknown_object
= FALSE
;
694 obj_length
= tvb_get_ntohs(tvb
, offset
);
697 MIN(obj_length
, tvb_reported_length_remaining(tvb
, offset
));
698 obj_end_offset
= offset
+ obj_trunc_length
;
701 c_type
= tvb_get_guint8(tvb
, offset
+ 3);
703 proto_item_set_text(tf_object
, "Interface Information Object");
704 if (tvb_reported_length_remaining(tvb
, offset
) < 4) {
705 /* Not enough room in the packet ! return unknown_object = TRUE */
709 if_index_flag
= (c_type
& INT_INFO_IFINDEX
) >> 3;
710 ipaddr_flag
= (c_type
& INT_INFO_IPADDR
) >> 2;
711 name_flag
= (c_type
& INT_INFO_NAME
) >> 1;
714 static const gint
*c_type_fields
[] = {
715 &hf_icmp_int_info_role
,
716 &hf_icmp_int_info_reserved
,
717 &hf_icmp_int_info_ifindex
,
718 &hf_icmp_int_info_ipaddr
,
719 &hf_icmp_int_info_name
,
720 &hf_icmp_int_info_mtu
,
723 proto_tree_add_bitmask(ext_object_tree
, tvb
, offset
+ 3,
725 ett_icmp_interface_info_object
,
726 c_type_fields
, ENC_BIG_ENDIAN
);
732 /*if ifIndex is set, next 32 bits are ifIndex */
734 if (obj_end_offset
>= offset
+ 4) {
735 if_index
= tvb_get_ntohl(tvb
, offset
);
736 proto_tree_add_text(ext_object_tree
,
738 "Interface Index: %u",
742 proto_tree_add_text(ext_object_tree
,
744 "Interface Index:(truncated)");
749 /* IP Address Sub Object */
750 if (ipaddr_flag
&& (obj_end_offset
>= offset
+ 2)) {
751 /* Address Family Identifier */
752 afi
= tvb_get_ntohs(tvb
, offset
);
755 * if afi = 1, IPv4 address, 2 bytes afi, 2 bytes rsvd, 4 bytes IP addr
756 * if afi = 2, IPv6 address, 2 bytes afi, 2 bytes rsvd, 6 bytes IP addr
758 ti
= proto_tree_add_text(ext_object_tree
, tvb
, offset
,
760 "IP Address Sub-Object");
762 int_ipaddr_object_tree
=
763 proto_item_add_subtree(ti
, ett_icmp_interface_ipaddr
);
765 proto_tree_add_uint(int_ipaddr_object_tree
,
766 hf_icmp_int_info_afi
, tvb
, offset
, 2,
771 if (afi
== 1 && (obj_end_offset
>= offset
+ 4)) {
772 proto_tree_add_ipv4(int_ipaddr_object_tree
,
773 hf_icmp_int_info_ipv4
, tvb
,
774 offset
, 4, tvb_get_ntohl(tvb
,
778 && (obj_end_offset
>= offset
+ INET6_ADDRLEN
)) {
779 tvb_get_ipv6(tvb
, offset
, &ipaddr_v6
);
780 proto_tree_add_ipv6(int_ipaddr_object_tree
,
781 hf_icmp_int_info_ipv6
, tvb
,
782 offset
, INET6_ADDRLEN
,
783 (guint8
*) & ipaddr_v6
);
784 offset
+= INET6_ADDRLEN
;
786 proto_tree_add_text(int_ipaddr_object_tree
, tvb
,
788 offset
- obj_end_offset
,
794 /* Interface Name Sub Object */
796 if (obj_end_offset
>= offset
+ 1) {
797 int_name_length
= tvb_get_guint8(tvb
, offset
);
798 ti
= proto_tree_add_text(ext_object_tree
, tvb
,
799 offset
, int_name_length
,
800 "Interface Name Sub-Object");
802 int_name_object_tree
=
803 proto_item_add_subtree(ti
,
804 ett_icmp_interface_name
);
805 proto_tree_add_text(int_name_object_tree
, tvb
,
806 offset
, 1, "Length: %u",
809 if (obj_end_offset
>= offset
+ 1 + int_name_length
) {
811 proto_tree_add_text(int_name_object_tree
, tvb
,
812 offset
+ 1, int_name_length
,
813 "Interface Name: %s",
814 tvb_format_text(tvb
, offset
+ 1, int_name_length
));
819 return unknown_object
;
821 } /*end dissect_interface_information_object */
824 dissect_extensions(tvbuff_t
* tvb
, gint offset
, proto_tree
* tree
)
829 guint16 cksum
, computed_cksum
;
830 guint16 obj_length
, obj_trunc_length
;
831 proto_item
*ti
, *tf_object
, *hidden_item
;
832 proto_tree
*ext_tree
, *ext_object_tree
;
834 guint reported_length
;
835 gboolean unknown_object
;
836 guint8 int_info_obj_count
;
842 int_info_obj_count
= 0;
844 reported_length
= tvb_reported_length_remaining(tvb
, offset
);
846 if (reported_length
< 4 /* Common header */ ) {
847 proto_tree_add_text(tree
, tvb
, offset
,
849 "ICMP Multi-Part Extensions (truncated)");
853 /* Add a tree for multi-part extensions RFC 4884 */
854 ti
= proto_tree_add_none_format(tree
, hf_icmp_ext
, tvb
,
855 offset
, reported_length
,
856 "ICMP Multi-Part Extensions");
858 ext_tree
= proto_item_add_subtree(ti
, ett_icmp_ext
);
861 version
= hi_nibble(tvb_get_guint8(tvb
, offset
));
862 proto_tree_add_uint(ext_tree
, hf_icmp_ext_version
, tvb
, offset
, 1,
866 proto_tree_add_item(ext_tree
, hf_icmp_ext_reserved
,
867 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
870 cksum
= tvb_get_ntohs(tvb
, offset
+ 2);
873 ip_checksum(tvb_get_ptr(tvb
, offset
, reported_length
),
876 if (computed_cksum
== 0) {
877 proto_tree_add_uint_format_value(ext_tree
, hf_icmp_ext_checksum
,
878 tvb
, offset
+ 2, 2, cksum
,
882 proto_tree_add_boolean(ext_tree
,
883 hf_icmp_ext_checksum_bad
, tvb
,
884 offset
+ 2, 2, FALSE
);
886 proto_tree_add_uint_format_value(ext_tree
, hf_icmp_ext_checksum
,
887 tvb
, offset
+ 2, 2, cksum
,
888 "0x%04x [incorrect, should be 0x%04x]",
889 cksum
, in_cksum_shouldbe(cksum
,
892 proto_tree_add_boolean(ext_tree
,
893 hf_icmp_ext_checksum_bad
, tvb
,
894 offset
+ 2, 2, TRUE
);
896 PROTO_ITEM_SET_HIDDEN(hidden_item
);
898 if (version
!= 1 && version
!= 2) {
899 /* Unsupported version */
900 proto_item_append_text(ti
, " (unsupported version)");
904 /* Skip the common header */
907 /* While there is enough room to read an object */
908 while (tvb_reported_length_remaining(tvb
, offset
) >=
909 4 /* Object header */ ) {
911 obj_length
= tvb_get_ntohs(tvb
, offset
);
915 tvb_reported_length_remaining(tvb
, offset
));
917 obj_end_offset
= offset
+ obj_trunc_length
;
919 /* Add a subtree for this object (the text will be reset later) */
920 tf_object
= proto_tree_add_text(ext_tree
, tvb
, offset
,
921 MAX(obj_trunc_length
, 4),
925 proto_item_add_subtree(tf_object
, ett_icmp_ext_object
);
927 proto_tree_add_uint(ext_object_tree
, hf_icmp_ext_length
,
928 tvb
, offset
, 2, obj_length
);
931 class_num
= tvb_get_guint8(tvb
, offset
+ 2);
932 proto_tree_add_uint(ext_object_tree
, hf_icmp_ext_class
,
933 tvb
, offset
+ 2, 1, class_num
);
936 c_type
= tvb_get_guint8(tvb
, offset
+ 3);
938 if (obj_length
< 4 /* Object header */ ) {
939 /* Thanks doc/README.developer :)) */
940 proto_item_set_text(tf_object
,
941 "Object with bad length");
947 case MPLS_STACK_ENTRY_OBJECT_CLASS
:
949 dissect_mpls_stack_entry_object(tvb
, offset
,
953 case INTERFACE_INFORMATION_OBJECT_CLASS
:
955 dissect_interface_information_object(tvb
,
959 int_info_obj_count
++;
960 if (int_info_obj_count
> 4) {
961 proto_item_set_text(tf_object
,
962 "More than 4 Interface Information Objects");
965 case MPLS_EXTENDED_PAYLOAD_OBJECT_CLASS
:
967 dissect_mpls_extended_payload_object(tvb
,
974 unknown_object
= TRUE
;
977 } /* end switch class_num */
979 /* Skip the object header */
982 /* The switches couldn't decode the object */
983 if (unknown_object
== TRUE
) {
984 proto_item_set_text(tf_object
,
985 "Unknown object (%d/%d)",
988 if (obj_trunc_length
> 4) {
989 proto_tree_add_text(ext_object_tree
, tvb
,
991 obj_trunc_length
- 4,
993 obj_trunc_length
- 4);
998 if (obj_trunc_length
< obj_length
) {
999 proto_item_append_text(tf_object
, " (truncated)");
1002 /* Go to the end of the object */
1003 offset
= obj_end_offset
;
1009 /* ======================================================================= */
1010 static icmp_transaction_t
*transaction_start(packet_info
* pinfo
,
1014 conversation_t
*conversation
;
1015 icmp_conv_info_t
*icmp_info
;
1016 icmp_transaction_t
*icmp_trans
;
1017 wmem_tree_key_t icmp_key
[3];
1020 /* Handle the conversation tracking */
1021 conversation
= _find_or_create_conversation(pinfo
);
1022 icmp_info
= (icmp_conv_info_t
*)conversation_get_proto_data(conversation
, proto_icmp
);
1023 if (icmp_info
== NULL
) {
1024 icmp_info
= wmem_new(wmem_file_scope(), icmp_conv_info_t
);
1025 icmp_info
->unmatched_pdus
= wmem_tree_new(wmem_file_scope());
1026 icmp_info
->matched_pdus
= wmem_tree_new(wmem_file_scope());
1027 conversation_add_proto_data(conversation
, proto_icmp
,
1031 if (!PINFO_FD_VISITED(pinfo
)) {
1032 /* this is a new request, create a new transaction structure and map it to the
1035 icmp_key
[0].length
= 2;
1036 icmp_key
[0].key
= key
;
1037 icmp_key
[1].length
= 0;
1038 icmp_key
[1].key
= NULL
;
1040 icmp_trans
= wmem_new(wmem_file_scope(), icmp_transaction_t
);
1041 icmp_trans
->rqst_frame
= PINFO_FD_NUM(pinfo
);
1042 icmp_trans
->resp_frame
= 0;
1043 icmp_trans
->rqst_time
= pinfo
->fd
->abs_ts
;
1044 nstime_set_zero(&icmp_trans
->resp_time
);
1045 wmem_tree_insert32_array(icmp_info
->unmatched_pdus
, icmp_key
,
1046 (void *) icmp_trans
);
1048 /* Already visited this frame */
1049 guint32 frame_num
= pinfo
->fd
->num
;
1051 icmp_key
[0].length
= 2;
1052 icmp_key
[0].key
= key
;
1053 icmp_key
[1].length
= 1;
1054 icmp_key
[1].key
= &frame_num
;
1055 icmp_key
[2].length
= 0;
1056 icmp_key
[2].key
= NULL
;
1059 (icmp_transaction_t
*)wmem_tree_lookup32_array(icmp_info
->matched_pdus
,
1062 if (icmp_trans
== NULL
) {
1066 /* Print state tracking in the tree */
1067 if (icmp_trans
->resp_frame
) {
1068 it
= proto_tree_add_uint(tree
, hf_icmp_resp_in
, NULL
, 0, 0,
1069 icmp_trans
->resp_frame
);
1070 PROTO_ITEM_SET_GENERATED(it
);
1072 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " (reply in %d)",
1073 icmp_trans
->resp_frame
);
1078 } /* transaction_start() */
1080 /* ======================================================================= */
1081 static icmp_transaction_t
*transaction_end(packet_info
* pinfo
,
1085 conversation_t
*conversation
;
1086 icmp_conv_info_t
*icmp_info
;
1087 icmp_transaction_t
*icmp_trans
;
1088 wmem_tree_key_t icmp_key
[3];
1094 find_conversation(pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
,
1095 pinfo
->ptype
, 0, 0, 0);
1096 if (conversation
== NULL
) {
1100 icmp_info
= (icmp_conv_info_t
*)conversation_get_proto_data(conversation
, proto_icmp
);
1101 if (icmp_info
== NULL
) {
1105 if (!PINFO_FD_VISITED(pinfo
)) {
1108 icmp_key
[0].length
= 2;
1109 icmp_key
[0].key
= key
;
1110 icmp_key
[1].length
= 0;
1111 icmp_key
[1].key
= NULL
;
1113 (icmp_transaction_t
*)wmem_tree_lookup32_array(icmp_info
->unmatched_pdus
,
1115 if (icmp_trans
== NULL
) {
1119 /* we have already seen this response, or an identical one */
1120 if (icmp_trans
->resp_frame
!= 0) {
1124 icmp_trans
->resp_frame
= PINFO_FD_NUM(pinfo
);
1126 /* we found a match. Add entries to the matched table for both request and reply frames
1128 icmp_key
[0].length
= 2;
1129 icmp_key
[0].key
= key
;
1130 icmp_key
[1].length
= 1;
1131 icmp_key
[1].key
= &frame_num
;
1132 icmp_key
[2].length
= 0;
1133 icmp_key
[2].key
= NULL
;
1135 frame_num
= icmp_trans
->rqst_frame
;
1136 wmem_tree_insert32_array(icmp_info
->matched_pdus
, icmp_key
,
1137 (void *) icmp_trans
);
1139 frame_num
= icmp_trans
->resp_frame
;
1140 wmem_tree_insert32_array(icmp_info
->matched_pdus
, icmp_key
,
1141 (void *) icmp_trans
);
1143 /* Already visited this frame */
1144 guint32 frame_num
= pinfo
->fd
->num
;
1146 icmp_key
[0].length
= 2;
1147 icmp_key
[0].key
= key
;
1148 icmp_key
[1].length
= 1;
1149 icmp_key
[1].key
= &frame_num
;
1150 icmp_key
[2].length
= 0;
1151 icmp_key
[2].key
= NULL
;
1154 (icmp_transaction_t
*)wmem_tree_lookup32_array(icmp_info
->matched_pdus
,
1157 if (icmp_trans
== NULL
) {
1163 it
= proto_tree_add_uint(tree
, hf_icmp_resp_to
, NULL
, 0, 0,
1164 icmp_trans
->rqst_frame
);
1165 PROTO_ITEM_SET_GENERATED(it
);
1167 nstime_delta(&ns
, &pinfo
->fd
->abs_ts
, &icmp_trans
->rqst_time
);
1168 icmp_trans
->resp_time
= ns
;
1169 resp_time
= nstime_to_msec(&ns
);
1170 it
= proto_tree_add_double_format_value(tree
, hf_icmp_resptime
,
1171 NULL
, 0, 0, resp_time
,
1172 "%.3f ms", resp_time
);
1173 PROTO_ITEM_SET_GENERATED(it
);
1175 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " (request in %d)",
1176 icmp_trans
->rqst_frame
);
1180 } /* transaction_end() */
1182 #define MSPERDAY 86400000
1184 /* ======================================================================= */
1186 get_best_guess_mstimeofday(tvbuff_t
* tvb
, gint offset
, guint32 comp_ts
)
1188 guint32 be_ts
, le_ts
;
1190 /* Account for the special case from RFC 792 as best we can by clearing
1191 * the msb. Ref: [Page 16] of http://tools.ietf.org/html/rfc792:
1193 If the time is not available in milliseconds or cannot be provided
1194 with respect to midnight UT then any time can be inserted in a
1195 timestamp provided the high order bit of the timestamp is also set
1196 to indicate this non-standard value.
1198 be_ts
= tvb_get_ntohl(tvb
, offset
) & 0x7fffffff;
1199 le_ts
= tvb_get_letohl(tvb
, offset
) & 0x7fffffff;
1201 if (be_ts
< MSPERDAY
&& le_ts
>= MSPERDAY
) {
1205 if (le_ts
< MSPERDAY
&& be_ts
>= MSPERDAY
) {
1209 if (be_ts
< MSPERDAY
&& le_ts
< MSPERDAY
) {
1210 guint32 saved_be_ts
= be_ts
;
1211 guint32 saved_le_ts
= le_ts
;
1213 /* Is this a rollover to a new day, clocks not synchronized, different
1214 * timezones between originate and receive/transmit, .. what??? */
1215 if (be_ts
< comp_ts
&& be_ts
<= (MSPERDAY
/ 4)
1216 && comp_ts
>= (MSPERDAY
- (MSPERDAY
/ 4)))
1217 be_ts
+= MSPERDAY
; /* Assume a rollover to a new day */
1218 if (le_ts
< comp_ts
&& le_ts
<= (MSPERDAY
/ 4)
1219 && comp_ts
>= (MSPERDAY
- (MSPERDAY
/ 4)))
1220 le_ts
+= MSPERDAY
; /* Assume a rollover to a new day */
1221 if (abs(be_ts
- comp_ts
) < abs(le_ts
- comp_ts
))
1226 /* Both are bigger than MSPERDAY, but neither one's msb's are set. This
1227 * is clearly invalid, but now what TODO? For now, take the one closest to
1228 * the comparative timestamp, which is another way of saying, "let's
1229 * return a deterministic wild guess. */
1230 if (abs(be_ts
- comp_ts
) < abs(le_ts
- comp_ts
)) {
1234 } /* get_best_guess_mstimeofday() */
1237 * RFC 792 for basic ICMP.
1238 * RFC 1191 for ICMP_FRAG_NEEDED (with MTU of next hop).
1239 * RFC 1256 for router discovery messages.
1240 * RFC 2002 and 3012 for Mobile IP stuff.
1243 dissect_icmp(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
)
1245 proto_tree
*icmp_tree
= NULL
;
1249 guint8 icmp_original_dgram_length
;
1250 guint length
, reported_length
;
1251 guint16 cksum
, computed_cksum
;
1252 const gchar
*type_str
, *code_str
;
1253 guint8 num_addrs
= 0;
1254 guint8 addr_entry_size
= 0;
1256 gboolean save_in_error_pkt
;
1259 guint32 conv_key
[2];
1260 icmp_transaction_t
*trans
= NULL
;
1261 nstime_t ts
, time_relative
;
1263 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "ICMP");
1264 col_clear(pinfo
->cinfo
, COL_INFO
);
1266 /* To do: check for runts, errs, etc. */
1267 icmp_type
= tvb_get_guint8(tvb
, 0);
1268 icmp_code
= tvb_get_guint8(tvb
, 1);
1269 cksum
= tvb_get_ntohs(tvb
, 2);
1270 /*length of original datagram carried in the ICMP payload. In terms of 32 bit
1272 icmp_original_dgram_length
= tvb_get_guint8(tvb
, 5);
1275 val_to_str_const(icmp_type
, icmp_type_str
,
1276 "Unknown ICMP (obsolete or malformed?)");
1278 switch (icmp_type
) {
1281 val_to_str(icmp_code
, unreach_code_str
,
1282 "Unknown code: %u");
1286 val_to_str(icmp_code
, redir_code_str
,
1287 "Unknown code: %u");
1291 val_to_str(icmp_code
, alt_host_code_str
,
1292 "Unknown code: %u");
1294 case ICMP_RTRADVERT
:
1295 switch (icmp_code
) {
1296 case 0: /* Mobile-Ip */
1297 case 16: /* Mobile-Ip */
1298 type_str
= "Mobile IP Advertisement";
1300 } /* switch icmp_code */
1302 val_to_str(icmp_code
, rtradvert_code_str
,
1303 "Unknown code: %u");
1307 val_to_str(icmp_code
, ttl_code_str
,
1308 "Unknown code: %u");
1310 case ICMP_PARAMPROB
:
1312 val_to_str(icmp_code
, par_code_str
,
1313 "Unknown code: %u");
1317 val_to_str(icmp_code
, photuris_code_str
,
1318 "Unknown code: %u");
1325 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%-20s", type_str
);
1327 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " (%s)", code_str
);
1330 length
= tvb_length(tvb
);
1331 reported_length
= tvb_reported_length(tvb
);
1333 ti
= proto_tree_add_item(tree
, proto_icmp
, tvb
, 0, length
, ENC_NA
);
1334 icmp_tree
= proto_item_add_subtree(ti
, ett_icmp
);
1336 ti
= proto_tree_add_item(icmp_tree
, hf_icmp_type
, tvb
, 0, 1,
1338 proto_item_append_text(ti
, " (%s)", type_str
);
1340 ti
= proto_tree_add_item(icmp_tree
, hf_icmp_code
, tvb
, 1, 1,
1343 proto_item_append_text(ti
, " (%s)", code_str
);
1346 if (!pinfo
->fragmented
&& length
>= reported_length
1347 && !pinfo
->flags
.in_error_pkt
) {
1348 /* The packet isn't part of a fragmented datagram, isn't
1349 truncated, and isn't the payload of an error packet, so we can checksum
1353 ip_checksum(tvb_get_ptr(tvb
, 0, reported_length
),
1355 if (computed_cksum
== 0) {
1356 proto_tree_add_uint_format_value(icmp_tree
,
1357 hf_icmp_checksum
, tvb
,
1362 proto_tree_add_boolean(icmp_tree
,
1363 hf_icmp_checksum_bad
,
1365 PROTO_ITEM_SET_HIDDEN(item
);
1367 proto_tree_add_uint_format_value(icmp_tree
,
1368 hf_icmp_checksum
, tvb
,
1370 "0x%04x [incorrect, should be 0x%04x]",
1372 in_cksum_shouldbe(cksum
,
1375 proto_tree_add_boolean(icmp_tree
,
1376 hf_icmp_checksum_bad
,
1378 PROTO_ITEM_SET_HIDDEN(item
);
1381 proto_tree_add_uint(icmp_tree
, hf_icmp_checksum
, tvb
, 2, 2,
1385 /* Decode the second 4 bytes of the packet. */
1386 switch (icmp_type
) {
1387 case ICMP_ECHOREPLY
:
1390 case ICMP_TSTAMPREPLY
:
1392 case ICMP_IREQREPLY
:
1394 case ICMP_MASKREPLY
:
1395 proto_tree_add_item(icmp_tree
, hf_icmp_ident
, tvb
, 4, 2,
1397 proto_tree_add_item(icmp_tree
, hf_icmp_ident_le
, tvb
, 4, 2,
1399 proto_tree_add_item(icmp_tree
, hf_icmp_seq_num
, tvb
, 6, 2,
1401 proto_tree_add_item(icmp_tree
, hf_icmp_seq_num_le
, tvb
, 6,
1402 2, ENC_LITTLE_ENDIAN
);
1403 col_append_fstr(pinfo
->cinfo
, COL_INFO
,
1404 " id=0x%04x, seq=%u/%u, ttl=%u",
1405 tvb_get_ntohs(tvb
, 4), tvb_get_ntohs(tvb
,
1407 tvb_get_letohs(tvb
, 6), pinfo
->ip_ttl
);
1412 /* If icmp_original_dgram_length > 0, then this packet is compliant with RFC 4884 and
1413 * interpret the 6th octet as length of the original datagram
1415 if (icmp_original_dgram_length
> 0) {
1416 ti
= proto_tree_add_item(icmp_tree
, hf_icmp_length
,
1419 proto_item_append_text(ti
,
1420 "Length of original datagram: %u",
1421 icmp_original_dgram_length
*
1426 switch (icmp_code
) {
1427 case ICMP_FRAG_NEEDED
:
1428 proto_tree_add_item(icmp_tree
, hf_icmp_mtu
, tvb
, 6,
1434 case ICMP_RTRADVERT
:
1435 num_addrs
= tvb_get_guint8(tvb
, 4);
1436 proto_tree_add_text(icmp_tree
, tvb
, 4, 1,
1437 "Number of addresses: %u", num_addrs
);
1438 addr_entry_size
= tvb_get_guint8(tvb
, 5);
1439 proto_tree_add_text(icmp_tree
, tvb
, 5, 1,
1440 "Address entry size: %u",
1442 proto_tree_add_text(icmp_tree
, tvb
, 6, 2, "Lifetime: %s",
1443 time_secs_to_str(tvb_get_ntohs
1447 case ICMP_PARAMPROB
:
1448 proto_tree_add_text(icmp_tree
, tvb
, 4, 1, "Pointer: %u",
1449 tvb_get_guint8(tvb
, 4));
1450 if (icmp_original_dgram_length
> 0) {
1451 ti
= proto_tree_add_item(icmp_tree
, hf_icmp_length
,
1454 proto_item_append_text(ti
,
1455 " Length of original datagram: %u",
1456 icmp_original_dgram_length
*
1462 proto_tree_add_item(icmp_tree
, hf_icmp_redir_gw
, tvb
, 4, 4,
1467 if (icmp_original_dgram_length
> 0) {
1468 ti
= proto_tree_add_item(icmp_tree
, hf_icmp_length
,
1471 proto_item_append_text(ti
,
1472 " Length of original datagram: %u",
1473 icmp_original_dgram_length
*
1478 /* Decode the additional information in the packet. */
1479 switch (icmp_type
) {
1482 case ICMP_PARAMPROB
:
1483 case ICMP_SOURCEQUENCH
:
1485 /* Save the current value of the "we're inside an error packet"
1486 flag, and set that flag; subdissectors may treat packets
1487 that are the payload of error packets differently from
1489 save_in_error_pkt
= pinfo
->flags
.in_error_pkt
;
1490 pinfo
->flags
.in_error_pkt
= TRUE
;
1492 /* Decode the IP header and first 64 bits of data from the
1493 original datagram. */
1494 next_tvb
= tvb_new_subset_remaining(tvb
, 8);
1496 /* If the packet is compliant with RFC 4884, then it has
1497 * icmp_original_dgram_length*4 bytes of original IP packet that needs
1498 * to be decoded, followed by extension objects.
1500 if (icmp_original_dgram_length
1501 && (tvb_reported_length(tvb
) >
1502 (guint
) (8 + icmp_original_dgram_length
* 4))
1503 && (tvb_get_ntohs(tvb
, 8 + 2) >
1504 (guint
) icmp_original_dgram_length
* 4)) {
1505 set_actual_length(next_tvb
,
1506 icmp_original_dgram_length
* 4);
1508 /* There is a collision between RFC 1812 and draft-ietf-mpls-icmp-02.
1509 We don't know how to decode the 128th and following bytes of the ICMP payload.
1510 According to draft-ietf-mpls-icmp-02, these bytes should be decoded as MPLS extensios
1511 whereas RFC 1812 tells us to decode them as a portion of the original packet.
1512 Let the user decide.
1514 Here the user decided to favor MPLS extensions.
1515 Force the IP dissector to decode only the first 128 bytes. */
1516 if ((tvb_reported_length(tvb
) > 8 + 128) &&
1518 && (tvb_get_ntohs(tvb
, 8 + 2) > 128)) {
1519 set_actual_length(next_tvb
, 128);
1523 call_dissector(ip_handle
, next_tvb
, pinfo
, icmp_tree
);
1525 /* Restore the "we're inside an error packet" flag. */
1526 pinfo
->flags
.in_error_pkt
= save_in_error_pkt
;
1528 /* Decode MPLS extensions if the payload has at least 128 bytes, and
1529 - the original packet in the ICMP payload has less than 128 bytes, or
1530 - the user favors the MPLS extensions analysis */
1531 if ((tvb_reported_length(tvb
) > 8 + 128)
1532 && (tvb_get_ntohs(tvb
, 8 + 2) <= 128
1533 || favor_icmp_mpls_ext
)) {
1534 dissect_extensions(tvb
, 8 + 128, icmp_tree
);
1537 case ICMP_ECHOREPLY
:
1539 if (icmp_type
== ICMP_ECHOREPLY
) {
1540 if (!pinfo
->flags
.in_error_pkt
) {
1542 (guint32
) tvb_get_ntohs(tvb
, 2);
1543 if (pinfo
->flags
.in_gre_pkt
)
1544 conv_key
[0] |= 0x00010000; /* set a bit for "in GRE" */
1546 (guint32
) ((tvb_get_ntohs(tvb
, 4) <<
1547 16) | tvb_get_ntohs(tvb
,
1550 transaction_end(pinfo
, icmp_tree
,
1554 if (!pinfo
->flags
.in_error_pkt
) {
1557 tmp
[0] = ~tvb_get_ntohs(tvb
, 2);
1558 tmp
[1] = ~0x0800; /* The difference between echo request & reply */
1560 ip_checksum((guint8
*) & tmp
,
1562 if (conv_key
[0] == 0) {
1563 conv_key
[0] = 0xffff;
1565 if (pinfo
->flags
.in_gre_pkt
) {
1566 conv_key
[0] |= 0x00010000; /* set a bit for "in GRE" */
1569 (guint32
) ((tvb_get_ntohs(tvb
, 4) <<
1570 16) | tvb_get_ntohs(tvb
,
1573 transaction_start(pinfo
, icmp_tree
,
1578 /* Make sure we have enough bytes in the payload before trying to
1579 * see if the data looks like a timestamp; otherwise we'll get
1580 * malformed packets as we try to access data that isn't there. */
1581 if (tvb_length_remaining(tvb
, 8) < 8) {
1582 if (tvb_length_remaining(tvb
, 8) > 0) {
1583 call_dissector(data_handle
,
1584 tvb_new_subset_remaining
1585 (tvb
, 8), pinfo
, icmp_tree
);
1590 /* Interpret the first 8 bytes of the icmp data as a timestamp
1591 * But only if it does look like it's a timestamp.
1594 * Timestamps could be in different formats depending on the OS
1596 ts
.secs
= tvb_get_ntohl(tvb
, 8);
1597 ts
.nsecs
= tvb_get_ntohl(tvb
, 8 + 4); /* Leave at microsec resolution for now */
1598 if (abs((guint32
) (ts
.secs
- pinfo
->fd
->abs_ts
.secs
)) >=
1599 3600 * 24 || ts
.nsecs
>= 1000000) {
1600 /* Timestamp does not look right in BE, try LE representation */
1601 ts
.secs
= tvb_get_letohl(tvb
, 8);
1602 ts
.nsecs
= tvb_get_letohl(tvb
, 8 + 4); /* Leave at microsec resolution for now */
1604 if (abs((guint32
) (ts
.secs
- pinfo
->fd
->abs_ts
.secs
)) <
1605 3600 * 24 && ts
.nsecs
< 1000000) {
1606 ts
.nsecs
*= 1000; /* Convert to nanosec resolution */
1607 proto_tree_add_time(icmp_tree
, hf_icmp_data_time
,
1609 nstime_delta(&time_relative
, &pinfo
->fd
->abs_ts
,
1611 ti
= proto_tree_add_time(icmp_tree
,
1612 hf_icmp_data_time_relative
,
1615 PROTO_ITEM_SET_GENERATED(ti
);
1616 call_dissector(data_handle
,
1617 tvb_new_subset_remaining(tvb
,
1621 call_dissector(data_handle
,
1622 tvb_new_subset_remaining(tvb
, 8),
1627 case ICMP_RTRADVERT
:
1628 if (addr_entry_size
== 2) {
1629 for (i
= 0; i
< num_addrs
; i
++) {
1630 proto_tree_add_text(icmp_tree
, tvb
,
1632 "Router address: %s",
1637 proto_tree_add_text(icmp_tree
, tvb
,
1639 "Preference level: %d",
1645 if ((icmp_code
== 0) || (icmp_code
== 16)) {
1647 dissect_mip_extensions(tvb
, 8 + i
* 8,
1651 call_dissector(data_handle
,
1652 tvb_new_subset_remaining(tvb
, 8),
1658 case ICMP_TSTAMPREPLY
:
1660 guint32 frame_ts
, orig_ts
;
1662 frame_ts
= (guint32
)(((pinfo
->fd
->abs_ts
.secs
* 1000) +
1663 (pinfo
->fd
->abs_ts
.nsecs
/ 1000000)) %
1667 get_best_guess_mstimeofday(tvb
, 8, frame_ts
);
1668 proto_tree_add_text(icmp_tree
, tvb
, 8, 4,
1669 "Originate timestamp: %s after midnight UTC",
1670 time_msecs_to_str(orig_ts
));
1672 proto_tree_add_text(icmp_tree
, tvb
, 12, 4,
1673 "Receive timestamp: %s after midnight UTC",
1675 (get_best_guess_mstimeofday
1676 (tvb
, 12, orig_ts
)));
1677 proto_tree_add_text(icmp_tree
, tvb
, 16, 4,
1678 "Transmit timestamp: %s after midnight UTC",
1680 (get_best_guess_mstimeofday
1681 (tvb
, 16, orig_ts
)));
1686 case ICMP_MASKREPLY
:
1687 proto_tree_add_text(icmp_tree
, tvb
, 8, 4,
1688 "Address mask: %s (0x%08x)",
1689 tvb_ip_to_str(tvb
, 8),
1690 tvb_get_ntohl(tvb
, 8));
1695 tap_queue_packet(icmp_tap
, pinfo
, trans
);
1699 void proto_register_icmp(void)
1701 static hf_register_info hf
[] = {
1703 {"Type", "icmp.type", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1707 {"Code", "icmp.code", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1711 {"Checksum", "icmp.checksum", FT_UINT16
, BASE_HEX
, NULL
,
1715 {&hf_icmp_checksum_bad
,
1716 {"Bad Checksum", "icmp.checksum_bad", FT_BOOLEAN
,
1717 BASE_NONE
, NULL
, 0x0,
1721 {"Identifier (BE)", "icmp.ident", FT_UINT16
, BASE_DEC_HEX
,
1723 "Identifier (big endian representation)", HFILL
}},
1726 {"Identifier (LE)", "icmp.ident", FT_UINT16
, BASE_DEC_HEX
,
1728 "Identifier (little endian representation)", HFILL
}},
1731 {"Sequence number (BE)", "icmp.seq", FT_UINT16
,
1732 BASE_DEC_HEX
, NULL
, 0x0,
1733 "Sequence number (big endian representation)", HFILL
}},
1735 {&hf_icmp_seq_num_le
,
1736 {"Sequence number (LE)", "icmp.seq_le", FT_UINT16
,
1738 0x0, "Sequence number (little endian representation)",
1742 {"MTU of next hop", "icmp.mtu", FT_UINT16
, BASE_DEC
, NULL
,
1747 {"Gateway address", "icmp.redir_gw", FT_IPv4
, BASE_NONE
,
1752 {"Extension Type", "icmp.mip.type", FT_UINT8
, BASE_DEC
,
1753 VALS(mip_extensions
), 0x0, NULL
, HFILL
}},
1755 {&hf_icmp_mip_length
,
1756 {"Length", "icmp.mip.length", FT_UINT8
, BASE_DEC
, NULL
,
1760 {&hf_icmp_mip_prefix_length
,
1761 {"Prefix Length", "icmp.mip.prefixlength", FT_UINT8
,
1762 BASE_DEC
, NULL
, 0x0,
1766 {"Sequence Number", "icmp.mip.seq", FT_UINT16
, BASE_DEC
,
1771 {"Registration Lifetime", "icmp.mip.life", FT_UINT16
,
1776 {&hf_icmp_mip_flags
,
1777 {"Flags", "icmp.mip.flags", FT_UINT16
, BASE_HEX
, NULL
,
1782 {"Registration Required", "icmp.mip.r", FT_BOOLEAN
, 16,
1784 "Registration with this FA is required", HFILL
}},
1787 {"Busy", "icmp.mip.b", FT_BOOLEAN
, 16, NULL
, 0x4000,
1788 "This FA will not accept requests at this time", HFILL
}},
1791 {"Home Agent", "icmp.mip.h", FT_BOOLEAN
, 16, NULL
, 0x2000,
1792 "Home Agent Services Offered", HFILL
}},
1795 {"Foreign Agent", "icmp.mip.f", FT_BOOLEAN
, 16, NULL
,
1797 "Foreign Agent Services Offered", HFILL
}},
1800 {"Minimal Encapsulation", "icmp.mip.m", FT_BOOLEAN
, 16,
1802 "Minimal encapsulation tunneled datagram support",
1806 {"GRE", "icmp.mip.g", FT_BOOLEAN
, 16, NULL
, 0x0400,
1807 "GRE encapsulated tunneled datagram support", HFILL
}},
1810 {"VJ Comp", "icmp.mip.v", FT_BOOLEAN
, 16, NULL
, 0x0200,
1811 "Van Jacobson Header Compression Support", HFILL
}},
1814 {"Reverse tunneling", "icmp.mip.rt", FT_BOOLEAN
, 16, NULL
,
1816 "Reverse tunneling support", HFILL
}},
1819 {"UDP tunneling", "icmp.mip.u", FT_BOOLEAN
, 16, NULL
,
1821 "UDP tunneling support", HFILL
}},
1824 {"Revocation support", "icmp.mip.x", FT_BOOLEAN
, 16, NULL
,
1826 "Registration revocation support", HFILL
}},
1828 {&hf_icmp_mip_reserved
,
1829 {"Reserved", "icmp.mip.reserved", FT_UINT16
, BASE_HEX
,
1834 {"Care-Of-Address", "icmp.mip.coa", FT_IPv4
, BASE_NONE
,
1838 {&hf_icmp_mip_challenge
,
1839 {"Challenge", "icmp.mip.challenge", FT_BYTES
, BASE_NONE
,
1844 {"ICMP Extensions", "icmp.ext", FT_NONE
, BASE_NONE
, NULL
,
1848 {&hf_icmp_ext_version
,
1849 {"Version", "icmp.ext.version", FT_UINT8
, BASE_DEC
, NULL
,
1853 {&hf_icmp_ext_reserved
,
1854 {"Reserved", "icmp.ext.res", FT_UINT16
, BASE_HEX
, NULL
,
1858 {&hf_icmp_ext_checksum
,
1859 {"Checksum", "icmp.ext.checksum", FT_UINT16
, BASE_HEX
,
1863 {&hf_icmp_ext_checksum_bad
,
1864 {"Bad Checksum", "icmp.ext.checksum_bad", FT_BOOLEAN
,
1869 {&hf_icmp_ext_length
,
1870 {"Length", "icmp.ext.length", FT_UINT16
, BASE_DEC
, NULL
,
1874 {&hf_icmp_ext_class
,
1875 {"Class", "icmp.ext.class", FT_UINT8
, BASE_DEC
, NULL
, 0x0,
1878 {&hf_icmp_ext_c_type
,
1879 {"C-Type", "icmp.ext.ctype", FT_UINT8
, BASE_DEC
, NULL
,
1883 {&hf_icmp_mpls_label
,
1884 {"Label", "icmp.mpls.label", FT_UINT24
, BASE_DEC
, NULL
,
1889 {"Experimental", "icmp.mpls.exp", FT_UINT24
, BASE_DEC
,
1894 {"Stack bit", "icmp.mpls.s", FT_BOOLEAN
, 24,
1895 TFS(&tfs_set_notset
), 0x01,
1899 {"Time to live", "icmp.mpls.ttl", FT_UINT8
, BASE_DEC
,
1904 {"Response frame", "icmp.resp_in", FT_FRAMENUM
, BASE_NONE
,
1906 "The frame number of the corresponding response",
1910 {"Request frame", "icmp.resp_to", FT_FRAMENUM
, BASE_NONE
,
1912 "The frame number of the corresponding request", HFILL
}},
1915 {"Response time", "icmp.resptime", FT_DOUBLE
, BASE_NONE
,
1917 "The time between the request and the response, in ms.",
1920 {&hf_icmp_data_time
,
1921 {"Timestamp from icmp data", "icmp.data_time",
1923 ABSOLUTE_TIME_LOCAL
, NULL
, 0x0,
1924 "The timestamp in the first 8 bytes of the icmp data",
1927 {&hf_icmp_data_time_relative
,
1928 {"Timestamp from icmp data (relative)",
1929 "icmp.data_time_relative",
1930 FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0x0,
1931 "The timestamp of the packet, relative to the timestamp in the first 8 bytes of the icmp data",
1935 {"Length of original datagram", "icmp.length", FT_UINT8
,
1938 "The length of the original datagram", HFILL
}},
1939 {&hf_icmp_int_info_role
,
1940 {"Interface Role", "icmp.int_info.role",
1941 FT_UINT8
, BASE_DEC
, VALS(interface_role_str
),
1942 INT_INFO_INTERFACE_ROLE
,
1944 {&hf_icmp_int_info_reserved
,
1945 {"Reserved", "icmp.int_info.reserved",
1946 FT_UINT8
, BASE_DEC
, NULL
, INT_INFO_RESERVED
,
1948 {&hf_icmp_int_info_ifindex
,
1949 {"ifIndex", "icmp.int_info.ifindex", FT_BOOLEAN
, 8, NULL
,
1951 "True: ifIndex of the interface included; False: ifIndex of the interface not included ",
1953 {&hf_icmp_int_info_ipaddr
,
1954 {"IP Address", "icmp.int_info.ipaddr", FT_BOOLEAN
, 8,
1957 "True: IP Address Sub-Object present; False: IP Address Sub-Object not present",
1959 {&hf_icmp_int_info_name
,
1960 {"Interface Name", "icmp.int_info.name", FT_BOOLEAN
, 8,
1963 "True: Interface Name Sub-Object present; False: Interface Name Sub-Object not present",
1965 {&hf_icmp_int_info_mtu
,
1966 {"MTU", "icmp.int_info.mtu", FT_BOOLEAN
, 8, NULL
,
1968 "True: MTU present; False: MTU not present", HFILL
}},
1969 {&hf_icmp_int_info_afi
,
1970 {"Address Family Identifier", "icmp.int_info.afi",
1971 FT_UINT16
, BASE_DEC
,
1973 "Address Family of the interface address", HFILL
}},
1974 {&hf_icmp_int_info_ipv4
,
1975 {"Source", "icmp.int_info.ipv4", FT_IPv4
, BASE_NONE
, NULL
,
1978 {&hf_icmp_int_info_ipv6
,
1979 {"Source", "icmp.int_info.ipv6", FT_IPv6
, BASE_NONE
, NULL
,
1984 static gint
*ett
[] = {
1987 &ett_icmp_mip_flags
,
1988 /* MPLS extensions */
1990 &ett_icmp_ext_object
,
1991 &ett_icmp_mpls_stack_object
,
1992 /* Interface Information Object RFC 5837 */
1993 &ett_icmp_interface_info_object
,
1994 &ett_icmp_interface_ipaddr
,
1995 &ett_icmp_interface_name
1998 module_t
*icmp_module
;
2001 proto_register_protocol("Internet Control Message Protocol",
2003 proto_register_field_array(proto_icmp
, hf
, array_length(hf
));
2004 proto_register_subtree_array(ett
, array_length(ett
));
2006 icmp_module
= prefs_register_protocol(proto_icmp
, NULL
);
2008 prefs_register_bool_preference(icmp_module
, "favor_icmp_mpls",
2009 "Favor ICMP extensions for MPLS",
2010 "Whether the 128th and following bytes of the ICMP payload should be decoded as MPLS extensions or as a portion of the original packet",
2011 &favor_icmp_mpls_ext
);
2013 register_dissector("icmp", dissect_icmp
, proto_icmp
);
2014 icmp_tap
= register_tap("icmp");
2017 void proto_reg_handoff_icmp(void)
2019 dissector_handle_t icmp_handle
;
2022 * Get handle for the IP dissector.
2024 ip_handle
= find_dissector("ip");
2025 icmp_handle
= find_dissector("icmp");
2026 data_handle
= find_dissector("data");
2028 dissector_add_uint("ip.proto", IP_PROTO_ICMP
, icmp_handle
);