2 * Routines for IP and miscellaneous IP protocol packet disassembly
4 * $Id: packet-ip.c,v 1.8 1998/10/16 01:18:31 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.
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;
57 static value_string secl_vals[] = {
58 {IPSEC_UNCLASSIFIED, "Unclassified"},
59 {IPSEC_CONFIDENTIAL, "Confidential"},
60 {IPSEC_EFTO, "EFTO" },
61 {IPSEC_MMMM, "MMMM" },
62 {IPSEC_RESTRICTED, "Restricted" },
63 {IPSEC_SECRET, "Secret" },
64 {IPSEC_TOPSECRET, "Top secret" },
65 {IPSEC_RESERVED1, "Reserved" },
66 {IPSEC_RESERVED2, "Reserved" },
67 {IPSEC_RESERVED3, "Reserved" },
68 {IPSEC_RESERVED4, "Reserved" },
69 {IPSEC_RESERVED5, "Reserved" },
70 {IPSEC_RESERVED6, "Reserved" },
71 {IPSEC_RESERVED7, "Reserved" },
72 {IPSEC_RESERVED8, "Reserved" },
75 tf = add_item_to_tree(opt_tree, offset, optlen, "%s:", name);
76 field_tree = gtk_tree_new();
77 add_subtree(tf, field_tree, ETT_IP_OPTION_SEC);
81 if ((secl_str = match_strval(val, secl_vals)))
82 add_item_to_tree(field_tree, offset, 2,
83 "Security: %s", secl_str);
85 add_item_to_tree(field_tree, offset, 2,
86 "Security: Unknown (0x%x)", val);
91 add_item_to_tree(field_tree, offset, 2,
92 "Compartments: %d", val);
96 add_item_to_tree(field_tree, offset, 2,
97 "Handling restrictions: %c%c", opd[0], opd[1]);
101 add_item_to_tree(field_tree, offset, 3,
102 "Transmission control code: %c%c%c", opd[0], opd[1], opd[2]);
106 dissect_ipopt_route(GtkWidget *opt_tree, const char *name,
107 const u_char *opd, int offset, guint optlen)
109 GtkWidget *field_tree = NULL, *tf;
114 tf = add_item_to_tree(opt_tree, offset, optlen, "%s (%d bytes)", name,
116 field_tree = gtk_tree_new();
117 add_subtree(tf, field_tree, ETT_IP_OPTION_ROUTE);
119 optoffset += 2; /* skip past type and length */
120 optlen -= 2; /* subtract size of type and length */
123 add_item_to_tree(field_tree, offset + optoffset, 1,
124 "Pointer: %d%s", ptr,
125 ((ptr < 4) ? " (points before first address)" :
126 ((ptr & 3) ? " (points to middle of address)" : "")));
130 ptr--; /* ptr is 1-origin */
134 add_item_to_tree(field_tree, offset, optlen,
135 "(suboption would go past end of option)");
139 /* Avoids alignment problems on many architectures. */
140 memcpy((char *)&addr, (char *)opd, sizeof(addr));
142 add_item_to_tree(field_tree, offset + optoffset, 4,
144 ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
145 ((optoffset == ptr) ? " <- (current)" : ""));
153 dissect_ipopt_sid(GtkWidget *opt_tree, const char *name, const u_char *opd,
154 int offset, guint optlen)
156 add_item_to_tree(opt_tree, offset, optlen,
157 "%s: %d", name, pntohs(opd));
162 dissect_ipopt_timestamp(GtkWidget *opt_tree, const char *name, const u_char *opd,
163 int offset, guint optlen)
165 GtkWidget *field_tree = NULL, *tf;
170 static value_string flag_vals[] = {
171 {IPOPT_TS_TSONLY, "Time stamps only" },
172 {IPOPT_TS_TSANDADDR, "Time stamp and address" },
173 {IPOPT_TS_PRESPEC, "Time stamps for prespecified addresses"},
179 tf = add_item_to_tree(opt_tree, offset, optlen, "%s:", name);
180 field_tree = gtk_tree_new();
181 add_subtree(tf, field_tree, ETT_IP_OPTION_TIMESTAMP);
183 optoffset += 2; /* skip past type and length */
184 optlen -= 2; /* subtract size of type and length */
187 add_item_to_tree(field_tree, offset + optoffset, 1,
188 "Pointer: %d%s", ptr,
189 ((ptr < 5) ? " (points before first address)" :
190 (((ptr - 1) & 3) ? " (points to middle of address)" : "")));
194 ptr--; /* ptr is 1-origin */
197 add_item_to_tree(field_tree, offset + optoffset, 1,
198 "Overflow: %d", flg >> 4);
200 if ((flg_str = match_strval(flg, flag_vals)))
201 add_item_to_tree(field_tree, offset + optoffset, 1,
202 "Flag: %s", flg_str);
204 add_item_to_tree(field_tree, offset + optoffset, 1,
205 "Flag: Unknown (0x%x)", flg);
211 if (flg == IPOPT_TS_TSANDADDR) {
213 add_item_to_tree(field_tree, offset + optoffset, optlen,
214 "(suboption would go past end of option)");
217 /* XXX - check whether it goes past end of packet */
222 add_item_to_tree(field_tree, offset + optoffset, optlen,
223 "(suboption would go past end of option)");
226 /* XXX - check whether it goes past end of packet */
227 memcpy((char *)&addr, (char *)opd, sizeof(addr));
230 add_item_to_tree(field_tree, offset, 8,
231 "Address = %s, time stamp = %u",
232 ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
237 add_item_to_tree(field_tree, offset + optoffset, optlen,
238 "(suboption would go past end of option)");
241 /* XXX - check whether it goes past end of packet */
245 add_item_to_tree(field_tree, offset + optoffset, 4,
246 "Time stamp = %u", ts);
252 static ip_tcp_opt ipopts[] = {
272 dissect_ipopt_security
276 "Strict source route",
283 "Loose source route",
306 IPOLEN_TIMESTAMP_MIN,
307 dissect_ipopt_timestamp
311 #define N_IP_OPTS (sizeof ipopts / sizeof ipopts[0])
313 /* Dissect the IP or TCP options in a packet. */
315 dissect_ip_tcp_options(GtkWidget *opt_tree, const u_char *opd, int offset,
316 guint length, ip_tcp_opt *opttab, int nopts, int eol)
324 for (optp = &opttab[0]; optp < &opttab[nopts]; optp++) {
325 if (optp->optcode == opt)
328 if (optp == &opttab[nopts]) {
329 add_item_to_tree(opt_tree, offset, 1, "Unknown");
330 /* We don't know how long this option is, so we don't know how much
331 of it to skip, so we just bail. */
334 --length; /* account for type byte */
335 if (optp->len_type != NO_LENGTH) {
336 /* Option has a length. Is it in the packet? */
338 /* Bogus - packet must at least include option code byte and
340 add_item_to_tree(opt_tree, offset, 1,
341 "%s (length byte past end of header)", optp->name);
344 len = *opd++; /* total including type, len */
345 --length; /* account for length byte */
347 /* Bogus - option length is too short to include option code and
349 add_item_to_tree(opt_tree, offset, 2,
350 "%s (with too-short option length = %u bytes)", optp->name, 2);
352 } else if (len - 2 > length) {
353 /* Bogus - option goes past the end of the header. */
354 add_item_to_tree(opt_tree, offset, length,
355 "%s (option goes past end of header)", optp->name);
357 } else if (optp->len_type == FIXED_LENGTH && len != optp->optlen) {
358 /* Bogus - option length isn't what it's supposed to be for this
360 add_item_to_tree(opt_tree, offset, len,
361 "%s (with option length = %u bytes; should be %u)", optp->name,
364 } else if (optp->len_type == VARIABLE_LENGTH && len < optp->optlen) {
365 /* Bogus - option length is less than what it's supposed to be for
367 add_item_to_tree(opt_tree, offset, len,
368 "%s (with option length = %u bytes; should be >= %u)", optp->name,
372 if (optp->dissect != NULL) {
373 /* Option has a dissector. */
374 (*optp->dissect)(opt_tree, optp->name, opd, offset, len);
376 /* Option has no data, hence no dissector. */
377 add_item_to_tree(opt_tree, offset, len, "%s", optp->name);
379 len -= 2; /* subtract size of type and length */
385 add_item_to_tree(opt_tree, offset, 1, "%s", optp->name);
394 dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
396 GtkWidget *ip_tree, *ti, *field_tree, *tf;
400 static value_string proto_vals[] = { {IP_PROTO_ICMP, "ICMP"},
401 {IP_PROTO_IGMP, "IGMP"},
402 {IP_PROTO_TCP, "TCP" },
403 {IP_PROTO_UDP, "UDP" },
404 {IP_PROTO_OSPF, "OSPF"},
408 /* To do: check for runts, errs, etc. */
409 /* Avoids alignment problems on many architectures. */
410 memcpy(&iph, &pd[offset], sizeof(e_ip));
411 iph.ip_len = ntohs(iph.ip_len);
412 iph.ip_id = ntohs(iph.ip_id);
413 iph.ip_off = ntohs(iph.ip_off);
414 iph.ip_sum = ntohs(iph.ip_sum);
416 hlen = iph.ip_hl * 4; /* IP header length, in bytes */
418 if (fd->win_info[COL_NUM]) {
425 /* Names are set in the associated dissect_* routines */
428 strcpy(fd->win_info[COL_PROTOCOL], "IP");
429 sprintf(fd->win_info[COL_INFO], "Unknown IP protocol (%02x)", iph.ip_p);
432 strcpy(fd->win_info[COL_SOURCE], get_hostname(iph.ip_src));
433 strcpy(fd->win_info[COL_DESTINATION], get_hostname(iph.ip_dst));
436 iph.ip_tos = IPTOS_TOS(iph.ip_tos);
437 switch (iph.ip_tos) {
439 strcpy(tos_str, "None");
442 strcpy(tos_str, "Minimize delay");
444 case IPTOS_THROUGHPUT:
445 strcpy(tos_str, "Maximize throughput");
447 case IPTOS_RELIABILITY:
448 strcpy(tos_str, "Maximize reliability");
451 strcpy(tos_str, "Minimize cost");
454 strcpy(tos_str, "Unknown. Malformed?");
459 ti = add_item_to_tree(GTK_WIDGET(tree), offset, hlen, "Internet Protocol");
460 ip_tree = gtk_tree_new();
461 add_subtree(ti, ip_tree, ETT_IP);
462 add_item_to_tree(ip_tree, offset, 1, "Version: %d", iph.ip_v);
463 add_item_to_tree(ip_tree, offset, 1, "Header length: %d bytes", hlen);
464 add_item_to_tree(ip_tree, offset + 1, 1, "Type of service: 0x%02x (%s)",
465 iph.ip_tos, tos_str);
466 add_item_to_tree(ip_tree, offset + 2, 2, "Total length: %d", iph.ip_len);
467 add_item_to_tree(ip_tree, offset + 4, 2, "Identification: 0x%04x",
469 /* To do: add flags */
470 add_item_to_tree(ip_tree, offset + 6, 2, "Fragment offset: %d",
471 iph.ip_off & IP_OFFSET);
472 add_item_to_tree(ip_tree, offset + 8, 1, "Time to live: %d",
474 if ((proto_str = match_strval(iph.ip_p, proto_vals)))
475 add_item_to_tree(ip_tree, offset + 9, 1, "Protocol: %s", proto_str);
477 add_item_to_tree(ip_tree, offset + 9, 1, "Protocol: Unknown (%x)",
479 add_item_to_tree(ip_tree, offset + 10, 2, "Header checksum: 0x%04x",
481 add_item_to_tree(ip_tree, offset + 12, 4, "Source address: %s",
482 get_hostname(iph.ip_src));
483 add_item_to_tree(ip_tree, offset + 16, 4, "Destination address: %s",
484 get_hostname(iph.ip_dst));
486 /* Decode IP options, if any. */
487 if (hlen > sizeof (e_ip)) {
488 /* There's more than just the fixed-length header. Decode the
490 optlen = hlen - sizeof (e_ip); /* length of options, in bytes */
491 tf = add_item_to_tree(ip_tree, offset + 20, optlen,
492 "Options: (%d bytes)", optlen);
493 field_tree = gtk_tree_new();
494 add_subtree(tf, field_tree, ETT_IP_OPTIONS);
495 dissect_ip_tcp_options(field_tree, &pd[offset + 20], offset + 20, optlen,
496 ipopts, N_IP_OPTS, IPOPT_END);
500 pi.srcip = ip_to_str( (guint8 *) &iph.ip_src);
501 pi.destip = ip_to_str( (guint8 *) &iph.ip_dst);
502 pi.ipproto = iph.ip_p;
503 pi.iplen = iph.ip_len;
504 pi.iphdrlen = iph.ip_hl;
505 pi.ip_src = iph.ip_src;
510 dissect_icmp(pd, offset, fd, tree);
513 dissect_igmp(pd, offset, fd, tree);
516 dissect_tcp(pd, offset, fd, tree);
519 dissect_udp(pd, offset, fd, tree);
522 dissect_ospf(pd, offset, fd, tree);
528 const gchar *unreach_str[] = {"Network unreachable",
530 "Protocol unreachable",
532 "Fragmentation needed",
533 "Source route failed",
534 "Administratively prohibited",
535 "Network unreachable for TOS",
536 "Host unreachable for TOS",
537 "Communication administratively filtered",
538 "Host precedence violation",
539 "Precedence cutoff in effect"};
541 const gchar *redir_str[] = {"Redirect for network",
543 "Redirect for TOS and network",
544 "Redirect for TOS and host"};
546 const gchar *ttl_str[] = {"TTL equals 0 during transit",
547 "TTL equals 0 during reassembly"};
549 const gchar *par_str[] = {"IP header bad", "Required option missing"};
552 dissect_icmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
554 GtkWidget *icmp_tree, *ti;
556 gchar type_str[64], code_str[64] = "";
558 /* Avoids alignment problems on many architectures. */
559 memcpy(&ih, &pd[offset], sizeof(e_icmp));
560 /* To do: check for runts, errs, etc. */
561 cksum = ntohs(ih.icmp_cksum);
563 switch (ih.icmp_type) {
565 strcpy(type_str, "Echo (ping) reply");
568 strcpy(type_str, "Destination unreachable");
569 if (ih.icmp_code < 12) {
570 sprintf(code_str, "(%s)", unreach_str[ih.icmp_code]);
572 strcpy(code_str, "(Unknown - error?)");
575 case ICMP_SOURCEQUENCH:
576 strcpy(type_str, "Source quench (flow control)");
579 strcpy(type_str, "Redirect");
580 if (ih.icmp_code < 4) {
581 sprintf(code_str, "(%s)", redir_str[ih.icmp_code]);
583 strcpy(code_str, "(Unknown - error?)");
587 strcpy(type_str, "Echo (ping) request");
590 strcpy(type_str, "Time-to-live exceeded");
591 if (ih.icmp_code < 2) {
592 sprintf(code_str, "(%s)", ttl_str[ih.icmp_code]);
594 strcpy(code_str, "(Unknown - error?)");
598 strcpy(type_str, "Parameter problem");
599 if (ih.icmp_code < 2) {
600 sprintf(code_str, "(%s)", par_str[ih.icmp_code]);
602 strcpy(code_str, "(Unknown - error?)");
606 strcpy(type_str, "Timestamp request");
608 case ICMP_TSTAMPREPLY:
609 strcpy(type_str, "Timestamp reply");
612 strcpy(type_str, "Address mask request");
615 strcpy(type_str, "Address mask reply");
618 strcpy(type_str, "Unknown ICMP (obsolete or malformed?)");
621 if (fd->win_info[COL_NUM]) {
622 strcpy(fd->win_info[COL_PROTOCOL], "ICMP");
623 strcpy(fd->win_info[COL_INFO], type_str);
627 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
628 "Internet Control Message Protocol");
629 icmp_tree = gtk_tree_new();
630 add_subtree(ti, icmp_tree, ETT_ICMP);
631 add_item_to_tree(icmp_tree, offset, 1, "Type: %d (%s)",
632 ih.icmp_type, type_str);
633 add_item_to_tree(icmp_tree, offset + 1, 1, "Code: %d %s",
634 ih.icmp_code, code_str);
635 add_item_to_tree(icmp_tree, offset + 2, 2, "Checksum: 0x%04x",
641 dissect_igmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
643 GtkWidget *igmp_tree, *ti;
645 gchar type_str[64] = "";
647 /* Avoids alignment problems on many architectures. */
648 memcpy(&ih, &pd[offset], sizeof(e_igmp));
649 /* To do: check for runts, errs, etc. */
650 cksum = ntohs(ih.igmp_cksum);
654 strcpy(type_str, "Router query");
657 strcpy(type_str, "Host response (v1)");
660 strcpy(type_str, "Leave group (v2)");
663 strcpy(type_str, "DVMRP");
666 strcpy(type_str, "PIM");
669 strcpy(type_str, "Host reponse (v2)");
672 strcpy(type_str, "Traceroute response");
675 strcpy(type_str, "Traceroute message");
678 strcpy(type_str, "Unknown IGMP");
681 if (fd->win_info[COL_NUM]) {
682 strcpy(fd->win_info[COL_PROTOCOL], "IGMP");
686 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
687 "Internet Group Management Protocol");
688 igmp_tree = gtk_tree_new();
689 add_subtree(ti, igmp_tree, ETT_IGMP);
690 add_item_to_tree(igmp_tree, offset, 1, "Version: %d",
692 add_item_to_tree(igmp_tree, offset , 1, "Type: %d (%s)",
693 ih.igmp_t, type_str);
694 add_item_to_tree(igmp_tree, offset + 1, 1, "Unused: 0x%02x",
696 add_item_to_tree(igmp_tree, offset + 2, 2, "Checksum: 0x%04x",
698 add_item_to_tree(igmp_tree, offset + 4, 4, "Group address: %s",
699 ip_to_str((guint8 *) &ih.igmp_gaddr));