IPv6: Use ipv6_pinfo_t instead of ws_ip to keep some state
authorJoão Valverde <joao.valverde@tecnico.ulisboa.pt>
Sun, 24 Jul 2016 18:11:01 +0000 (19:11 +0100)
committerJoão Valverde <j@v6e.pt>
Mon, 25 Jul 2016 10:04:49 +0000 (10:04 +0000)
To perform IPv6 defragmentation we need to compute the IPv6 fragment header
payload length by subtracting the length of intermediate extension headers
from the IPv6 payload length.

Add a new frag_plen field to ipv6_pinfo_t to do that instead of (ab)using
struct ws_ip.

Note: The RFC 2460 rules for fragment header order are stricter than the code
suggests but that shouldn't be a problem here.

Change-Id: I76f3cb3a1a29d96b080d3d53c0f493f9d0b2786c
Reviewed-on: https://code.wireshark.org/review/16637
Petri-Dish: João Valverde <j@v6e.pt>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: João Valverde <j@v6e.pt>
epan/dissectors/packet-ip.h
epan/dissectors/packet-ipsec.c
epan/dissectors/packet-ipv6.c
epan/dissectors/packet-ipv6.h
epan/dissectors/packet-mip6.c
epan/dissectors/packet-shim6.c

index adb84a0e5fe4ec080f54191e2e009d3a428b93a8..04ac8b07163766c72e57d3b0885f5786567ba8b8 100644 (file)
@@ -33,7 +33,7 @@ typedef struct _ws_ip
     guint8  ip_ver;     /* 4 or 6 */
     guint8  ip_tos;     /* IPv4: type of service;   IPv6: traffic class */
     guint32 ip_flw;     /* IPv4: (zero);            IPv6: flow label */
-    guint32 ip_len;     /* IPv4: total length;      IPv6: payload length (minus extensions) */
+    guint32 ip_len;     /* IPv4: total length;      IPv6: payload length */
     guint16 ip_id;      /* IPv4: identification;    IPv6: (zero) */
     guint16 ip_off;     /* IPv4: fragment offset;   IPv6: (zero) */
     guint8  ip_ttl;     /* IPv4: time-to-live;      IPv6: hop limit */
index 7998af1a03d8934581f53b7283bcd933fb848342..853ad5251a05f3b40baacfd13acf1b57b565a72c 100644 (file)
@@ -1099,7 +1099,6 @@ dissect_ah(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
   tvbuff_t   *next_tvb;
   dissector_handle_t dissector_handle;
   guint32 saved_match_uint;
-  ws_ip *iph = (ws_ip *)data;
 
   col_set_str(pinfo->cinfo, COL_PROTOCOL, "AH");
   col_clear(pinfo->cinfo, COL_INFO);
@@ -1113,6 +1112,7 @@ dissect_ah(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
   if (pinfo->dst.type == AT_IPv6) {
     ipv6_pinfo_t *ipv6_pinfo = p_get_ipv6_pinfo(pinfo);
 
+    ipv6_pinfo->frag_plen -= ah_hdr_len;
     if (ipv6_pinfo->ipv6_tree != NULL) {
       root_tree = ipv6_pinfo->ipv6_tree;
       ipv6_pinfo->ipv6_item_len += ah_hdr_len;
@@ -1137,13 +1137,8 @@ dissect_ah(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
 
   next_tvb = tvb_new_subset_remaining(tvb, ah_hdr_len);
 
-  if (iph != NULL) {
-      iph->ip_nxt = ah_nxt;
-      iph->ip_len -= ah_hdr_len;
-  }
-
   if (pinfo->dst.type == AT_IPv6) {
-    ipv6_dissect_next(ah_nxt, next_tvb, pinfo, tree, iph);
+    ipv6_dissect_next(ah_nxt, next_tvb, pinfo, tree, (ws_ip *)data);
   } else {
     /* do lookup with the subdissector table */
     saved_match_uint  = pinfo->match_uint;
index 2c16ed5c8921935f8253da35ec0ada70fd8b5721..10e3c1e700d17027a1bb9f900c8cced4012f1c51 100644 (file)
@@ -1097,7 +1097,6 @@ dissect_routing6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data
     int                offset = 0;
     tvbuff_t          *next_tvb;
     ipv6_pinfo_t      *ipv6_pinfo = p_get_ipv6_pinfo(pinfo);
-    ws_ip             *iph = (ws_ip *)data;
 
     col_append_sep_str(pinfo->cinfo, COL_INFO, " , ", "IPv6 routing");
 
@@ -1105,6 +1104,7 @@ dissect_routing6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data
     len = (rt.ip6r_len + 1) << 3;
 
     root_tree = tree;
+    ipv6_pinfo->frag_plen -= len;
     if (ipv6_pinfo->ipv6_tree != NULL) {
         root_tree = ipv6_pinfo->ipv6_tree;
         ipv6_pinfo->ipv6_item_len += len;
@@ -1152,12 +1152,8 @@ dissect_routing6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data
         break;
     }
 
-    if (iph != NULL) {
-        iph->ip_nxt = rt.ip6r_nxt;
-        iph->ip_len -= len;
-    }
     next_tvb = tvb_new_subset_remaining(tvb, len);
-    ipv6_dissect_next(rt.ip6r_nxt, next_tvb, pinfo, tree, iph);
+    ipv6_dissect_next(rt.ip6r_nxt, next_tvb, pinfo, tree, (ws_ip *)data);
     return tvb_captured_length(tvb);
 }
 
@@ -1175,7 +1171,6 @@ dissect_fraghdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
     gboolean         show_data = FALSE;
     gboolean         reassembled;
     tvbuff_t        *next_tvb;
-    ws_ip           *iph = (ws_ip *)data;
 
     nxt = tvb_get_guint8(tvb, offset);
     offlg = tvb_get_ntohs(tvb, offset + 2);
@@ -1186,6 +1181,7 @@ dissect_fraghdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
                         frag_off, frag_flg ? "y" : "n", frag_ident, nxt);
 
     root_tree = tree;
+    ipv6_pinfo->frag_plen -= 8;
     if (ipv6_pinfo->ipv6_tree != NULL) {
         root_tree = ipv6_pinfo->ipv6_tree;
         ipv6_pinfo->ipv6_item_len += 8;
@@ -1216,9 +1212,9 @@ dissect_fraghdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
     proto_tree_add_item(frag_tree, hf_ipv6_fraghdr_ident, tvb, offset, 4, ENC_BIG_ENDIAN);
     offset += 4;
 
-    if (iph != NULL) {
+    if (ipv6_pinfo->frag_plen > 0) {
         if ((frag_off != 0) || frag_flg) {
-            reassembled = ipv6_reassemble_do(&tvb, &offset, pinfo, frag_tree, iph->ip_len - 8,
+            reassembled = ipv6_reassemble_do(&tvb, &offset, pinfo, frag_tree, ipv6_pinfo->frag_plen,
                                              frag_off, frag_flg, frag_ident, &show_data);
             if (show_data) {
                 next_tvb = tvb_new_subset_remaining(tvb, offset);
@@ -1226,19 +1222,16 @@ dissect_fraghdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
                 return tvb_captured_length(tvb);
             }
             if (reassembled) {
-                iph->ip_nxt = nxt;
+                ipv6_pinfo->frag_plen = 0;
                 next_tvb = tvb_new_subset_remaining(tvb, offset);
-                iph->ip_len = tvb_reported_length_remaining(next_tvb, 0);
-                ipv6_dissect_next(nxt, next_tvb, pinfo, tree, iph);
+                ipv6_dissect_next(nxt, next_tvb, pinfo, tree, (ws_ip *)data);
                 return tvb_captured_length(tvb);
             }
         }
-
-        iph->ip_nxt = nxt;
-        iph->ip_len -= 8;
     }
+
     next_tvb = tvb_new_subset_remaining(tvb, offset);
-    ipv6_dissect_next(nxt, next_tvb, pinfo, tree, iph);
+    ipv6_dissect_next(nxt, next_tvb, pinfo, tree, (ws_ip *)data);
     return tvb_captured_length(tvb);
 }
 
@@ -1687,6 +1680,7 @@ dissect_opts(tvbuff_t *tvb, int offset, proto_tree *tree, packet_info *pinfo, ws
     offset_end = offset + len;
 
     root_tree = tree;
+    ipv6_pinfo->frag_plen -= len;
     if (ipv6_pinfo->ipv6_tree != NULL) {
         root_tree = ipv6_pinfo->ipv6_tree;
         ipv6_pinfo->ipv6_item_len += len;
@@ -1832,10 +1826,6 @@ dissect_opts(tvbuff_t *tvb, int offset, proto_tree *tree, packet_info *pinfo, ws
         }
     }
 
-    if (iph != NULL) {
-        iph->ip_nxt = nxt;
-        iph->ip_len -= len;
-    }
     next_tvb = tvb_new_subset_remaining(tvb, len);
     ipv6_dissect_next(nxt, next_tvb, pinfo, tree, iph);
     return tvb_captured_length(tvb);
@@ -2184,6 +2174,7 @@ dissect_ipv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_
 
     ipv6_pinfo->jumbo_plen = 0;
     ipv6_pinfo->ip6_plen = g_ntohs(ipv6->ip6_plen);
+    ipv6_pinfo->frag_plen = ipv6_pinfo->ip6_plen;
     if (!ipv6_exthdr_under_root) {
         ipv6_pinfo->ipv6_tree = ipv6_tree;
         ipv6_pinfo->ipv6_item_len = IPv6_HDR_SIZE;
index fdac35e8ab4dd5dc4be7f1c64e017c0dc50c8a5f..1ddccadaae615b8e3372b4ce2722d87076ade229 100644 (file)
@@ -106,6 +106,7 @@ extern "C" {
 typedef struct {
     guint32     jumbo_plen;
     guint16     ip6_plen;
+    gint        frag_plen;
     proto_tree *ipv6_tree;
     gint        ipv6_item_len;
 } ipv6_pinfo_t;
index b6adb249e861876d24ae28d6730b8662a6f70d18..be33258bb094a674e93ac072c0b622a45bdf060a 100644 (file)
@@ -4067,7 +4067,6 @@ dissect_mip6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
     guint       len, offset = 0, start_offset = offset;
     proto_item *ti, *header_item;
     tvbuff_t   *next_tvb;
-    ws_ip      *iph = (ws_ip *)data;
 
     /* Make entries in Protocol column and Info column on summary display */
     col_set_str(pinfo->cinfo, COL_PROTOCOL, "MIPv6");
@@ -4080,6 +4079,7 @@ dissect_mip6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
     if (pinfo->dst.type == AT_IPv6) {
         ipv6_pinfo_t *ipv6_pinfo = p_get_ipv6_pinfo(pinfo);
 
+        ipv6_pinfo->frag_plen -= len;
         if (ipv6_pinfo->ipv6_tree != NULL) {
             root_tree = ipv6_pinfo->ipv6_tree;
             ipv6_pinfo->ipv6_item_len += len;
@@ -4215,31 +4215,16 @@ dissect_mip6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
         dissect_mip6_options(tvb, mip6_tree, offset, len, pinfo);
     }
 
-    /*
-     * XXX - why are we doing this?  We're not guaranteed that there's
-     * a ws_ip structure to modify here, as we can be called not only
-     * from the IPv4 or IPv6 dissectors, but also from, for example,
-     * the AH and ESP dissectors.
-     *
-     * This needs to be rethought.
-     */
-    if (iph != NULL)
-        iph->ip_nxt = pproto;
-
     if ((type == MIP6_FNA) && (pproto == IP_PROTO_IPV6)) {
         col_set_str(pinfo->cinfo, COL_INFO, "Fast Neighbor Advertisement[Fast Binding Update]");
         next_tvb = tvb_new_subset_remaining(tvb, len + 8);
-        if (iph != NULL)
-            iph->ip_len -= len + 8;
-        ipv6_dissect_next(pproto, next_tvb, pinfo, tree, iph);
+        ipv6_dissect_next(pproto, next_tvb, pinfo, tree, (ws_ip *)data);
     }
 
     if ((type == MIP6_FBACK) && (pproto == IP_PROTO_AH)) {
         col_set_str(pinfo->cinfo, COL_INFO, "Fast Binding Acknowledgment");
         next_tvb = tvb_new_subset_remaining(tvb, len + offset);
-        if (iph != NULL)
-            iph->ip_len -= len + offset;
-        ipv6_dissect_next(pproto, next_tvb, pinfo, tree, iph);
+        ipv6_dissect_next(pproto, next_tvb, pinfo, tree, (ws_ip *)data);
     }
 
     return tvb_captured_length(tvb);
index e439a2c5b4d9ee1b8f814b0a2eeb217b8fd549e9..fe9b3fb575d7a54f7204b7e7f3dcc8830427ac2c 100644 (file)
@@ -572,7 +572,6 @@ dissect_shim6(tvbuff_t *tvb, packet_info * pinfo, proto_tree *tree, void* data)
     proto_item      *ti, *ti_len;
     guint8           tmp[5];
     tvbuff_t        *next_tvb;
-    ws_ip           *iph = (ws_ip *)data;
 
     tvb_memcpy(tvb, (guint8 *)&shim, offset, sizeof(shim));
     len = (shim.ip6s_len + 1) << 3;
@@ -589,6 +588,7 @@ dissect_shim6(tvbuff_t *tvb, packet_info * pinfo, proto_tree *tree, void* data)
     if (pinfo->dst.type == AT_IPv6) {
         ipv6_pinfo_t *ipv6_pinfo = p_get_ipv6_pinfo(pinfo);
 
+        ipv6_pinfo->frag_plen -= len;
         if (ipv6_pinfo->ipv6_tree != NULL) {
             root_tree = ipv6_pinfo->ipv6_tree;
             ipv6_pinfo->ipv6_item_len += len;
@@ -663,12 +663,8 @@ dissect_shim6(tvbuff_t *tvb, packet_info * pinfo, proto_tree *tree, void* data)
         }
     }
 
-    if (iph != NULL) {
-        iph->ip_nxt = shim.ip6s_nxt;
-        iph->ip_len -= len;
-    }
     next_tvb = tvb_new_subset_remaining(tvb, len);
-    ipv6_dissect_next(shim.ip6s_nxt, next_tvb, pinfo, tree, iph);
+    ipv6_dissect_next(shim.ip6s_nxt, next_tvb, pinfo, tree, (ws_ip *)data);
     return tvb_captured_length(tvb);
 }