2 * Routines for IP and miscellaneous IP protocol packet disassembly
4 * $Id: packet-ip.c,v 1.11 1998/11/12 00:06:28 gram 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.
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
47 extern packet_info pi;
50 dissect_ipopt_security(GtkWidget *opt_tree, const char *name,
51 const u_char *opd, int offset, guint optlen)
53 GtkWidget *field_tree = NULL, *tf;
55 static const value_string secl_vals[] = {
56 {IPSEC_UNCLASSIFIED, "Unclassified"},
57 {IPSEC_CONFIDENTIAL, "Confidential"},
58 {IPSEC_EFTO, "EFTO" },
59 {IPSEC_MMMM, "MMMM" },
60 {IPSEC_RESTRICTED, "Restricted" },
61 {IPSEC_SECRET, "Secret" },
62 {IPSEC_TOPSECRET, "Top secret" },
63 {IPSEC_RESERVED1, "Reserved" },
64 {IPSEC_RESERVED2, "Reserved" },
65 {IPSEC_RESERVED3, "Reserved" },
66 {IPSEC_RESERVED4, "Reserved" },
67 {IPSEC_RESERVED5, "Reserved" },
68 {IPSEC_RESERVED6, "Reserved" },
69 {IPSEC_RESERVED7, "Reserved" },
70 {IPSEC_RESERVED8, "Reserved" },
73 tf = add_item_to_tree(opt_tree, offset, optlen, "%s:", name);
74 field_tree = gtk_tree_new();
75 add_subtree(tf, field_tree, ETT_IP_OPTION_SEC);
79 add_item_to_tree(field_tree, offset, 2,
80 "Security: %s", val_to_str(val, secl_vals, "Unknown (0x%x)"));
85 add_item_to_tree(field_tree, offset, 2,
86 "Compartments: %d", val);
90 add_item_to_tree(field_tree, offset, 2,
91 "Handling restrictions: %c%c", opd[0], opd[1]);
95 add_item_to_tree(field_tree, offset, 3,
96 "Transmission control code: %c%c%c", opd[0], opd[1], opd[2]);
100 dissect_ipopt_route(GtkWidget *opt_tree, const char *name,
101 const u_char *opd, int offset, guint optlen)
103 GtkWidget *field_tree = NULL, *tf;
108 tf = add_item_to_tree(opt_tree, offset, optlen, "%s (%d bytes)", name,
110 field_tree = gtk_tree_new();
111 add_subtree(tf, field_tree, ETT_IP_OPTION_ROUTE);
113 optoffset += 2; /* skip past type and length */
114 optlen -= 2; /* subtract size of type and length */
117 add_item_to_tree(field_tree, offset + optoffset, 1,
118 "Pointer: %d%s", ptr,
119 ((ptr < 4) ? " (points before first address)" :
120 ((ptr & 3) ? " (points to middle of address)" : "")));
124 ptr--; /* ptr is 1-origin */
128 add_item_to_tree(field_tree, offset, optlen,
129 "(suboption would go past end of option)");
133 /* Avoids alignment problems on many architectures. */
134 memcpy((char *)&addr, (char *)opd, sizeof(addr));
136 add_item_to_tree(field_tree, offset + optoffset, 4,
138 ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
139 ((optoffset == ptr) ? " <- (current)" : ""));
147 dissect_ipopt_sid(GtkWidget *opt_tree, const char *name, const u_char *opd,
148 int offset, guint optlen)
150 add_item_to_tree(opt_tree, offset, optlen,
151 "%s: %d", name, pntohs(opd));
156 dissect_ipopt_timestamp(GtkWidget *opt_tree, const char *name, const u_char *opd,
157 int offset, guint optlen)
159 GtkWidget *field_tree = NULL, *tf;
163 static const value_string flag_vals[] = {
164 {IPOPT_TS_TSONLY, "Time stamps only" },
165 {IPOPT_TS_TSANDADDR, "Time stamp and address" },
166 {IPOPT_TS_PRESPEC, "Time stamps for prespecified addresses"},
172 tf = add_item_to_tree(opt_tree, offset, optlen, "%s:", name);
173 field_tree = gtk_tree_new();
174 add_subtree(tf, field_tree, ETT_IP_OPTION_TIMESTAMP);
176 optoffset += 2; /* skip past type and length */
177 optlen -= 2; /* subtract size of type and length */
180 add_item_to_tree(field_tree, offset + optoffset, 1,
181 "Pointer: %d%s", ptr,
182 ((ptr < 5) ? " (points before first address)" :
183 (((ptr - 1) & 3) ? " (points to middle of address)" : "")));
187 ptr--; /* ptr is 1-origin */
190 add_item_to_tree(field_tree, offset + optoffset, 1,
191 "Overflow: %d", flg >> 4);
193 add_item_to_tree(field_tree, offset + optoffset, 1,
194 "Flag: %s", val_to_str(flg, flag_vals, "Unknown (0x%x)"));
200 if (flg == IPOPT_TS_TSANDADDR) {
202 add_item_to_tree(field_tree, offset + optoffset, optlen,
203 "(suboption would go past end of option)");
206 /* XXX - check whether it goes past end of packet */
211 add_item_to_tree(field_tree, offset + optoffset, optlen,
212 "(suboption would go past end of option)");
215 /* XXX - check whether it goes past end of packet */
216 memcpy((char *)&addr, (char *)opd, sizeof(addr));
219 add_item_to_tree(field_tree, offset, 8,
220 "Address = %s, time stamp = %u",
221 ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
226 add_item_to_tree(field_tree, offset + optoffset, optlen,
227 "(suboption would go past end of option)");
230 /* XXX - check whether it goes past end of packet */
234 add_item_to_tree(field_tree, offset + optoffset, 4,
235 "Time stamp = %u", ts);
241 static ip_tcp_opt ipopts[] = {
261 dissect_ipopt_security
265 "Strict source route",
272 "Loose source route",
295 IPOLEN_TIMESTAMP_MIN,
296 dissect_ipopt_timestamp
300 #define N_IP_OPTS (sizeof ipopts / sizeof ipopts[0])
302 /* Dissect the IP or TCP options in a packet. */
304 dissect_ip_tcp_options(GtkWidget *opt_tree, const u_char *opd, int offset,
305 guint length, ip_tcp_opt *opttab, int nopts, int eol)
313 for (optp = &opttab[0]; optp < &opttab[nopts]; optp++) {
314 if (optp->optcode == opt)
317 if (optp == &opttab[nopts]) {
318 add_item_to_tree(opt_tree, offset, 1, "Unknown");
319 /* We don't know how long this option is, so we don't know how much
320 of it to skip, so we just bail. */
323 --length; /* account for type byte */
324 if (optp->len_type != NO_LENGTH) {
325 /* Option has a length. Is it in the packet? */
327 /* Bogus - packet must at least include option code byte and
329 add_item_to_tree(opt_tree, offset, 1,
330 "%s (length byte past end of header)", optp->name);
333 len = *opd++; /* total including type, len */
334 --length; /* account for length byte */
336 /* Bogus - option length is too short to include option code and
338 add_item_to_tree(opt_tree, offset, 2,
339 "%s (with too-short option length = %u bytes)", optp->name, 2);
341 } else if (len - 2 > length) {
342 /* Bogus - option goes past the end of the header. */
343 add_item_to_tree(opt_tree, offset, length,
344 "%s (option goes past end of header)", optp->name);
346 } else if (optp->len_type == FIXED_LENGTH && len != optp->optlen) {
347 /* Bogus - option length isn't what it's supposed to be for this
349 add_item_to_tree(opt_tree, offset, len,
350 "%s (with option length = %u bytes; should be %u)", optp->name,
353 } else if (optp->len_type == VARIABLE_LENGTH && len < optp->optlen) {
354 /* Bogus - option length is less than what it's supposed to be for
356 add_item_to_tree(opt_tree, offset, len,
357 "%s (with option length = %u bytes; should be >= %u)", optp->name,
361 if (optp->dissect != NULL) {
362 /* Option has a dissector. */
363 (*optp->dissect)(opt_tree, optp->name, opd, offset, len);
365 /* Option has no data, hence no dissector. */
366 add_item_to_tree(opt_tree, offset, len, "%s", optp->name);
368 len -= 2; /* subtract size of type and length */
374 add_item_to_tree(opt_tree, offset, 1, "%s", optp->name);
383 dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
385 GtkWidget *ip_tree, *ti, *field_tree, *tf;
388 static const value_string proto_vals[] = { {IP_PROTO_ICMP, "ICMP"},
389 {IP_PROTO_IGMP, "IGMP"},
390 {IP_PROTO_TCP, "TCP" },
391 {IP_PROTO_UDP, "UDP" },
392 {IP_PROTO_OSPF, "OSPF"},
396 /* To do: check for runts, errs, etc. */
397 /* Avoids alignment problems on many architectures. */
398 memcpy(&iph, &pd[offset], sizeof(e_ip));
399 iph.ip_len = ntohs(iph.ip_len);
400 iph.ip_id = ntohs(iph.ip_id);
401 iph.ip_off = ntohs(iph.ip_off);
402 iph.ip_sum = ntohs(iph.ip_sum);
404 hlen = iph.ip_hl * 4; /* IP header length, in bytes */
406 if (fd->win_info[COL_NUM]) {
413 /* Names are set in the associated dissect_* routines */
416 strcpy(fd->win_info[COL_PROTOCOL], "IP");
417 sprintf(fd->win_info[COL_INFO], "Unknown IP protocol (%02x)", iph.ip_p);
420 strcpy(fd->win_info[COL_SOURCE], get_hostname(iph.ip_src));
421 strcpy(fd->win_info[COL_DESTINATION], get_hostname(iph.ip_dst));
424 iph.ip_tos = IPTOS_TOS(iph.ip_tos);
425 switch (iph.ip_tos) {
427 strcpy(tos_str, "None");
430 strcpy(tos_str, "Minimize cost");
432 case IPTOS_RELIABILITY:
433 strcpy(tos_str, "Maximize reliability");
435 case IPTOS_THROUGHPUT:
436 strcpy(tos_str, "Maximize throughput");
439 strcpy(tos_str, "Minimize delay");
442 strcpy(tos_str, "Maximize security");
445 strcpy(tos_str, "Unknown. Malformed?");
450 ti = add_item_to_tree(GTK_WIDGET(tree), offset, hlen, "Internet Protocol");
451 ip_tree = gtk_tree_new();
452 add_subtree(ti, ip_tree, ETT_IP);
453 add_item_to_tree(ip_tree, offset, 1, "Version: %d", iph.ip_v);
454 add_item_to_tree(ip_tree, offset, 1, "Header length: %d bytes", hlen);
455 add_item_to_tree(ip_tree, offset + 1, 1, "Type of service: 0x%02x (%s)",
456 iph.ip_tos, tos_str);
457 add_item_to_tree(ip_tree, offset + 2, 2, "Total length: %d", iph.ip_len);
458 add_item_to_tree(ip_tree, offset + 4, 2, "Identification: 0x%04x",
460 /* To do: add flags */
461 add_item_to_tree(ip_tree, offset + 6, 2, "Fragment offset: %d",
462 iph.ip_off & IP_OFFSET);
463 add_item_to_tree(ip_tree, offset + 8, 1, "Time to live: %d",
465 add_item_to_tree(ip_tree, offset + 9, 1, "Protocol: %s",
466 val_to_str(iph.ip_p, proto_vals, "Unknown (%x)"));
467 add_item_to_tree(ip_tree, offset + 10, 2, "Header checksum: 0x%04x",
469 add_item_to_tree(ip_tree, offset + 12, 4, "Source address: %s",
470 get_hostname(iph.ip_src));
471 add_item_to_tree(ip_tree, offset + 16, 4, "Destination address: %s",
472 get_hostname(iph.ip_dst));
474 /* Decode IP options, if any. */
475 if (hlen > sizeof (e_ip)) {
476 /* There's more than just the fixed-length header. Decode the
478 optlen = hlen - sizeof (e_ip); /* length of options, in bytes */
479 tf = add_item_to_tree(ip_tree, offset + 20, optlen,
480 "Options: (%d bytes)", optlen);
481 field_tree = gtk_tree_new();
482 add_subtree(tf, field_tree, ETT_IP_OPTIONS);
483 dissect_ip_tcp_options(field_tree, &pd[offset + 20], offset + 20, optlen,
484 ipopts, N_IP_OPTS, IPOPT_END);
488 pi.srcip = ip_to_str( (guint8 *) &iph.ip_src);
489 pi.destip = ip_to_str( (guint8 *) &iph.ip_dst);
490 pi.ipproto = iph.ip_p;
491 pi.iplen = iph.ip_len;
492 pi.iphdrlen = iph.ip_hl;
493 pi.ip_src = iph.ip_src;
498 dissect_icmp(pd, offset, fd, tree);
501 dissect_igmp(pd, offset, fd, tree);
504 dissect_tcp(pd, offset, fd, tree);
507 dissect_udp(pd, offset, fd, tree);
510 dissect_ospf(pd, offset, fd, tree);
516 const gchar *unreach_str[] = {"Network unreachable",
518 "Protocol unreachable",
520 "Fragmentation needed",
521 "Source route failed",
522 "Administratively prohibited",
523 "Network unreachable for TOS",
524 "Host unreachable for TOS",
525 "Communication administratively filtered",
526 "Host precedence violation",
527 "Precedence cutoff in effect"};
529 const gchar *redir_str[] = {"Redirect for network",
531 "Redirect for TOS and network",
532 "Redirect for TOS and host"};
534 const gchar *ttl_str[] = {"TTL equals 0 during transit",
535 "TTL equals 0 during reassembly"};
537 const gchar *par_str[] = {"IP header bad", "Required option missing"};
540 dissect_icmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
542 GtkWidget *icmp_tree, *ti;
544 gchar type_str[64], code_str[64] = "";
546 /* Avoids alignment problems on many architectures. */
547 memcpy(&ih, &pd[offset], sizeof(e_icmp));
548 /* To do: check for runts, errs, etc. */
549 cksum = ntohs(ih.icmp_cksum);
551 switch (ih.icmp_type) {
553 strcpy(type_str, "Echo (ping) reply");
556 strcpy(type_str, "Destination unreachable");
557 if (ih.icmp_code < 12) {
558 sprintf(code_str, "(%s)", unreach_str[ih.icmp_code]);
560 strcpy(code_str, "(Unknown - error?)");
563 case ICMP_SOURCEQUENCH:
564 strcpy(type_str, "Source quench (flow control)");
567 strcpy(type_str, "Redirect");
568 if (ih.icmp_code < 4) {
569 sprintf(code_str, "(%s)", redir_str[ih.icmp_code]);
571 strcpy(code_str, "(Unknown - error?)");
575 strcpy(type_str, "Echo (ping) request");
578 strcpy(type_str, "Time-to-live exceeded");
579 if (ih.icmp_code < 2) {
580 sprintf(code_str, "(%s)", ttl_str[ih.icmp_code]);
582 strcpy(code_str, "(Unknown - error?)");
586 strcpy(type_str, "Parameter problem");
587 if (ih.icmp_code < 2) {
588 sprintf(code_str, "(%s)", par_str[ih.icmp_code]);
590 strcpy(code_str, "(Unknown - error?)");
594 strcpy(type_str, "Timestamp request");
596 case ICMP_TSTAMPREPLY:
597 strcpy(type_str, "Timestamp reply");
600 strcpy(type_str, "Address mask request");
603 strcpy(type_str, "Address mask reply");
606 strcpy(type_str, "Unknown ICMP (obsolete or malformed?)");
609 if (fd->win_info[COL_NUM]) {
610 strcpy(fd->win_info[COL_PROTOCOL], "ICMP");
611 strcpy(fd->win_info[COL_INFO], type_str);
615 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
616 "Internet Control Message Protocol");
617 icmp_tree = gtk_tree_new();
618 add_subtree(ti, icmp_tree, ETT_ICMP);
619 add_item_to_tree(icmp_tree, offset, 1, "Type: %d (%s)",
620 ih.icmp_type, type_str);
621 add_item_to_tree(icmp_tree, offset + 1, 1, "Code: %d %s",
622 ih.icmp_code, code_str);
623 add_item_to_tree(icmp_tree, offset + 2, 2, "Checksum: 0x%04x",
629 dissect_igmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
631 GtkWidget *igmp_tree, *ti;
633 gchar type_str[64] = "";
635 /* Avoids alignment problems on many architectures. */
636 memcpy(&ih, &pd[offset], sizeof(e_igmp));
637 /* To do: check for runts, errs, etc. */
638 cksum = ntohs(ih.igmp_cksum);
642 strcpy(type_str, "Router query");
645 strcpy(type_str, "Host response (v1)");
648 strcpy(type_str, "Leave group (v2)");
651 strcpy(type_str, "DVMRP");
654 strcpy(type_str, "PIM");
657 strcpy(type_str, "Host reponse (v2)");
660 strcpy(type_str, "Traceroute response");
663 strcpy(type_str, "Traceroute message");
666 strcpy(type_str, "Unknown IGMP");
669 if (fd->win_info[COL_NUM]) {
670 strcpy(fd->win_info[COL_PROTOCOL], "IGMP");
674 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
675 "Internet Group Management Protocol");
676 igmp_tree = gtk_tree_new();
677 add_subtree(ti, igmp_tree, ETT_IGMP);
678 add_item_to_tree(igmp_tree, offset, 1, "Version: %d",
680 add_item_to_tree(igmp_tree, offset , 1, "Type: %d (%s)",
681 ih.igmp_t, type_str);
682 add_item_to_tree(igmp_tree, offset + 1, 1, "Unused: 0x%02x",
684 add_item_to_tree(igmp_tree, offset + 2, 2, "Checksum: 0x%04x",
686 add_item_to_tree(igmp_tree, offset + 4, 4, "Group address: %s",
687 ip_to_str((guint8 *) &ih.igmp_gaddr));