2 * Routines for IP and miscellaneous IP protocol packet disassembly
4 * $Id: packet-ip.c,v 1.39 1999/08/21 21:06:11 gerald Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
45 #ifndef __PACKET_IP_H__
46 #include "packet-ip.h"
49 static int proto_ip = -1;
50 static int hf_ip_version = -1;
51 static int hf_ip_hdr_len = -1;
52 static int hf_ip_tos = -1;
53 static int hf_ip_tos_precedence = -1;
54 static int hf_ip_len = -1;
55 static int hf_ip_id = -1;
56 static int hf_ip_dst = -1;
57 static int hf_ip_src = -1;
58 static int hf_ip_addr = -1;
59 static int hf_ip_flags = -1;
60 static int hf_ip_frag_offset = -1;
61 static int hf_ip_ttl = -1;
62 static int hf_ip_proto = -1;
63 static int hf_ip_checksum = -1;
65 static int proto_igmp = -1;
66 static int hf_igmp_version = -1;
67 static int hf_igmp_type = -1;
68 static int hf_igmp_unused = -1;
69 static int hf_igmp_checksum = -1;
70 static int hf_igmp_group = -1;
72 static int proto_icmp = -1;
75 /* ICMP structs and definitions */
76 typedef struct _e_icmp {
81 struct { /* Address mask request/reply */
86 struct { /* Timestap request/reply */
93 guint32 zero; /* Unreachable */
97 #define ICMP_ECHOREPLY 0
98 #define ICMP_UNREACH 3
99 #define ICMP_SOURCEQUENCH 4
100 #define ICMP_REDIRECT 5
102 #define ICMP_RTRADVERT 9
103 #define ICMP_RTRSOLICIT 10
104 #define ICMP_TIMXCEED 11
105 #define ICMP_PARAMPROB 12
106 #define ICMP_TSTAMP 13
107 #define ICMP_TSTAMPREPLY 14
109 #define ICMP_IREQREPLY 16
110 #define ICMP_MASKREQ 17
111 #define ICMP_MASKREPLY 18
113 /* ICMP UNREACHABLE */
115 #define ICMP_NET_UNREACH 0 /* Network Unreachable */
116 #define ICMP_HOST_UNREACH 1 /* Host Unreachable */
117 #define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */
118 #define ICMP_PORT_UNREACH 3 /* Port Unreachable */
119 #define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */
120 #define ICMP_SR_FAILED 5 /* Source Route failed */
121 #define ICMP_NET_UNKNOWN 6
122 #define ICMP_HOST_UNKNOWN 7
123 #define ICMP_HOST_ISOLATED 8
124 #define ICMP_NET_ANO 9
125 #define ICMP_HOST_ANO 10
126 #define ICMP_NET_UNR_TOS 11
127 #define ICMP_HOST_UNR_TOS 12
128 #define ICMP_PKT_FILTERED 13 /* Packet filtered */
129 #define ICMP_PREC_VIOLATION 14 /* Precedence violation */
130 #define ICMP_PREC_CUTOFF 15 /* Precedence cut off */
133 /* IGMP structs and definitions */
134 typedef struct _e_igmp {
135 guint8 igmp_v_t; /* combines igmp_v and igmp_t */
141 #define IGMP_M_QRY 0x01
142 #define IGMP_V1_M_RPT 0x02
143 #define IGMP_V2_LV_GRP 0x07
144 #define IGMP_DVMRP 0x03
145 #define IGMP_PIM 0x04
146 #define IGMP_V2_M_RPT 0x06
147 #define IGMP_MTRC_RESP 0x1e
148 #define IGMP_MTRC 0x1f
150 /* IP structs and definitions */
152 typedef struct _e_ip {
153 guint8 ip_v_hl; /* combines ip_v and ip_hl */
166 #define IP_CE 0x8000 /* Flag: "Congestion" */
167 #define IP_DF 0x4000 /* Flag: "Don't Fragment" */
168 #define IP_MF 0x2000 /* Flag: "More Fragments" */
169 #define IP_OFFSET 0x1FFF /* "Fragment Offset" part */
171 #define IPTOS_TOS_MASK 0x1E
172 #define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK)
173 #define IPTOS_NONE 0x00
174 #define IPTOS_LOWCOST 0x02
175 #define IPTOS_RELIABILITY 0x04
176 #define IPTOS_THROUGHPUT 0x08
177 #define IPTOS_LOWDELAY 0x10
178 #define IPTOS_SECURITY 0x1E
180 #define IPTOS_PREC_MASK 0xE0
181 #define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK)
182 #define IPTOS_PREC_NETCONTROL 0xe0
183 #define IPTOS_PREC_INTERNETCONTROL 0xc0
184 #define IPTOS_PREC_CRITIC_ECP 0xa0
185 #define IPTOS_PREC_FLASHOVERRIDE 0x80
186 #define IPTOS_PREC_FLASH 0x60
187 #define IPTOS_PREC_IMMEDIATE 0x40
188 #define IPTOS_PREC_PRIORITY 0x20
189 #define IPTOS_PREC_ROUTINE 0x00
192 #define IPOPT_COPY 0x80
194 #define IPOPT_CONTROL 0x00
195 #define IPOPT_RESERVED1 0x20
196 #define IPOPT_MEASUREMENT 0x40
197 #define IPOPT_RESERVED2 0x60
199 #define IPOPT_END (0 |IPOPT_CONTROL)
200 #define IPOPT_NOOP (1 |IPOPT_CONTROL)
201 #define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY)
202 #define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY)
203 #define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT)
204 #define IPOPT_RR (7 |IPOPT_CONTROL)
205 #define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY)
206 #define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY)
207 #define IPOPT_RA (20|IPOPT_CONTROL|IPOPT_COPY)
209 /* IP option lengths */
210 #define IPOLEN_SEC 11
211 #define IPOLEN_LSRR_MIN 3
212 #define IPOLEN_TIMESTAMP_MIN 5
213 #define IPOLEN_RR_MIN 3
215 #define IPOLEN_SSRR_MIN 3
217 #define IPSEC_UNCLASSIFIED 0x0000
218 #define IPSEC_CONFIDENTIAL 0xF135
219 #define IPSEC_EFTO 0x789A
220 #define IPSEC_MMMM 0xBC4D
221 #define IPSEC_RESTRICTED 0xAF13
222 #define IPSEC_SECRET 0xD788
223 #define IPSEC_TOPSECRET 0x6BC5
224 #define IPSEC_RESERVED1 0x35E2
225 #define IPSEC_RESERVED2 0x9AF1
226 #define IPSEC_RESERVED3 0x4D78
227 #define IPSEC_RESERVED4 0x24BD
228 #define IPSEC_RESERVED5 0x135E
229 #define IPSEC_RESERVED6 0x89AF
230 #define IPSEC_RESERVED7 0xC4D6
231 #define IPSEC_RESERVED8 0xE26B
233 #define IPOPT_TS_TSONLY 0 /* timestamps only */
234 #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
235 #define IPOPT_TS_PRESPEC 3 /* specified modules only */
239 capture_ip(const u_char *pd, int offset, guint32 cap_len, packet_counts *ld) {
240 switch (pd[offset + 9]) {
262 dissect_ipopt_security(proto_tree *opt_tree, const char *name,
263 const u_char *opd, int offset, guint optlen)
265 proto_tree *field_tree = NULL;
268 static const value_string secl_vals[] = {
269 {IPSEC_UNCLASSIFIED, "Unclassified"},
270 {IPSEC_CONFIDENTIAL, "Confidential"},
271 {IPSEC_EFTO, "EFTO" },
272 {IPSEC_MMMM, "MMMM" },
273 {IPSEC_RESTRICTED, "Restricted" },
274 {IPSEC_SECRET, "Secret" },
275 {IPSEC_TOPSECRET, "Top secret" },
276 {IPSEC_RESERVED1, "Reserved" },
277 {IPSEC_RESERVED2, "Reserved" },
278 {IPSEC_RESERVED3, "Reserved" },
279 {IPSEC_RESERVED4, "Reserved" },
280 {IPSEC_RESERVED5, "Reserved" },
281 {IPSEC_RESERVED6, "Reserved" },
282 {IPSEC_RESERVED7, "Reserved" },
283 {IPSEC_RESERVED8, "Reserved" },
286 tf = proto_tree_add_text(opt_tree, offset, optlen, "%s:", name);
287 field_tree = proto_item_add_subtree(tf, ETT_IP_OPTION_SEC);
291 proto_tree_add_text(field_tree, offset, 2,
292 "Security: %s", val_to_str(val, secl_vals, "Unknown (0x%x)"));
297 proto_tree_add_text(field_tree, offset, 2,
298 "Compartments: %d", val);
302 proto_tree_add_text(field_tree, offset, 2,
303 "Handling restrictions: %c%c", opd[0], opd[1]);
307 proto_tree_add_text(field_tree, offset, 3,
308 "Transmission control code: %c%c%c", opd[0], opd[1], opd[2]);
312 dissect_ipopt_route(proto_tree *opt_tree, const char *name,
313 const u_char *opd, int offset, guint optlen)
315 proto_tree *field_tree = NULL;
321 tf = proto_tree_add_text(opt_tree, offset, optlen, "%s (%d bytes)", name,
323 field_tree = proto_item_add_subtree(tf, ETT_IP_OPTION_ROUTE);
325 optoffset += 2; /* skip past type and length */
326 optlen -= 2; /* subtract size of type and length */
329 proto_tree_add_text(field_tree, offset + optoffset, 1,
330 "Pointer: %d%s", ptr,
331 ((ptr < 4) ? " (points before first address)" :
332 ((ptr & 3) ? " (points to middle of address)" : "")));
336 ptr--; /* ptr is 1-origin */
340 proto_tree_add_text(field_tree, offset, optlen,
341 "(suboption would go past end of option)");
345 /* Avoids alignment problems on many architectures. */
346 memcpy((char *)&addr, (char *)opd, sizeof(addr));
348 proto_tree_add_text(field_tree, offset + optoffset, 4,
350 ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
351 ((optoffset == ptr) ? " <- (current)" : ""));
359 dissect_ipopt_sid(proto_tree *opt_tree, const char *name, const u_char *opd,
360 int offset, guint optlen)
362 proto_tree_add_text(opt_tree, offset, optlen,
363 "%s: %d", name, pntohs(opd));
368 dissect_ipopt_timestamp(proto_tree *opt_tree, const char *name, const u_char *opd,
369 int offset, guint optlen)
371 proto_tree *field_tree = NULL;
376 static const value_string flag_vals[] = {
377 {IPOPT_TS_TSONLY, "Time stamps only" },
378 {IPOPT_TS_TSANDADDR, "Time stamp and address" },
379 {IPOPT_TS_PRESPEC, "Time stamps for prespecified addresses"},
385 tf = proto_tree_add_text(opt_tree, offset, optlen, "%s:", name);
386 field_tree = proto_item_add_subtree(tf, ETT_IP_OPTION_TIMESTAMP);
388 optoffset += 2; /* skip past type and length */
389 optlen -= 2; /* subtract size of type and length */
392 proto_tree_add_text(field_tree, offset + optoffset, 1,
393 "Pointer: %d%s", ptr,
394 ((ptr < 5) ? " (points before first address)" :
395 (((ptr - 1) & 3) ? " (points to middle of address)" : "")));
399 ptr--; /* ptr is 1-origin */
402 proto_tree_add_text(field_tree, offset + optoffset, 1,
403 "Overflow: %d", flg >> 4);
405 proto_tree_add_text(field_tree, offset + optoffset, 1,
406 "Flag: %s", val_to_str(flg, flag_vals, "Unknown (0x%x)"));
412 if (flg == IPOPT_TS_TSANDADDR) {
414 proto_tree_add_text(field_tree, offset + optoffset, optlen,
415 "(suboption would go past end of option)");
418 /* XXX - check whether it goes past end of packet */
423 proto_tree_add_text(field_tree, offset + optoffset, optlen,
424 "(suboption would go past end of option)");
427 /* XXX - check whether it goes past end of packet */
428 memcpy((char *)&addr, (char *)opd, sizeof(addr));
431 proto_tree_add_text(field_tree, offset, 8,
432 "Address = %s, time stamp = %u",
433 ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
438 proto_tree_add_text(field_tree, offset + optoffset, optlen,
439 "(suboption would go past end of option)");
442 /* XXX - check whether it goes past end of packet */
446 proto_tree_add_text(field_tree, offset + optoffset, 4,
447 "Time stamp = %u", ts);
453 static ip_tcp_opt ipopts[] = {
473 dissect_ipopt_security
477 "Strict source route",
484 "Loose source route",
507 IPOLEN_TIMESTAMP_MIN,
508 dissect_ipopt_timestamp
512 #define N_IP_OPTS (sizeof ipopts / sizeof ipopts[0])
514 /* Dissect the IP or TCP options in a packet. */
516 dissect_ip_tcp_options(proto_tree *opt_tree, const u_char *opd, int offset,
517 guint length, ip_tcp_opt *opttab, int nopts, int eol)
525 for (optp = &opttab[0]; optp < &opttab[nopts]; optp++) {
526 if (optp->optcode == opt)
529 if (optp == &opttab[nopts]) {
530 proto_tree_add_text(opt_tree, offset, 1, "Unknown");
531 /* We don't know how long this option is, so we don't know how much
532 of it to skip, so we just bail. */
535 --length; /* account for type byte */
536 if (optp->len_type != NO_LENGTH) {
537 /* Option has a length. Is it in the packet? */
539 /* Bogus - packet must at least include option code byte and
541 proto_tree_add_text(opt_tree, offset, 1,
542 "%s (length byte past end of header)", optp->name);
545 len = *opd++; /* total including type, len */
546 --length; /* account for length byte */
548 /* Bogus - option length is too short to include option code and
550 proto_tree_add_text(opt_tree, offset, 2,
551 "%s (with too-short option length = %u bytes)", optp->name, 2);
553 } else if (len - 2 > length) {
554 /* Bogus - option goes past the end of the header. */
555 proto_tree_add_text(opt_tree, offset, length,
556 "%s (option goes past end of header)", optp->name);
558 } else if (optp->len_type == FIXED_LENGTH && len != optp->optlen) {
559 /* Bogus - option length isn't what it's supposed to be for this
561 proto_tree_add_text(opt_tree, offset, len,
562 "%s (with option length = %u bytes; should be %u)", optp->name,
565 } else if (optp->len_type == VARIABLE_LENGTH && len < optp->optlen) {
566 /* Bogus - option length is less than what it's supposed to be for
568 proto_tree_add_text(opt_tree, offset, len,
569 "%s (with option length = %u bytes; should be >= %u)", optp->name,
573 if (optp->dissect != NULL) {
574 /* Option has a dissector. */
575 (*optp->dissect)(opt_tree, optp->name, opd, offset, len);
577 /* Option has no data, hence no dissector. */
578 proto_tree_add_text(opt_tree, offset, len, "%s", optp->name);
580 len -= 2; /* subtract size of type and length */
586 proto_tree_add_text(opt_tree, offset, 1, "%s", optp->name);
594 static const value_string proto_vals[] = { {IP_PROTO_ICMP, "ICMP"},
595 {IP_PROTO_IGMP, "IGMP"},
596 {IP_PROTO_TCP, "TCP" },
597 {IP_PROTO_UDP, "UDP" },
598 {IP_PROTO_OSPF, "OSPF"},
601 static const value_string precedence_vals[] = {
602 { IPTOS_PREC_ROUTINE, "routine" },
603 { IPTOS_PREC_PRIORITY, "priority" },
604 { IPTOS_PREC_IMMEDIATE, "immediate" },
605 { IPTOS_PREC_FLASH, "flash" },
606 { IPTOS_PREC_FLASHOVERRIDE, "flash override" },
607 { IPTOS_PREC_CRITIC_ECP, "CRITIC/ECP" },
608 { IPTOS_PREC_INTERNETCONTROL, "internetwork control" },
609 { IPTOS_PREC_NETCONTROL, "network control" },
612 static const value_string iptos_vals[] = {
613 { IPTOS_NONE, "None" },
614 { IPTOS_LOWCOST, "Minimize cost" },
615 { IPTOS_RELIABILITY, "Maximize reliability" },
616 { IPTOS_THROUGHPUT, "Maximize throughput" },
617 { IPTOS_LOWDELAY, "Minimize delay" },
618 { IPTOS_SECURITY, "Maximize security" },
623 dissect_ip(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
625 proto_tree *ip_tree, *field_tree;
628 guint hlen, optlen, len;
633 /* To do: check for runts, errs, etc. */
634 /* Avoids alignment problems on many architectures. */
635 memcpy(&iph, &pd[offset], sizeof(e_ip));
636 iph.ip_len = ntohs(iph.ip_len);
637 iph.ip_id = ntohs(iph.ip_id);
638 iph.ip_off = ntohs(iph.ip_off);
639 iph.ip_sum = ntohs(iph.ip_sum);
641 /* Length of IP datagram plus headers above it. */
642 len = iph.ip_len + offset;
644 /* Set the payload and captured-payload lengths to the minima of (the
645 IP length plus the length of the headers above it) and the frame
649 if (pi.captured_len > len)
650 pi.captured_len = len;
652 hlen = lo_nibble(iph.ip_v_hl) * 4; /* IP header length, in bytes */
664 /* Names are set in the associated dissect_* routines */
667 if (check_col(fd, COL_PROTOCOL))
668 col_add_str(fd, COL_PROTOCOL, "IP");
669 if (check_col(fd, COL_INFO))
670 col_add_fstr(fd, COL_INFO, "Unknown IP protocol (0x%02x)", iph.ip_p);
673 if (check_col(fd, COL_RES_NET_SRC))
674 col_add_str(fd, COL_RES_NET_SRC, get_hostname(iph.ip_src));
675 if (check_col(fd, COL_UNRES_NET_SRC))
676 col_add_str(fd, COL_UNRES_NET_SRC, ip_to_str((guint8 *) &iph.ip_src));
677 if (check_col(fd, COL_RES_NET_DST))
678 col_add_str(fd, COL_RES_NET_DST, get_hostname(iph.ip_dst));
679 if (check_col(fd, COL_UNRES_NET_DST))
680 col_add_str(fd, COL_UNRES_NET_DST, ip_to_str((guint8 *) &iph.ip_dst));
684 switch (IPTOS_TOS(iph.ip_tos)) {
686 strcpy(tos_str, "None");
689 strcpy(tos_str, "Minimize cost");
691 case IPTOS_RELIABILITY:
692 strcpy(tos_str, "Maximize reliability");
694 case IPTOS_THROUGHPUT:
695 strcpy(tos_str, "Maximize throughput");
698 strcpy(tos_str, "Minimize delay");
701 strcpy(tos_str, "Maximize security");
704 strcpy(tos_str, "Unknown. Malformed?");
708 ti = proto_tree_add_item(tree, proto_ip, offset, hlen, NULL);
709 ip_tree = proto_item_add_subtree(ti, ETT_IP);
711 proto_tree_add_item(ip_tree, hf_ip_version, offset, 1, hi_nibble(iph.ip_v_hl));
712 proto_tree_add_item_format(ip_tree, hf_ip_hdr_len, offset, 1, hlen,
713 "Header length: %d bytes", hlen);
714 tf = proto_tree_add_item_format(ip_tree, hf_ip_tos, offset + 1, 1, iph.ip_tos,
715 "Type of service: 0x%02x (%s)", iph.ip_tos,
716 val_to_str( IPTOS_TOS(iph.ip_tos), iptos_vals, "Unknown") );
718 field_tree = proto_item_add_subtree(tf, ETT_IP_TOS);
719 proto_tree_add_item_format(field_tree, hf_ip_tos_precedence, offset + 1, 1,
720 iph.ip_tos & IPTOS_PREC_MASK, decode_enumerated_bitfield(iph.ip_tos, IPTOS_PREC_MASK,
721 sizeof (iph.ip_tos)*8, precedence_vals, "%s precedence"));
723 proto_tree_add_text(field_tree, offset + 1, 1, "%s",
724 decode_boolean_bitfield(iph.ip_tos, IPTOS_LOWDELAY,
725 sizeof (iph.ip_tos)*8, "low delay", "normal delay"));
726 proto_tree_add_text(field_tree, offset + 1, 1, "%s",
727 decode_boolean_bitfield(iph.ip_tos, IPTOS_THROUGHPUT,
728 sizeof (iph.ip_tos)*8, "high throughput", "normal throughput"));
729 proto_tree_add_text(field_tree, offset + 1, 1, "%s",
730 decode_boolean_bitfield(iph.ip_tos, IPTOS_RELIABILITY,
731 sizeof (iph.ip_tos)*8, "high reliability", "normal reliability"));
732 proto_tree_add_text(field_tree, offset + 1, 1, "%s",
733 decode_boolean_bitfield(iph.ip_tos, IPTOS_LOWCOST,
734 sizeof (iph.ip_tos)*8, "low cost", "normal cost"));
735 proto_tree_add_item(ip_tree, hf_ip_len, offset + 2, 2, iph.ip_len);
736 proto_tree_add_item_format(ip_tree, hf_ip_id, offset + 4, 2, iph.ip_id, "Identification: 0x%04x",
739 flags = (iph.ip_off & (IP_DF|IP_MF)) >> 12;
740 tf = proto_tree_add_item_format(ip_tree, hf_ip_flags, offset + 6, 2, flags,
741 "Flags: 0x%x", flags);
742 field_tree = proto_item_add_subtree(tf, ETT_IP_OFF);
743 proto_tree_add_text(field_tree, offset + 6, 2, "%s",
744 decode_boolean_bitfield(iph.ip_off >> 8, IP_DF >> 8, 8, "don't fragment",
746 proto_tree_add_text(field_tree, offset + 6, 2, "%s",
747 decode_boolean_bitfield(iph.ip_off >> 8, IP_MF >> 8, 8, "more fragments",
750 proto_tree_add_item(ip_tree, hf_ip_frag_offset, offset + 6, 2,
751 iph.ip_off & IP_OFFSET);
752 proto_tree_add_item(ip_tree, hf_ip_ttl, offset + 8, 1, iph.ip_ttl);
753 proto_tree_add_item(ip_tree, hf_ip_proto, offset + 9, 1, iph.ip_p);
754 proto_tree_add_item_format(ip_tree, hf_ip_checksum, offset + 10, 2, iph.ip_sum,
755 "Header checksum: 0x%04x", iph.ip_sum);
757 proto_tree_add_item(ip_tree, hf_ip_src, offset + 12, 4, iph.ip_src);
758 proto_tree_add_item(ip_tree, hf_ip_dst, offset + 16, 4, iph.ip_dst);
759 proto_tree_add_item_hidden(ip_tree, hf_ip_addr, offset + 12, 4, iph.ip_src);
760 proto_tree_add_item_hidden(ip_tree, hf_ip_addr, offset + 16, 4, iph.ip_dst);
762 /* Decode IP options, if any. */
763 if (hlen > sizeof (e_ip)) {
764 /* There's more than just the fixed-length header. Decode the
766 optlen = hlen - sizeof (e_ip); /* length of options, in bytes */
767 tf = proto_tree_add_text(ip_tree, offset + 20, optlen,
768 "Options: (%d bytes)", optlen);
769 field_tree = proto_item_add_subtree(tf, ETT_IP_OPTIONS);
770 dissect_ip_tcp_options(field_tree, &pd[offset + 20], offset + 20, optlen,
771 ipopts, N_IP_OPTS, IPOPT_END);
775 pi.ipproto = iph.ip_p;
776 pi.iplen = iph.ip_len;
777 pi.iphdrlen = lo_nibble(iph.ip_v_hl);
778 pi.ip_src = iph.ip_src;
779 pi.ip_dst = iph.ip_dst;
781 /* Skip over header + options */
784 if (iph.ip_off & IP_OFFSET) {
786 if (check_col(fd, COL_INFO))
787 col_add_fstr(fd, COL_INFO, "Fragmented IP protocol (proto=%02x, off=%d)",
788 iph.ip_p, iph.ip_off & IP_OFFSET);
789 dissect_data(pd, offset, fd, tree);
796 dissect_icmp(pd, offset, fd, tree);
799 dissect_igmp(pd, offset, fd, tree);
802 dissect_tcp(pd, offset, fd, tree);
805 dissect_udp(pd, offset, fd, tree);
808 dissect_ospf(pd, offset, fd, tree);
811 dissect_rsvp(pd, offset, fd, tree);
814 advance = dissect_ah(pd, offset, fd, tree);
819 dissect_gre(pd, offset, fd, tree);
822 dissect_esp(pd, offset, fd, tree);
825 dissect_ipv6(pd, offset, fd, tree);
831 static const gchar *unreach_str[] = {"Network unreachable",
833 "Protocol unreachable",
835 "Fragmentation needed",
836 "Source route failed",
837 "Destination network unknown",
838 "Destination host unknown",
839 "Source host isolated",
840 "Network administratively prohibited",
841 "Host administratively prohibited",
842 "Network unreachable for TOS",
843 "Host unreachable for TOS",
844 "Communication administratively filtered",
845 "Host precedence violation",
846 "Precedence cutoff in effect"};
848 #define N_UNREACH (sizeof unreach_str / sizeof unreach_str[0])
850 static const gchar *redir_str[] = {"Redirect for network",
852 "Redirect for TOS and network",
853 "Redirect for TOS and host"};
855 #define N_REDIRECT (sizeof redir_str / sizeof redir_str[0])
857 static const gchar *ttl_str[] = {"TTL equals 0 during transit",
858 "TTL equals 0 during reassembly"};
860 #define N_TIMXCEED (sizeof ttl_str / sizeof ttl_str[0])
862 static const gchar *par_str[] = {"IP header bad", "Required option missing"};
864 #define N_PARAMPROB (sizeof par_str / sizeof par_str[0])
867 dissect_icmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
869 proto_tree *icmp_tree;
872 gchar type_str[64], code_str[64] = "";
873 guint8 num_addrs = 0;
874 guint8 addr_entry_size = 0;
877 /* Avoids alignment problems on many architectures. */
878 memcpy(&ih, &pd[offset], sizeof(e_icmp));
879 /* To do: check for runts, errs, etc. */
880 cksum = ntohs(ih.icmp_cksum);
882 switch (ih.icmp_type) {
884 strcpy(type_str, "Echo (ping) reply");
887 strcpy(type_str, "Destination unreachable");
888 if (ih.icmp_code < N_UNREACH) {
889 sprintf(code_str, "(%s)", unreach_str[ih.icmp_code]);
891 strcpy(code_str, "(Unknown - error?)");
894 case ICMP_SOURCEQUENCH:
895 strcpy(type_str, "Source quench (flow control)");
898 strcpy(type_str, "Redirect");
899 if (ih.icmp_code < N_REDIRECT) {
900 sprintf(code_str, "(%s)", redir_str[ih.icmp_code]);
902 strcpy(code_str, "(Unknown - error?)");
906 strcpy(type_str, "Echo (ping) request");
909 strcpy(type_str, "Router advertisement");
911 case ICMP_RTRSOLICIT:
912 strcpy(type_str, "Router solicitation");
915 strcpy(type_str, "Time-to-live exceeded");
916 if (ih.icmp_code < N_TIMXCEED) {
917 sprintf(code_str, "(%s)", ttl_str[ih.icmp_code]);
919 strcpy(code_str, "(Unknown - error?)");
923 strcpy(type_str, "Parameter problem");
924 if (ih.icmp_code < N_PARAMPROB) {
925 sprintf(code_str, "(%s)", par_str[ih.icmp_code]);
927 strcpy(code_str, "(Unknown - error?)");
931 strcpy(type_str, "Timestamp request");
933 case ICMP_TSTAMPREPLY:
934 strcpy(type_str, "Timestamp reply");
937 strcpy(type_str, "Information request");
940 strcpy(type_str, "Information reply");
943 strcpy(type_str, "Address mask request");
946 strcpy(type_str, "Address mask reply");
949 strcpy(type_str, "Unknown ICMP (obsolete or malformed?)");
952 if (check_col(fd, COL_PROTOCOL))
953 col_add_str(fd, COL_PROTOCOL, "ICMP");
954 if (check_col(fd, COL_INFO))
955 col_add_str(fd, COL_INFO, type_str);
958 ti = proto_tree_add_item(tree, proto_icmp, offset, 4, NULL);
959 icmp_tree = proto_item_add_subtree(ti, ETT_ICMP);
960 proto_tree_add_text(icmp_tree, offset, 1, "Type: %d (%s)",
961 ih.icmp_type, type_str);
962 proto_tree_add_text(icmp_tree, offset + 1, 1, "Code: %d %s",
963 ih.icmp_code, code_str);
964 proto_tree_add_text(icmp_tree, offset + 2, 2, "Checksum: 0x%04x",
967 /* Decode the second 4 bytes of the packet. */
968 switch (ih.icmp_type) {
972 case ICMP_TSTAMPREPLY:
977 proto_tree_add_text(icmp_tree, offset + 4, 2, "Identifier: 0x%04x",
978 pntohs(&pd[offset + 4]));
979 proto_tree_add_text(icmp_tree, offset + 6, 2, "Sequence number: %u",
980 pntohs(&pd[offset + 6]));
984 switch (ih.icmp_code) {
985 case ICMP_FRAG_NEEDED:
986 proto_tree_add_text(icmp_tree, offset + 6, 2, "MTU of next hop: %u",
987 pntohs(&pd[offset + 6]));
993 num_addrs = pd[offset + 4];
994 proto_tree_add_text(icmp_tree, offset + 4, 1, "Number of addresses: %u",
996 addr_entry_size = pd[offset + 5];
997 proto_tree_add_text(icmp_tree, offset + 5, 1, "Address entry size: %u",
999 proto_tree_add_text(icmp_tree, offset + 6, 2, "Lifetime: %s",
1000 time_secs_to_str(pntohs(&pd[offset + 6])));
1003 case ICMP_PARAMPROB:
1004 proto_tree_add_text(icmp_tree, offset + 4, 1, "Pointer: %u",
1009 proto_tree_add_text(icmp_tree, offset + 4, 4, "Gateway address: %s",
1010 ip_to_str((guint8 *)&pd[offset + 4]));
1014 /* Decode the additional information in the packet. */
1015 switch (ih.icmp_type) {
1018 case ICMP_PARAMPROB:
1019 case ICMP_SOURCEQUENCH:
1021 /* Decode the IP header and first 64 bits of data from the
1024 XXX - for now, just display it as data; not all dissection
1025 routines can handle a short packet without exploding. */
1026 dissect_data(pd, offset + 8, fd, icmp_tree);
1029 case ICMP_ECHOREPLY:
1031 dissect_data(pd, offset + 8, fd, icmp_tree);
1034 case ICMP_RTRADVERT:
1035 if (addr_entry_size == 2) {
1036 for (i = 0; i < num_addrs; i++) {
1037 proto_tree_add_text(icmp_tree, offset + 8 + (i*8), 4,
1038 "Router address: %s",
1039 ip_to_str((guint8 *)&pd[offset + 8 + (i*8)]));
1040 proto_tree_add_text(icmp_tree, offset + 12 + (i*8), 4,
1041 "Preference level: %d", pntohl(&pd[offset + 12 + (i*8)]));
1044 dissect_data(pd, offset + 8, fd, icmp_tree);
1048 case ICMP_TSTAMPREPLY:
1049 proto_tree_add_text(icmp_tree, offset + 8, 4, "Originate timestamp: %u",
1050 pntohl(&pd[offset + 8]));
1051 proto_tree_add_text(icmp_tree, offset + 12, 4, "Originate timestamp: %u",
1052 pntohl(&pd[offset + 12]));
1053 proto_tree_add_text(icmp_tree, offset + 16, 4, "Receive timestamp: %u",
1054 pntohl(&pd[offset + 16]));
1055 proto_tree_add_text(icmp_tree, offset + 20, 4, "Transmit timestamp: %u",
1056 pntohl(&pd[offset + 20]));
1060 case ICMP_MASKREPLY:
1061 proto_tree_add_text(icmp_tree, offset + 8, 4, "Address mask: %s (0x%8x)",
1062 ip_to_str((guint8 *)&pd[offset + 8]), pntohl(&pd[offset + 8]));
1069 dissect_igmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
1071 proto_tree *igmp_tree;
1074 gchar type_str[64] = "";
1076 /* Avoids alignment problems on many architectures. */
1077 memcpy(&ih, &pd[offset], sizeof(e_igmp));
1078 /* To do: check for runts, errs, etc. */
1079 cksum = ntohs(ih.igmp_cksum);
1081 switch (lo_nibble(ih.igmp_v_t)) {
1083 strcpy(type_str, "Router query");
1086 strcpy(type_str, "Host response (v1)");
1088 case IGMP_V2_LV_GRP:
1089 strcpy(type_str, "Leave group (v2)");
1092 strcpy(type_str, "DVMRP");
1095 strcpy(type_str, "PIM");
1098 strcpy(type_str, "Host reponse (v2)");
1100 case IGMP_MTRC_RESP:
1101 strcpy(type_str, "Traceroute response");
1104 strcpy(type_str, "Traceroute message");
1107 strcpy(type_str, "Unknown IGMP");
1110 if (check_col(fd, COL_PROTOCOL))
1111 col_add_str(fd, COL_PROTOCOL, "IGMP");
1112 if (check_col(fd, COL_INFO))
1113 col_add_str(fd, COL_INFO, type_str);
1115 ti = proto_tree_add_item(tree, proto_igmp, offset, 8, NULL);
1116 igmp_tree = proto_item_add_subtree(ti, ETT_IGMP);
1117 proto_tree_add_text(igmp_tree, offset, 1, "Version: %d",
1118 hi_nibble(ih.igmp_v_t));
1119 proto_tree_add_text(igmp_tree, offset , 1, "Type: %d (%s)",
1120 lo_nibble(ih.igmp_v_t), type_str);
1121 proto_tree_add_text(igmp_tree, offset + 1, 1, "Unused: 0x%02x",
1123 proto_tree_add_text(igmp_tree, offset + 2, 2, "Checksum: 0x%04x",
1125 proto_tree_add_text(igmp_tree, offset + 4, 4, "Group address: %s",
1126 ip_to_str((guint8 *) &ih.igmp_gaddr));
1131 proto_register_igmp(void)
1133 static hf_register_info hf[] = {
1136 { "Version", "igmp.version", FT_UINT8, NULL }},
1139 { "Type", "igmp.type", FT_UINT8, NULL }},
1142 { "Unused", "igmp.unused", FT_UINT8, NULL }},
1144 { &hf_igmp_checksum,
1145 { "Checksum", "igmp.checksum", FT_UINT16, NULL }},
1148 { "Group address", "igmp.group", FT_IPv4, NULL }}
1151 proto_igmp = proto_register_protocol ("Internet Group Management Protocol", "igmp");
1152 proto_register_field_array(proto_igmp, hf, array_length(hf));
1156 proto_register_ip(void)
1158 static hf_register_info hf[] = {
1161 { "Version", "ip.version", FT_UINT8, NULL }},
1164 { "Header Length", "ip.hdr_len", FT_UINT8, NULL }},
1167 { "Type of Service", "ip.tos", FT_UINT8, NULL }},
1169 { &hf_ip_tos_precedence,
1170 { "Precedence", "ip.tos.precedence", FT_VALS_UINT8, VALS(precedence_vals) }},
1173 { "Total Length", "ip.len", FT_UINT16 }},
1176 { "Identification", "ip.id", FT_UINT32 }},
1179 { "Destination", "ip.dst", FT_IPv4, NULL }},
1182 { "Source", "ip.src", FT_IPv4, NULL }},
1185 { "Source or Destination Address", "ip.addr", FT_IPv4, NULL }},
1188 { "Flags", "ip.flags", FT_UINT16, NULL }},
1190 { &hf_ip_frag_offset,
1191 { "Fragment offset", "ip.frag_offset", FT_UINT16, NULL }},
1194 { "Time to live", "ip.ttl", FT_UINT8, NULL }},
1197 { "Protocol", "ip.proto", FT_VALS_UINT8, VALS(proto_vals) }},
1200 { "Header checksum", "ip.checksum", FT_UINT16, NULL }}
1203 proto_ip = proto_register_protocol ("Internet Protocol", "ip");
1204 proto_register_field_array(proto_ip, hf, array_length(hf));
1208 proto_register_icmp(void)
1210 proto_icmp = proto_register_protocol ("Internet Control Message Protocol", "icmp");