You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/src/defrag.c

2591 lines
65 KiB
C

/* Copyright (C) 2007-2012 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Endace Technology Limited, Jason Ish <jason.ish@endace.com>
*
* Defragmentation module.
* References:
* - RFC 815
* - OpenBSD PF's IP normalizaton (pf_norm.c)
*
* \todo pool for frag packet storage
* \todo policy bsd-right
* \todo profile hash function
* \todo log anomalies
*/
#include "suricata-common.h"
#include "queue.h"
#include "suricata.h"
#include "threads.h"
#include "conf.h"
#include "decode-ipv6.h"
#include "util-hashlist.h"
#include "util-pool.h"
#include "util-time.h"
#include "util-print.h"
#include "util-debug.h"
#include "util-fix_checksum.h"
#include "util-random.h"
#include "stream-tcp-private.h"
#include "stream-tcp-reassemble.h"
#include "util-host-os-info.h"
#include "defrag.h"
#include "defrag-hash.h"
#include "defrag-queue.h"
#include "defrag-config.h"
#include "tmqh-packetpool.h"
#include "decode.h"
#ifdef UNITTESTS
#include "util-unittest.h"
#endif
#define DEFAULT_DEFRAG_HASH_SIZE 0xffff
#define DEFAULT_DEFRAG_POOL_SIZE 0xffff
/**
* Default timeout (in seconds) before a defragmentation tracker will
* be released.
*/
#define TIMEOUT_DEFAULT 60
/**
* Maximum allowed timeout, 24 hours.
*/
#define TIMEOUT_MAX (60 * 60 * 24)
/**
* Minimum allowed timeout, 1 second.
*/
#define TIMEOUT_MIN 1
/** Fragment reassembly policies. */
enum defrag_policies {
DEFRAG_POLICY_FIRST = 1,
DEFRAG_POLICY_LAST,
DEFRAG_POLICY_BSD,
DEFRAG_POLICY_BSD_RIGHT,
DEFRAG_POLICY_LINUX,
DEFRAG_POLICY_WINDOWS,
DEFRAG_POLICY_SOLARIS,
DEFRAG_POLICY_DEFAULT = DEFRAG_POLICY_BSD,
};
static int default_policy = DEFRAG_POLICY_BSD;
/** The global DefragContext so all threads operate from the same
* context. */
static DefragContext *defrag_context;
/**
* Utility/debugging function to dump the frags associated with a
* tracker. Only enable when unit tests are enabled.
*/
#if 0
#ifdef UNITTESTS
static void
DumpFrags(DefragTracker *tracker)
{
Frag *frag;
printf("Dumping frags for packet: ID=%d\n", tracker->id);
TAILQ_FOREACH(frag, &tracker->frags, next) {
printf("-> Frag: frag_offset=%d, frag_len=%d, data_len=%d, ltrim=%d, skip=%d\n", frag->offset, frag->len, frag->data_len, frag->ltrim, frag->skip);
PrintRawDataFp(stdout, frag->pkt, frag->len);
}
}
#endif /* UNITTESTS */
#endif
/**
* \brief Reset a frag for reuse in a pool.
*/
static void
DefragFragReset(Frag *frag)
{
if (frag->pkt != NULL)
SCFree(frag->pkt);
memset(frag, 0, sizeof(*frag));
}
/**
* \brief Allocate a new frag for use in a pool.
*/
static int
DefragFragInit(void *data, void *initdata)
{
Frag *frag = data;
memset(frag, 0, sizeof(*frag));
return 1;
}
/**
* \brief Free all frags associated with a tracker.
*/
void
DefragTrackerFreeFrags(DefragTracker *tracker)
{
Frag *frag;
/* Lock the frag pool as we'll be return items to it. */
SCMutexLock(&defrag_context->frag_pool_lock);
while ((frag = TAILQ_FIRST(&tracker->frags)) != NULL) {
TAILQ_REMOVE(&tracker->frags, frag, next);
/* Don't SCFree the frag, just give it back to its pool. */
DefragFragReset(frag);
PoolReturn(defrag_context->frag_pool, frag);
}
SCMutexUnlock(&defrag_context->frag_pool_lock);
}
/**
* \brief Create a new DefragContext.
*
* \retval On success a return an initialized DefragContext, otherwise
* NULL will be returned.
*/
static DefragContext *
DefragContextNew(void)
{
DefragContext *dc;
dc = SCCalloc(1, sizeof(*dc));
if (unlikely(dc == NULL))
return NULL;
/* Initialize the pool of trackers. */
intmax_t tracker_pool_size;
if (!ConfGetInt("defrag.trackers", &tracker_pool_size) || tracker_pool_size == 0) {
tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
}
/* Initialize the pool of frags. */
intmax_t frag_pool_size;
if (!ConfGetInt("defrag.max-frags", &frag_pool_size) || frag_pool_size == 0) {
frag_pool_size = DEFAULT_DEFRAG_POOL_SIZE;
}
intmax_t frag_pool_prealloc = frag_pool_size / 2;
dc->frag_pool = PoolInit(frag_pool_size, frag_pool_prealloc,
sizeof(Frag),
NULL, DefragFragInit, dc, NULL, NULL);
if (dc->frag_pool == NULL) {
SCLogError(SC_ERR_MEM_ALLOC,
"Defrag: Failed to initialize fragment pool.");
exit(EXIT_FAILURE);
}
if (SCMutexInit(&dc->frag_pool_lock, NULL) != 0) {
SCLogError(SC_ERR_MUTEX,
"Defrag: Failed to initialize frag pool mutex.");
exit(EXIT_FAILURE);
}
/* Set the default timeout. */
intmax_t timeout;
if (!ConfGetInt("defrag.timeout", &timeout)) {
dc->timeout = TIMEOUT_DEFAULT;
}
else {
if (timeout < TIMEOUT_MIN) {
SCLogError(SC_ERR_INVALID_ARGUMENT,
"defrag: Timeout less than minimum allowed value.");
exit(EXIT_FAILURE);
}
else if (timeout > TIMEOUT_MAX) {
SCLogError(SC_ERR_INVALID_ARGUMENT,
"defrag: Tiemout greater than maximum allowed value.");
exit(EXIT_FAILURE);
}
dc->timeout = timeout;
}
SCLogDebug("Defrag Initialized:");
SCLogDebug("\tTimeout: %"PRIuMAX, (uintmax_t)dc->timeout);
SCLogDebug("\tMaximum defrag trackers: %"PRIuMAX, tracker_pool_size);
SCLogDebug("\tPreallocated defrag trackers: %"PRIuMAX, tracker_pool_size);
SCLogDebug("\tMaximum fragments: %"PRIuMAX, (uintmax_t)frag_pool_size);
SCLogDebug("\tPreallocated fragments: %"PRIuMAX, (uintmax_t)frag_pool_prealloc);
return dc;
}
static void
DefragContextDestroy(DefragContext *dc)
{
if (dc == NULL)
return;
PoolFree(dc->frag_pool);
SCFree(dc);
}
/**
* Attempt to re-assemble a packet.
*
* \param tracker The defragmentation tracker to reassemble from.
*/
static Packet *
Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
{
Packet *rp = NULL;
/* Should not be here unless we have seen the last fragment. */
if (!tracker->seen_last)
return NULL;
/* Check that we have all the data. Relies on the fact that
* fragments are inserted if frag_offset order. */
Frag *frag;
int len = 0;
TAILQ_FOREACH(frag, &tracker->frags, next) {
if (frag->skip)
continue;
if (frag == TAILQ_FIRST(&tracker->frags)) {
if (frag->offset != 0) {
goto done;
}
len = frag->data_len;
}
else {
if (frag->offset > len) {
/* This fragment starts after the end of the previous
* fragment. We have a hole. */
goto done;
}
else {
len += frag->data_len;
}
}
}
/* Allocate a Packet for the reassembled packet. On failure we
* SCFree all the resources held by this tracker. */
rp = PacketDefragPktSetup(p, NULL, 0, IPV4_GET_IPPROTO(p));
if (rp == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for "
"fragmentation re-assembly, dumping fragments.");
goto error_remove_tracker;
}
PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
rp->recursion_level = p->recursion_level;
int fragmentable_offset = 0;
int fragmentable_len = 0;
int hlen = 0;
int ip_hdr_offset = 0;
TAILQ_FOREACH(frag, &tracker->frags, next) {
SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
frag, frag->data_len, frag->offset, frag->pcap_cnt);
if (frag->skip)
continue;
if (frag->data_len - frag->ltrim <= 0)
continue;
if (frag->offset == 0) {
if (PacketCopyData(rp, frag->pkt, frag->len) == -1)
goto error_remove_tracker;
hlen = frag->hlen;
ip_hdr_offset = frag->ip_hdr_offset;
/* This is the start of the fragmentable portion of the
* first packet. All fragment offsets are relative to
* this. */
fragmentable_offset = frag->ip_hdr_offset + frag->hlen;
fragmentable_len = frag->data_len;
}
else {
int pkt_end = fragmentable_offset + frag->offset + frag->data_len;
if (pkt_end > (int)MAX_PAYLOAD_SIZE) {
SCLogWarning(SC_ERR_REASSEMBLY, "Failed re-assemble "
"fragmented packet, exceeds size of packet buffer.");
goto error_remove_tracker;
}
if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim,
frag->pkt + frag->data_offset + frag->ltrim,
frag->data_len - frag->ltrim) == -1) {
goto error_remove_tracker;
}
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",
ip_hdr_offset, hlen, fragmentable_len);
rp->ip4h = (IPV4Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
int old = rp->ip4h->ip_len + rp->ip4h->ip_off;
rp->ip4h->ip_len = htons(fragmentable_len + hlen);
rp->ip4h->ip_off = 0;
rp->ip4h->ip_csum = FixChecksum(rp->ip4h->ip_csum,
old, rp->ip4h->ip_len + rp->ip4h->ip_off);
SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len);
tracker->remove = 1;
DefragTrackerFreeFrags(tracker);
done:
return rp;
error_remove_tracker:
tracker->remove = 1;
DefragTrackerFreeFrags(tracker);
if (rp != NULL)
PacketFreeOrRelease(rp);
return NULL;
}
/**
* Attempt to re-assemble a packet.
*
* \param tracker The defragmentation tracker to reassemble from.
*/
static Packet *
Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
{
Packet *rp = NULL;
/* Should not be here unless we have seen the last fragment. */
if (!tracker->seen_last)
return NULL;
/* Check that we have all the data. Relies on the fact that
* fragments are inserted if frag_offset order. */
Frag *frag;
int len = 0;
TAILQ_FOREACH(frag, &tracker->frags, next) {
if (frag->skip)
continue;
if (frag == TAILQ_FIRST(&tracker->frags)) {
if (frag->offset != 0) {
goto done;
}
len = frag->data_len;
}
else {
if (frag->offset > len) {
/* This fragment starts after the end of the previous
* fragment. We have a hole. */
goto done;
}
else {
len += frag->data_len;
}
}
}
/* Allocate a Packet for the reassembled packet. On failure we
* SCFree all the resources held by this tracker. */
rp = PacketDefragPktSetup(p, (uint8_t *)p->ip6h,
IPV6_GET_PLEN(p) + sizeof(IPV6Hdr), 0);
if (rp == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for "
"fragmentation re-assembly, dumping fragments.");
goto error_remove_tracker;
}
PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
ipv6 defrag: fix unfragmentable exthdr handling Fix or rather implement handling of unfragmentable exthdrs in ipv6. The exthdr(s) appearing before the frag header were copied into the reassembled packet correctly, however the stripping of the frag header did not work correctly. Example: The common case is a frag header directly after the ipv6 header: [ipv6 header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[frag header]->[icmpv6 (part2)] This would result in: [ipv6 header]->[icmpv6] The ipv6 headers 'next header' setting would be updated to point to whatever the frag header was pointing to. This would also happen when is this case: [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part2)] The result would be: [ipv6 header]->[hop header]->[icmpv6] However, here too the ipv6 header would have been updated to point to what the frag header pointed at. So it would consider the hop header as if it was an ICMPv6 header, or whatever the frag header pointed at. The result is that packets would not be correctly parsed, and thus this issue can lead to evasion. This patch implements handling of the unfragmentable part. In the first segment that is stored in the list for reassembly, this patch detects unfragmentable headers and updates it to have the last unfragmentable header point to the layer after the frag header. Also, the ipv6 headers 'next hdr' is only updated if no unfragmentable headers are used. If they are used, the original value is correct. Reported-By: Rafael Schaefer <rschaefer@ernw.de> Bug #1244.
11 years ago
int unfragmentable_len = 0;
int fragmentable_offset = 0;
int fragmentable_len = 0;
int ip_hdr_offset = 0;
uint8_t next_hdr = 0;
TAILQ_FOREACH(frag, &tracker->frags, next) {
if (frag->skip)
continue;
if (frag->data_len - frag->ltrim <= 0)
continue;
if (frag->offset == 0) {
IPV6FragHdr *frag_hdr = (IPV6FragHdr *)(frag->pkt +
frag->frag_hdr_offset);
next_hdr = frag_hdr->ip6fh_nxt;
/* This is the first packet, we use this packets link and
* IPv6 headers. We also copy in its data, but remove the
* fragmentation header. */
if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1)
goto error_remove_tracker;
if (PacketCopyDataOffset(rp, frag->frag_hdr_offset,
frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr),
frag->data_len) == -1)
goto error_remove_tracker;
ip_hdr_offset = frag->ip_hdr_offset;
/* This is the start of the fragmentable portion of the
* first packet. All fragment offsets are relative to
* this. */
fragmentable_offset = frag->frag_hdr_offset;
fragmentable_len = frag->data_len;
ipv6 defrag: fix unfragmentable exthdr handling Fix or rather implement handling of unfragmentable exthdrs in ipv6. The exthdr(s) appearing before the frag header were copied into the reassembled packet correctly, however the stripping of the frag header did not work correctly. Example: The common case is a frag header directly after the ipv6 header: [ipv6 header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[frag header]->[icmpv6 (part2)] This would result in: [ipv6 header]->[icmpv6] The ipv6 headers 'next header' setting would be updated to point to whatever the frag header was pointing to. This would also happen when is this case: [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part2)] The result would be: [ipv6 header]->[hop header]->[icmpv6] However, here too the ipv6 header would have been updated to point to what the frag header pointed at. So it would consider the hop header as if it was an ICMPv6 header, or whatever the frag header pointed at. The result is that packets would not be correctly parsed, and thus this issue can lead to evasion. This patch implements handling of the unfragmentable part. In the first segment that is stored in the list for reassembly, this patch detects unfragmentable headers and updates it to have the last unfragmentable header point to the layer after the frag header. Also, the ipv6 headers 'next hdr' is only updated if no unfragmentable headers are used. If they are used, the original value is correct. Reported-By: Rafael Schaefer <rschaefer@ernw.de> Bug #1244.
11 years ago
/* unfragmentable part is the part between the ipv6 header
* and the frag header. */
unfragmentable_len = (fragmentable_offset - ip_hdr_offset) - IPV6_HEADER_LEN;
if (unfragmentable_len >= fragmentable_offset)
goto error_remove_tracker;
}
else {
if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim,
frag->pkt + frag->data_offset + frag->ltrim,
frag->data_len - frag->ltrim) == -1)
goto error_remove_tracker;
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);
ipv6 defrag: fix unfragmentable exthdr handling Fix or rather implement handling of unfragmentable exthdrs in ipv6. The exthdr(s) appearing before the frag header were copied into the reassembled packet correctly, however the stripping of the frag header did not work correctly. Example: The common case is a frag header directly after the ipv6 header: [ipv6 header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[frag header]->[icmpv6 (part2)] This would result in: [ipv6 header]->[icmpv6] The ipv6 headers 'next header' setting would be updated to point to whatever the frag header was pointing to. This would also happen when is this case: [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part2)] The result would be: [ipv6 header]->[hop header]->[icmpv6] However, here too the ipv6 header would have been updated to point to what the frag header pointed at. So it would consider the hop header as if it was an ICMPv6 header, or whatever the frag header pointed at. The result is that packets would not be correctly parsed, and thus this issue can lead to evasion. This patch implements handling of the unfragmentable part. In the first segment that is stored in the list for reassembly, this patch detects unfragmentable headers and updates it to have the last unfragmentable header point to the layer after the frag header. Also, the ipv6 headers 'next hdr' is only updated if no unfragmentable headers are used. If they are used, the original value is correct. Reported-By: Rafael Schaefer <rschaefer@ernw.de> Bug #1244.
11 years ago
rp->ip6h->s_ip6_plen = htons(fragmentable_len + unfragmentable_len);
/* if we have no unfragmentable part, so no ext hdrs before the frag
* header, we need to update the ipv6 headers next header field. This
* points to the frag header, and we will make it point to the layer
* directly after the frag header. */
if (unfragmentable_len == 0)
rp->ip6h->s_ip6_nxt = next_hdr;
SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) +
unfragmentable_len + fragmentable_len);
tracker->remove = 1;
DefragTrackerFreeFrags(tracker);
done:
return rp;
error_remove_tracker:
tracker->remove = 1;
DefragTrackerFreeFrags(tracker);
if (rp != NULL)
PacketFreeOrRelease(rp);
return NULL;
}
/**
* Insert a new IPv4/IPv6 fragment into a tracker.
*
* \todo Allocate packet buffers from a pool.
*/
static Packet *
DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p, PacketQueue *pq)
{
Packet *r = NULL;
int ltrim = 0;
uint8_t more_frags;
uint16_t frag_offset;
/* IPv4 header length - IPv4 only. */
uint16_t hlen = 0;
/* This is the offset of the start of the data in the packet that
* falls after the IP header. */
uint16_t data_offset;
/* The length of the (fragmented) data. This is the length of the
* data that falls after the IP header. */
uint16_t data_len;
/* Where the fragment ends. */
uint16_t frag_end;
/* Offset in the packet to the IPv6 header. */
uint16_t ip_hdr_offset;
/* Offset in the packet to the IPv6 frag header. IPv6 only. */
uint16_t frag_hdr_offset = 0;
/* Address family */
int af = tracker->af;
ipv6 defrag: fix unfragmentable exthdr handling Fix or rather implement handling of unfragmentable exthdrs in ipv6. The exthdr(s) appearing before the frag header were copied into the reassembled packet correctly, however the stripping of the frag header did not work correctly. Example: The common case is a frag header directly after the ipv6 header: [ipv6 header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[frag header]->[icmpv6 (part2)] This would result in: [ipv6 header]->[icmpv6] The ipv6 headers 'next header' setting would be updated to point to whatever the frag header was pointing to. This would also happen when is this case: [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part2)] The result would be: [ipv6 header]->[hop header]->[icmpv6] However, here too the ipv6 header would have been updated to point to what the frag header pointed at. So it would consider the hop header as if it was an ICMPv6 header, or whatever the frag header pointed at. The result is that packets would not be correctly parsed, and thus this issue can lead to evasion. This patch implements handling of the unfragmentable part. In the first segment that is stored in the list for reassembly, this patch detects unfragmentable headers and updates it to have the last unfragmentable header point to the layer after the frag header. Also, the ipv6 headers 'next hdr' is only updated if no unfragmentable headers are used. If they are used, the original value is correct. Reported-By: Rafael Schaefer <rschaefer@ernw.de> Bug #1244.
11 years ago
/* settings for updating a payload when an ip6 fragment with
* unfragmentable exthdrs are encountered. */
int ip6_nh_set_offset = 0;
uint8_t ip6_nh_set_value = 0;
#ifdef DEBUG
uint64_t pcap_cnt = p->pcap_cnt;
#endif
if (tracker->af == AF_INET) {
more_frags = IPV4_GET_MF(p);
frag_offset = IPV4_GET_IPOFFSET(p) << 3;
hlen = IPV4_GET_HLEN(p);
data_offset = (uint8_t *)p->ip4h + hlen - GET_PKT_DATA(p);
data_len = IPV4_GET_IPLEN(p) - hlen;
frag_end = frag_offset + data_len;
ip_hdr_offset = (uint8_t *)p->ip4h - GET_PKT_DATA(p);
/* Ignore fragment if the end of packet extends past the
* maximum size of a packet. */
if (IPV4_HEADER_LEN + frag_offset + data_len > IPV4_MAXPACKET_LEN) {
ENGINE_SET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE);
return NULL;
}
}
else if (tracker->af == AF_INET6) {
more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
data_offset = p->ip6eh.fh_data_offset;
data_len = p->ip6eh.fh_data_len;
frag_end = frag_offset + data_len;
ip_hdr_offset = (uint8_t *)p->ip6h - GET_PKT_DATA(p);
frag_hdr_offset = p->ip6eh.fh_header_offset;
SCLogDebug("mf %s frag_offset %u data_offset %u, data_len %u, "
"frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u",
more_frags ? "true" : "false", frag_offset, data_offset,
data_len, frag_end, ip_hdr_offset, frag_hdr_offset);
ipv6 defrag: fix unfragmentable exthdr handling Fix or rather implement handling of unfragmentable exthdrs in ipv6. The exthdr(s) appearing before the frag header were copied into the reassembled packet correctly, however the stripping of the frag header did not work correctly. Example: The common case is a frag header directly after the ipv6 header: [ipv6 header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[frag header]->[icmpv6 (part2)] This would result in: [ipv6 header]->[icmpv6] The ipv6 headers 'next header' setting would be updated to point to whatever the frag header was pointing to. This would also happen when is this case: [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part2)] The result would be: [ipv6 header]->[hop header]->[icmpv6] However, here too the ipv6 header would have been updated to point to what the frag header pointed at. So it would consider the hop header as if it was an ICMPv6 header, or whatever the frag header pointed at. The result is that packets would not be correctly parsed, and thus this issue can lead to evasion. This patch implements handling of the unfragmentable part. In the first segment that is stored in the list for reassembly, this patch detects unfragmentable headers and updates it to have the last unfragmentable header point to the layer after the frag header. Also, the ipv6 headers 'next hdr' is only updated if no unfragmentable headers are used. If they are used, the original value is correct. Reported-By: Rafael Schaefer <rschaefer@ernw.de> Bug #1244.
11 years ago
/* handle unfragmentable exthdrs */
if (ip_hdr_offset + IPV6_HEADER_LEN < frag_hdr_offset) {
SCLogDebug("we have exthdrs before fraghdr %u bytes",
(uint32_t)(frag_hdr_offset - (ip_hdr_offset + IPV6_HEADER_LEN)));
ipv6 defrag: fix unfragmentable exthdr handling Fix or rather implement handling of unfragmentable exthdrs in ipv6. The exthdr(s) appearing before the frag header were copied into the reassembled packet correctly, however the stripping of the frag header did not work correctly. Example: The common case is a frag header directly after the ipv6 header: [ipv6 header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[frag header]->[icmpv6 (part2)] This would result in: [ipv6 header]->[icmpv6] The ipv6 headers 'next header' setting would be updated to point to whatever the frag header was pointing to. This would also happen when is this case: [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part2)] The result would be: [ipv6 header]->[hop header]->[icmpv6] However, here too the ipv6 header would have been updated to point to what the frag header pointed at. So it would consider the hop header as if it was an ICMPv6 header, or whatever the frag header pointed at. The result is that packets would not be correctly parsed, and thus this issue can lead to evasion. This patch implements handling of the unfragmentable part. In the first segment that is stored in the list for reassembly, this patch detects unfragmentable headers and updates it to have the last unfragmentable header point to the layer after the frag header. Also, the ipv6 headers 'next hdr' is only updated if no unfragmentable headers are used. If they are used, the original value is correct. Reported-By: Rafael Schaefer <rschaefer@ernw.de> Bug #1244.
11 years ago
/* get the offset of the 'next' field in exthdr before the FH,
* relative to the buffer start */
/* store offset and FH 'next' value for updating frag buffer below */
ip6_nh_set_offset = p->ip6eh.fh_prev_hdr_offset;
ipv6 defrag: fix unfragmentable exthdr handling Fix or rather implement handling of unfragmentable exthdrs in ipv6. The exthdr(s) appearing before the frag header were copied into the reassembled packet correctly, however the stripping of the frag header did not work correctly. Example: The common case is a frag header directly after the ipv6 header: [ipv6 header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[frag header]->[icmpv6 (part2)] This would result in: [ipv6 header]->[icmpv6] The ipv6 headers 'next header' setting would be updated to point to whatever the frag header was pointing to. This would also happen when is this case: [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part2)] The result would be: [ipv6 header]->[hop header]->[icmpv6] However, here too the ipv6 header would have been updated to point to what the frag header pointed at. So it would consider the hop header as if it was an ICMPv6 header, or whatever the frag header pointed at. The result is that packets would not be correctly parsed, and thus this issue can lead to evasion. This patch implements handling of the unfragmentable part. In the first segment that is stored in the list for reassembly, this patch detects unfragmentable headers and updates it to have the last unfragmentable header point to the layer after the frag header. Also, the ipv6 headers 'next hdr' is only updated if no unfragmentable headers are used. If they are used, the original value is correct. Reported-By: Rafael Schaefer <rschaefer@ernw.de> Bug #1244.
11 years ago
ip6_nh_set_value = IPV6_EXTHDR_GET_FH_NH(p);
SCLogDebug("offset %d, value %u", ip6_nh_set_offset, ip6_nh_set_value);
}
/* Ignore fragment if the end of packet extends past the
* maximum size of a packet. */
if (frag_offset + data_len > IPV6_MAXPACKET) {
ENGINE_SET_EVENT(p, IPV6_FRAG_PKT_TOO_LARGE);
return NULL;
}
}
else {
/* Abort - should not happen. */
SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid address family, aborting.");
return NULL;
}
/* Update timeout. */
tracker->timeout.tv_sec = p->ts.tv_sec + tracker->host_timeout;
tracker->timeout.tv_usec = p->ts.tv_usec;
Frag *prev = NULL, *next;
int overlap = 0;
if (!TAILQ_EMPTY(&tracker->frags)) {
TAILQ_FOREACH(prev, &tracker->frags, next) {
ltrim = 0;
next = TAILQ_NEXT(prev, next);
switch (tracker->policy) {
case DEFRAG_POLICY_BSD:
if (frag_offset < prev->offset + prev->data_len) {
if (frag_offset >= prev->offset) {
ltrim = prev->offset + prev->data_len - frag_offset;
overlap++;
}
if ((next != NULL) && (frag_end > next->offset)) {
next->ltrim = frag_end - next->offset;
overlap++;
}
if ((frag_offset < prev->offset) &&
(frag_end >= prev->offset + prev->data_len)) {
prev->skip = 1;
overlap++;
}
goto insert;
}
break;
case DEFRAG_POLICY_LINUX:
if (frag_offset < prev->offset + prev->data_len) {
if (frag_offset > prev->offset) {
ltrim = prev->offset + prev->data_len - frag_offset;
overlap++;
}
if ((next != NULL) && (frag_end > next->offset)) {
next->ltrim = frag_end - next->offset;
overlap++;
}
if ((frag_offset < prev->offset) &&
(frag_end >= prev->offset + prev->data_len)) {
prev->skip = 1;
overlap++;
}
goto insert;
}
break;
case DEFRAG_POLICY_WINDOWS:
if (frag_offset < prev->offset + prev->data_len) {
if (frag_offset >= prev->offset) {
ltrim = prev->offset + prev->data_len - frag_offset;
overlap++;
}
if ((frag_offset < prev->offset) &&
(frag_end > prev->offset + prev->data_len)) {
prev->skip = 1;
overlap++;
}
goto insert;
}
break;
case DEFRAG_POLICY_SOLARIS:
if (frag_offset < prev->offset + prev->data_len) {
if (frag_offset >= prev->offset) {
ltrim = prev->offset + prev->data_len - frag_offset;
overlap++;
}
if ((frag_offset < prev->offset) &&
(frag_end >= prev->offset + prev->data_len)) {
prev->skip = 1;
overlap++;
}
goto insert;
}
break;
case DEFRAG_POLICY_FIRST:
if ((frag_offset >= prev->offset) &&
(frag_end <= prev->offset + prev->data_len)) {
overlap++;
goto done;
}
if (frag_offset < prev->offset) {
goto insert;
}
if (frag_offset < prev->offset + prev->data_len) {
ltrim = prev->offset + prev->data_len - frag_offset;
overlap++;
goto insert;
}
break;
case DEFRAG_POLICY_LAST:
if (frag_offset <= prev->offset) {
if (frag_end > prev->offset) {
prev->ltrim = frag_end - prev->offset;
overlap++;
}
goto insert;
}
break;
default:
break;
}
}
}
insert:
if (data_len - ltrim <= 0) {
if (af == AF_INET) {
ENGINE_SET_EVENT(p, IPV4_FRAG_TOO_LARGE);
} else {
ENGINE_SET_EVENT(p, IPV6_FRAG_TOO_LARGE);
}
goto done;
}
/* Allocate fragment and insert. */
SCMutexLock(&defrag_context->frag_pool_lock);
Frag *new = PoolGet(defrag_context->frag_pool);
SCMutexUnlock(&defrag_context->frag_pool_lock);
if (new == NULL) {
if (af == AF_INET) {
ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED);
} else {
ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED);
}
goto done;
}
new->pkt = SCMalloc(GET_PKT_LEN(p));
if (new->pkt == NULL) {
SCMutexLock(&defrag_context->frag_pool_lock);
PoolReturn(defrag_context->frag_pool, new);
SCMutexUnlock(&defrag_context->frag_pool_lock);
if (af == AF_INET) {
ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED);
} else {
ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED);
}
goto done;
}
memcpy(new->pkt, GET_PKT_DATA(p) + ltrim, GET_PKT_LEN(p) - ltrim);
new->len = GET_PKT_LEN(p) - ltrim;
ipv6 defrag: fix unfragmentable exthdr handling Fix or rather implement handling of unfragmentable exthdrs in ipv6. The exthdr(s) appearing before the frag header were copied into the reassembled packet correctly, however the stripping of the frag header did not work correctly. Example: The common case is a frag header directly after the ipv6 header: [ipv6 header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[frag header]->[icmpv6 (part2)] This would result in: [ipv6 header]->[icmpv6] The ipv6 headers 'next header' setting would be updated to point to whatever the frag header was pointing to. This would also happen when is this case: [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part1)] [ipv6 header]->[hop header]->[frag header]->[icmpv6 (part2)] The result would be: [ipv6 header]->[hop header]->[icmpv6] However, here too the ipv6 header would have been updated to point to what the frag header pointed at. So it would consider the hop header as if it was an ICMPv6 header, or whatever the frag header pointed at. The result is that packets would not be correctly parsed, and thus this issue can lead to evasion. This patch implements handling of the unfragmentable part. In the first segment that is stored in the list for reassembly, this patch detects unfragmentable headers and updates it to have the last unfragmentable header point to the layer after the frag header. Also, the ipv6 headers 'next hdr' is only updated if no unfragmentable headers are used. If they are used, the original value is correct. Reported-By: Rafael Schaefer <rschaefer@ernw.de> Bug #1244.
11 years ago
/* in case of unfragmentable exthdrs, update the 'next hdr' field
* in the raw buffer so the reassembled packet will point to the
* correct next header after stripping the frag header */
if (ip6_nh_set_offset > 0 && frag_offset == 0 && ltrim == 0) {
if (new->len > ip6_nh_set_offset) {
SCLogDebug("updating frag to have 'correct' nh value: %u -> %u",
new->pkt[ip6_nh_set_offset], ip6_nh_set_value);
new->pkt[ip6_nh_set_offset] = ip6_nh_set_value;
}
}
new->hlen = hlen;
new->offset = frag_offset + ltrim;
new->data_offset = data_offset;
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
Frag *frag;
TAILQ_FOREACH(frag, &tracker->frags, next) {
if (new->offset < frag->offset)
break;
}
if (frag == NULL) {
TAILQ_INSERT_TAIL(&tracker->frags, new, next);
}
else {
TAILQ_INSERT_BEFORE(frag, new, next);
}
if (!more_frags) {
tracker->seen_last = 1;
}
if (tracker->seen_last) {
if (tracker->af == AF_INET) {
r = Defrag4Reassemble(tv, tracker, p);
if (r != NULL && tv != NULL && dtv != NULL) {
StatsIncr(tv, dtv->counter_defrag_ipv4_reassembled);
if (pq && DecodeIPV4(tv, dtv, r, (void *)r->ip4h,
IPV4_GET_IPLEN(r), pq) != TM_ECODE_OK) {
UNSET_TUNNEL_PKT(r);
r->root = NULL;
TmqhOutputPacketpool(tv, r);
r = NULL;
} else {
PacketDefragPktSetupParent(p);
}
}
}
else if (tracker->af == AF_INET6) {
r = Defrag6Reassemble(tv, tracker, p);
if (r != NULL && tv != NULL && dtv != NULL) {
StatsIncr(tv, dtv->counter_defrag_ipv6_reassembled);
if (pq && DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h,
IPV6_GET_PLEN(r) + IPV6_HEADER_LEN,
pq) != TM_ECODE_OK) {
UNSET_TUNNEL_PKT(r);
r->root = NULL;
TmqhOutputPacketpool(tv, r);
r = NULL;
} else {
PacketDefragPktSetupParent(p);
}
}
}
}
done:
if (overlap) {
if (af == AF_INET) {
ENGINE_SET_EVENT(p, IPV4_FRAG_OVERLAP);
}
else {
ENGINE_SET_EVENT(p, IPV6_FRAG_OVERLAP);
}
}
return r;
}
/**
* \brief Get the defrag policy based on the destination address of
* the packet.
*
* \param p The packet used to get the destination address.
*
* \retval The defrag policy to use.
*/
uint8_t
DefragGetOsPolicy(Packet *p)
{
int policy = -1;
if (PKT_IS_IPV4(p)) {
policy = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
}
else if (PKT_IS_IPV6(p)) {
policy = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
}
if (policy == -1) {
return default_policy;
}
/* Map the OS policies returned from the configured host info to
* defrag specific policies. */
switch (policy) {
/* BSD. */
case OS_POLICY_BSD:
case OS_POLICY_HPUX10:
case OS_POLICY_IRIX:
return DEFRAG_POLICY_BSD;
/* BSD-Right. */
case OS_POLICY_BSD_RIGHT:
return DEFRAG_POLICY_BSD_RIGHT;
/* Linux. */
case OS_POLICY_OLD_LINUX:
case OS_POLICY_LINUX:
return DEFRAG_POLICY_LINUX;
/* First. */
case OS_POLICY_OLD_SOLARIS:
case OS_POLICY_HPUX11:
case OS_POLICY_MACOS:
case OS_POLICY_FIRST:
return DEFRAG_POLICY_FIRST;
/* Solaris. */
case OS_POLICY_SOLARIS:
return DEFRAG_POLICY_SOLARIS;
/* Windows. */
case OS_POLICY_WINDOWS:
case OS_POLICY_VISTA:
case OS_POLICY_WINDOWS2K3:
return DEFRAG_POLICY_WINDOWS;
/* Last. */
case OS_POLICY_LAST:
return DEFRAG_POLICY_LAST;
default:
return default_policy;
}
}
/** \internal
*
* \retval NULL or a *LOCKED* tracker */
static DefragTracker *
DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
{
return DefragGetTrackerFromHash(p);
}
/**
* \brief Entry point for IPv4 and IPv6 fragments.
*
* \param tv ThreadVars for the calling decoder.
* \param p The packet fragment.
*
* \retval A new Packet resembling the re-assembled packet if the most
* recent fragment allowed the packet to be re-assembled, otherwise
* NULL is returned.
*/
Packet *
Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, PacketQueue *pq)
{
uint16_t frag_offset;
uint8_t more_frags;
DefragTracker *tracker;
int af;
if (PKT_IS_IPV4(p)) {
af = AF_INET;
more_frags = IPV4_GET_MF(p);
frag_offset = IPV4_GET_IPOFFSET(p);
}
else if (PKT_IS_IPV6(p)) {
af = AF_INET6;
frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
}
else {
return NULL;
}
if (frag_offset == 0 && more_frags == 0) {
return NULL;
}
if (tv != NULL && dtv != NULL) {
if (af == AF_INET) {
StatsIncr(tv, dtv->counter_defrag_ipv4_fragments);
}
else if (af == AF_INET6) {
StatsIncr(tv, dtv->counter_defrag_ipv6_fragments);
}
}
/* return a locked tracker or NULL */
tracker = DefragGetTracker(tv, dtv, p);
if (tracker == NULL)
return NULL;
Packet *rp = DefragInsertFrag(tv, dtv, tracker, p, pq);
DefragTrackerRelease(tracker);
return rp;
}
void
DefragInit(void)
{
intmax_t tracker_pool_size;
if (!ConfGetInt("defrag.trackers", &tracker_pool_size)) {
tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
}
/* Load the defrag-per-host lookup. */
DefragPolicyLoadFromConfig();
/* Allocate the DefragContext. */
defrag_context = DefragContextNew();
if (defrag_context == NULL) {
SCLogError(SC_ERR_MEM_ALLOC,
"Failed to allocate memory for the Defrag module.");
exit(EXIT_FAILURE);
}
DefragSetDefaultTimeout(defrag_context->timeout);
DefragInitConfig(FALSE);
}
void DefragDestroy(void)
{
DefragHashShutdown();
DefragContextDestroy(defrag_context);
defrag_context = NULL;
DefragTreeDestroy();
}
#ifdef UNITTESTS
#define IP_MF 0x2000
/**
* Allocate a test packet. Nothing to fancy, just a simple IP packet
* with some payload of no particular protocol.
*/
static Packet *
BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content,
int content_len)
{
Packet *p = NULL;
int hlen = 20;
int ttl = 64;
uint8_t *pcontent;
IPV4Hdr ip4h;
p = SCCalloc(1, sizeof(*p) + default_packet_size);
if (unlikely(p == NULL))
return NULL;
PACKET_INITIALIZE(p);
gettimeofday(&p->ts, NULL);
//p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
ip4h.ip_verhl = 4 << 4;
ip4h.ip_verhl |= hlen >> 2;
ip4h.ip_len = htons(hlen + content_len);
ip4h.ip_id = htons(id);
ip4h.ip_off = htons(off);
if (mf)
ip4h.ip_off = htons(IP_MF | off);
else
ip4h.ip_off = htons(off);
ip4h.ip_ttl = ttl;
ip4h.ip_proto = IPPROTO_ICMP;
ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
/* copy content_len crap, we need full length */
PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
SET_IPV4_SRC_ADDR(p, &p->src);
SET_IPV4_DST_ADDR(p, &p->dst);
pcontent = SCCalloc(1, content_len);
if (unlikely(pcontent == NULL))
return NULL;
memset(pcontent, content, content_len);
PacketCopyDataOffset(p, hlen, pcontent, content_len);
SET_PKT_LEN(p, hlen + content_len);
SCFree(pcontent);
p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)GET_PKT_DATA(p), hlen);
/* Self test. */
if (IPV4_GET_VER(p) != 4)
goto error;
if (IPV4_GET_HLEN(p) != hlen)
goto error;
if (IPV4_GET_IPLEN(p) != hlen + content_len)
goto error;
if (IPV4_GET_IPID(p) != id)
goto error;
if (IPV4_GET_IPOFFSET(p) != off)
goto error;
if (IPV4_GET_MF(p) != mf)
goto error;
if (IPV4_GET_IPTTL(p) != ttl)
goto error;
if (IPV4_GET_IPPROTO(p) != IPPROTO_ICMP)
goto error;
return p;
error:
if (p != NULL)
SCFree(p);
return NULL;
}
void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt,
uint16_t hdrextlen, uint16_t plen,
uint16_t prev_hdrextlen);
static Packet *
IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content,
int content_len)
{
Packet *p = NULL;
uint8_t *pcontent;
IPV6Hdr ip6h;
p = SCCalloc(1, sizeof(*p) + default_packet_size);
if (unlikely(p == NULL))
return NULL;
PACKET_INITIALIZE(p);
gettimeofday(&p->ts, NULL);
ip6h.s_ip6_nxt = 44;
ip6h.s_ip6_hlim = 2;
/* Source and dest address - very bogus addresses. */
ip6h.s_ip6_src[0] = 0x01010101;
ip6h.s_ip6_src[1] = 0x01010101;
ip6h.s_ip6_src[2] = 0x01010101;
ip6h.s_ip6_src[3] = 0x01010101;
ip6h.s_ip6_dst[0] = 0x02020202;
ip6h.s_ip6_dst[1] = 0x02020202;
ip6h.s_ip6_dst[2] = 0x02020202;
ip6h.s_ip6_dst[3] = 0x02020202;
/* copy content_len crap, we need full length */
PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
IPV6_SET_RAW_VER(p->ip6h, 6);
/* Fragmentation header. */
IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
fh->ip6fh_nxt = IPPROTO_ICMP;
fh->ip6fh_ident = htonl(id);
fh->ip6fh_offlg = htons((off << 3) | mf);
DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
pcontent = SCCalloc(1, content_len);
if (unlikely(pcontent == NULL))
return NULL;
memset(pcontent, content, content_len);
PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len);
SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
SCFree(pcontent);
p->ip6h->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
SET_IPV6_SRC_ADDR(p, &p->src);
SET_IPV6_DST_ADDR(p, &p->dst);
/* Self test. */
if (IPV6_GET_VER(p) != 6)
goto error;
if (IPV6_GET_NH(p) != 44)
goto error;
if (IPV6_GET_PLEN(p) != sizeof(IPV6FragHdr) + content_len)
goto error;
return p;
error:
fprintf(stderr, "Error building test packet.\n");
if (p != NULL)
SCFree(p);
return NULL;
}
/**
* Test the simplest possible re-assembly scenario. All packet in
* order and no overlaps.
*/
static int
DefragInOrderSimpleTest(void)
{
Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
Packet *reassembled = NULL;
int id = 12;
int i;
int ret = 0;
DefragInit();
p1 = BuildTestPacket(id, 0, 1, 'A', 8);
if (p1 == NULL)
goto end;
p2 = BuildTestPacket(id, 1, 1, 'B', 8);
if (p2 == NULL)
goto end;
p3 = BuildTestPacket(id, 2, 0, 'C', 3);
if (p3 == NULL)
goto end;
if (Defrag(NULL, NULL, p1, NULL) != NULL)
goto end;
if (Defrag(NULL, NULL, p2, NULL) != NULL)
goto end;
reassembled = Defrag(NULL, NULL, p3, NULL);
if (reassembled == NULL) {
goto end;
}
if (IPV4_GET_HLEN(reassembled) != 20) {
goto end;
}
if (IPV4_GET_IPLEN(reassembled) != 39) {
goto end;
}
/* 20 bytes in we should find 8 bytes of A. */
for (i = 20; i < 20 + 8; i++) {
if (GET_PKT_DATA(reassembled)[i] != 'A') {
goto end;
}
}
/* 28 bytes in we should find 8 bytes of B. */
for (i = 28; i < 28 + 8; i++) {
if (GET_PKT_DATA(reassembled)[i] != 'B') {
goto end;
}
}
/* And 36 bytes in we should find 3 bytes of C. */
for (i = 36; i < 36 + 3; i++) {
if (GET_PKT_DATA(reassembled)[i] != 'C')
goto end;
}
ret = 1;
end:
if (p1 != NULL)
SCFree(p1);
if (p2 != NULL)
SCFree(p2);
if (p3 != NULL)
SCFree(p3);
if (reassembled != NULL)
SCFree(reassembled);
DefragDestroy();
return ret;
}
/**
* Simple fragmented packet in reverse order.
*/
static int
DefragReverseSimpleTest(void)
{
Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
Packet *reassembled = NULL;
int id = 12;
int i;
int ret = 0;
DefragInit();
p1 = BuildTestPacket(id, 0, 1, 'A', 8);
if (p1 == NULL)
goto end;
p2 = BuildTestPacket(id, 1, 1, 'B', 8);
if (p2 == NULL)
goto end;
p3 = BuildTestPacket(id, 2, 0, 'C', 3);
if (p3 == NULL)
goto end;
if (Defrag(NULL, NULL, p3, NULL) != NULL)
goto end;
if (Defrag(NULL, NULL, p2, NULL) != NULL)
goto end;
reassembled = Defrag(NULL, NULL, p1, NULL);
if (reassembled == NULL)
goto end;
if (IPV4_GET_HLEN(reassembled) != 20)
goto end;
if (IPV4_GET_IPLEN(reassembled) != 39)
goto end;
/* 20 bytes in we should find 8 bytes of A. */
for (i = 20; i < 20 + 8; i++) {
if (GET_PKT_DATA(reassembled)[i] != 'A')
goto end;
}
/* 28 bytes in we should find 8 bytes of B. */
for (i = 28; i < 28 + 8; i++) {
if (GET_PKT_DATA(reassembled)[i] != 'B')
goto end;
}
/* And 36 bytes in we should find 3 bytes of C. */
for (i = 36; i < 36 + 3; i++) {
if (GET_PKT_DATA(reassembled)[i] != 'C')
goto end;
}
ret = 1;
end:
if (p1 != NULL)
SCFree(p1);
if (p2 != NULL)
SCFree(p2);
if (p3 != NULL)
SCFree(p3);
if (reassembled != NULL)
SCFree(reassembled);
DefragDestroy();
return ret;
}
/**
* Test the simplest possible re-assembly scenario. All packet in
* order and no overlaps.
*/
static int
IPV6DefragInOrderSimpleTest(void)
{
Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
Packet *reassembled = NULL;
int id = 12;
int i;
int ret = 0;
DefragInit();
p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8);
if (p1 == NULL)
goto end;
p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8);
if (p2 == NULL)
goto end;
p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3);
if (p3 == NULL)
goto end;
if (Defrag(NULL, NULL, p1, NULL) != NULL)
goto end;
if (Defrag(NULL, NULL, p2, NULL) != NULL)
goto end;
reassembled = Defrag(NULL, NULL, p3, NULL);
if (reassembled == NULL)
goto end;
if (IPV6_GET_PLEN(reassembled) != 19)
goto end;
/* 40 bytes in we should find 8 bytes of A. */
for (i = 40; i < 40 + 8; i++) {
if (GET_PKT_DATA(reassembled)[i] != 'A')
goto end;
}
/* 28 bytes in we should find 8 bytes of B. */
for (i = 48; i < 48 + 8; i++) {
if (GET_PKT_DATA(reassembled)[i] != 'B')
goto end;
}
/* And 36 bytes in we should find 3 bytes of C. */
for (i = 56; i < 56 + 3; i++) {
if (GET_PKT_DATA(reassembled)[i] != 'C')
goto end;
}
ret = 1;
end:
if (p1 != NULL)
SCFree(p1);
if (p2 != NULL)
SCFree(p2);
if (p3 != NULL)
SCFree(p3);
if (reassembled != NULL)
SCFree(reassembled);
DefragDestroy();
return ret;
}
static int
IPV6DefragReverseSimpleTest(void)
{
DefragContext *dc = NULL;
Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
Packet *reassembled = NULL;
int id = 12;
int i;
int ret = 0;
DefragInit();
dc = DefragContextNew();
if (dc == NULL)
goto end;
p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8);
if (p1 == NULL)
goto end;
p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8);
if (p2 == NULL)
goto end;
p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3);
if (p3 == NULL)
goto end;
if (Defrag(NULL, NULL, p3, NULL) != NULL)
goto end;
if (Defrag(NULL, NULL, p2, NULL) != NULL)
goto end;
reassembled = Defrag(NULL, NULL, p1, NULL);
if (reassembled == NULL)
goto end;
/* 40 bytes in we should find 8 bytes of A. */
for (i = 40; i < 40 + 8; i++) {
if (GET_PKT_DATA(reassembled)[i] != 'A')
goto end;
}
/* 28 bytes in we should find 8 bytes of B. */
for (i = 48; i < 48 + 8; i++) {
if (GET_PKT_DATA(reassembled)[i] != 'B')
goto end;
}
/* And 36 bytes in we should find 3 bytes of C. */
for (i = 56; i < 56 + 3; i++) {
if (GET_PKT_DATA(reassembled)[i] != 'C')
goto end;
}
ret = 1;
end:
if (dc != NULL)
DefragContextDestroy(dc);
if (p1 != NULL)
SCFree(p1);
if (p2 != NULL)
SCFree(p2);
if (p3 != NULL)
SCFree(p3);
if (reassembled != NULL)
SCFree(reassembled);
DefragDestroy();
return ret;
}
static int
DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len)
{
int i;
int ret = 0;
DefragInit();
/*
* Build the packets.
*/
int id = 1;
Packet *packets[17];
memset(packets, 0x00, sizeof(packets));
/*
* Original fragments.
*/
/* A*24 at 0. */
packets[0] = BuildTestPacket(id, 0, 1, 'A', 24);
/* B*15 at 32. */
packets[1] = BuildTestPacket(id, 32 >> 3, 1, 'B', 16);
/* C*24 at 48. */
packets[2] = BuildTestPacket(id, 48 >> 3, 1, 'C', 24);
/* D*8 at 80. */
packets[3] = BuildTestPacket(id, 80 >> 3, 1, 'D', 8);
/* E*16 at 104. */
packets[4] = BuildTestPacket(id, 104 >> 3, 1, 'E', 16);
/* F*24 at 120. */
packets[5] = BuildTestPacket(id, 120 >> 3, 1, 'F', 24);
/* G*16 at 144. */
packets[6] = BuildTestPacket(id, 144 >> 3, 1, 'G', 16);
/* H*16 at 160. */
packets[7] = BuildTestPacket(id, 160 >> 3, 1, 'H', 16);
/* I*8 at 176. */
packets[8] = BuildTestPacket(id, 176 >> 3, 1, 'I', 8);
/*
* Overlapping subsequent fragments.
*/
/* J*32 at 8. */
packets[9] = BuildTestPacket(id, 8 >> 3, 1, 'J', 32);
/* K*24 at 48. */
packets[10] = BuildTestPacket(id, 48 >> 3, 1, 'K', 24);
/* L*24 at 72. */
packets[11] = BuildTestPacket(id, 72 >> 3, 1, 'L', 24);
/* M*24 at 96. */
packets[12] = BuildTestPacket(id, 96 >> 3, 1, 'M', 24);
/* N*8 at 128. */
packets[13] = BuildTestPacket(id, 128 >> 3, 1, 'N', 8);
/* O*8 at 152. */
packets[14] = BuildTestPacket(id, 152 >> 3, 1, 'O', 8);
/* P*8 at 160. */
packets[15] = BuildTestPacket(id, 160 >> 3, 1, 'P', 8);
/* Q*16 at 176. */
packets[16] = BuildTestPacket(id, 176 >> 3, 0, 'Q', 16);
default_policy = policy;
/* Send all but the last. */
for (i = 0; i < 9; i++) {
Packet *tp = Defrag(NULL, NULL, packets[i], NULL);
if (tp != NULL) {
SCFree(tp);
goto end;
}
if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
goto end;
}
}
int overlap = 0;
for (; i < 16; i++) {
Packet *tp = Defrag(NULL, NULL, packets[i], NULL);
if (tp != NULL) {
SCFree(tp);
goto end;
}
if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
overlap++;
}
}
if (!overlap) {
goto end;
}
/* And now the last one. */
Packet *reassembled = Defrag(NULL, NULL, packets[16], NULL);
if (reassembled == NULL) {
goto end;
}
if (IPV4_GET_HLEN(reassembled) != 20) {
goto end;
}
if (IPV4_GET_IPLEN(reassembled) != 20 + 192) {
goto end;
}
if (memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0) {
goto end;
}
SCFree(reassembled);
/* Make sure all frags were returned back to the pool. */
if (defrag_context->frag_pool->outstanding != 0) {
goto end;
}
ret = 1;
end:
for (i = 0; i < 17; i++) {
SCFree(packets[i]);
}
DefragDestroy();
return ret;
}
static int
IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len)
{
int i;
int ret = 0;
DefragInit();
/*
* Build the packets.
*/
int id = 1;
Packet *packets[17];
memset(packets, 0x00, sizeof(packets));
/*
* Original fragments.
*/
/* A*24 at 0. */
packets[0] = IPV6BuildTestPacket(id, 0, 1, 'A', 24);
/* B*15 at 32. */
packets[1] = IPV6BuildTestPacket(id, 32 >> 3, 1, 'B', 16);
/* C*24 at 48. */
packets[2] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'C', 24);
/* D*8 at 80. */
packets[3] = IPV6BuildTestPacket(id, 80 >> 3, 1, 'D', 8);
/* E*16 at 104. */
packets[4] = IPV6BuildTestPacket(id, 104 >> 3, 1, 'E', 16);
/* F*24 at 120. */
packets[5] = IPV6BuildTestPacket(id, 120 >> 3, 1, 'F', 24);
/* G*16 at 144. */
packets[6] = IPV6BuildTestPacket(id, 144 >> 3, 1, 'G', 16);
/* H*16 at 160. */
packets[7] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'H', 16);
/* I*8 at 176. */
packets[8] = IPV6BuildTestPacket(id, 176 >> 3, 1, 'I', 8);
/*
* Overlapping subsequent fragments.
*/
/* J*32 at 8. */
packets[9] = IPV6BuildTestPacket(id, 8 >> 3, 1, 'J', 32);
/* K*24 at 48. */
packets[10] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'K', 24);
/* L*24 at 72. */
packets[11] = IPV6BuildTestPacket(id, 72 >> 3, 1, 'L', 24);
/* M*24 at 96. */
packets[12] = IPV6BuildTestPacket(id, 96 >> 3, 1, 'M', 24);
/* N*8 at 128. */
packets[13] = IPV6BuildTestPacket(id, 128 >> 3, 1, 'N', 8);
/* O*8 at 152. */
packets[14] = IPV6BuildTestPacket(id, 152 >> 3, 1, 'O', 8);
/* P*8 at 160. */
packets[15] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'P', 8);
/* Q*16 at 176. */
packets[16] = IPV6BuildTestPacket(id, 176 >> 3, 0, 'Q', 16);
default_policy = policy;
/* Send all but the last. */
for (i = 0; i < 9; i++) {
Packet *tp = Defrag(NULL, NULL, packets[i], NULL);
if (tp != NULL) {
SCFree(tp);
goto end;
}
if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
goto end;
}
}
int overlap = 0;
for (; i < 16; i++) {
Packet *tp = Defrag(NULL, NULL, packets[i], NULL);
if (tp != NULL) {
SCFree(tp);
goto end;
}
if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
overlap++;
}
}
if (!overlap)
goto end;
/* And now the last one. */
Packet *reassembled = Defrag(NULL, NULL, packets[16], NULL);
if (reassembled == NULL)
goto end;
if (memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0)
goto end;
if (IPV6_GET_PLEN(reassembled) != 192)
goto end;
SCFree(reassembled);
/* Make sure all frags were returned to the pool. */
if (defrag_context->frag_pool->outstanding != 0) {
printf("defrag_context->frag_pool->outstanding %u: ", defrag_context->frag_pool->outstanding);
goto end;
}
ret = 1;
end:
for (i = 0; i < 17; i++) {
SCFree(packets[i]);
}
DefragDestroy();
return ret;
}
static int
DefragSturgesNovakBsdTest(void)
{
/* Expected data. */
u_char expected[] = {
"AAAAAAAA"
"AAAAAAAA"
"AAAAAAAA"
"JJJJJJJJ"
"JJJJJJJJ"
"BBBBBBBB"
"CCCCCCCC"
"CCCCCCCC"
"CCCCCCCC"
"LLLLLLLL"
"LLLLLLLL"
"LLLLLLLL"
"MMMMMMMM"
"MMMMMMMM"
"MMMMMMMM"
"FFFFFFFF"
"FFFFFFFF"
"FFFFFFFF"
"GGGGGGGG"
"GGGGGGGG"
"HHHHHHHH"
"HHHHHHHH"
"IIIIIIII"
"QQQQQQQQ"
};
return DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, sizeof(expected));
}
static int
IPV6DefragSturgesNovakBsdTest(void)
{
/* Expected data. */
u_char expected[] = {
"AAAAAAAA"
"AAAAAAAA"
"AAAAAAAA"
"JJJJJJJJ"
"JJJJJJJJ"
"BBBBBBBB"
"CCCCCCCC"
"CCCCCCCC"
"CCCCCCCC"
"LLLLLLLL"
"LLLLLLLL"
"LLLLLLLL"
"MMMMMMMM"
"MMMMMMMM"
"MMMMMMMM"
"FFFFFFFF"
"FFFFFFFF"
"FFFFFFFF"
"GGGGGGGG"
"GGGGGGGG"
"HHHHHHHH"
"HHHHHHHH"
"IIIIIIII"
"QQQQQQQQ"
};
return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, sizeof(expected));
}
static int
DefragSturgesNovakLinuxTest(void)
{
/* Expected data. */
u_char expected[] = {
"AAAAAAAA"
"AAAAAAAA"
"AAAAAAAA"
"JJJJJJJJ"
"JJJJJJJJ"
"BBBBBBBB"
"KKKKKKKK"
"KKKKKKKK"
"KKKKKKKK"
"LLLLLLLL"
"LLLLLLLL"
"LLLLLLLL"
"MMMMMMMM"
"MMMMMMMM"
"MMMMMMMM"
"FFFFFFFF"
"FFFFFFFF"
"FFFFFFFF"
"GGGGGGGG"
"GGGGGGGG"
"PPPPPPPP"
"HHHHHHHH"
"QQQQQQQQ"
"QQQQQQQQ"
};
return DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, sizeof(expected));
}
static int
IPV6DefragSturgesNovakLinuxTest(void)
{
/* Expected data. */
u_char expected[] = {
"AAAAAAAA"
"AAAAAAAA"
"AAAAAAAA"
"JJJJJJJJ"
"JJJJJJJJ"
"BBBBBBBB"
"KKKKKKKK"
"KKKKKKKK"
"KKKKKKKK"
"LLLLLLLL"
"LLLLLLLL"
"LLLLLLLL"
"MMMMMMMM"
"MMMMMMMM"
"MMMMMMMM"
"FFFFFFFF"
"FFFFFFFF"
"FFFFFFFF"
"GGGGGGGG"
"GGGGGGGG"
"PPPPPPPP"
"HHHHHHHH"
"QQQQQQQQ"
"QQQQQQQQ"
};
return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
sizeof(expected));
}
static int
DefragSturgesNovakWindowsTest(void)
{
/* Expected data. */
u_char expected[] = {
"AAAAAAAA"
"AAAAAAAA"
"AAAAAAAA"
"JJJJJJJJ"
"BBBBBBBB"
"BBBBBBBB"
"CCCCCCCC"
"CCCCCCCC"
"CCCCCCCC"
"LLLLLLLL"
"LLLLLLLL"
"LLLLLLLL"
"MMMMMMMM"
"EEEEEEEE"
"EEEEEEEE"
"FFFFFFFF"
"FFFFFFFF"
"FFFFFFFF"
"GGGGGGGG"
"GGGGGGGG"
"HHHHHHHH"
"HHHHHHHH"
"IIIIIIII"
"QQQQQQQQ"
};
return DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected));
}
static int
IPV6DefragSturgesNovakWindowsTest(void)
{
/* Expected data. */
u_char expected[] = {
"AAAAAAAA"
"AAAAAAAA"
"AAAAAAAA"
"JJJJJJJJ"
"BBBBBBBB"
"BBBBBBBB"
"CCCCCCCC"
"CCCCCCCC"
"CCCCCCCC"
"LLLLLLLL"
"LLLLLLLL"
"LLLLLLLL"
"MMMMMMMM"
"EEEEEEEE"
"EEEEEEEE"
"FFFFFFFF"
"FFFFFFFF"
"FFFFFFFF"
"GGGGGGGG"
"GGGGGGGG"
"HHHHHHHH"
"HHHHHHHH"
"IIIIIIII"
"QQQQQQQQ"
};
return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
sizeof(expected));
}
static int
DefragSturgesNovakSolarisTest(void)
{
/* Expected data. */
u_char expected[] = {
"AAAAAAAA"
"AAAAAAAA"
"AAAAAAAA"
"JJJJJJJJ"
"BBBBBBBB"
"BBBBBBBB"
"CCCCCCCC"
"CCCCCCCC"
"CCCCCCCC"
"LLLLLLLL"
"LLLLLLLL"
"LLLLLLLL"
"MMMMMMMM"
"MMMMMMMM"
"MMMMMMMM"
"FFFFFFFF"
"FFFFFFFF"
"FFFFFFFF"
"GGGGGGGG"
"GGGGGGGG"
"HHHHHHHH"
"HHHHHHHH"
"IIIIIIII"
"QQQQQQQQ"
};
return DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected));
}
static int
IPV6DefragSturgesNovakSolarisTest(void)
{
/* Expected data. */
u_char expected[] = {
"AAAAAAAA"
"AAAAAAAA"
"AAAAAAAA"
"JJJJJJJJ"
"BBBBBBBB"
"BBBBBBBB"
"CCCCCCCC"
"CCCCCCCC"
"CCCCCCCC"
"LLLLLLLL"
"LLLLLLLL"
"LLLLLLLL"
"MMMMMMMM"
"MMMMMMMM"
"MMMMMMMM"
"FFFFFFFF"
"FFFFFFFF"
"FFFFFFFF"
"GGGGGGGG"
"GGGGGGGG"
"HHHHHHHH"
"HHHHHHHH"
"IIIIIIII"
"QQQQQQQQ"
};
return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
sizeof(expected));
}
static int
DefragSturgesNovakFirstTest(void)
{
/* Expected data. */
u_char expected[] = {
"AAAAAAAA"
"AAAAAAAA"
"AAAAAAAA"
"JJJJJJJJ"
"BBBBBBBB"
"BBBBBBBB"
"CCCCCCCC"
"CCCCCCCC"
"CCCCCCCC"
"LLLLLLLL"
"DDDDDDDD"
"LLLLLLLL"
"MMMMMMMM"
"EEEEEEEE"
"EEEEEEEE"
"FFFFFFFF"
"FFFFFFFF"
"FFFFFFFF"
"GGGGGGGG"
"GGGGGGGG"
"HHHHHHHH"
"HHHHHHHH"
"IIIIIIII"
"QQQQQQQQ"
};
return DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected, sizeof(expected));
}
static int
IPV6DefragSturgesNovakFirstTest(void)
{
/* Expected data. */
u_char expected[] = {
"AAAAAAAA"
"AAAAAAAA"
"AAAAAAAA"
"JJJJJJJJ"
"BBBBBBBB"
"BBBBBBBB"
"CCCCCCCC"
"CCCCCCCC"
"CCCCCCCC"
"LLLLLLLL"
"DDDDDDDD"
"LLLLLLLL"
"MMMMMMMM"
"EEEEEEEE"
"EEEEEEEE"
"FFFFFFFF"
"FFFFFFFF"
"FFFFFFFF"
"GGGGGGGG"
"GGGGGGGG"
"HHHHHHHH"
"HHHHHHHH"
"IIIIIIII"
"QQQQQQQQ"
};
return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
sizeof(expected));
}
static int
DefragSturgesNovakLastTest(void)
{
/* Expected data. */
u_char expected[] = {
"AAAAAAAA"
"JJJJJJJJ"
"JJJJJJJJ"
"JJJJJJJJ"
"JJJJJJJJ"
"BBBBBBBB"
"KKKKKKKK"
"KKKKKKKK"
"KKKKKKKK"
"LLLLLLLL"
"LLLLLLLL"
"LLLLLLLL"
"MMMMMMMM"
"MMMMMMMM"
"MMMMMMMM"
"FFFFFFFF"
"NNNNNNNN"
"FFFFFFFF"
"GGGGGGGG"
"OOOOOOOO"
"PPPPPPPP"
"HHHHHHHH"
"QQQQQQQQ"
"QQQQQQQQ"
};
return DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, sizeof(expected));
}
static int
IPV6DefragSturgesNovakLastTest(void)
{
/* Expected data. */
u_char expected[] = {
"AAAAAAAA"
"JJJJJJJJ"
"JJJJJJJJ"
"JJJJJJJJ"
"JJJJJJJJ"
"BBBBBBBB"
"KKKKKKKK"
"KKKKKKKK"
"KKKKKKKK"
"LLLLLLLL"
"LLLLLLLL"
"LLLLLLLL"
"MMMMMMMM"
"MMMMMMMM"
"MMMMMMMM"
"FFFFFFFF"
"NNNNNNNN"
"FFFFFFFF"
"GGGGGGGG"
"OOOOOOOO"
"PPPPPPPP"
"HHHHHHHH"
"QQQQQQQQ"
"QQQQQQQQ"
};
return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
sizeof(expected));
}
static int
DefragTimeoutTest(void)
{
int i;
int ret = 0;
/* Setup a small numberr of trackers. */
if (ConfSet("defrag.trackers", "16") != 1) {
printf("ConfSet failed: ");
goto end;
}
DefragInit();
/* Load in 16 packets. */
for (i = 0; i < 16; i++) {
Packet *p = BuildTestPacket(i, 0, 1, 'A' + i, 16);
if (p == NULL)
goto end;
Packet *tp = Defrag(NULL, NULL, p, NULL);
SCFree(p);
if (tp != NULL) {
SCFree(tp);
goto end;
}
}
/* Build a new packet but push the timestamp out by our timeout.
* This should force our previous fragments to be timed out. */
Packet *p = BuildTestPacket(99, 0, 1, 'A' + i, 16);
if (p == NULL)
goto end;
p->ts.tv_sec += (defrag_context->timeout + 1);
Packet *tp = Defrag(NULL, NULL, p, NULL);
if (tp != NULL) {
SCFree(tp);
goto end;
}
DefragTracker *tracker = DefragLookupTrackerFromHash(p);
if (tracker == NULL)
goto end;
if (tracker->id != 99)
goto end;
SCFree(p);
ret = 1;
end:
DefragDestroy();
return ret;
}
/**
* QA found that if you send a packet where more frags is 0, offset is
* > 0 and there is no data in the packet that the re-assembler will
* fail. The fix was simple, but this unit test is just to make sure
* its not introduced.
*/
static int
DefragIPv4NoDataTest(void)
{
DefragContext *dc = NULL;
Packet *p = NULL;
int id = 12;
int ret = 0;
DefragInit();
dc = DefragContextNew();
if (dc == NULL)
goto end;
/* This packet has an offset > 0, more frags set to 0 and no data. */
p = BuildTestPacket(id, 1, 0, 'A', 0);
if (p == NULL)
goto end;
/* We do not expect a packet returned. */
if (Defrag(NULL, NULL, p, NULL) != NULL)
goto end;
/* The fragment should have been ignored so no fragments should
* have been allocated from the pool. */
if (dc->frag_pool->outstanding != 0)
return 0;
ret = 1;
end:
if (dc != NULL)
DefragContextDestroy(dc);
if (p != NULL)
SCFree(p);
DefragDestroy();
return ret;
}
static int
DefragIPv4TooLargeTest(void)
{
DefragContext *dc = NULL;
Packet *p = NULL;
int ret = 0;
DefragInit();
dc = DefragContextNew();
if (dc == NULL)
goto end;
/* Create a fragment that would extend past the max allowable size
* for an IPv4 packet. */
p = BuildTestPacket(1, 8183, 0, 'A', 71);
if (p == NULL)
goto end;
/* We do not expect a packet returned. */
if (Defrag(NULL, NULL, p, NULL) != NULL)
goto end;
if (!ENGINE_ISSET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE))
goto end;
/* The fragment should have been ignored so no fragments should have
* been allocated from the pool. */
if (dc->frag_pool->outstanding != 0)
return 0;
ret = 1;
end:
if (dc != NULL)
DefragContextDestroy(dc);
if (p != NULL)
SCFree(p);
DefragDestroy();
return ret;
}
/**
* Test that fragments in different VLANs that would otherwise be
* re-assembled, are not re-assembled. Just use simple in-order
* fragments.
*/
static int
DefragVlanTest(void)
{
Packet *p1 = NULL, *p2 = NULL, *r = NULL;
int ret = 0;
DefragInit();
p1 = BuildTestPacket(1, 0, 1, 'A', 8);
if (p1 == NULL)
goto end;
p2 = BuildTestPacket(1, 1, 0, 'B', 8);
if (p2 == NULL)
goto end;
/* With no VLAN IDs set, packets should re-assemble. */
if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL)
goto end;
if ((r = Defrag(NULL, NULL, p2, NULL)) == NULL)
goto end;
SCFree(r);
/* With mismatched VLANs, packets should not re-assemble. */
p1->vlan_id[0] = 1;
p2->vlan_id[0] = 2;
if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL)
goto end;
if ((r = Defrag(NULL, NULL, p2, NULL)) != NULL)
goto end;
/* Pass. */
ret = 1;
end:
if (p1 != NULL)
SCFree(p1);
if (p2 != NULL)
SCFree(p2);
DefragDestroy();
return ret;
}
/**
* Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
*/
static int
DefragVlanQinQTest(void)
{
Packet *p1 = NULL, *p2 = NULL, *r = NULL;
int ret = 0;
DefragInit();
p1 = BuildTestPacket(1, 0, 1, 'A', 8);
if (p1 == NULL)
goto end;
p2 = BuildTestPacket(1, 1, 0, 'B', 8);
if (p2 == NULL)
goto end;
/* With no VLAN IDs set, packets should re-assemble. */
if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL)
goto end;
if ((r = Defrag(NULL, NULL, p2, NULL)) == NULL)
goto end;
SCFree(r);
/* With mismatched VLANs, packets should not re-assemble. */
p1->vlan_id[0] = 1;
p2->vlan_id[0] = 1;
p1->vlan_id[1] = 1;
p2->vlan_id[1] = 2;
if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL)
goto end;
if ((r = Defrag(NULL, NULL, p2, NULL)) != NULL)
goto end;
/* Pass. */
ret = 1;
end:
if (p1 != NULL)
SCFree(p1);
if (p2 != NULL)
SCFree(p2);
DefragDestroy();
return ret;
}
static int DefragTrackerReuseTest(void)
{
int ret = 0;
int id = 1;
Packet *p1 = NULL;
DefragTracker *tracker1 = NULL, *tracker2 = NULL;
DefragInit();
/* Build a packet, its not a fragment but shouldn't matter for
* this test. */
p1 = BuildTestPacket(id, 0, 0, 'A', 8);
if (p1 == NULL) {
goto end;
}
/* Get a tracker. It shouldn't look like its already in use. */
tracker1 = DefragGetTracker(NULL, NULL, p1);
if (tracker1 == NULL) {
goto end;
}
if (tracker1->seen_last) {
goto end;
}
if (tracker1->remove) {
goto end;
}
DefragTrackerRelease(tracker1);
/* Get a tracker again, it should be the same one. */
tracker2 = DefragGetTracker(NULL, NULL, p1);
if (tracker2 == NULL) {
goto end;
}
if (tracker2 != tracker1) {
goto end;
}
DefragTrackerRelease(tracker1);
/* Now mark the tracker for removal. It should not be returned
* when we get a tracker for a packet that may have the same
* attributes. */
tracker1->remove = 1;
tracker2 = DefragGetTracker(NULL, NULL, p1);
if (tracker2 == NULL) {
goto end;
}
if (tracker2 == tracker1) {
goto end;
}
if (tracker2->remove) {
goto end;
}
ret = 1;
end:
if (p1 != NULL) {
SCFree(p1);
}
DefragDestroy();
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;
defrag tests: fix compiler warnings defrag.c:2423:9: error: variable 'p' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:5: note: remove the 'if' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2423:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2423:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~ defrag.c:2427:5: note: variable 'p' is declared here Packet *p = Defrag(NULL, NULL, p1, NULL); ^ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:5: note: remove the 'if' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~ defrag.c:2490:5: note: variable 'p' is declared here Packet *p = Defrag(NULL, NULL, p1, NULL); ^ 6 errors generated. make[3]: *** [defrag.o] Error 1
10 years ago
Packet *p = NULL;
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;
}
defrag tests: fix compiler warnings defrag.c:2423:9: error: variable 'p' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:5: note: remove the 'if' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2423:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2423:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~ defrag.c:2427:5: note: variable 'p' is declared here Packet *p = Defrag(NULL, NULL, p1, NULL); ^ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:5: note: remove the 'if' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~ defrag.c:2490:5: note: variable 'p' is declared here Packet *p = Defrag(NULL, NULL, p1, NULL); ^ 6 errors generated. make[3]: *** [defrag.o] Error 1
10 years ago
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;
defrag tests: fix compiler warnings defrag.c:2423:9: error: variable 'p' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:5: note: remove the 'if' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2423:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2423:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~ defrag.c:2427:5: note: variable 'p' is declared here Packet *p = Defrag(NULL, NULL, p1, NULL); ^ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:5: note: remove the 'if' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~ defrag.c:2490:5: note: variable 'p' is declared here Packet *p = Defrag(NULL, NULL, p1, NULL); ^ 6 errors generated. make[3]: *** [defrag.o] Error 1
10 years ago
Packet *p = NULL;
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;
}
defrag tests: fix compiler warnings defrag.c:2423:9: error: variable 'p' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:5: note: remove the 'if' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2423:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2423:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~ defrag.c:2460:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2423:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~ defrag.c:2427:5: note: variable 'p' is declared here Packet *p = Defrag(NULL, NULL, p1, NULL); ^ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:5: note: remove the 'if' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~ defrag.c:2486:9: error: variable 'p' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~ defrag.c:2523:9: note: uninitialized use occurs here if (p != NULL) { ^ defrag.c:2486:9: note: remove the '||' if its condition is always false if (p1 == NULL || p2 == NULL || p3 == NULL) { ^~~~~~~~~~~~~ defrag.c:2490:5: note: variable 'p' is declared here Packet *p = Defrag(NULL, NULL, p1, NULL); ^ 6 errors generated. make[3]: *** [defrag.o] Error 1
10 years ago
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
DefragRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest);
UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest);
UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest);
UtRegisterTest("DefragSturgesNovakLinuxTest", DefragSturgesNovakLinuxTest);
UtRegisterTest("DefragSturgesNovakWindowsTest",
DefragSturgesNovakWindowsTest);
UtRegisterTest("DefragSturgesNovakSolarisTest",
DefragSturgesNovakSolarisTest);
UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest);
UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest);
UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest);
UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest);
UtRegisterTest("IPV6DefragSturgesNovakBsdTest",
IPV6DefragSturgesNovakBsdTest);
UtRegisterTest("IPV6DefragSturgesNovakLinuxTest",
IPV6DefragSturgesNovakLinuxTest);
UtRegisterTest("IPV6DefragSturgesNovakWindowsTest",
IPV6DefragSturgesNovakWindowsTest);
UtRegisterTest("IPV6DefragSturgesNovakSolarisTest",
IPV6DefragSturgesNovakSolarisTest);
UtRegisterTest("IPV6DefragSturgesNovakFirstTest",
IPV6DefragSturgesNovakFirstTest);
UtRegisterTest("IPV6DefragSturgesNovakLastTest",
IPV6DefragSturgesNovakLastTest);
UtRegisterTest("DefragVlanTest", DefragVlanTest);
UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
#endif /* UNITTESTS */
}