|
|
@ -113,6 +113,9 @@ typedef struct _frag {
|
|
|
|
uint16_t frag_hdr_offset; /**< Offset in the packet where the frag
|
|
|
|
uint16_t frag_hdr_offset; /**< Offset in the packet where the frag
|
|
|
|
* header starts. */
|
|
|
|
* header starts. */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t ipv4_hdr_offset; /**< Offset in the packet where the IPv4
|
|
|
|
|
|
|
|
* header starts. */
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t data_offset; /**< Offset to the packet data. */
|
|
|
|
uint16_t data_offset; /**< Offset to the packet data. */
|
|
|
|
uint16_t data_len; /**< Length of data. */
|
|
|
|
uint16_t data_len; /**< Length of data. */
|
|
|
|
|
|
|
|
|
|
|
@ -480,19 +483,30 @@ void DefragContextDestroy(DefragContext *dc) {
|
|
|
|
static void
|
|
|
|
static void
|
|
|
|
Defrag4InsertFrag(DefragContext *dc, DefragTracker *tracker, Packet *p)
|
|
|
|
Defrag4InsertFrag(DefragContext *dc, DefragTracker *tracker, Packet *p)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Frag *frag, *prev, *new;
|
|
|
|
int ltrim = 0;
|
|
|
|
uint16_t offset = IPV4_GET_IPOFFSET(p) << 3;
|
|
|
|
|
|
|
|
uint16_t len = IPV4_GET_IPLEN(p);
|
|
|
|
|
|
|
|
uint8_t hlen = IPV4_GET_HLEN(p);
|
|
|
|
|
|
|
|
uint8_t more_frags = IPV4_GET_MF(p);
|
|
|
|
|
|
|
|
int end = offset + len - hlen;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ltrim = 0; /* Number of bytes to trim from front of packet. */
|
|
|
|
uint16_t frag_offset = IPV4_GET_IPOFFSET(p) << 3;
|
|
|
|
|
|
|
|
|
|
|
|
int remove = 0; /* Will be set if we need to remove a fragment. */
|
|
|
|
uint16_t hlen = IPV4_GET_HLEN(p);
|
|
|
|
|
|
|
|
|
|
|
|
int before = 0; /* Set if fragment should be inserted before
|
|
|
|
/* This is the offset of the start of the data in the packet that
|
|
|
|
* instead of after. */
|
|
|
|
* falls after the IP header. */
|
|
|
|
|
|
|
|
uint16_t data_offset = (uint8_t *)p->ip4h + hlen - p->pkt;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The length of the (fragmented) data. This is the length of the
|
|
|
|
|
|
|
|
* data that falls after the IP header. */
|
|
|
|
|
|
|
|
uint16_t data_len = IPV4_GET_IPLEN(p) - hlen;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Where the fragment ends. */
|
|
|
|
|
|
|
|
uint16_t frag_end = frag_offset + data_len;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Offset in the packet to the IPv6 header. */
|
|
|
|
|
|
|
|
uint16_t ipv4_hdr_offset = (uint8_t *)p->ip4h - p->pkt;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
/* Offset in the packet to the IPv6 frag header. */
|
|
|
|
|
|
|
|
uint16_t frag_hdr_offset = (uint8_t *)p->ip6eh.ip6fh - p->pkt;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* Lock this tracker as we'll be doing list operations on it. */
|
|
|
|
/* Lock this tracker as we'll be doing list operations on it. */
|
|
|
|
SCMutexLock(&tracker->lock);
|
|
|
|
SCMutexLock(&tracker->lock);
|
|
|
@ -501,181 +515,134 @@ Defrag4InsertFrag(DefragContext *dc, DefragTracker *tracker, Packet *p)
|
|
|
|
tracker->timeout = p->ts;
|
|
|
|
tracker->timeout = p->ts;
|
|
|
|
tracker->timeout.tv_sec += dc->timeout;
|
|
|
|
tracker->timeout.tv_sec += dc->timeout;
|
|
|
|
|
|
|
|
|
|
|
|
prev = NULL;
|
|
|
|
Frag *prev = NULL, *next;;
|
|
|
|
if (!TAILQ_EMPTY(&tracker->frags)) {
|
|
|
|
if (!TAILQ_EMPTY(&tracker->frags)) {
|
|
|
|
|
|
|
|
TAILQ_FOREACH(prev, &tracker->frags, next) {
|
|
|
|
/* First compare against the last frag. In the normal case
|
|
|
|
|
|
|
|
* this new fragment should fall after the last frag. */
|
|
|
|
|
|
|
|
frag = TAILQ_LAST(&tracker->frags, frag_tailq);
|
|
|
|
|
|
|
|
if (offset >= frag->offset + frag->len - frag->hlen) {
|
|
|
|
|
|
|
|
prev = frag;
|
|
|
|
|
|
|
|
goto insert;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Find where in the list to add this fragment. */
|
|
|
|
|
|
|
|
TAILQ_FOREACH(frag, &tracker->frags, next) {
|
|
|
|
|
|
|
|
int prev_end = frag->offset + frag->len - frag->hlen;
|
|
|
|
|
|
|
|
prev = frag;
|
|
|
|
|
|
|
|
ltrim = 0;
|
|
|
|
ltrim = 0;
|
|
|
|
|
|
|
|
next = TAILQ_NEXT(prev, next);
|
|
|
|
|
|
|
|
|
|
|
|
switch (tracker->policy) {
|
|
|
|
switch (tracker->policy) {
|
|
|
|
case POLICY_LAST:
|
|
|
|
case POLICY_BSD:
|
|
|
|
if (offset <= frag->offset) {
|
|
|
|
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;
|
|
|
|
goto insert;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case POLICY_FIRST:
|
|
|
|
case POLICY_LINUX:
|
|
|
|
if ((offset >= frag->offset) && (end <= prev_end)) {
|
|
|
|
if (frag_offset < prev->offset + prev->data_len) {
|
|
|
|
/* Packet is wholly contained within a previous
|
|
|
|
if (frag_offset > prev->offset) {
|
|
|
|
* packet. Drop. */
|
|
|
|
ltrim = prev->offset + prev->data_len - frag_offset;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((next != NULL) && (frag_end > next->offset)) {
|
|
|
|
else if (offset < frag->offset) {
|
|
|
|
next->ltrim = frag_end - next->offset;
|
|
|
|
before = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((frag_offset < prev->offset) &&
|
|
|
|
|
|
|
|
(frag_end >= prev->offset + prev->data_len)) {
|
|
|
|
|
|
|
|
prev->skip = 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
goto insert;
|
|
|
|
goto insert;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (offset < prev_end) {
|
|
|
|
break;
|
|
|
|
ltrim = prev_end - offset;
|
|
|
|
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;
|
|
|
|
goto insert;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case POLICY_SOLARIS:
|
|
|
|
case POLICY_SOLARIS:
|
|
|
|
if ((offset < frag->offset) && (end >= prev_end)) {
|
|
|
|
if (frag_offset < prev->offset + prev->data_len) {
|
|
|
|
remove = 1;
|
|
|
|
if (frag_offset >= prev->offset) {
|
|
|
|
goto insert;
|
|
|
|
ltrim = prev->offset + prev->data_len - frag_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fall-through. */
|
|
|
|
|
|
|
|
case POLICY_WINDOWS:
|
|
|
|
|
|
|
|
if (offset < frag->offset) {
|
|
|
|
|
|
|
|
if (end > prev_end) {
|
|
|
|
|
|
|
|
/* Starts before previous frag, and ends after
|
|
|
|
|
|
|
|
* previous drop. Drop the previous
|
|
|
|
|
|
|
|
* fragment. */
|
|
|
|
|
|
|
|
remove = 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ((frag_offset < prev->offset) &&
|
|
|
|
/* Fill hole before previous fragment, trim
|
|
|
|
(frag_end >= prev->offset + prev->data_len)) {
|
|
|
|
* this frags length. */
|
|
|
|
prev->skip = 1;
|
|
|
|
len = hlen + (frag->offset - offset);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
goto insert;
|
|
|
|
goto insert;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((offset >= frag->offset) && (end <= prev_end)) {
|
|
|
|
break;
|
|
|
|
/* New frag is completey contained within a
|
|
|
|
case POLICY_FIRST:
|
|
|
|
* previous frag, drop. */
|
|
|
|
if ((frag_offset >= prev->offset) &&
|
|
|
|
|
|
|
|
(frag_end <= prev->offset + prev->data_len))
|
|
|
|
goto done;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
if (frag_offset < prev->offset)
|
|
|
|
else if ((offset == frag->offset) && (end > prev_end)) {
|
|
|
|
goto insert;
|
|
|
|
/* This fragment is filling a hole afte the
|
|
|
|
if (frag_offset < prev->offset + prev->data_len) {
|
|
|
|
* previous frag. Trim the front . */
|
|
|
|
ltrim = prev->offset + prev->data_len - frag_offset;
|
|
|
|
ltrim = end - prev_end;
|
|
|
|
|
|
|
|
goto insert;
|
|
|
|
goto insert;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Fall-through. */
|
|
|
|
break;
|
|
|
|
case POLICY_LINUX: {
|
|
|
|
case POLICY_LAST:
|
|
|
|
if (offset == frag->offset) {
|
|
|
|
if (frag_offset <= prev->offset) {
|
|
|
|
if (end >= prev_end) {
|
|
|
|
if (frag_end > prev->offset)
|
|
|
|
/* Fragment starts at same offset as previous
|
|
|
|
prev->ltrim = frag_end - prev->offset;
|
|
|
|
* fragment and extends past the end of the
|
|
|
|
|
|
|
|
* previous fragment. Replace it
|
|
|
|
|
|
|
|
* completely. */
|
|
|
|
|
|
|
|
remove = 1;
|
|
|
|
|
|
|
|
goto insert;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (end < prev_end) {
|
|
|
|
|
|
|
|
/* Fragment starts at the same offset as
|
|
|
|
|
|
|
|
* previous fragment but doesn't overlap it
|
|
|
|
|
|
|
|
* completely, insert it after the previous
|
|
|
|
|
|
|
|
* fragment and it will take precedence on
|
|
|
|
|
|
|
|
* re-assembly. */
|
|
|
|
|
|
|
|
goto insert;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fall-through. */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case POLICY_BSD:
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
if (offset < prev_end) {
|
|
|
|
|
|
|
|
/* Fragment overlaps with previous fragment,
|
|
|
|
|
|
|
|
* process. */
|
|
|
|
|
|
|
|
if (offset >= frag->offset) {
|
|
|
|
|
|
|
|
if (end <= prev_end) {
|
|
|
|
|
|
|
|
/* New fragment falls completely within a
|
|
|
|
|
|
|
|
* previous fragment, new fragment will be
|
|
|
|
|
|
|
|
* dropped. */
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
/* New fragment extends past the end of
|
|
|
|
|
|
|
|
* the previous fragment. Trim off the
|
|
|
|
|
|
|
|
* front of the new fragment that overlaps
|
|
|
|
|
|
|
|
* with the previous fragment. */
|
|
|
|
|
|
|
|
ltrim = prev_end - offset;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
/* New fragment starts before the previous
|
|
|
|
|
|
|
|
* fragment and extends to the end of past the
|
|
|
|
|
|
|
|
* end of the previous fragment. Remove the
|
|
|
|
|
|
|
|
* previous fragment. */
|
|
|
|
|
|
|
|
remove = 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
goto insert;
|
|
|
|
goto insert;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
insert:
|
|
|
|
insert:
|
|
|
|
|
|
|
|
|
|
|
|
if (len - hlen - ltrim == 0) {
|
|
|
|
if (data_len - ltrim <= 0) {
|
|
|
|
/* No data left. */
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Allocate frag and insert. */
|
|
|
|
/* Allocate fragment and insert. */
|
|
|
|
SCMutexLock(&dc->frag_pool_lock);
|
|
|
|
SCMutexLock(&dc->frag_pool_lock);
|
|
|
|
new = PoolGet(dc->frag_pool);
|
|
|
|
Frag *new = PoolGet(dc->frag_pool);
|
|
|
|
SCMutexUnlock(&dc->frag_pool_lock);
|
|
|
|
SCMutexUnlock(&dc->frag_pool_lock);
|
|
|
|
if (new == NULL)
|
|
|
|
if (new == NULL)
|
|
|
|
goto done;
|
|
|
|
goto done;
|
|
|
|
new->pkt = malloc(len);
|
|
|
|
new->pkt = malloc(p->pktlen);
|
|
|
|
if (new->pkt == NULL) {
|
|
|
|
if (new->pkt == NULL) {
|
|
|
|
SCMutexLock(&dc->frag_pool_lock);
|
|
|
|
SCMutexLock(&dc->frag_pool_lock);
|
|
|
|
PoolReturn(dc->frag_pool, new);
|
|
|
|
PoolReturn(dc->frag_pool, new);
|
|
|
|
SCMutexUnlock(&dc->frag_pool_lock);
|
|
|
|
SCMutexUnlock(&dc->frag_pool_lock);
|
|
|
|
goto done;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BUG_ON(ltrim > len);
|
|
|
|
memcpy(new->pkt, p->pkt + ltrim, p->pktlen - ltrim);
|
|
|
|
memcpy(new->pkt, (uint8_t *)p->ip4h + ltrim, len - ltrim);
|
|
|
|
new->len = p->pktlen - ltrim;
|
|
|
|
new->offset = offset + ltrim;
|
|
|
|
|
|
|
|
new->len = len - ltrim;
|
|
|
|
|
|
|
|
new->hlen = hlen;
|
|
|
|
new->hlen = hlen;
|
|
|
|
new->more_frags = more_frags;
|
|
|
|
new->offset = frag_offset + ltrim;
|
|
|
|
|
|
|
|
new->data_offset = data_offset;
|
|
|
|
|
|
|
|
new->data_len = data_len - ltrim;
|
|
|
|
|
|
|
|
new->ipv4_hdr_offset = ipv4_hdr_offset;
|
|
|
|
|
|
|
|
|
|
|
|
if (prev) {
|
|
|
|
Frag *frag;
|
|
|
|
if (before) {
|
|
|
|
TAILQ_FOREACH(frag, &tracker->frags, next) {
|
|
|
|
TAILQ_INSERT_BEFORE(prev, new, next);
|
|
|
|
if (frag_offset < frag->offset)
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
else {
|
|
|
|
|
|
|
|
TAILQ_INSERT_AFTER(&tracker->frags, prev, new, next);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (frag == NULL) {
|
|
|
|
TAILQ_INSERT_HEAD(&tracker->frags, new, next);
|
|
|
|
TAILQ_INSERT_TAIL(&tracker->frags, new, next);
|
|
|
|
|
|
|
|
}
|
|
|
|
if (remove) {
|
|
|
|
else {
|
|
|
|
TAILQ_REMOVE(&tracker->frags, prev, next);
|
|
|
|
TAILQ_INSERT_BEFORE(frag, new, next);
|
|
|
|
DefragFragReset(prev);
|
|
|
|
|
|
|
|
SCMutexLock(&dc->frag_pool_lock);
|
|
|
|
|
|
|
|
PoolReturn(dc->frag_pool, prev);
|
|
|
|
|
|
|
|
SCMutexUnlock(&dc->frag_pool_lock);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
done:
|
|
|
|
SCMutexUnlock(&tracker->lock);
|
|
|
|
SCMutexUnlock(&tracker->lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
static void
|
|
|
|
Defrag6InsertFrag(DefragContext *dc, DefragTracker *tracker, Packet *p)
|
|
|
|
Defrag6InsertFrag(DefragContext *dc, DefragTracker *tracker, Packet *p)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -844,47 +811,47 @@ done:
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* \param tracker The defragmentation tracker to reassemble from.
|
|
|
|
* \param tracker The defragmentation tracker to reassemble from.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static Packet *
|
|
|
|
Packet *
|
|
|
|
Defrag4Reassemble(ThreadVars *tv, DefragContext *dc, DefragTracker *tracker,
|
|
|
|
Defrag4Reassemble(ThreadVars *tv, DefragContext *dc, DefragTracker *tracker,
|
|
|
|
Packet *p)
|
|
|
|
Packet *p)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Frag *frag, *prev = NULL;
|
|
|
|
|
|
|
|
Packet *rp = NULL;
|
|
|
|
Packet *rp = NULL;
|
|
|
|
int offset = 0;
|
|
|
|
|
|
|
|
int hlen = 0;
|
|
|
|
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Lock the tracker. */
|
|
|
|
|
|
|
|
SCMutexLock(&tracker->lock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Should not be here unless we have seen the last fragment. */
|
|
|
|
/* Should not be here unless we have seen the last fragment. */
|
|
|
|
if (!tracker->seen_last)
|
|
|
|
if (!tracker->seen_last)
|
|
|
|
return NULL;
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
|
|
/* Check that we have all the data. */
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
int len = 0;
|
|
|
|
TAILQ_FOREACH(frag, &tracker->frags, next) {
|
|
|
|
TAILQ_FOREACH(frag, &tracker->frags, next) {
|
|
|
|
|
|
|
|
if (frag->skip)
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
if (frag == TAILQ_FIRST(&tracker->frags)) {
|
|
|
|
if (frag == TAILQ_FIRST(&tracker->frags)) {
|
|
|
|
/* First frag should have an offset of 0. */
|
|
|
|
|
|
|
|
if (frag->offset != 0) {
|
|
|
|
if (frag->offset != 0) {
|
|
|
|
goto done;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
len = frag->len - frag->hlen;
|
|
|
|
len = frag->data_len;
|
|
|
|
hlen = frag->hlen;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
if ((frag->offset - frag->hlen) <= len) {
|
|
|
|
if (frag->offset > len) {
|
|
|
|
len = MAX(len, frag->offset + frag->len - frag->hlen);
|
|
|
|
/* This fragment starts after the end of the previous
|
|
|
|
|
|
|
|
* fragment. We have a hole. */
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
goto done;
|
|
|
|
len += frag->data_len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Length (ip_len) of re-assembled packet. The length of the IP
|
|
|
|
/* Allocate a Packet for the reassembled packet. On failure we
|
|
|
|
* header was added when we hit the first fragment above. */
|
|
|
|
* free all the resources held by this tracker. */
|
|
|
|
len += hlen;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (tv == NULL) {
|
|
|
|
if (tv == NULL) {
|
|
|
|
/* Unit test. */
|
|
|
|
/* Unit test. */
|
|
|
|
rp = SetupPkt();
|
|
|
|
rp = SetupPkt();
|
|
|
@ -895,7 +862,6 @@ Defrag4Reassemble(ThreadVars *tv, DefragContext *dc, DefragTracker *tracker,
|
|
|
|
rp = TunnelPktSetup(tv, NULL, p, (uint8_t *)p->ip4h, IPV4_GET_IPLEN(p),
|
|
|
|
rp = TunnelPktSetup(tv, NULL, p, (uint8_t *)p->ip4h, IPV4_GET_IPLEN(p),
|
|
|
|
IPV4_GET_IPPROTO(p));
|
|
|
|
IPV4_GET_IPPROTO(p));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (rp == NULL) {
|
|
|
|
if (rp == NULL) {
|
|
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for fragmentation re-assembly, dumping fragments.");
|
|
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for fragmentation re-assembly, dumping fragments.");
|
|
|
|
SCMutexLock(&dc->frag_table_lock);
|
|
|
|
SCMutexLock(&dc->frag_table_lock);
|
|
|
@ -908,60 +874,46 @@ Defrag4Reassemble(ThreadVars *tv, DefragContext *dc, DefragTracker *tracker,
|
|
|
|
goto done;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
offset = 0;
|
|
|
|
int payload_len = 0;
|
|
|
|
prev = NULL;
|
|
|
|
int fragmentable_offset = 0;
|
|
|
|
|
|
|
|
int pktlen = 0;
|
|
|
|
|
|
|
|
int hlen = 0;
|
|
|
|
TAILQ_FOREACH(frag, &tracker->frags, next) {
|
|
|
|
TAILQ_FOREACH(frag, &tracker->frags, next) {
|
|
|
|
|
|
|
|
if (frag->skip)
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (frag->data_len - frag->ltrim <= 0)
|
|
|
|
|
|
|
|
continue;
|
|
|
|
if (frag->offset == 0) {
|
|
|
|
if (frag->offset == 0) {
|
|
|
|
/* This is the first packet. We use this packets IP
|
|
|
|
/* This is the first packet, we use this packets link and
|
|
|
|
* header. */
|
|
|
|
* IPv4 header. We also copy in its data. */
|
|
|
|
memcpy(rp->pkt, frag->pkt, frag->len);
|
|
|
|
memcpy(rp->pkt, frag->pkt, frag->len);
|
|
|
|
|
|
|
|
rp->ip4h = (IPV4Hdr *)(rp->pkt + frag->ipv4_hdr_offset);
|
|
|
|
hlen = frag->hlen;
|
|
|
|
hlen = frag->hlen;
|
|
|
|
offset = frag->len - frag->hlen;
|
|
|
|
|
|
|
|
|
|
|
|
/* This is the start of the fragmentable portion of the
|
|
|
|
|
|
|
|
* first packet. All fragment offsets are relative to
|
|
|
|
|
|
|
|
* this. */
|
|
|
|
|
|
|
|
fragmentable_offset = frag->ipv4_hdr_offset + frag->hlen;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pktlen = frag->ipv4_hdr_offset + sizeof(IPV4Hdr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
/* Subsequent packets, copy them in minus their IP header. */
|
|
|
|
memcpy(rp->pkt + fragmentable_offset + frag->offset + frag->ltrim,
|
|
|
|
|
|
|
|
frag->pkt + frag->data_offset + frag->ltrim,
|
|
|
|
int diff = 0;
|
|
|
|
frag->data_len - frag->ltrim);
|
|
|
|
switch (tracker->policy) {
|
|
|
|
payload_len += frag->data_len - frag->ltrim;
|
|
|
|
case POLICY_LAST:
|
|
|
|
|
|
|
|
case POLICY_FIRST:
|
|
|
|
|
|
|
|
case POLICY_WINDOWS:
|
|
|
|
|
|
|
|
case POLICY_SOLARIS:
|
|
|
|
|
|
|
|
memcpy(rp->pkt + hlen + frag->offset,
|
|
|
|
|
|
|
|
frag->pkt + frag->hlen,
|
|
|
|
|
|
|
|
frag->len - frag->hlen);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case POLICY_LINUX:
|
|
|
|
|
|
|
|
if (frag->offset == prev->offset) {
|
|
|
|
|
|
|
|
memcpy(rp->pkt + hlen + frag->offset,
|
|
|
|
|
|
|
|
frag->pkt + frag->hlen,
|
|
|
|
|
|
|
|
frag->len - frag->hlen);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case POLICY_BSD:
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
if (frag->offset < offset)
|
|
|
|
|
|
|
|
diff = offset - frag->offset;
|
|
|
|
|
|
|
|
memcpy(rp->pkt + hlen + frag->offset + diff,
|
|
|
|
|
|
|
|
frag->pkt + frag->hlen + diff,
|
|
|
|
|
|
|
|
frag->len - frag->hlen - diff);
|
|
|
|
|
|
|
|
offset = frag->offset + frag->len - frag->hlen;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
prev = frag;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rp->pktlen = hlen + offset;
|
|
|
|
BUG_ON(rp->ip4h == NULL);
|
|
|
|
rp->ip4h = (IPV4Hdr *)rp->pkt;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Checksum fixup. */
|
|
|
|
|
|
|
|
int old = rp->ip4h->ip_len + rp->ip4h->ip_off;
|
|
|
|
int old = rp->ip4h->ip_len + rp->ip4h->ip_off;
|
|
|
|
rp->ip4h->ip_len = htons(offset + hlen);
|
|
|
|
rp->ip4h->ip_len = htons(payload_len + hlen);
|
|
|
|
rp->ip4h->ip_off = 0;
|
|
|
|
rp->ip4h->ip_off = 0;
|
|
|
|
rp->ip4h->ip_csum = FixChecksum(rp->ip4h->ip_csum,
|
|
|
|
rp->ip4h->ip_csum = FixChecksum(rp->ip4h->ip_csum,
|
|
|
|
old, rp->ip4h->ip_len + rp->ip4h->ip_off);
|
|
|
|
old, rp->ip4h->ip_len + rp->ip4h->ip_off);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rp->pktlen = pktlen + payload_len;
|
|
|
|
|
|
|
|
|
|
|
|
/* Remove the frag tracker. */
|
|
|
|
/* Remove the frag tracker. */
|
|
|
|
HashListTableRemove(dc->frag_table, tracker, sizeof(tracker));
|
|
|
|
HashListTableRemove(dc->frag_table, tracker, sizeof(tracker));
|
|
|
|
DefragTrackerReset(tracker);
|
|
|
|
DefragTrackerReset(tracker);
|
|
|
@ -974,6 +926,11 @@ done:
|
|
|
|
return rp;
|
|
|
|
return rp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Attempt to re-assemble a packet.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* \param tracker The defragmentation tracker to reassemble from.
|
|
|
|
|
|
|
|
*/
|
|
|
|
static Packet *
|
|
|
|
static Packet *
|
|
|
|
Defrag6Reassemble(ThreadVars *tv, DefragContext *dc, DefragTracker *tracker,
|
|
|
|
Defrag6Reassemble(ThreadVars *tv, DefragContext *dc, DefragTracker *tracker,
|
|
|
|
Packet *p)
|
|
|
|
Packet *p)
|
|
|
@ -1074,12 +1031,20 @@ Defrag6Reassemble(ThreadVars *tv, DefragContext *dc, DefragTracker *tracker,
|
|
|
|
rp->ip6h->s_ip6_plen = htons(payload_len);
|
|
|
|
rp->ip6h->s_ip6_plen = htons(payload_len);
|
|
|
|
rp->pktlen = pktlen + payload_len;
|
|
|
|
rp->pktlen = pktlen + payload_len;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Remove the frag tracker. */
|
|
|
|
|
|
|
|
HashListTableRemove(dc->frag_table, tracker, sizeof(tracker));
|
|
|
|
|
|
|
|
DefragTrackerReset(tracker);
|
|
|
|
|
|
|
|
SCMutexLock(&dc->tracker_pool_lock);
|
|
|
|
|
|
|
|
PoolReturn(dc->tracker_pool, tracker);
|
|
|
|
|
|
|
|
SCMutexUnlock(&dc->tracker_pool_lock);
|
|
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
done:
|
|
|
|
SCMutexUnlock(&tracker->lock);
|
|
|
|
SCMutexUnlock(&tracker->lock);
|
|
|
|
return rp;
|
|
|
|
return rp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* \brief Timeout a tracker.
|
|
|
|
* \brief Timeout a tracker.
|
|
|
|
*
|
|
|
|
*
|
|
|
@ -1446,6 +1411,7 @@ DefragInOrderSimpleTest(void)
|
|
|
|
goto end;
|
|
|
|
goto end;
|
|
|
|
if (Defrag4(NULL, dc, p2) != NULL)
|
|
|
|
if (Defrag4(NULL, dc, p2) != NULL)
|
|
|
|
goto end;
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
|
|
|
|
reassembled = Defrag4(NULL, dc, p3);
|
|
|
|
reassembled = Defrag4(NULL, dc, p3);
|
|
|
|
if (reassembled == NULL)
|
|
|
|
if (reassembled == NULL)
|
|
|
|
goto end;
|
|
|
|
goto end;
|
|
|
@ -1470,6 +1436,7 @@ DefragInOrderSimpleTest(void)
|
|
|
|
|
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
ret = 1;
|
|
|
|
end:
|
|
|
|
end:
|
|
|
|
|
|
|
|
|
|
|
|
if (dc != NULL)
|
|
|
|
if (dc != NULL)
|
|
|
|
DefragContextDestroy(dc);
|
|
|
|
DefragContextDestroy(dc);
|
|
|
|
if (p1 != NULL)
|
|
|
|
if (p1 != NULL)
|
|
|
|