Note that for THE3GPP_IPV6_DNS_SERVERS we probably *do* need to handle
[obnox/wireshark/wip.git] / packet-ip.c
index 843048c6db4a7616bf9f6a33af5e848eeea4f20e..3812bba19130745bd2b1fe5ec9c086ec998c3902 100644 (file)
@@ -1,7 +1,7 @@
 /* packet-ip.c
  * Routines for IP and miscellaneous IP protocol packet disassembly
  *
- * $Id: packet-ip.c,v 1.184 2003/03/03 23:20:57 sahlberg Exp $
+ * $Id: packet-ip.c,v 1.202 2004/02/18 06:43:00 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -37,6 +37,7 @@
 #include <epan/packet.h>
 #include <epan/resolv.h>
 #include "ipproto.h"
+#include "ip_opts.h"
 #include "prefs.h"
 #include "reassemble.h"
 #include "etypes.h"
@@ -83,6 +84,7 @@ static int hf_ip_dst = -1;
 static int hf_ip_src = -1;
 static int hf_ip_addr = -1;
 static int hf_ip_flags = -1;
+static int hf_ip_flags_rf = -1;
 static int hf_ip_flags_df = -1;
 static int hf_ip_flags_mf = -1;
 static int hf_ip_frag_offset = -1;
@@ -97,6 +99,7 @@ static int hf_ip_fragment_overlap_conflict = -1;
 static int hf_ip_fragment_multiple_tails = -1;
 static int hf_ip_fragment_too_long_fragment = -1;
 static int hf_ip_fragment_error = -1;
+static int hf_ip_reassembled_in = -1;
 
 static gint ett_ip = -1;
 static gint ett_ip_dsfield = -1;
@@ -119,11 +122,11 @@ static const fragment_items ip_frag_items = {
        &hf_ip_fragment_multiple_tails,
        &hf_ip_fragment_too_long_fragment,
        &hf_ip_fragment_error,
+       &hf_ip_reassembled_in,
        "fragments"
 };
 
-/* Used by IPv6 as well, so not static */
-dissector_table_t ip_dissector_table;
+static dissector_table_t ip_dissector_table;
 
 static dissector_handle_t ip_handle;
 static dissector_handle_t data_handle;
@@ -133,6 +136,11 @@ static int hf_icmp_type = -1;
 static int hf_icmp_code = -1;
 static int hf_icmp_checksum = -1;
 static int hf_icmp_checksum_bad = -1;
+static int hf_icmp_ident = -1;
+static int hf_icmp_seq_num = -1;
+static int hf_icmp_mtu = -1;
+static int hf_icmp_redir_gw = -1;
+
 
 /* Mobile ip */
 static int hf_icmp_mip_type = -1;
@@ -213,7 +221,7 @@ static gint ett_icmp_mip_flags = -1;
 #define        IPH_MIN_LEN     20
 
 /* IP flags. */
-#define IP_CE          0x8000          /* Flag: "Congestion"           */
+#define IP_RF          0x8000          /* Flag: "Reserved bit"         */
 #define IP_DF          0x4000          /* Flag: "Don't Fragment"       */
 #define IP_MF          0x2000          /* Flag: "More Fragments"       */
 #define IP_OFFSET      0x1FFF          /* "Fragment Offset" part       */
@@ -321,11 +329,13 @@ static gint ett_icmp_mip_flags = -1;
  * defragmentation of IPv4
  */
 static GHashTable *ip_fragment_table = NULL;
+static GHashTable *ip_reassembled_table = NULL;
 
 static void
 ip_defragment_init(void)
 {
   fragment_table_init(&ip_fragment_table);
+  reassembled_table_init(&ip_reassembled_table);
 }
 
 void
@@ -794,11 +804,6 @@ static const true_false_string tos_set_high = {
   "Normal"
 };
 
-static const true_false_string flags_set_truth = {
-  "Set",
-  "Not set"
-};
-
 static guint16 ip_checksum(const guint8 *ptr, int len)
 {
        vec_t cksum_vec[1];
@@ -813,12 +818,13 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
   proto_tree *ip_tree = NULL, *field_tree;
   proto_item *ti = NULL, *tf;
+  guint32    addr;
   int        offset = 0;
   guint      hlen, optlen;
   guint16    flags;
   guint8     nxt;
   guint16    ipsum;
-  fragment_data *ipfd_head;
+  fragment_data *ipfd_head=NULL;
   tvbuff_t   *next_tvb;
   gboolean   update_col_info = TRUE;
   gboolean   save_fragmented;
@@ -831,7 +837,6 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
      eip_current=0;
   }
   iph=&eip_arr[eip_current];
-  pinfo->private_data=iph;
 
   if (check_col(pinfo->cinfo, COL_PROTOCOL))
     col_set_str(pinfo->cinfo, COL_PROTOCOL, "IP");
@@ -919,15 +924,16 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
   iph->ip_id  = tvb_get_ntohs(tvb, offset + 4);
   if (tree)
-    proto_tree_add_uint(ip_tree, hf_ip_id, tvb, offset + 4, 2, iph->ip_id);
+    proto_tree_add_uint_format(ip_tree, hf_ip_id, tvb, offset + 4, 2, iph->ip_id, "Identification: 0x%04x (%d)", iph->ip_id, iph->ip_id);
 
   iph->ip_off = tvb_get_ntohs(tvb, offset + 6);
   if (tree) {
-    flags = (iph->ip_off & (IP_DF|IP_MF)) >> 12;
+    flags = (iph->ip_off & (IP_RF | IP_DF | IP_MF)) >> 12;
     tf = proto_tree_add_uint(ip_tree, hf_ip_flags, tvb, offset + 6, 1, flags);
     field_tree = proto_item_add_subtree(tf, ett_ip_off);
-    proto_tree_add_boolean(field_tree, hf_ip_flags_df, tvb, offset + 6, 1, flags),
-    proto_tree_add_boolean(field_tree, hf_ip_flags_mf, tvb, offset + 6, 1, flags),
+    proto_tree_add_boolean(field_tree, hf_ip_flags_rf, tvb, offset + 6, 1, flags);
+    proto_tree_add_boolean(field_tree, hf_ip_flags_df, tvb, offset + 6, 1, flags);
+    proto_tree_add_boolean(field_tree, hf_ip_flags_mf, tvb, offset + 6, 1, flags);
 
     proto_tree_add_uint(ip_tree, hf_ip_frag_offset, tvb, offset + 6, 2,
       (iph->ip_off & IP_OFFSET)*8);
@@ -967,24 +973,31 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
       proto_tree_add_uint(ip_tree, hf_ip_checksum, tvb, offset + 10, 2, iph->ip_sum);
   }
 
-  tvb_memcpy(tvb, (guint8 *)&iph->ip_src, offset + 12, 4);
+  SET_ADDRESS(&pinfo->net_src, AT_IPv4, 4, tvb_get_ptr(tvb, offset + IPH_SRC, 4));
+  SET_ADDRESS(&pinfo->src, AT_IPv4, 4, tvb_get_ptr(tvb, offset + IPH_SRC, 4));
+  SET_ADDRESS(&iph->ip_src, AT_IPv4, 4, tvb_get_ptr(tvb, offset + IPH_SRC, 4));
   if (tree) {
+    memcpy(&addr, iph->ip_src.data, 4);
     if (ip_summary_in_tree) {
       proto_item_append_text(ti, ", Src Addr: %s (%s)",
-               get_hostname(iph->ip_src), ip_to_str((guint8 *) &iph->ip_src));
+               get_hostname(addr), ip_to_str((guint8 *) iph->ip_src.data));
     }
-    proto_tree_add_ipv4(ip_tree, hf_ip_src, tvb, offset + 12, 4, iph->ip_src);
-    proto_tree_add_ipv4_hidden(ip_tree, hf_ip_addr, tvb, offset + 12, 4, iph->ip_src);
+    proto_tree_add_ipv4(ip_tree, hf_ip_src, tvb, offset + 12, 4, addr);
+    proto_tree_add_ipv4_hidden(ip_tree, hf_ip_addr, tvb, offset + 12, 4, addr);
   }
 
-  tvb_memcpy(tvb, (guint8 *)&iph->ip_dst, offset + 16, 4);
+  SET_ADDRESS(&pinfo->net_dst, AT_IPv4, 4, tvb_get_ptr(tvb, offset + IPH_DST, 4));
+  SET_ADDRESS(&pinfo->dst, AT_IPv4, 4, tvb_get_ptr(tvb, offset + IPH_DST, 4));
+  SET_ADDRESS(&iph->ip_dst, AT_IPv4, 4, tvb_get_ptr(tvb, offset + IPH_DST, 4));
+
   if (tree) {
+    memcpy(&addr, iph->ip_dst.data, 4);
     if (ip_summary_in_tree) {
       proto_item_append_text(ti, ", Dst Addr: %s (%s)",
-               get_hostname(iph->ip_dst), ip_to_str((guint8 *) &iph->ip_dst));
+               get_hostname(addr), ip_to_str((guint8 *) iph->ip_dst.data));
     }
-    proto_tree_add_ipv4(ip_tree, hf_ip_dst, tvb, offset + 16, 4, iph->ip_dst);
-    proto_tree_add_ipv4_hidden(ip_tree, hf_ip_addr, tvb, offset + 16, 4, iph->ip_dst);
+    proto_tree_add_ipv4(ip_tree, hf_ip_dst, tvb, offset + 16, 4, addr);
+    proto_tree_add_ipv4_hidden(ip_tree, hf_ip_addr, tvb, offset + 16, 4, addr);
   }
 
   if (tree) {
@@ -1005,12 +1018,7 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
   pinfo->iplen = iph->ip_len;
 
-  pinfo->iphdrlen = lo_nibble(iph->ip_v_hl);
-
-  SET_ADDRESS(&pinfo->net_src, AT_IPv4, 4, tvb_get_ptr(tvb, offset + IPH_SRC, 4));
-  SET_ADDRESS(&pinfo->src, AT_IPv4, 4, tvb_get_ptr(tvb, offset + IPH_SRC, 4));
-  SET_ADDRESS(&pinfo->net_dst, AT_IPv4, 4, tvb_get_ptr(tvb, offset + IPH_DST, 4));
-  SET_ADDRESS(&pinfo->dst, AT_IPv4, 4, tvb_get_ptr(tvb, offset + IPH_DST, 4));
+  pinfo->iphdrlen = hlen;
 
   /* Skip over header + options */
   offset += hlen;
@@ -1022,34 +1030,17 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
    */
   save_fragmented = pinfo->fragmented;
   if (ip_defragment && (iph->ip_off & (IP_MF|IP_OFFSET)) &&
-       tvb_reported_length(tvb) <= tvb_length(tvb) && ipsum == 0) {
-    ipfd_head = fragment_add(tvb, offset, pinfo, iph->ip_id,
+      tvb_bytes_exist(tvb, offset, pinfo->iplen - pinfo->iphdrlen) &&
+      ipsum == 0) {
+    ipfd_head = fragment_add_check(tvb, offset, pinfo, iph->ip_id,
                             ip_fragment_table,
+                            ip_reassembled_table,
                             (iph->ip_off & IP_OFFSET)*8,
-                            pinfo->iplen - (pinfo->iphdrlen*4),
+                            pinfo->iplen - pinfo->iphdrlen,
                             iph->ip_off & IP_MF);
 
-    if (ipfd_head != NULL) {
-      /* OK, we have the complete reassembled payload.
-         Allocate a new tvbuff, referring to the reassembled payload. */
-      next_tvb = tvb_new_real_data(ipfd_head->data, ipfd_head->datalen,
-       ipfd_head->datalen);
-
-      /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
-         were handed refers, so it'll get cleaned up when that tvbuff
-         is cleaned up. */
-      tvb_set_child_real_data_tvbuff(tvb, next_tvb);
-
-      /* Add the defragmented data to the data source list. */
-      add_new_data_source(pinfo, next_tvb, "Reassembled IPv4");
-
-      /* show all fragments */
-      update_col_info = !show_fragment_tree(ipfd_head, &ip_frag_items,
-        ip_tree, pinfo, next_tvb);
-    } else {
-      /* We don't have the complete reassembled payload. */
-      next_tvb = NULL;
-    }
+    next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled IPv4",
+      ipfd_head, &ip_frag_items, &update_col_info, ip_tree);
   } else {
     /* If this is the first fragment, dissect its contents, otherwise
        just show it as a fragment.
@@ -1078,9 +1069,17 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
   if (next_tvb == NULL) {
     /* Just show this as a fragment. */
-    if (check_col(pinfo->cinfo, COL_INFO))
+    if (check_col(pinfo->cinfo, COL_INFO)) {
       col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented IP protocol (proto=%s 0x%02x, off=%u)",
        ipprotostr(iph->ip_p), iph->ip_p, (iph->ip_off & IP_OFFSET) * 8);
+    }
+    if( ipfd_head && ipfd_head->reassembled_in != pinfo->fd->num ){
+      if (check_col(pinfo->cinfo, COL_INFO)) {
+        col_append_fstr(pinfo->cinfo, COL_INFO, " [Reassembled in #%u]",
+          ipfd_head->reassembled_in);
+      }
+    }
+
     call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
                    tree);
     pinfo->fragmented = save_fragmented;
@@ -1284,8 +1283,8 @@ static const gchar *redir_str[] = {"Redirect for network",
 
 #define        N_REDIRECT      (sizeof redir_str / sizeof redir_str[0])
 
-static const gchar *ttl_str[] = {"TTL equals 0 during transit",
-                                 "TTL equals 0 during reassembly"};
+static const gchar *ttl_str[] = {"Time to live exceeded in transit",
+                                 "Fragment reassembly time exceeded"};
 
 #define        N_TIMXCEED      (sizeof ttl_str / sizeof ttl_str[0])
 
@@ -1452,17 +1451,14 @@ dissect_icmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
       case ICMP_IREQREPLY:
       case ICMP_MASKREQ:
       case ICMP_MASKREPLY:
-       proto_tree_add_text(icmp_tree, tvb, 4, 2, "Identifier: 0x%04x",
-         tvb_get_ntohs(tvb, 4));
-       proto_tree_add_text(icmp_tree, tvb, 6, 2, "Sequence number: %02x:%02x",
-         tvb_get_guint8(tvb, 6), tvb_get_guint8(tvb, 7));
+        proto_tree_add_item(icmp_tree, hf_icmp_ident, tvb, 4, 2, FALSE);
+        proto_tree_add_item(icmp_tree, hf_icmp_seq_num, tvb, 6, 2, FALSE);
        break;
 
       case ICMP_UNREACH:
         switch (icmp_code) {
           case ICMP_FRAG_NEEDED:
-            proto_tree_add_text(icmp_tree, tvb, 6, 2, "MTU of next hop: %u",
-                  tvb_get_ntohs(tvb, 6));
+            proto_tree_add_item(icmp_tree, hf_icmp_mtu, tvb, 6, 2, FALSE);
             break;
        }
         break;
@@ -1484,8 +1480,7 @@ dissect_icmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        break;
 
       case ICMP_REDIRECT:
-       proto_tree_add_text(icmp_tree, tvb, 4, 4, "Gateway address: %s",
-         ip_to_str(tvb_get_ptr(tvb, 4, 4)));
+        proto_tree_add_item(icmp_tree, hf_icmp_redir_gw, tvb, 4, 4, FALSE);
        break;
     }
 
@@ -1640,12 +1635,16 @@ proto_register_ip(void)
                { "Flags",              "ip.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
                        "", HFILL }},
 
+               { &hf_ip_flags_rf,
+               { "Reserved bit",       "ip.flags.rb", FT_BOOLEAN, 4, TFS(&flags_set_truth), IP_RF >> 12,
+                       "", HFILL }},
+
                { &hf_ip_flags_df,
-               { "Don't fragment",     "ip.flags.df", FT_BOOLEAN, 4, TFS(&flags_set_truth), IP_DF>>12,
+               { "Don't fragment",     "ip.flags.df", FT_BOOLEAN, 4, TFS(&flags_set_truth), IP_DF >> 12,
                        "", HFILL }},
 
                { &hf_ip_flags_mf,
-               { "More fragments",     "ip.flags.mf", FT_BOOLEAN, 4, TFS(&flags_set_truth), IP_MF>>12,
+               { "More fragments",     "ip.flags.mf", FT_BOOLEAN, 4, TFS(&flags_set_truth), IP_MF >> 12,
                        "", HFILL }},
 
                { &hf_ip_frag_offset,
@@ -1695,6 +1694,10 @@ proto_register_ip(void)
                { &hf_ip_fragments,
                { "IP Fragments", "ip.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
                        "IP Fragments", HFILL }},
+
+               { &hf_ip_reassembled_in,
+               { "Reassembled IP in frame", "ip.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+                       "This IP packet is reassembled in this frame", HFILL }}
        };
        static gint *ett[] = {
                &ett_ip,
@@ -1781,6 +1784,22 @@ proto_register_icmp(void)
       { "Bad Checksum",        "icmp.checksum_bad",    FT_BOOLEAN, BASE_NONE,  NULL, 0x0,
        "", HFILL }},
 
+    { &hf_icmp_ident,
+      {"Identifier", "icmp.ident",              FT_UINT16, BASE_HEX,    NULL, 0x0,
+       "", HFILL }},
+
+    { &hf_icmp_seq_num,
+      {"Sequence number", "icmp.seq",           FT_UINT16, BASE_HEX,    NULL, 0x0,
+       "", HFILL }},
+
+    { &hf_icmp_mtu,
+      {"MTU of next hop", "icmp.mtu",           FT_UINT16, BASE_DEC,    NULL, 0x0,
+       "", HFILL}},
+
+    { &hf_icmp_redir_gw,
+      {"Gateway address", "icmp.redir_gw",      FT_IPv4, BASE_NONE,     NULL, 0x0,
+       "", HFILL }},
+
     { &hf_icmp_mip_type,
       { "Extension Type", "icmp.mip.type",     FT_UINT8, BASE_DEC,
        VALS(mip_extensions), 0x0,"", HFILL}},