diff --git a/src/defrag.c b/src/defrag.c index 594c9d0dd9..fede1b927a 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -256,7 +256,8 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) goto done; } else { - len += frag->data_len; + /* Update the packet length to the largest known data offset. */ + len = MAX(len, frag->offset + frag->data_len); } } @@ -414,7 +415,7 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) goto done; } else { - len += frag->data_len; + len = MAX(len, frag->offset + frag->data_len); } } } @@ -3057,6 +3058,116 @@ static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test(void) PASS; } +/** + * Reassembly should fail. + * + * |0 |8 |16 |24 |32 |40 |48 | + * |========|========|========|========|========|========|========| + * | | |AABBCCDD|AABBDDCC| | | | + * | | | | | |AACCBBDD| | + * | |AACCDDBB|AADDBBCC| | | | | + * |ZZZZZZZZ| | | | | | | + * | | | | | | |DDCCBBAA| + */ +static int DefragBsdMissingFragmentIpv4Test(void) +{ + DefragInit(); + default_policy = DEFRAG_POLICY_BSD; + Packet *packets[5]; + + FAIL_IF_NOT(BuildIpv4TestPacketWithContent( + &packets[0], IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16)); + + FAIL_IF_NOT(BuildIpv4TestPacketWithContent( + &packets[1], IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8)); + + FAIL_IF_NOT(BuildIpv4TestPacketWithContent( + &packets[2], IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16)); + + /* ICMP header. */ + FAIL_IF_NOT(BuildIpv4TestPacketWithContent( + &packets[3], IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8)); + + FAIL_IF_NOT(BuildIpv4TestPacketWithContent( + &packets[4], IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8)); + + Packet *r = Defrag(NULL, NULL, packets[0]); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[1]); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[2]); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[3]); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[4]); + FAIL_IF_NOT_NULL(r); + +#if 0 + PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20); +#endif + + for (int i = 0; i < 5; i++) { + SCFree(packets[i]); + } + + DefragDestroy(); + + PASS; +} + +static int DefragBsdMissingFragmentIpv6Test(void) +{ + DefragInit(); + default_policy = DEFRAG_POLICY_BSD; + Packet *packets[5]; + + packets[0] = BuildIpv6TestPacketWithContent( + IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16); + + packets[1] = + BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8); + + packets[2] = BuildIpv6TestPacketWithContent( + IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16); + + /* ICMP header. */ + packets[3] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8); + + packets[4] = + BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8); + + Packet *r = Defrag(NULL, NULL, packets[0]); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[1]); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[2]); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[3]); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[4]); + FAIL_IF_NOT_NULL(r); + +#if 0 + PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40); +#endif + + for (int i = 0; i < 5; i++) { + SCFree(packets[i]); + } + + DefragDestroy(); + + PASS; +} + #endif /* UNITTESTS */ void DefragRegisterTests(void) @@ -3107,5 +3218,7 @@ void DefragRegisterTests(void) DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2); UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2", DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2); + UtRegisterTest("DefragBsdMissingFragmentIpv4Test", DefragBsdMissingFragmentIpv4Test); + UtRegisterTest("DefragBsdMissingFragmentIpv6Test", DefragBsdMissingFragmentIpv6Test); #endif /* UNITTESTS */ }