|
|
|
|
@ -88,7 +88,6 @@ typedef struct _DefragContext {
|
|
|
|
|
time_t timeout; /**< Default timeout. */
|
|
|
|
|
|
|
|
|
|
uint8_t default_policy; /**< Default policy. */
|
|
|
|
|
|
|
|
|
|
} DefragContext;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -137,8 +136,8 @@ typedef struct _DefragTracker {
|
|
|
|
|
|
|
|
|
|
struct timeval timeout; /**< When this tracker will timeout. */
|
|
|
|
|
|
|
|
|
|
uint8_t family; /**< Address family for this tracker, AF_INET or
|
|
|
|
|
* AF_INET6. */
|
|
|
|
|
uint8_t af; /**< Address family for this tracker, AF_INET or
|
|
|
|
|
* AF_INET6. */
|
|
|
|
|
|
|
|
|
|
uint32_t id; /**< IP ID for this tracker. 32 bits for IPv6, 16
|
|
|
|
|
* for IPv4. */
|
|
|
|
|
@ -197,13 +196,13 @@ DefragHashFunc(HashListTable *ht, void *data, uint16_t datalen)
|
|
|
|
|
DefragTracker *p = (DefragTracker *)data;
|
|
|
|
|
uint32_t key;
|
|
|
|
|
|
|
|
|
|
if (p->family == AF_INET) {
|
|
|
|
|
key = (defrag_hash_rand + p->family +
|
|
|
|
|
if (p->af == AF_INET) {
|
|
|
|
|
key = (defrag_hash_rand + p->af +
|
|
|
|
|
p->src_addr.addr_data32[0] + p->dst_addr.addr_data32[0]) %
|
|
|
|
|
defrag_hash_size;
|
|
|
|
|
}
|
|
|
|
|
else if (p->family == AF_INET6) {
|
|
|
|
|
key = (defrag_hash_rand + p->family +
|
|
|
|
|
else if (p->af == AF_INET6) {
|
|
|
|
|
key = (defrag_hash_rand + p->af +
|
|
|
|
|
p->src_addr.addr_data32[0] + p->src_addr.addr_data32[1] +
|
|
|
|
|
p->src_addr.addr_data32[2] + p->src_addr.addr_data32[3] +
|
|
|
|
|
p->dst_addr.addr_data32[0] + p->dst_addr.addr_data32[1] +
|
|
|
|
|
@ -227,7 +226,7 @@ DefragHashCompare(void *a, uint16_t a_len, void *b, uint16_t b_len)
|
|
|
|
|
DefragTracker *dta = (DefragTracker *)a;
|
|
|
|
|
DefragTracker *dtb = (DefragTracker *)b;
|
|
|
|
|
|
|
|
|
|
if (dta->family != dtb->family)
|
|
|
|
|
if (dta->af != dtb->af)
|
|
|
|
|
return 0;
|
|
|
|
|
else if (dta->id != dtb->id)
|
|
|
|
|
return 0;
|
|
|
|
|
@ -413,7 +412,7 @@ DefragContextNew(void)
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
if (SCMutexInit(&dc->tracker_pool_lock, NULL) != 0) {
|
|
|
|
|
SCLogError(SC_ERR_MEM_ALLOC,
|
|
|
|
|
SCLogError(SC_ERR_MUTEX,
|
|
|
|
|
"Defrag: Failed to initialize tracker pool mutex.");
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
@ -429,7 +428,7 @@ DefragContextNew(void)
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
if (SCMutexInit(&dc->frag_pool_lock, NULL) != 0) {
|
|
|
|
|
SCLogError(SC_ERR_MEM_ALLOC,
|
|
|
|
|
SCLogError(SC_ERR_MUTEX,
|
|
|
|
|
"Defrag: Failed to initialize frag pool mutex.");
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
@ -475,218 +474,6 @@ DefragContextDestroy(DefragContext *dc)
|
|
|
|
|
free(dc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Insert a new IPv4/IPv6 fragment into a tracker.
|
|
|
|
|
*
|
|
|
|
|
* \todo Allocate packet buffers from a pool.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
DefragInsertFrag(DefragContext *dc, DefragTracker *tracker, Packet *p)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if (tracker->family == 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 - p->pkt;
|
|
|
|
|
data_len = IPV4_GET_IPLEN(p) - hlen;
|
|
|
|
|
frag_end = frag_offset + data_len;
|
|
|
|
|
ip_hdr_offset = (uint8_t *)p->ip4h - p->pkt;
|
|
|
|
|
|
|
|
|
|
/* 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) {
|
|
|
|
|
/** \todo Perhaps log something? */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (tracker->family == AF_INET6) {
|
|
|
|
|
more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
|
|
|
|
|
frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
|
|
|
|
|
data_offset = (uint8_t *)p->ip6eh.ip6fh + sizeof(IPV6FragHdr) - p->pkt;
|
|
|
|
|
data_len = IPV6_GET_PLEN(p) - (
|
|
|
|
|
((uint8_t *)p->ip6eh.ip6fh + sizeof(IPV6FragHdr)) -
|
|
|
|
|
((uint8_t *)p->ip6h + sizeof(IPV6Hdr)));
|
|
|
|
|
frag_end = frag_offset + data_len;
|
|
|
|
|
ip_hdr_offset = (uint8_t *)p->ip6h - p->pkt;
|
|
|
|
|
frag_hdr_offset = (uint8_t *)p->ip6eh.ip6fh - p->pkt;
|
|
|
|
|
|
|
|
|
|
/* Ignore fragment if the end of packet extends past the
|
|
|
|
|
* maximum size of a packet. */
|
|
|
|
|
if (frag_offset + data_len > IPV6_MAXPACKET) {
|
|
|
|
|
/** \todo Perhaps log something? */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Abort - should not happen. */
|
|
|
|
|
SCLogError(SC_INVALID_ARGUMENT, "Invalid address family, aborting.");
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Lock this tracker as we'll be doing list operations on it. */
|
|
|
|
|
SCMutexLock(&tracker->lock);
|
|
|
|
|
|
|
|
|
|
/* Update timeout. */
|
|
|
|
|
tracker->timeout = p->ts;
|
|
|
|
|
tracker->timeout.tv_sec += dc->timeout;
|
|
|
|
|
|
|
|
|
|
Frag *prev = NULL, *next;;
|
|
|
|
|
if (!TAILQ_EMPTY(&tracker->frags)) {
|
|
|
|
|
TAILQ_FOREACH(prev, &tracker->frags, next) {
|
|
|
|
|
ltrim = 0;
|
|
|
|
|
next = TAILQ_NEXT(prev, next);
|
|
|
|
|
|
|
|
|
|
switch (tracker->policy) {
|
|
|
|
|
case POLICY_BSD:
|
|
|
|
|
if (frag_offset < prev->offset + prev->data_len) {
|
|
|
|
|
if (frag_offset >= prev->offset) {
|
|
|
|
|
ltrim = prev->offset + prev->data_len - frag_offset;
|
|
|
|
|
}
|
|
|
|
|
if ((next != NULL) && (frag_end > next->offset)) {
|
|
|
|
|
next->ltrim = frag_end - next->offset;
|
|
|
|
|
}
|
|
|
|
|
if ((frag_offset < prev->offset) &&
|
|
|
|
|
(frag_end >= prev->offset + prev->data_len)) {
|
|
|
|
|
prev->skip = 1;
|
|
|
|
|
}
|
|
|
|
|
goto insert;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case POLICY_LINUX:
|
|
|
|
|
if (frag_offset < prev->offset + prev->data_len) {
|
|
|
|
|
if (frag_offset > prev->offset) {
|
|
|
|
|
ltrim = prev->offset + prev->data_len - frag_offset;
|
|
|
|
|
}
|
|
|
|
|
if ((next != NULL) && (frag_end > next->offset)) {
|
|
|
|
|
next->ltrim = frag_end - next->offset;
|
|
|
|
|
}
|
|
|
|
|
if ((frag_offset < prev->offset) &&
|
|
|
|
|
(frag_end >= prev->offset + prev->data_len)) {
|
|
|
|
|
prev->skip = 1;
|
|
|
|
|
}
|
|
|
|
|
goto insert;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case POLICY_WINDOWS:
|
|
|
|
|
if (frag_offset < prev->offset + prev->data_len) {
|
|
|
|
|
if (frag_offset >= prev->offset) {
|
|
|
|
|
ltrim = prev->offset + prev->data_len - frag_offset;
|
|
|
|
|
}
|
|
|
|
|
if ((frag_offset < prev->offset) &&
|
|
|
|
|
(frag_end > prev->offset + prev->data_len)) {
|
|
|
|
|
prev->skip = 1;
|
|
|
|
|
}
|
|
|
|
|
goto insert;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case POLICY_SOLARIS:
|
|
|
|
|
if (frag_offset < prev->offset + prev->data_len) {
|
|
|
|
|
if (frag_offset >= prev->offset) {
|
|
|
|
|
ltrim = prev->offset + prev->data_len - frag_offset;
|
|
|
|
|
}
|
|
|
|
|
if ((frag_offset < prev->offset) &&
|
|
|
|
|
(frag_end >= prev->offset + prev->data_len)) {
|
|
|
|
|
prev->skip = 1;
|
|
|
|
|
}
|
|
|
|
|
goto insert;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case POLICY_FIRST:
|
|
|
|
|
if ((frag_offset >= prev->offset) &&
|
|
|
|
|
(frag_end <= prev->offset + prev->data_len))
|
|
|
|
|
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;
|
|
|
|
|
goto insert;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case POLICY_LAST:
|
|
|
|
|
if (frag_offset <= prev->offset) {
|
|
|
|
|
if (frag_end > prev->offset)
|
|
|
|
|
prev->ltrim = frag_end - prev->offset;
|
|
|
|
|
goto insert;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
insert:
|
|
|
|
|
|
|
|
|
|
if (data_len - ltrim <= 0) {
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Allocate fragment and insert. */
|
|
|
|
|
SCMutexLock(&dc->frag_pool_lock);
|
|
|
|
|
Frag *new = PoolGet(dc->frag_pool);
|
|
|
|
|
SCMutexUnlock(&dc->frag_pool_lock);
|
|
|
|
|
if (new == NULL) {
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
new->pkt = malloc(p->pktlen);
|
|
|
|
|
if (new->pkt == NULL) {
|
|
|
|
|
SCMutexLock(&dc->frag_pool_lock);
|
|
|
|
|
PoolReturn(dc->frag_pool, new);
|
|
|
|
|
SCMutexUnlock(&dc->frag_pool_lock);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
memcpy(new->pkt, p->pkt + ltrim, p->pktlen - ltrim);
|
|
|
|
|
new->len = p->pktlen - ltrim;
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
Frag *frag;
|
|
|
|
|
TAILQ_FOREACH(frag, &tracker->frags, next) {
|
|
|
|
|
if (frag_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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
SCMutexUnlock(&tracker->lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Attempt to re-assemble a packet.
|
|
|
|
|
@ -703,9 +490,6 @@ Defrag4Reassemble(ThreadVars *tv, DefragContext *dc, DefragTracker *tracker,
|
|
|
|
|
if (!tracker->seen_last)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* Lock the tracker. */
|
|
|
|
|
SCMutexLock(&tracker->lock);
|
|
|
|
|
|
|
|
|
|
/* Check that we have all the data. Relies on the fact that
|
|
|
|
|
* fragments are inserted if frag_offset order. */
|
|
|
|
|
Frag *frag;
|
|
|
|
|
@ -806,7 +590,6 @@ remove_tracker:
|
|
|
|
|
SCMutexUnlock(&dc->tracker_pool_lock);
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
SCMutexUnlock(&tracker->lock);
|
|
|
|
|
return rp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -825,9 +608,6 @@ Defrag6Reassemble(ThreadVars *tv, DefragContext *dc, DefragTracker *tracker,
|
|
|
|
|
if (!tracker->seen_last)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* Lock the tracker. */
|
|
|
|
|
SCMutexLock(&tracker->lock);
|
|
|
|
|
|
|
|
|
|
/* Check that we have all the data. Relies on the fact that
|
|
|
|
|
* fragments are inserted if frag_offset order. */
|
|
|
|
|
Frag *frag;
|
|
|
|
|
@ -919,10 +699,232 @@ remove_tracker:
|
|
|
|
|
SCMutexUnlock(&dc->tracker_pool_lock);
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
SCMutexUnlock(&tracker->lock);
|
|
|
|
|
return rp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Insert a new IPv4/IPv6 fragment into a tracker.
|
|
|
|
|
*
|
|
|
|
|
* \todo Allocate packet buffers from a pool.
|
|
|
|
|
*/
|
|
|
|
|
static Packet *
|
|
|
|
|
DefragInsertFrag(ThreadVars *tv, DefragContext *dc, DefragTracker *tracker,
|
|
|
|
|
Packet *p)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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 - p->pkt;
|
|
|
|
|
data_len = IPV4_GET_IPLEN(p) - hlen;
|
|
|
|
|
frag_end = frag_offset + data_len;
|
|
|
|
|
ip_hdr_offset = (uint8_t *)p->ip4h - p->pkt;
|
|
|
|
|
|
|
|
|
|
/* 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) {
|
|
|
|
|
/** \todo Perhaps log something? */
|
|
|
|
|
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 = (uint8_t *)p->ip6eh.ip6fh + sizeof(IPV6FragHdr) - p->pkt;
|
|
|
|
|
data_len = IPV6_GET_PLEN(p) - (
|
|
|
|
|
((uint8_t *)p->ip6eh.ip6fh + sizeof(IPV6FragHdr)) -
|
|
|
|
|
((uint8_t *)p->ip6h + sizeof(IPV6Hdr)));
|
|
|
|
|
frag_end = frag_offset + data_len;
|
|
|
|
|
ip_hdr_offset = (uint8_t *)p->ip6h - p->pkt;
|
|
|
|
|
frag_hdr_offset = (uint8_t *)p->ip6eh.ip6fh - p->pkt;
|
|
|
|
|
|
|
|
|
|
/* Ignore fragment if the end of packet extends past the
|
|
|
|
|
* maximum size of a packet. */
|
|
|
|
|
if (frag_offset + data_len > IPV6_MAXPACKET) {
|
|
|
|
|
/** \todo Perhaps log something? */
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Abort - should not happen. */
|
|
|
|
|
SCLogWarning(SC_INVALID_ARGUMENT, "Invalid address family, aborting.");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Lock this tracker as we'll be doing list operations on it. */
|
|
|
|
|
SCMutexLock(&tracker->lock);
|
|
|
|
|
|
|
|
|
|
/* Update timeout. */
|
|
|
|
|
tracker->timeout = p->ts;
|
|
|
|
|
tracker->timeout.tv_sec += dc->timeout;
|
|
|
|
|
|
|
|
|
|
Frag *prev = NULL, *next;;
|
|
|
|
|
if (!TAILQ_EMPTY(&tracker->frags)) {
|
|
|
|
|
TAILQ_FOREACH(prev, &tracker->frags, next) {
|
|
|
|
|
ltrim = 0;
|
|
|
|
|
next = TAILQ_NEXT(prev, next);
|
|
|
|
|
|
|
|
|
|
switch (tracker->policy) {
|
|
|
|
|
case POLICY_BSD:
|
|
|
|
|
if (frag_offset < prev->offset + prev->data_len) {
|
|
|
|
|
if (frag_offset >= prev->offset) {
|
|
|
|
|
ltrim = prev->offset + prev->data_len - frag_offset;
|
|
|
|
|
}
|
|
|
|
|
if ((next != NULL) && (frag_end > next->offset)) {
|
|
|
|
|
next->ltrim = frag_end - next->offset;
|
|
|
|
|
}
|
|
|
|
|
if ((frag_offset < prev->offset) &&
|
|
|
|
|
(frag_end >= prev->offset + prev->data_len)) {
|
|
|
|
|
prev->skip = 1;
|
|
|
|
|
}
|
|
|
|
|
goto insert;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case POLICY_LINUX:
|
|
|
|
|
if (frag_offset < prev->offset + prev->data_len) {
|
|
|
|
|
if (frag_offset > prev->offset) {
|
|
|
|
|
ltrim = prev->offset + prev->data_len - frag_offset;
|
|
|
|
|
}
|
|
|
|
|
if ((next != NULL) && (frag_end > next->offset)) {
|
|
|
|
|
next->ltrim = frag_end - next->offset;
|
|
|
|
|
}
|
|
|
|
|
if ((frag_offset < prev->offset) &&
|
|
|
|
|
(frag_end >= prev->offset + prev->data_len)) {
|
|
|
|
|
prev->skip = 1;
|
|
|
|
|
}
|
|
|
|
|
goto insert;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case POLICY_WINDOWS:
|
|
|
|
|
if (frag_offset < prev->offset + prev->data_len) {
|
|
|
|
|
if (frag_offset >= prev->offset) {
|
|
|
|
|
ltrim = prev->offset + prev->data_len - frag_offset;
|
|
|
|
|
}
|
|
|
|
|
if ((frag_offset < prev->offset) &&
|
|
|
|
|
(frag_end > prev->offset + prev->data_len)) {
|
|
|
|
|
prev->skip = 1;
|
|
|
|
|
}
|
|
|
|
|
goto insert;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case POLICY_SOLARIS:
|
|
|
|
|
if (frag_offset < prev->offset + prev->data_len) {
|
|
|
|
|
if (frag_offset >= prev->offset) {
|
|
|
|
|
ltrim = prev->offset + prev->data_len - frag_offset;
|
|
|
|
|
}
|
|
|
|
|
if ((frag_offset < prev->offset) &&
|
|
|
|
|
(frag_end >= prev->offset + prev->data_len)) {
|
|
|
|
|
prev->skip = 1;
|
|
|
|
|
}
|
|
|
|
|
goto insert;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case POLICY_FIRST:
|
|
|
|
|
if ((frag_offset >= prev->offset) &&
|
|
|
|
|
(frag_end <= prev->offset + prev->data_len))
|
|
|
|
|
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;
|
|
|
|
|
goto insert;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case POLICY_LAST:
|
|
|
|
|
if (frag_offset <= prev->offset) {
|
|
|
|
|
if (frag_end > prev->offset)
|
|
|
|
|
prev->ltrim = frag_end - prev->offset;
|
|
|
|
|
goto insert;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
insert:
|
|
|
|
|
|
|
|
|
|
if (data_len - ltrim <= 0) {
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Allocate fragment and insert. */
|
|
|
|
|
SCMutexLock(&dc->frag_pool_lock);
|
|
|
|
|
Frag *new = PoolGet(dc->frag_pool);
|
|
|
|
|
SCMutexUnlock(&dc->frag_pool_lock);
|
|
|
|
|
if (new == NULL) {
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
new->pkt = malloc(p->pktlen);
|
|
|
|
|
if (new->pkt == NULL) {
|
|
|
|
|
SCMutexLock(&dc->frag_pool_lock);
|
|
|
|
|
PoolReturn(dc->frag_pool, new);
|
|
|
|
|
SCMutexUnlock(&dc->frag_pool_lock);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
memcpy(new->pkt, p->pkt + ltrim, p->pktlen - ltrim);
|
|
|
|
|
new->len = p->pktlen - ltrim;
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
Frag *frag;
|
|
|
|
|
TAILQ_FOREACH(frag, &tracker->frags, next) {
|
|
|
|
|
if (frag_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, dc, tracker, p);
|
|
|
|
|
else if (tracker->af == AF_INET6)
|
|
|
|
|
r = Defrag6Reassemble(tv, dc, tracker, p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
SCMutexUnlock(&tracker->lock);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Timeout a tracker.
|
|
|
|
|
*
|
|
|
|
|
@ -965,7 +967,6 @@ DefragGetTracker(DefragContext *dc, DefragTracker *lookup_key, Packet *p)
|
|
|
|
|
SCMutexLock(&dc->frag_table_lock);
|
|
|
|
|
tracker = HashListTableLookup(dc->frag_table, lookup_key,
|
|
|
|
|
sizeof(*lookup_key));
|
|
|
|
|
SCMutexUnlock(&dc->frag_table_lock);
|
|
|
|
|
if (tracker == NULL) {
|
|
|
|
|
SCMutexLock(&dc->tracker_pool_lock);
|
|
|
|
|
tracker = PoolGet(dc->tracker_pool);
|
|
|
|
|
@ -978,10 +979,10 @@ DefragGetTracker(DefragContext *dc, DefragTracker *lookup_key, Packet *p)
|
|
|
|
|
if (tracker == NULL) {
|
|
|
|
|
/* Report memory error - actually a pool allocation error. */
|
|
|
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Defrag: Failed to allocate tracker.");
|
|
|
|
|
return NULL;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
DefragTrackerReset(tracker);
|
|
|
|
|
tracker->family = lookup_key->family;
|
|
|
|
|
tracker->af = lookup_key->af;
|
|
|
|
|
tracker->id = lookup_key->id;
|
|
|
|
|
tracker->src_addr = lookup_key->src_addr;
|
|
|
|
|
tracker->dst_addr = lookup_key->dst_addr;
|
|
|
|
|
@ -989,17 +990,19 @@ DefragGetTracker(DefragContext *dc, DefragTracker *lookup_key, Packet *p)
|
|
|
|
|
/* XXX Do policy lookup. */
|
|
|
|
|
tracker->policy = dc->default_policy;
|
|
|
|
|
|
|
|
|
|
SCMutexLock(&dc->frag_table_lock);
|
|
|
|
|
if (HashListTableAdd(dc->frag_table, tracker, sizeof(*tracker)) != 0) {
|
|
|
|
|
/* Failed to add new tracker. */
|
|
|
|
|
SCMutexUnlock(&dc->frag_table_lock);
|
|
|
|
|
SCLogError(SC_ERR_MEM_ALLOC,
|
|
|
|
|
"Defrag: Failed to add new tracker to hash table.");
|
|
|
|
|
return NULL;
|
|
|
|
|
SCMutexLock(&dc->tracker_pool_lock);
|
|
|
|
|
PoolReturn(dc->tracker_pool, tracker);
|
|
|
|
|
SCMutexUnlock(&dc->tracker_pool_lock);
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
SCMutexUnlock(&dc->frag_table_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
SCMutexUnlock(&dc->frag_table_lock);
|
|
|
|
|
return tracker;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1049,7 +1052,7 @@ Defrag(ThreadVars *tv, DefragContext *dc, Packet *p)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create a lookup key. */
|
|
|
|
|
lookup.family = af;
|
|
|
|
|
lookup.af = af;
|
|
|
|
|
lookup.id = id;
|
|
|
|
|
lookup.src_addr = p->src;
|
|
|
|
|
lookup.dst_addr = p->dst;
|
|
|
|
|
@ -1058,17 +1061,7 @@ Defrag(ThreadVars *tv, DefragContext *dc, Packet *p)
|
|
|
|
|
if (tracker == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
DefragInsertFrag(dc, tracker, p);
|
|
|
|
|
if (tracker->seen_last) {
|
|
|
|
|
Packet *rp = NULL;
|
|
|
|
|
if (af == AF_INET)
|
|
|
|
|
rp = Defrag4Reassemble(tv, dc, tracker, p);
|
|
|
|
|
else if (af == AF_INET6)
|
|
|
|
|
rp = Defrag6Reassemble(tv, dc, tracker, p);
|
|
|
|
|
return rp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
return DefragInsertFrag(tv, dc, tracker, p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
@ -2342,7 +2335,7 @@ DefragIPv4NoDataTest(void)
|
|
|
|
|
DefragContext *dc = NULL;
|
|
|
|
|
Packet *p = NULL;
|
|
|
|
|
int id = 12;
|
|
|
|
|
int ret;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
DefragInit();
|
|
|
|
|
|
|
|
|
|
@ -2380,7 +2373,7 @@ DefragIPv4TooLargeTest(void)
|
|
|
|
|
{
|
|
|
|
|
DefragContext *dc = NULL;
|
|
|
|
|
Packet *p = NULL;
|
|
|
|
|
int ret;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
DefragInit();
|
|
|
|
|
|
|
|
|
|
|