From: Jason Ish Date: Thu, 27 Aug 2015 19:59:30 +0000 (-0600) Subject: defrag: stop reassembly at the first packet with more flags not set X-Git-Tag: suricata-3.0RC1~76 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f223c6dba2f62550ad6bece750d4dded2041858;p=thirdparty%2Fsuricata.git defrag: stop reassembly at the first packet with more flags not set --- diff --git a/src/defrag.c b/src/defrag.c index 6f0260e3ef..956fe7ded4 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -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 */ }