]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
defrag: stop reassembly at the first packet with more flags not set
authorJason Ish <ish@unx.ca>
Thu, 27 Aug 2015 19:59:30 +0000 (13:59 -0600)
committerVictor Julien <victor@inliniac.net>
Thu, 8 Oct 2015 08:35:45 +0000 (10:35 +0200)
src/defrag.c

index 6f0260e3ef0bbe561e13dce7cdc18b5041921be9..956fe7ded4da7a23e869fa464c7e76102e787dd5 100644 (file)
@@ -337,6 +337,10 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
             if (frag->offset + frag->data_len > fragmentable_len)
                 fragmentable_len = frag->offset + frag->data_len;
         }
+
+        if (!frag->more_frags) {
+            break;
+        }
     }
 
     SCLogDebug("ip_hdr_offset %u, hlen %u, fragmentable_len %u",
@@ -460,6 +464,10 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
             if (frag->offset + frag->data_len > fragmentable_len)
                 fragmentable_len = frag->offset + frag->data_len;
         }
+
+        if (!frag->more_frags) {
+            break;
+        }
     }
 
     rp->ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
@@ -747,6 +755,7 @@ insert:
     new->data_len = data_len - ltrim;
     new->ip_hdr_offset = ip_hdr_offset;
     new->frag_hdr_offset = frag_hdr_offset;
+    new->more_frags = more_frags;
 #ifdef DEBUG
     new->pcap_cnt = pcap_cnt;
 #endif
@@ -2392,6 +2401,132 @@ end:
     return ret;
 }
 
+/**
+ * IPV4: Test the case where you have a packet fragmented in 3 parts
+ * and send like:
+ * - Offset: 2; MF: 1
+ * - Offset: 0; MF: 1
+ * - Offset: 1; MF: 0
+ *
+ * Only the fragments with offset 0 and 1 should be reassembled.
+ */
+static int DefragMfIpv4Test(void)
+{
+    int retval = 0;
+    int ip_id = 9;
+
+    DefragInit();
+
+    Packet *p1 = BuildTestPacket(ip_id, 2, 1, 'C', 8);
+    Packet *p2 = BuildTestPacket(ip_id, 0, 1, 'A', 8);
+    Packet *p3 = BuildTestPacket(ip_id, 1, 0, 'B', 8);
+    if (p1 == NULL || p2 == NULL || p3 == NULL) {
+        goto end;
+    }
+
+    Packet *p = Defrag(NULL, NULL, p1, NULL);
+    if (p != NULL) {
+        goto end;
+    }
+
+    p = Defrag(NULL, NULL, p2, NULL);
+    if (p != NULL) {
+        goto end;
+    }
+
+    /* This should return a packet as MF=0. */
+    p = Defrag(NULL, NULL, p3, NULL);
+    if (p == NULL) {
+        goto end;
+    }
+
+    /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
+     * fragments should be in the re-assembled packet. */
+    if (IPV4_GET_IPLEN(p) != 36) {
+        goto end;
+    }
+
+    retval = 1;
+end:
+    if (p1 != NULL) {
+        SCFree(p1);
+    }
+    if (p2 != NULL) {
+        SCFree(p2);
+    }
+    if (p3 != NULL) {
+        SCFree(p3);
+    }
+    if (p != NULL) {
+        SCFree(p);
+    }
+    DefragDestroy();
+    return retval;
+}
+
+/**
+ * IPV6: Test the case where you have a packet fragmented in 3 parts
+ * and send like:
+ * - Offset: 2; MF: 1
+ * - Offset: 0; MF: 1
+ * - Offset: 1; MF: 0
+ *
+ * Only the fragments with offset 0 and 1 should be reassembled.
+ */
+static int DefragMfIpv6Test(void)
+{
+    int retval = 0;
+    int ip_id = 9;
+
+    DefragInit();
+
+    Packet *p1 = IPV6BuildTestPacket(ip_id, 2, 1, 'C', 8);
+    Packet *p2 = IPV6BuildTestPacket(ip_id, 0, 1, 'A', 8);
+    Packet *p3 = IPV6BuildTestPacket(ip_id, 1, 0, 'B', 8);
+    if (p1 == NULL || p2 == NULL || p3 == NULL) {
+        goto end;
+    }
+
+    Packet *p = Defrag(NULL, NULL, p1, NULL);
+    if (p != NULL) {
+        goto end;
+    }
+
+    p = Defrag(NULL, NULL, p2, NULL);
+    if (p != NULL) {
+        goto end;
+    }
+
+    /* This should return a packet as MF=0. */
+    p = Defrag(NULL, NULL, p3, NULL);
+    if (p == NULL) {
+        goto end;
+    }
+
+    /* For IPv6 the expected length is just the length of the payload
+     * of 2 fragments, so 16. */
+    if (IPV6_GET_PLEN(p) != 16) {
+        goto end;
+    }
+
+    retval = 1;
+end:
+    if (p1 != NULL) {
+        SCFree(p1);
+    }
+    if (p2 != NULL) {
+        SCFree(p2);
+    }
+    if (p3 != NULL) {
+        SCFree(p3);
+    }
+    if (p != NULL) {
+        SCFree(p);
+    }
+    DefragDestroy();
+    return retval;
+}
+
 #endif /* UNITTESTS */
 
 void
@@ -2437,11 +2572,11 @@ DefragRegisterTests(void)
 
     UtRegisterTest("DefragVlanTest", DefragVlanTest, 1);
     UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest, 1);
-
     UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest, 1);
-
     UtRegisterTest("DefragTimeoutTest",
         DefragTimeoutTest, 1);
+    UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test, 1);
+    UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test, 1);
 #endif /* UNITTESTS */
 }