2 * Routines for IP and miscellaneous IP protocol packet disassembly
4 * $Id: packet-ip.c,v 1.14 1999/02/08 20:02:34 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>
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 const 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 const 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 const 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"},
395 static const value_string precedence_vals[] = {
396 { IPTOS_PREC_ROUTINE, "routine" },
397 { IPTOS_PREC_PRIORITY, "priority" },
398 { IPTOS_PREC_IMMEDIATE, "immediate" },
399 { IPTOS_PREC_FLASH, "flash" },
400 { IPTOS_PREC_FLASHOVERRIDE, "flash override" },
401 { IPTOS_PREC_CRITIC_ECP, "CRITIC/ECP" },
402 { IPTOS_PREC_INTERNETCONTROL, "internetwork control" },
403 { IPTOS_PREC_NETCONTROL, "network control" },
406 /* To do: check for runts, errs, etc. */
407 /* Avoids alignment problems on many architectures. */
408 memcpy(&iph, &pd[offset], sizeof(e_ip));
409 iph.ip_len = ntohs(iph.ip_len);
410 iph.ip_id = ntohs(iph.ip_id);
411 iph.ip_off = ntohs(iph.ip_off);
412 iph.ip_sum = ntohs(iph.ip_sum);
414 hlen = lo_nibble(iph.ip_v_hl) * 4; /* IP header length, in bytes */
422 /* Names are set in the associated dissect_* routines */
425 if (check_col(fd, COL_PROTOCOL))
426 col_add_str(fd, COL_PROTOCOL, "IP");
427 if (check_col(fd, COL_INFO))
428 col_add_fstr(fd, COL_INFO, "Unknown IP protocol (%02x)", iph.ip_p);
431 if (check_col(fd, COL_RES_NET_SRC))
432 col_add_str(fd, COL_RES_NET_SRC, get_hostname(iph.ip_src));
433 if (check_col(fd, COL_UNRES_NET_SRC))
434 col_add_str(fd, COL_UNRES_NET_SRC, ip_to_str((guint8 *) &iph.ip_src));
435 if (check_col(fd, COL_RES_NET_DST))
436 col_add_str(fd, COL_RES_NET_DST, get_hostname(iph.ip_dst));
437 if (check_col(fd, COL_UNRES_NET_DST))
438 col_add_str(fd, COL_UNRES_NET_DST, ip_to_str((guint8 *) &iph.ip_dst));
440 iph.ip_tos = IPTOS_TOS(iph.ip_tos);
441 switch (iph.ip_tos) {
443 strcpy(tos_str, "None");
446 strcpy(tos_str, "Minimize cost");
448 case IPTOS_RELIABILITY:
449 strcpy(tos_str, "Maximize reliability");
451 case IPTOS_THROUGHPUT:
452 strcpy(tos_str, "Maximize throughput");
455 strcpy(tos_str, "Minimize delay");
458 strcpy(tos_str, "Maximize security");
461 strcpy(tos_str, "Unknown. Malformed?");
466 ti = add_item_to_tree(GTK_WIDGET(tree), offset, hlen, "Internet Protocol");
467 ip_tree = gtk_tree_new();
468 add_subtree(ti, ip_tree, ETT_IP);
469 add_item_to_tree(ip_tree, offset, 1, "Version: %d", hi_nibble(iph.ip_v_hl));
470 add_item_to_tree(ip_tree, offset, 1, "Header length: %d bytes", hlen);
471 tf = add_item_to_tree(ip_tree, offset + 1, 1, "Type of service: 0x%02x (%s)",
472 iph.ip_tos, tos_str);
473 field_tree = gtk_tree_new();
474 add_subtree(tf, field_tree, ETT_IP_TOS);
475 add_item_to_tree(field_tree, offset + 1, 1, "%s",
476 decode_enumerated_bitfield(iph.ip_tos, IPTOS_PREC_MASK,
477 sizeof (iph.ip_tos)*8, precedence_vals,
479 add_item_to_tree(field_tree, offset + 1, 1, "%s",
480 decode_boolean_bitfield(iph.ip_tos, IPTOS_LOWDELAY,
481 sizeof (iph.ip_tos)*8, "low delay", "normal delay"));
482 add_item_to_tree(field_tree, offset + 1, 1, "%s",
483 decode_boolean_bitfield(iph.ip_tos, IPTOS_THROUGHPUT,
484 sizeof (iph.ip_tos)*8, "high throughput", "normal throughput"));
485 add_item_to_tree(field_tree, offset + 1, 1, "%s",
486 decode_boolean_bitfield(iph.ip_tos, IPTOS_RELIABILITY,
487 sizeof (iph.ip_tos)*8, "high reliability", "normal reliability"));
488 add_item_to_tree(field_tree, offset + 1, 1, "%s",
489 decode_boolean_bitfield(iph.ip_tos, IPTOS_LOWCOST,
490 sizeof (iph.ip_tos)*8, "low cost", "normal cost"));
491 add_item_to_tree(ip_tree, offset + 2, 2, "Total length: %d", iph.ip_len);
492 add_item_to_tree(ip_tree, offset + 4, 2, "Identification: 0x%04x",
494 tf = add_item_to_tree(ip_tree, offset + 6, 2, "Flags: 0x%x",
495 (iph.ip_off & (IP_DF|IP_MF)) >> 12);
496 field_tree = gtk_tree_new();
497 add_subtree(tf, field_tree, ETT_IP_OFF);
498 add_item_to_tree(field_tree, offset + 6, 2, "%s",
499 decode_boolean_bitfield(iph.ip_off >> 8, IP_DF >> 8, 8, "don't fragment",
501 add_item_to_tree(field_tree, offset + 6, 2, "%s",
502 decode_boolean_bitfield(iph.ip_off >> 8, IP_MF >> 8, 8, "more fragments",
504 add_item_to_tree(ip_tree, offset + 6, 2, "Fragment offset: %d",
505 iph.ip_off & IP_OFFSET);
506 add_item_to_tree(ip_tree, offset + 8, 1, "Time to live: %d",
508 add_item_to_tree(ip_tree, offset + 9, 1, "Protocol: %s",
509 val_to_str(iph.ip_p, proto_vals, "Unknown (%x)"));
510 add_item_to_tree(ip_tree, offset + 10, 2, "Header checksum: 0x%04x",
512 add_item_to_tree(ip_tree, offset + 12, 4, "Source address: %s (%s)",
513 get_hostname(iph.ip_src),
514 ip_to_str((guint8 *) &iph.ip_src));
515 add_item_to_tree(ip_tree, offset + 16, 4, "Destination address: %s (%s)",
516 get_hostname(iph.ip_dst),
517 ip_to_str((guint8 *) &iph.ip_dst));
519 /* Decode IP options, if any. */
520 if (hlen > sizeof (e_ip)) {
521 /* There's more than just the fixed-length header. Decode the
523 optlen = hlen - sizeof (e_ip); /* length of options, in bytes */
524 tf = add_item_to_tree(ip_tree, offset + 20, optlen,
525 "Options: (%d bytes)", optlen);
526 field_tree = gtk_tree_new();
527 add_subtree(tf, field_tree, ETT_IP_OPTIONS);
528 dissect_ip_tcp_options(field_tree, &pd[offset + 20], offset + 20, optlen,
529 ipopts, N_IP_OPTS, IPOPT_END);
533 pi.srcip = ip_to_str( (guint8 *) &iph.ip_src);
534 pi.destip = ip_to_str( (guint8 *) &iph.ip_dst);
535 pi.ipproto = iph.ip_p;
536 pi.iplen = iph.ip_len;
537 pi.iphdrlen = lo_nibble(iph.ip_v_hl);
538 pi.ip_src = iph.ip_src;
543 dissect_icmp(pd, offset, fd, tree);
546 dissect_igmp(pd, offset, fd, tree);
549 dissect_tcp(pd, offset, fd, tree);
552 dissect_udp(pd, offset, fd, tree);
555 dissect_ospf(pd, offset, fd, tree);
561 const gchar *unreach_str[] = {"Network unreachable",
563 "Protocol unreachable",
565 "Fragmentation needed",
566 "Source route failed",
567 "Administratively prohibited",
568 "Network unreachable for TOS",
569 "Host unreachable for TOS",
570 "Communication administratively filtered",
571 "Host precedence violation",
572 "Precedence cutoff in effect"};
574 const gchar *redir_str[] = {"Redirect for network",
576 "Redirect for TOS and network",
577 "Redirect for TOS and host"};
579 const gchar *ttl_str[] = {"TTL equals 0 during transit",
580 "TTL equals 0 during reassembly"};
582 const gchar *par_str[] = {"IP header bad", "Required option missing"};
585 dissect_icmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
587 GtkWidget *icmp_tree, *ti;
589 gchar type_str[64], code_str[64] = "";
591 /* Avoids alignment problems on many architectures. */
592 memcpy(&ih, &pd[offset], sizeof(e_icmp));
593 /* To do: check for runts, errs, etc. */
594 cksum = ntohs(ih.icmp_cksum);
596 switch (ih.icmp_type) {
598 strcpy(type_str, "Echo (ping) reply");
601 strcpy(type_str, "Destination unreachable");
602 if (ih.icmp_code < 12) {
603 sprintf(code_str, "(%s)", unreach_str[ih.icmp_code]);
605 strcpy(code_str, "(Unknown - error?)");
608 case ICMP_SOURCEQUENCH:
609 strcpy(type_str, "Source quench (flow control)");
612 strcpy(type_str, "Redirect");
613 if (ih.icmp_code < 4) {
614 sprintf(code_str, "(%s)", redir_str[ih.icmp_code]);
616 strcpy(code_str, "(Unknown - error?)");
620 strcpy(type_str, "Echo (ping) request");
623 strcpy(type_str, "Time-to-live exceeded");
624 if (ih.icmp_code < 2) {
625 sprintf(code_str, "(%s)", ttl_str[ih.icmp_code]);
627 strcpy(code_str, "(Unknown - error?)");
631 strcpy(type_str, "Parameter problem");
632 if (ih.icmp_code < 2) {
633 sprintf(code_str, "(%s)", par_str[ih.icmp_code]);
635 strcpy(code_str, "(Unknown - error?)");
639 strcpy(type_str, "Timestamp request");
641 case ICMP_TSTAMPREPLY:
642 strcpy(type_str, "Timestamp reply");
645 strcpy(type_str, "Address mask request");
648 strcpy(type_str, "Address mask reply");
651 strcpy(type_str, "Unknown ICMP (obsolete or malformed?)");
654 if (check_col(fd, COL_PROTOCOL))
655 col_add_str(fd, COL_PROTOCOL, "ICMP");
656 if (check_col(fd, COL_INFO))
657 col_add_str(fd, COL_INFO, type_str);
660 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
661 "Internet Control Message Protocol");
662 icmp_tree = gtk_tree_new();
663 add_subtree(ti, icmp_tree, ETT_ICMP);
664 add_item_to_tree(icmp_tree, offset, 1, "Type: %d (%s)",
665 ih.icmp_type, type_str);
666 add_item_to_tree(icmp_tree, offset + 1, 1, "Code: %d %s",
667 ih.icmp_code, code_str);
668 add_item_to_tree(icmp_tree, offset + 2, 2, "Checksum: 0x%04x",
674 dissect_igmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
676 GtkWidget *igmp_tree, *ti;
678 gchar type_str[64] = "";
680 /* Avoids alignment problems on many architectures. */
681 memcpy(&ih, &pd[offset], sizeof(e_igmp));
682 /* To do: check for runts, errs, etc. */
683 cksum = ntohs(ih.igmp_cksum);
685 switch (lo_nibble(ih.igmp_v_t)) {
687 strcpy(type_str, "Router query");
690 strcpy(type_str, "Host response (v1)");
693 strcpy(type_str, "Leave group (v2)");
696 strcpy(type_str, "DVMRP");
699 strcpy(type_str, "PIM");
702 strcpy(type_str, "Host reponse (v2)");
705 strcpy(type_str, "Traceroute response");
708 strcpy(type_str, "Traceroute message");
711 strcpy(type_str, "Unknown IGMP");
714 if (check_col(fd, COL_PROTOCOL))
715 col_add_str(fd, COL_PROTOCOL, "IGMP");
716 if (check_col(fd, COL_INFO))
717 col_add_str(fd, COL_INFO, type_str);
720 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
721 "Internet Group Management Protocol");
722 igmp_tree = gtk_tree_new();
723 add_subtree(ti, igmp_tree, ETT_IGMP);
724 add_item_to_tree(igmp_tree, offset, 1, "Version: %d",
725 hi_nibble(ih.igmp_v_t));
726 add_item_to_tree(igmp_tree, offset , 1, "Type: %d (%s)",
727 lo_nibble(ih.igmp_v_t), type_str);
728 add_item_to_tree(igmp_tree, offset + 1, 1, "Unused: 0x%02x",
730 add_item_to_tree(igmp_tree, offset + 2, 2, "Checksum: 0x%04x",
732 add_item_to_tree(igmp_tree, offset + 4, 4, "Group address: %s",
733 ip_to_str((guint8 *) &ih.igmp_gaddr));