2 * Routines for IP and miscellaneous IP protocol packet disassembly
4 * $Id: packet-ip.c,v 1.9 1998/10/20 05:31:00 guy 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.
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
39 #ifdef HAVE_NETINET_IN_H
40 # include <netinet/in.h>
48 extern packet_info pi;
51 dissect_ipopt_security(GtkWidget *opt_tree, const char *name,
52 const u_char *opd, int offset, guint optlen)
54 GtkWidget *field_tree = NULL, *tf;
56 static value_string secl_vals[] = {
57 {IPSEC_UNCLASSIFIED, "Unclassified"},
58 {IPSEC_CONFIDENTIAL, "Confidential"},
59 {IPSEC_EFTO, "EFTO" },
60 {IPSEC_MMMM, "MMMM" },
61 {IPSEC_RESTRICTED, "Restricted" },
62 {IPSEC_SECRET, "Secret" },
63 {IPSEC_TOPSECRET, "Top secret" },
64 {IPSEC_RESERVED1, "Reserved" },
65 {IPSEC_RESERVED2, "Reserved" },
66 {IPSEC_RESERVED3, "Reserved" },
67 {IPSEC_RESERVED4, "Reserved" },
68 {IPSEC_RESERVED5, "Reserved" },
69 {IPSEC_RESERVED6, "Reserved" },
70 {IPSEC_RESERVED7, "Reserved" },
71 {IPSEC_RESERVED8, "Reserved" },
74 tf = add_item_to_tree(opt_tree, offset, optlen, "%s:", name);
75 field_tree = gtk_tree_new();
76 add_subtree(tf, field_tree, ETT_IP_OPTION_SEC);
80 add_item_to_tree(field_tree, offset, 2,
81 "Security: %s", val_to_str(val, secl_vals, "Unknown (0x%x)"));
86 add_item_to_tree(field_tree, offset, 2,
87 "Compartments: %d", val);
91 add_item_to_tree(field_tree, offset, 2,
92 "Handling restrictions: %c%c", opd[0], opd[1]);
96 add_item_to_tree(field_tree, offset, 3,
97 "Transmission control code: %c%c%c", opd[0], opd[1], opd[2]);
101 dissect_ipopt_route(GtkWidget *opt_tree, const char *name,
102 const u_char *opd, int offset, guint optlen)
104 GtkWidget *field_tree = NULL, *tf;
109 tf = add_item_to_tree(opt_tree, offset, optlen, "%s (%d bytes)", name,
111 field_tree = gtk_tree_new();
112 add_subtree(tf, field_tree, ETT_IP_OPTION_ROUTE);
114 optoffset += 2; /* skip past type and length */
115 optlen -= 2; /* subtract size of type and length */
118 add_item_to_tree(field_tree, offset + optoffset, 1,
119 "Pointer: %d%s", ptr,
120 ((ptr < 4) ? " (points before first address)" :
121 ((ptr & 3) ? " (points to middle of address)" : "")));
125 ptr--; /* ptr is 1-origin */
129 add_item_to_tree(field_tree, offset, optlen,
130 "(suboption would go past end of option)");
134 /* Avoids alignment problems on many architectures. */
135 memcpy((char *)&addr, (char *)opd, sizeof(addr));
137 add_item_to_tree(field_tree, offset + optoffset, 4,
139 ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
140 ((optoffset == ptr) ? " <- (current)" : ""));
148 dissect_ipopt_sid(GtkWidget *opt_tree, const char *name, const u_char *opd,
149 int offset, guint optlen)
151 add_item_to_tree(opt_tree, offset, optlen,
152 "%s: %d", name, pntohs(opd));
157 dissect_ipopt_timestamp(GtkWidget *opt_tree, const char *name, const u_char *opd,
158 int offset, guint optlen)
160 GtkWidget *field_tree = NULL, *tf;
164 static value_string flag_vals[] = {
165 {IPOPT_TS_TSONLY, "Time stamps only" },
166 {IPOPT_TS_TSANDADDR, "Time stamp and address" },
167 {IPOPT_TS_PRESPEC, "Time stamps for prespecified addresses"},
173 tf = add_item_to_tree(opt_tree, offset, optlen, "%s:", name);
174 field_tree = gtk_tree_new();
175 add_subtree(tf, field_tree, ETT_IP_OPTION_TIMESTAMP);
177 optoffset += 2; /* skip past type and length */
178 optlen -= 2; /* subtract size of type and length */
181 add_item_to_tree(field_tree, offset + optoffset, 1,
182 "Pointer: %d%s", ptr,
183 ((ptr < 5) ? " (points before first address)" :
184 (((ptr - 1) & 3) ? " (points to middle of address)" : "")));
188 ptr--; /* ptr is 1-origin */
191 add_item_to_tree(field_tree, offset + optoffset, 1,
192 "Overflow: %d", flg >> 4);
194 add_item_to_tree(field_tree, offset + optoffset, 1,
195 "Flag: %s", val_to_str(flg, flag_vals, "Unknown (0x%x)"));
201 if (flg == IPOPT_TS_TSANDADDR) {
203 add_item_to_tree(field_tree, offset + optoffset, optlen,
204 "(suboption would go past end of option)");
207 /* XXX - check whether it goes past end of packet */
212 add_item_to_tree(field_tree, offset + optoffset, optlen,
213 "(suboption would go past end of option)");
216 /* XXX - check whether it goes past end of packet */
217 memcpy((char *)&addr, (char *)opd, sizeof(addr));
220 add_item_to_tree(field_tree, offset, 8,
221 "Address = %s, time stamp = %u",
222 ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
227 add_item_to_tree(field_tree, offset + optoffset, optlen,
228 "(suboption would go past end of option)");
231 /* XXX - check whether it goes past end of packet */
235 add_item_to_tree(field_tree, offset + optoffset, 4,
236 "Time stamp = %u", ts);
242 static ip_tcp_opt ipopts[] = {
262 dissect_ipopt_security
266 "Strict source route",
273 "Loose source route",
296 IPOLEN_TIMESTAMP_MIN,
297 dissect_ipopt_timestamp
301 #define N_IP_OPTS (sizeof ipopts / sizeof ipopts[0])
303 /* Dissect the IP or TCP options in a packet. */
305 dissect_ip_tcp_options(GtkWidget *opt_tree, const u_char *opd, int offset,
306 guint length, ip_tcp_opt *opttab, int nopts, int eol)
314 for (optp = &opttab[0]; optp < &opttab[nopts]; optp++) {
315 if (optp->optcode == opt)
318 if (optp == &opttab[nopts]) {
319 add_item_to_tree(opt_tree, offset, 1, "Unknown");
320 /* We don't know how long this option is, so we don't know how much
321 of it to skip, so we just bail. */
324 --length; /* account for type byte */
325 if (optp->len_type != NO_LENGTH) {
326 /* Option has a length. Is it in the packet? */
328 /* Bogus - packet must at least include option code byte and
330 add_item_to_tree(opt_tree, offset, 1,
331 "%s (length byte past end of header)", optp->name);
334 len = *opd++; /* total including type, len */
335 --length; /* account for length byte */
337 /* Bogus - option length is too short to include option code and
339 add_item_to_tree(opt_tree, offset, 2,
340 "%s (with too-short option length = %u bytes)", optp->name, 2);
342 } else if (len - 2 > length) {
343 /* Bogus - option goes past the end of the header. */
344 add_item_to_tree(opt_tree, offset, length,
345 "%s (option goes past end of header)", optp->name);
347 } else if (optp->len_type == FIXED_LENGTH && len != optp->optlen) {
348 /* Bogus - option length isn't what it's supposed to be for this
350 add_item_to_tree(opt_tree, offset, len,
351 "%s (with option length = %u bytes; should be %u)", optp->name,
354 } else if (optp->len_type == VARIABLE_LENGTH && len < optp->optlen) {
355 /* Bogus - option length is less than what it's supposed to be for
357 add_item_to_tree(opt_tree, offset, len,
358 "%s (with option length = %u bytes; should be >= %u)", optp->name,
362 if (optp->dissect != NULL) {
363 /* Option has a dissector. */
364 (*optp->dissect)(opt_tree, optp->name, opd, offset, len);
366 /* Option has no data, hence no dissector. */
367 add_item_to_tree(opt_tree, offset, len, "%s", optp->name);
369 len -= 2; /* subtract size of type and length */
375 add_item_to_tree(opt_tree, offset, 1, "%s", optp->name);
384 dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
386 GtkWidget *ip_tree, *ti, *field_tree, *tf;
389 static value_string proto_vals[] = { {IP_PROTO_ICMP, "ICMP"},
390 {IP_PROTO_IGMP, "IGMP"},
391 {IP_PROTO_TCP, "TCP" },
392 {IP_PROTO_UDP, "UDP" },
393 {IP_PROTO_OSPF, "OSPF"},
397 /* To do: check for runts, errs, etc. */
398 /* Avoids alignment problems on many architectures. */
399 memcpy(&iph, &pd[offset], sizeof(e_ip));
400 iph.ip_len = ntohs(iph.ip_len);
401 iph.ip_id = ntohs(iph.ip_id);
402 iph.ip_off = ntohs(iph.ip_off);
403 iph.ip_sum = ntohs(iph.ip_sum);
405 hlen = iph.ip_hl * 4; /* IP header length, in bytes */
407 if (fd->win_info[COL_NUM]) {
414 /* Names are set in the associated dissect_* routines */
417 strcpy(fd->win_info[COL_PROTOCOL], "IP");
418 sprintf(fd->win_info[COL_INFO], "Unknown IP protocol (%02x)", iph.ip_p);
421 strcpy(fd->win_info[COL_SOURCE], get_hostname(iph.ip_src));
422 strcpy(fd->win_info[COL_DESTINATION], get_hostname(iph.ip_dst));
425 iph.ip_tos = IPTOS_TOS(iph.ip_tos);
426 switch (iph.ip_tos) {
428 strcpy(tos_str, "None");
431 strcpy(tos_str, "Minimize delay");
433 case IPTOS_THROUGHPUT:
434 strcpy(tos_str, "Maximize throughput");
436 case IPTOS_RELIABILITY:
437 strcpy(tos_str, "Maximize reliability");
440 strcpy(tos_str, "Minimize cost");
443 strcpy(tos_str, "Unknown. Malformed?");
448 ti = add_item_to_tree(GTK_WIDGET(tree), offset, hlen, "Internet Protocol");
449 ip_tree = gtk_tree_new();
450 add_subtree(ti, ip_tree, ETT_IP);
451 add_item_to_tree(ip_tree, offset, 1, "Version: %d", iph.ip_v);
452 add_item_to_tree(ip_tree, offset, 1, "Header length: %d bytes", hlen);
453 add_item_to_tree(ip_tree, offset + 1, 1, "Type of service: 0x%02x (%s)",
454 iph.ip_tos, tos_str);
455 add_item_to_tree(ip_tree, offset + 2, 2, "Total length: %d", iph.ip_len);
456 add_item_to_tree(ip_tree, offset + 4, 2, "Identification: 0x%04x",
458 /* To do: add flags */
459 add_item_to_tree(ip_tree, offset + 6, 2, "Fragment offset: %d",
460 iph.ip_off & IP_OFFSET);
461 add_item_to_tree(ip_tree, offset + 8, 1, "Time to live: %d",
463 add_item_to_tree(ip_tree, offset + 9, 1, "Protocol: %s",
464 val_to_str(iph.ip_p, proto_vals, "Unknown (%x)"));
465 add_item_to_tree(ip_tree, offset + 10, 2, "Header checksum: 0x%04x",
467 add_item_to_tree(ip_tree, offset + 12, 4, "Source address: %s",
468 get_hostname(iph.ip_src));
469 add_item_to_tree(ip_tree, offset + 16, 4, "Destination address: %s",
470 get_hostname(iph.ip_dst));
472 /* Decode IP options, if any. */
473 if (hlen > sizeof (e_ip)) {
474 /* There's more than just the fixed-length header. Decode the
476 optlen = hlen - sizeof (e_ip); /* length of options, in bytes */
477 tf = add_item_to_tree(ip_tree, offset + 20, optlen,
478 "Options: (%d bytes)", optlen);
479 field_tree = gtk_tree_new();
480 add_subtree(tf, field_tree, ETT_IP_OPTIONS);
481 dissect_ip_tcp_options(field_tree, &pd[offset + 20], offset + 20, optlen,
482 ipopts, N_IP_OPTS, IPOPT_END);
486 pi.srcip = ip_to_str( (guint8 *) &iph.ip_src);
487 pi.destip = ip_to_str( (guint8 *) &iph.ip_dst);
488 pi.ipproto = iph.ip_p;
489 pi.iplen = iph.ip_len;
490 pi.iphdrlen = iph.ip_hl;
491 pi.ip_src = iph.ip_src;
496 dissect_icmp(pd, offset, fd, tree);
499 dissect_igmp(pd, offset, fd, tree);
502 dissect_tcp(pd, offset, fd, tree);
505 dissect_udp(pd, offset, fd, tree);
508 dissect_ospf(pd, offset, fd, tree);
514 const gchar *unreach_str[] = {"Network unreachable",
516 "Protocol unreachable",
518 "Fragmentation needed",
519 "Source route failed",
520 "Administratively prohibited",
521 "Network unreachable for TOS",
522 "Host unreachable for TOS",
523 "Communication administratively filtered",
524 "Host precedence violation",
525 "Precedence cutoff in effect"};
527 const gchar *redir_str[] = {"Redirect for network",
529 "Redirect for TOS and network",
530 "Redirect for TOS and host"};
532 const gchar *ttl_str[] = {"TTL equals 0 during transit",
533 "TTL equals 0 during reassembly"};
535 const gchar *par_str[] = {"IP header bad", "Required option missing"};
538 dissect_icmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
540 GtkWidget *icmp_tree, *ti;
542 gchar type_str[64], code_str[64] = "";
544 /* Avoids alignment problems on many architectures. */
545 memcpy(&ih, &pd[offset], sizeof(e_icmp));
546 /* To do: check for runts, errs, etc. */
547 cksum = ntohs(ih.icmp_cksum);
549 switch (ih.icmp_type) {
551 strcpy(type_str, "Echo (ping) reply");
554 strcpy(type_str, "Destination unreachable");
555 if (ih.icmp_code < 12) {
556 sprintf(code_str, "(%s)", unreach_str[ih.icmp_code]);
558 strcpy(code_str, "(Unknown - error?)");
561 case ICMP_SOURCEQUENCH:
562 strcpy(type_str, "Source quench (flow control)");
565 strcpy(type_str, "Redirect");
566 if (ih.icmp_code < 4) {
567 sprintf(code_str, "(%s)", redir_str[ih.icmp_code]);
569 strcpy(code_str, "(Unknown - error?)");
573 strcpy(type_str, "Echo (ping) request");
576 strcpy(type_str, "Time-to-live exceeded");
577 if (ih.icmp_code < 2) {
578 sprintf(code_str, "(%s)", ttl_str[ih.icmp_code]);
580 strcpy(code_str, "(Unknown - error?)");
584 strcpy(type_str, "Parameter problem");
585 if (ih.icmp_code < 2) {
586 sprintf(code_str, "(%s)", par_str[ih.icmp_code]);
588 strcpy(code_str, "(Unknown - error?)");
592 strcpy(type_str, "Timestamp request");
594 case ICMP_TSTAMPREPLY:
595 strcpy(type_str, "Timestamp reply");
598 strcpy(type_str, "Address mask request");
601 strcpy(type_str, "Address mask reply");
604 strcpy(type_str, "Unknown ICMP (obsolete or malformed?)");
607 if (fd->win_info[COL_NUM]) {
608 strcpy(fd->win_info[COL_PROTOCOL], "ICMP");
609 strcpy(fd->win_info[COL_INFO], type_str);
613 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
614 "Internet Control Message Protocol");
615 icmp_tree = gtk_tree_new();
616 add_subtree(ti, icmp_tree, ETT_ICMP);
617 add_item_to_tree(icmp_tree, offset, 1, "Type: %d (%s)",
618 ih.icmp_type, type_str);
619 add_item_to_tree(icmp_tree, offset + 1, 1, "Code: %d %s",
620 ih.icmp_code, code_str);
621 add_item_to_tree(icmp_tree, offset + 2, 2, "Checksum: 0x%04x",
627 dissect_igmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
629 GtkWidget *igmp_tree, *ti;
631 gchar type_str[64] = "";
633 /* Avoids alignment problems on many architectures. */
634 memcpy(&ih, &pd[offset], sizeof(e_igmp));
635 /* To do: check for runts, errs, etc. */
636 cksum = ntohs(ih.igmp_cksum);
640 strcpy(type_str, "Router query");
643 strcpy(type_str, "Host response (v1)");
646 strcpy(type_str, "Leave group (v2)");
649 strcpy(type_str, "DVMRP");
652 strcpy(type_str, "PIM");
655 strcpy(type_str, "Host reponse (v2)");
658 strcpy(type_str, "Traceroute response");
661 strcpy(type_str, "Traceroute message");
664 strcpy(type_str, "Unknown IGMP");
667 if (fd->win_info[COL_NUM]) {
668 strcpy(fd->win_info[COL_PROTOCOL], "IGMP");
672 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
673 "Internet Group Management Protocol");
674 igmp_tree = gtk_tree_new();
675 add_subtree(ti, igmp_tree, ETT_IGMP);
676 add_item_to_tree(igmp_tree, offset, 1, "Version: %d",
678 add_item_to_tree(igmp_tree, offset , 1, "Type: %d (%s)",
679 ih.igmp_t, type_str);
680 add_item_to_tree(igmp_tree, offset + 1, 1, "Unused: 0x%02x",
682 add_item_to_tree(igmp_tree, offset + 2, 2, "Checksum: 0x%04x",
684 add_item_to_tree(igmp_tree, offset + 4, 4, "Group address: %s",
685 ip_to_str((guint8 *) &ih.igmp_gaddr));