add IPv4 & IPv6 frag reassemble test case

This commit is contained in:
luwenpeng
2024-02-23 18:19:52 +08:00
parent 5cd0571b4d
commit 2e748e0821
12 changed files with 1462 additions and 328 deletions

View File

@@ -1,32 +0,0 @@
#include "ip_fragment.h"
/*
* Return the number of fragmented packets, stored in the pkts_out array
* Packets in the pkts_out array should be freed by calling the packet_free() function
*/
uint16_t ipv4_fragment_packet(struct packet *pkt_in, struct packet **pkts_out, uint16_t n_pkts_out, uint16_t mtu_size)
{
if (pkt_in == NULL || pkts_out == NULL || n_pkts_out == 0)
{
IP_FRAGMENT_LOG_ERROR("invalid input parameters");
return 0;
}
// TODO
return 0;
}
uint16_t ipv6_fragment_packet(struct packet *pkt_in, struct packet **pkts_out, uint16_t n_pkts_out, uint16_t mtu_size)
{
if (pkt_in == NULL || pkts_out == NULL || n_pkts_out == 0)
{
IP_FRAGMENT_LOG_ERROR("invalid input parameters");
return 0;
}
// TODO
return 0;
}

View File

@@ -1,26 +0,0 @@
#ifndef _IP_FRAGMENT_H
#define _IP_FRAGMENT_H
#ifdef __cpluscplus
extern "C"
{
#endif
#include "packet.h"
#include "log.h"
#define IP_FRAGMENT_LOG_DEBUG(format, ...) LOG_DEBUG("ip_fragment", format, ##__VA_ARGS__)
#define IP_FRAGMENT_LOG_ERROR(format, ...) LOG_ERROR("ip_fragment", format, ##__VA_ARGS__)
/*
* Return the number of fragmented packets, stored in the pkts_out array
* Packets in the pkts_out array should be freed by calling the packet_free() function
*/
uint16_t ipv4_fragment_packet(struct packet *pkt_in, struct packet **pkts_out, uint16_t n_pkts_out, uint16_t mtu_size);
uint16_t ipv6_fragment_packet(struct packet *pkt_in, struct packet **pkts_out, uint16_t n_pkts_out, uint16_t mtu_size);
#ifdef __cpluscplus
}
#endif
#endif

View File

@@ -12,39 +12,45 @@
#include "packet_helpers.h" #include "packet_helpers.h"
#include "ip_reassemble.h" #include "ip_reassemble.h"
#define IP_FRAG_HASH_FNUM 2
#define PRIME_VALUE 0xeaad8405
#define IP_FRAG_TBL_POS(mgr, sig) ((mgr)->table + ((sig) & (mgr)->entry_mask))
#define IPV4_KEYLEN 1 #define IPV4_KEYLEN 1
#define IPV6_KEYLEN 4 #define IPV6_KEYLEN 4
#define IPv6_KEY_BYTES(key) (key)[0], (key)[1], (key)[2], (key)[3] #define PRIME_VALUE 0xeaad8405
#define IP_FRAG_HASH_FNUM 2
#define IP_FRAG_TBL_POS(mgr, sig) ((mgr)->table + ((sig) & (mgr)->entry_mask))
#define IP_REASSEMBLE_DEBUG_ARG1(desc, key, ...) \ #define KEY_TO_STR(key, str_str, dst_str) \
do \ do \
{ \ { \
if ((key)->src_dst_len == IPV4_KEYLEN) \ if ((key)->src_dst_len == IPV4_KEYLEN) \
{ \ { \
IP_REASSEMBLE_DEBUG(desc, "key <%lu, %#x>", (key)->src_dst_addr[0], (key)->ip_id); \ uint32_t src_addr = (key)->src_dst_addr[0] >> 32; \
} \ uint32_t dst_addr = (key)->src_dst_addr[0] & 0xffffffff; \
else \ inet_ntop(AF_INET, &src_addr, src_str, INET6_ADDRSTRLEN); \
{ \ inet_ntop(AF_INET, &dst_addr, dst_str, INET6_ADDRSTRLEN); \
IP_REASSEMBLE_DEBUG(desc, "key <%08lu%08lu%08lu%08lu, %#x>", IPv6_KEY_BYTES((key)->src_dst_addr), (key)->ip_id); \ } \
} \ else \
{ \
inet_ntop(AF_INET6, &(key)->src_dst_addr[0], src_str, INET6_ADDRSTRLEN); \
inet_ntop(AF_INET6, &(key)->src_dst_addr[2], dst_str, INET6_ADDRSTRLEN); \
} \
} while (0) } while (0)
#define IP_REASSEMBLE_ERROR_ARG1(desc, key, ...) \ #define IP_REASSEMBLE_DEBUG1(desc, key, ...) \
do \ do \
{ \ { \
if ((key)->src_dst_len == IPV4_KEYLEN) \ char src_str[INET6_ADDRSTRLEN] = {0}; \
{ \ char dst_str[INET6_ADDRSTRLEN] = {0}; \
IP_REASSEMBLE_ERROR(desc, "key <%lu, %#x>", (key)->src_dst_addr[0], (key)->ip_id); \ KEY_TO_STR(key, src_str, dst_str); \
} \ IP_REASSEMBLE_DEBUG("%s (%s->%s 0x%0x)", desc, src_str, dst_str, (key)->ip_id); \
else \ } while (0)
{ \
IP_REASSEMBLE_ERROR(desc, "key <%08lu%08lu%08lu%08lu, %#x>", IPv6_KEY_BYTES((key)->src_dst_addr), (key)->ip_id); \ #define IP_REASSEMBLE_ERROR1(desc, key, ...) \
} \ do \
{ \
char src_str[INET6_ADDRSTRLEN] = {0}; \
char dst_str[INET6_ADDRSTRLEN] = {0}; \
KEY_TO_STR(key, src_str, dst_str); \
IP_REASSEMBLE_ERROR("%s (%s->%s 0x%0x)", desc, src_str, dst_str, (key)->ip_id); \
} while (0) } while (0)
/****************************************************************************** /******************************************************************************
@@ -61,18 +67,21 @@ enum
struct ip_frag_hdr struct ip_frag_hdr
{ {
void *hdr_data; // need be freed
uint16_t hdr_len;
uint16_t l3_offset; uint16_t l3_offset;
uint16_t l3_len; uint16_t l3_len;
uint16_t hdr_len;
uint8_t next_proto; uint8_t next_proto;
void *hdr_data; // need be freed
}; };
struct ip_frag_pkt struct ip_frag_pkt
{ {
uint16_t offset;
uint16_t len;
void *data; // need be freed void *data; // need be freed
uint16_t len;
uint16_t offset;
}; };
struct ip_flow_key struct ip_flow_key
@@ -99,15 +108,6 @@ struct ip_flow
struct ip_frag_pkt frags[IP_MAX_FRAG_NUM]; // first two entries in the frags[] array are for the last and first fragments. struct ip_frag_pkt frags[IP_MAX_FRAG_NUM]; // first two entries in the frags[] array are for the last and first fragments.
}; };
struct ip_reassemble_stat
{
uint64_t find_num;
uint64_t add_num;
uint64_t del_num;
uint64_t fail_total;
uint64_t fail_nospace;
};
struct ip_reassemble_manager struct ip_reassemble_manager
{ {
// config // config
@@ -131,13 +131,40 @@ struct ip_reassemble_manager
struct ip_flow **tqh_last; struct ip_flow **tqh_last;
} lru; } lru;
struct ip_flow *last; struct ip_flow *last;
struct ip_flow *table; // array of ip_frag_pkt struct ip_flow *table; // array of ip_flow
}; };
/****************************************************************************** /******************************************************************************
* Private API * utils
******************************************************************************/ ******************************************************************************/
#define ip_reassemble_stat_inc(mgr, filed, key) \
{ \
if ((key)->src_dst_len == IPV4_KEYLEN) \
{ \
(mgr)->stat.ip4_flow_##filed++; \
} \
else \
{ \
(mgr)->stat.ip6_flow_##filed++; \
} \
}
static inline void *memdup(const void *src, size_t len)
{
if (src == NULL || len == 0)
{
return NULL;
}
void *dst = malloc(len);
if (dst == NULL)
{
return NULL;
}
return memcpy(dst, src, len);
}
static inline uint32_t combine32ms1b(uint32_t x) static inline uint32_t combine32ms1b(uint32_t x)
{ {
x |= x >> 1; x |= x >> 1;
@@ -195,7 +222,7 @@ static inline int ip_reassemble_check_config(const struct ip_reassemble_config *
} }
/****************************************************************************** /******************************************************************************
* struct ip_flow_key * ip flow key
******************************************************************************/ ******************************************************************************/
static inline void ipv4_flow_key_hash(const struct ip_flow_key *key, uint32_t *value1, uint32_t *value2) static inline void ipv4_flow_key_hash(const struct ip_flow_key *key, uint32_t *value1, uint32_t *value2)
@@ -267,27 +294,13 @@ static inline void ip_flow_key_zero(struct ip_flow_key *key)
key->src_dst_len = 0; key->src_dst_len = 0;
key->ip_id = 0; key->ip_id = 0;
key->proto = 0;
} }
/****************************************************************************** /******************************************************************************
* struct ip_frag_hdr * ip frag hdr
******************************************************************************/ ******************************************************************************/
static inline void *memdup(const void *src, size_t len)
{
if (src == NULL || len == 0)
{
return NULL;
}
void *dst = malloc(len);
if (dst == NULL)
{
return NULL;
}
return memcpy(dst, src, len);
}
static inline void ip_frag_hdr_init(struct ip_frag_hdr *hdr, const struct packet *pkt) static inline void ip_frag_hdr_init(struct ip_frag_hdr *hdr, const struct packet *pkt)
{ {
struct layer_record *layer = pkt->frag_layer; struct layer_record *layer = pkt->frag_layer;
@@ -325,21 +338,47 @@ static inline void ip_frag_hdr_free(struct ip_frag_hdr *hdr)
} }
/****************************************************************************** /******************************************************************************
* struct ip_flow * ip frag pkt
******************************************************************************/
static inline void ip_frag_pkt_init(struct ip_frag_pkt *frag, void *data, uint16_t len, uint16_t offset)
{
frag->data = memdup(data, len);
frag->len = len;
frag->offset = offset;
}
static inline void ip_frag_pkt_free(struct ip_frag_pkt *frag)
{
if (frag)
{
if (frag->data)
{
free(frag->data);
frag->data = NULL;
}
frag->len = 0;
frag->offset = 0;
}
}
/******************************************************************************
* ip flow
******************************************************************************/ ******************************************************************************/
static inline void ip_flow_init(struct ip_flow *flow, const struct ip_flow_key *key) static inline void ip_flow_init(struct ip_flow *flow, const struct ip_flow_key *key)
{ {
static const struct ip_frag_pkt zero_frag = { static const struct ip_frag_pkt zero_frag = {
.offset = 0,
.len = 0,
.data = NULL, .data = NULL,
.len = 0,
.offset = 0,
}; };
flow->lru.tqe_next = NULL; flow->lru.tqe_next = NULL;
flow->lru.tqe_prev = NULL; flow->lru.tqe_prev = NULL;
flow->key = *key; flow->key = *key;
flow->create_time = timestamp_get_msec(); flow->create_time = timestamp_get_sec();
flow->expected_total_size = UINT32_MAX; flow->expected_total_size = UINT32_MAX;
flow->received_frag_size = 0; flow->received_frag_size = 0;
flow->next_fill_idx = IP_MIN_FRAG_NUM; flow->next_fill_idx = IP_MIN_FRAG_NUM;
@@ -352,13 +391,7 @@ static inline void ip_flow_free(struct ip_flow *flow)
for (uint32_t i = 0; i < IP_MAX_FRAG_NUM; i++) for (uint32_t i = 0; i < IP_MAX_FRAG_NUM; i++)
{ {
struct ip_frag_pkt *frag = &flow->frags[i]; struct ip_frag_pkt *frag = &flow->frags[i];
frag->offset = 0; ip_frag_pkt_free(frag);
frag->len = 0;
if (frag->data != NULL)
{
free(frag->data);
frag->data = NULL;
}
} }
ip_flow_key_zero(&flow->key); ip_flow_key_zero(&flow->key);
ip_frag_hdr_free(&flow->hdr); ip_frag_hdr_free(&flow->hdr);
@@ -371,17 +404,30 @@ static inline int ip_flow_is_ready(struct ip_flow *flow)
// return 0 : success // return 0 : success
// return -1 : failed // return -1 : failed
static inline int ip_flow_update(struct ip_flow *flow, const struct packet *pkt, static inline int ip_flow_update(struct ip_reassemble_manager *mgr,
char *data, uint16_t len, uint16_t offset, bool more_frags) struct ip_flow *flow, const struct packet *pkt,
char *frag_data, uint16_t frag_len, uint16_t frag_offset, bool more_frags)
{ {
uint32_t idx; uint32_t idx;
struct ip_frag_pkt *frag_pkt;
if (offset == 0) /*
* Internet Protocol, Version 6 (IPv6) Specification
*
* https://datatracker.ietf.org/doc/html/rfc8200#section-4.5
*
* It should be noted that fragments may be duplicated in the
* network. Instead of treating these exact duplicate fragments
* as overlapping fragments, an implementation may choose to
* detect this case and drop exact duplicate fragments while
* keeping the other fragments belonging to the same packet.
*/
if (frag_offset == 0)
{ {
if (flow->frags[IP_FIRST_FRAG_IDX].data != NULL) if (flow->frags[IP_FIRST_FRAG_IDX].data != NULL)
{ {
IP_REASSEMBLE_ERROR_ARG1("duplicate first fragment encountered: ", &flow->key); IP_REASSEMBLE_DEBUG1("duplicate first fragment bypass", &flow->key);
return -1; ip_reassemble_stat_inc(mgr, bypass_dup_fist_frag, &flow->key);
return 0;
} }
idx = IP_FIRST_FRAG_IDX; idx = IP_FIRST_FRAG_IDX;
ip_frag_hdr_init(&flow->hdr, pkt); ip_frag_hdr_init(&flow->hdr, pkt);
@@ -390,53 +436,56 @@ static inline int ip_flow_update(struct ip_flow *flow, const struct packet *pkt,
{ {
if (flow->frags[IP_LAST_FRAG_IDX].data != NULL) if (flow->frags[IP_LAST_FRAG_IDX].data != NULL)
{ {
IP_REASSEMBLE_ERROR_ARG1("duplicate last fragment encountered: ", &flow->key); IP_REASSEMBLE_DEBUG1("duplicate last fragment bypass", &flow->key);
return -1; ip_reassemble_stat_inc(mgr, bypass_dup_last_frag, &flow->key);
return 0;
} }
idx = IP_LAST_FRAG_IDX; idx = IP_LAST_FRAG_IDX;
flow->expected_total_size = offset + len; flow->expected_total_size = frag_offset + frag_len;
} }
else else
{ {
if (flow->next_fill_idx >= IP_MAX_FRAG_NUM) if (flow->next_fill_idx >= IP_MAX_FRAG_NUM)
{ {
IP_REASSEMBLE_ERROR_ARG1("max number of fragment exceeded: ", &flow->key); IP_REASSEMBLE_ERROR1("max number of fragment exceeded", &flow->key);
ip_reassemble_stat_inc(mgr, fail_many_frag, &flow->key);
return -1; return -1;
} }
idx = flow->next_fill_idx; idx = flow->next_fill_idx;
flow->next_fill_idx++; flow->next_fill_idx++;
} }
flow->received_frag_size += len; flow->received_frag_size += frag_len;
flow->frags[idx].data = memdup(data, len); frag_pkt = &flow->frags[idx];
flow->frags[idx].offset = offset; ip_frag_pkt_init(frag_pkt, frag_data, frag_len, frag_offset);
flow->frags[idx].len = len;
return 0; return 0;
} }
/****************************************************************************** /******************************************************************************
* ip flow table * ip reassemble manager add/del/reuse/find/update flow
******************************************************************************/ ******************************************************************************/
static inline void ip_flow_table_add(struct ip_reassemble_manager *mgr, struct ip_flow *flow) static inline void ip_reassemble_manager_add_flow(struct ip_reassemble_manager *mgr, struct ip_flow *flow)
{ {
ip_reassemble_stat_inc(mgr, add, &flow->key);
TAILQ_INSERT_TAIL(&mgr->lru, flow, lru); TAILQ_INSERT_TAIL(&mgr->lru, flow, lru);
mgr->entry_used++; mgr->entry_used++;
mgr->stat.add_num++;
} }
static inline void ip_flow_table_del(struct ip_reassemble_manager *mgr, struct ip_flow *flow) static inline void ip_reassemble_manager_del_flow(struct ip_reassemble_manager *mgr, struct ip_flow *flow)
{ {
ip_reassemble_stat_inc(mgr, del, &flow->key);
TAILQ_REMOVE(&mgr->lru, flow, lru); TAILQ_REMOVE(&mgr->lru, flow, lru);
mgr->entry_used--; mgr->entry_used--;
mgr->stat.del_num++;
} }
static inline void ip_flow_table_reuse(struct ip_reassemble_manager *mgr, struct ip_flow *flow) static inline void ip_reassemble_manager_reuse_flow(struct ip_reassemble_manager *mgr, struct ip_flow *flow, const struct ip_flow_key *key)
{ {
ip_flow_table_del(mgr, flow); ip_reassemble_manager_del_flow(mgr, flow);
ip_flow_table_add(mgr, flow); ip_flow_free(flow);
ip_flow_init(flow, key);
ip_reassemble_manager_add_flow(mgr, flow);
} }
/* /*
@@ -444,9 +493,9 @@ static inline void ip_flow_table_reuse(struct ip_reassemble_manager *mgr, struct
* free : the first empty entry in the bucket * free : the first empty entry in the bucket
* expired: the first timed-out entry in the bucket * expired: the first timed-out entry in the bucket
*/ */
static struct ip_flow *ip_flow_table_find(struct ip_reassemble_manager *mgr, const struct ip_flow_key *key, struct ip_flow **free, struct ip_flow **expired) static struct ip_flow *ip_reassemble_manager_find_flow(struct ip_reassemble_manager *mgr, const struct ip_flow_key *key, struct ip_flow **free, struct ip_flow **expired)
{ {
mgr->stat.find_num++; ip_reassemble_stat_inc(mgr, find, key);
if (mgr->last != NULL && ip_flow_key_cmp(key, &mgr->last->key) == 0) if (mgr->last != NULL && ip_flow_key_cmp(key, &mgr->last->key) == 0)
{ {
@@ -455,10 +504,6 @@ static struct ip_flow *ip_flow_table_find(struct ip_reassemble_manager *mgr, con
uint32_t sig1 = 0; uint32_t sig1 = 0;
uint32_t sig2 = 0; uint32_t sig2 = 0;
uint64_t timeout = mgr->timeout;
uint32_t assoc = mgr->bucket_entries;
uint64_t tms = timestamp_get_msec();
if (key->src_dst_len == IPV4_KEYLEN) if (key->src_dst_len == IPV4_KEYLEN)
{ {
ipv4_flow_key_hash(key, &sig1, &sig2); ipv4_flow_key_hash(key, &sig1, &sig2);
@@ -475,6 +520,9 @@ static struct ip_flow *ip_flow_table_find(struct ip_reassemble_manager *mgr, con
// search in the bucket // search in the bucket
struct ip_flow *old = NULL; struct ip_flow *old = NULL;
struct ip_flow *empty = NULL; struct ip_flow *empty = NULL;
uint64_t timeout = mgr->timeout;
uint32_t assoc = mgr->bucket_entries;
uint64_t tms = timestamp_get_sec();
for (uint32_t i = 0; i != assoc; i++) for (uint32_t i = 0; i != assoc; i++)
{ {
if (ip_flow_key_cmp(key, &p1[i].key) == 0) if (ip_flow_key_cmp(key, &p1[i].key) == 0)
@@ -487,7 +535,7 @@ static struct ip_flow *ip_flow_table_find(struct ip_reassemble_manager *mgr, con
{ {
empty = (empty == NULL) ? (p1 + i) : empty; empty = (empty == NULL) ? (p1 + i) : empty;
} }
else if (timeout + p1[i].create_time < tms) else if (timeout + p1[i].create_time <= tms)
{ {
old = (old == NULL) ? (p1 + i) : old; old = (old == NULL) ? (p1 + i) : old;
} }
@@ -502,7 +550,7 @@ static struct ip_flow *ip_flow_table_find(struct ip_reassemble_manager *mgr, con
{ {
empty = (empty == NULL) ? (p2 + i) : empty; empty = (empty == NULL) ? (p2 + i) : empty;
} }
else if (timeout + p2[i].create_time < tms) else if (timeout + p2[i].create_time <= tms)
{ {
old = (old == NULL) ? (p2 + i) : old; old = (old == NULL) ? (p2 + i) : old;
} }
@@ -513,22 +561,20 @@ static struct ip_flow *ip_flow_table_find(struct ip_reassemble_manager *mgr, con
return NULL; return NULL;
} }
static struct ip_flow *ip_flow_table_update(struct ip_reassemble_manager *mgr, const struct ip_flow_key *key) static struct ip_flow *ip_reassemble_manager_update_flow(struct ip_reassemble_manager *mgr, const struct ip_flow_key *key)
{ {
struct ip_flow *flow = NULL;
struct ip_flow *free = NULL; struct ip_flow *free = NULL;
struct ip_flow *expired = NULL; struct ip_flow *expired = NULL;
struct ip_flow *flow = NULL;
uint64_t tms = timestamp_get_msec();
flow = ip_flow_table_find(mgr, key, &free, &expired); flow = ip_reassemble_manager_find_flow(mgr, key, &free, &expired);
if (flow == NULL) if (flow == NULL)
{ {
if (expired) if (expired)
{ {
IP_REASSEMBLE_DEBUG_ARG1("ip flow new (use expired iterm): ", key); IP_REASSEMBLE_DEBUG1("add ip flow success: reuse expired entry", key);
ip_flow_free(expired); ip_reassemble_manager_reuse_flow(mgr, expired, key);
ip_flow_init(expired, key); ip_reassemble_stat_inc(mgr, timeout, key);
ip_flow_table_reuse(mgr, expired);
mgr->last = expired; mgr->last = expired;
return expired; return expired;
@@ -536,28 +582,27 @@ static struct ip_flow *ip_flow_table_update(struct ip_reassemble_manager *mgr, c
if (free) if (free)
{ {
IP_REASSEMBLE_DEBUG_ARG1("ip flow new (use free iterm): ", key); IP_REASSEMBLE_DEBUG1("add ip flow success: use free entry", key);
ip_flow_init(free, key); ip_flow_init(free, key);
ip_flow_table_add(mgr, free); ip_reassemble_manager_add_flow(mgr, free);
mgr->last = free; mgr->last = free;
return free; return free;
} }
// no space // no space
IP_REASSEMBLE_DEBUG_ARG1("bucket full discarding new fragmented packets: ", key); IP_REASSEMBLE_ERROR1("add ip flow failed: bucket full", key);
mgr->stat.fail_nospace++; ip_reassemble_stat_inc(mgr, fail_no_space, key);
return NULL; return NULL;
} }
else else
{ {
// expired // expired
if (mgr->timeout + flow->create_time < tms) if (mgr->timeout + flow->create_time <= timestamp_get_sec())
{ {
IP_REASSEMBLE_DEBUG_ARG1("ip flow find, but expired: ", key); IP_REASSEMBLE_DEBUG1("add ip flow success: reuse expired entry", key);
ip_flow_free(flow); ip_reassemble_manager_reuse_flow(mgr, flow, key);
ip_flow_init(flow, key); ip_reassemble_stat_inc(mgr, timeout, key);
ip_flow_table_reuse(mgr, flow);
mgr->last = flow; mgr->last = flow;
return flow; return flow;
@@ -565,41 +610,33 @@ static struct ip_flow *ip_flow_table_update(struct ip_reassemble_manager *mgr, c
// not expired // not expired
else else
{ {
IP_REASSEMBLE_DEBUG_ARG1("ip flow find, not expired: ", key); IP_REASSEMBLE_DEBUG1("find ip flow success: not expire", key);
mgr->last = flow; mgr->last = flow;
return flow; return flow;
} }
} }
} }
void ip_flow_table_expire(struct ip_reassemble_manager *mgr)
{
struct ip_flow *flow = NULL;
uint64_t curr_ts = timestamp_get_msec();
uint64_t timeout = mgr->timeout;
TAILQ_FOREACH(flow, &mgr->lru, lru)
if (timeout + flow->create_time < curr_ts)
{
IP_REASSEMBLE_DEBUG_ARG1("time expires discarding old fragmented packets: ", &flow->key);
ip_flow_free(flow);
ip_flow_table_del(mgr, flow);
}
}
/****************************************************************************** /******************************************************************************
* frag reassemble * frag reassemble
******************************************************************************/ ******************************************************************************/
static struct packet *ip_frag_reassemble(struct ip_flow *flow) static struct packet *ip_frag_reassemble(struct ip_reassemble_manager *mgr, struct ip_flow *flow)
{ {
struct ip_frag_pkt *first = &flow->frags[IP_FIRST_FRAG_IDX]; struct ip_frag_pkt *first = &flow->frags[IP_FIRST_FRAG_IDX];
struct ip_frag_pkt *last = &flow->frags[IP_LAST_FRAG_IDX]; struct ip_frag_pkt *last = &flow->frags[IP_LAST_FRAG_IDX];
struct ip_frag_pkt *temp = NULL; struct ip_frag_pkt *temp = NULL;
uint32_t loop = 0;
uint16_t last_offset = last->offset;
struct ip *ip4_hdr = NULL;
struct ip6_hdr *ip6_hdr = NULL;
// calculate the length of the reassembled packet // calculate the length of the reassembled packet
uint32_t buff_len = flow->expected_total_size + flow->hdr.hdr_len; uint32_t packet_len = flow->expected_total_size + flow->hdr.hdr_len;
char *buff = (char *)calloc(1, buff_len + sizeof(struct packet)); char *buff = (char *)calloc(1, packet_len + sizeof(struct packet));
if (buff == NULL) if (buff == NULL)
{ {
IP_REASSEMBLE_ERROR("unable to allocate memory"); IP_REASSEMBLE_ERROR("unable to allocate memory");
@@ -607,20 +644,17 @@ static struct packet *ip_frag_reassemble(struct ip_flow *flow)
} }
char *ptr = buff + sizeof(struct packet); char *ptr = buff + sizeof(struct packet);
char *end = ptr + buff_len; char *end = ptr + packet_len;
// copy last frag // copy last frag
if (last->len > end - ptr) if (last->len > end - ptr)
{ {
IP_REASSEMBLE_ERROR_ARG1("last packet length is greater than the expected reassembled length: ", &flow->key); IP_REASSEMBLE_ERROR1("last frag length not match expected reassembled length", &flow->key);
free(buff); goto error_out_invalid_length;
return NULL;
} }
end -= last->len; end -= last->len;
memcpy(end, last->data, last->len); memcpy(end, last->data, last->len);
uint32_t loop = 0;
uint16_t last_offset = last->offset;
while (first->len != last_offset) while (first->len != last_offset)
{ {
/* /*
@@ -631,22 +665,15 @@ static struct packet *ip_frag_reassemble(struct ip_flow *flow)
* will use the more recently arrived copy in the data buffer and * will use the more recently arrived copy in the data buffer and
* datagram delivered. * datagram delivered.
*/ */
for (uint32_t i = flow->next_fill_idx - 1; i >= IP_MIN_FRAG_NUM; i--) for (uint32_t i = flow->next_fill_idx - 1; i >= IP_MIN_FRAG_NUM; i--)
{ {
if (i == IP_FIRST_FRAG_IDX || i == IP_LAST_FRAG_IDX)
{
continue;
}
temp = &flow->frags[i]; temp = &flow->frags[i];
if (temp->offset + temp->len == last_offset) if (temp->offset + temp->len == last_offset)
{ {
if (temp->len > end - ptr) if (temp->len > end - ptr)
{ {
IP_REASSEMBLE_ERROR_ARG1("middle fragment packet length doesn't match last fragment packet offset: ", &flow->key); IP_REASSEMBLE_ERROR1("middle frag length not match expected reassembled length", &flow->key);
free(buff); goto error_out_invalid_length;
return NULL;
} }
end -= temp->len; end -= temp->len;
@@ -656,11 +683,10 @@ static struct packet *ip_frag_reassemble(struct ip_flow *flow)
} }
} }
if (loop > flow->next_fill_idx) if (loop > flow->next_fill_idx - IP_MIN_FRAG_NUM)
{ {
IP_REASSEMBLE_ERROR_ARG1("holes appear during frag reassemble: ", &flow->key); IP_REASSEMBLE_ERROR1("overlap appear during frag reassemble", &flow->key);
free(buff); goto error_out_overlap;
return NULL;
} }
loop++; loop++;
@@ -669,9 +695,8 @@ static struct packet *ip_frag_reassemble(struct ip_flow *flow)
// copy fist fragment data // copy fist fragment data
if (first->len > end - ptr) if (first->len > end - ptr)
{ {
IP_REASSEMBLE_ERROR_ARG1("last packet length is greater than the expected reassembled length: ", &flow->key); IP_REASSEMBLE_ERROR1("first frag length not match expected reassembled length", &flow->key);
free(buff); goto error_out_invalid_length;
return NULL;
} }
end -= first->len; end -= first->len;
memcpy(end, first->data, first->len); memcpy(end, first->data, first->len);
@@ -679,37 +704,46 @@ static struct packet *ip_frag_reassemble(struct ip_flow *flow)
// copy frag hdr // copy frag hdr
if (flow->hdr.hdr_len > end - ptr) if (flow->hdr.hdr_len > end - ptr)
{ {
IP_REASSEMBLE_ERROR_ARG1("hdr length is greater than the expected reassembled length: ", &flow->key); IP_REASSEMBLE_ERROR1("packet header length not match expected reassembled length", &flow->key);
free(buff); goto error_out_invalid_length;
return NULL;
} }
end -= flow->hdr.hdr_len; end -= flow->hdr.hdr_len;
memcpy(end, flow->hdr.hdr_data, flow->hdr.hdr_len); memcpy(end, flow->hdr.hdr_data, flow->hdr.hdr_len);
// assert
assert(ptr == end); assert(ptr == end);
if (flow->key.src_dst_len == IPV4_KEYLEN) if (flow->key.src_dst_len == IPV4_KEYLEN)
{ {
// update ip total length & ip checksum // update ip total length & ip checksum
struct ip *hdr = (struct ip *)(ptr + flow->hdr.l3_offset); ip4_hdr = (struct ip *)(ptr + flow->hdr.l3_offset);
ipv4_hdr_set_total_len(hdr, buff_len - flow->hdr.l3_offset); // update total length ipv4_hdr_set_total_len(ip4_hdr, packet_len - flow->hdr.l3_offset); // update total length
ipv4_hdr_set_mf_flag(hdr, false); // update more fragment flag ipv4_hdr_set_mf_flag(ip4_hdr, false); // update more fragment flag
ipv4_hdr_set_frag_offset(hdr, 0); // update fragment offset ipv4_hdr_set_frag_offset(ip4_hdr, 0); // update fragment offset
hdr->ip_sum = 0; // update checksum ip4_hdr->ip_sum = 0; // update checksum
hdr->ip_sum = checksum((char *)hdr, flow->hdr.l3_len); ip4_hdr->ip_sum = checksum((char *)ip4_hdr, flow->hdr.l3_len);
} }
else else
{ {
// update ipv6 payload length & next header // update ipv6 payload length & next header
struct ip6_hdr *hdr = (struct ip6_hdr *)(ptr + flow->hdr.l3_offset); ip6_hdr = (struct ip6_hdr *)(ptr + flow->hdr.l3_offset);
ipv6_hdr_set_payload_len(hdr, flow->expected_total_size); // update payload length ipv6_hdr_set_payload_len(ip6_hdr, flow->expected_total_size); // update payload length
ipv6_hdr_set_next_header(hdr, flow->hdr.next_proto); // update next header ipv6_hdr_set_next_header(ip6_hdr, flow->hdr.next_proto); // update next header
} }
// create a new packet // create a new packet
struct packet *new_pkt = (struct packet *)buff; packet_parse((struct packet *)buff, buff + sizeof(struct packet), packet_len);
packet_parse(new_pkt, buff + sizeof(struct packet), buff_len); return (struct packet *)buff;
return new_pkt; error_out_invalid_length:
ip_reassemble_stat_inc(mgr, fail_invalid_length, &flow->key);
free(buff);
return NULL;
error_out_overlap:
ip_reassemble_stat_inc(mgr, fail_overlap, &flow->key);
free(buff);
return NULL;
} }
/****************************************************************************** /******************************************************************************
@@ -781,9 +815,60 @@ void ip_reassemble_manager_destory(struct ip_reassemble_manager *mgr)
} }
} }
void ip_reassemble_manager_stat(struct ip_reassemble_manager *mgr) void ip_reassemble_manager_expire(struct ip_reassemble_manager *mgr)
{ {
// TODO struct ip_flow *flow = NULL;
uint64_t curr_ts = timestamp_get_sec();
uint64_t timeout = mgr->timeout;
TAILQ_FOREACH(flow, &mgr->lru, lru)
if (timeout + flow->create_time <= curr_ts)
{
IP_REASSEMBLE_DEBUG1("expire ip flow: discarding old fragmented packets", &flow->key);
ip_reassemble_manager_del_flow(mgr, flow);
ip_reassemble_stat_inc(mgr, timeout, &flow->key);
ip_flow_free(flow);
}
}
void ip_reassemble_manager_print_stat(struct ip_reassemble_manager *mgr)
{
if (mgr)
{
IP_REASSEMBLE_DEBUG("ip4_flow_find : %lu", mgr->stat.ip4_flow_find);
IP_REASSEMBLE_DEBUG("ip4_flow_add : %lu", mgr->stat.ip4_flow_add);
IP_REASSEMBLE_DEBUG("ip4_flow_del : %lu", mgr->stat.ip4_flow_del);
IP_REASSEMBLE_DEBUG("ip4_flow_timeout : %lu", mgr->stat.ip4_flow_timeout);
IP_REASSEMBLE_DEBUG("ip4_flow_fail_no_space : %lu", mgr->stat.ip4_flow_fail_no_space);
IP_REASSEMBLE_DEBUG("ip4_flow_fail_overlap : %lu", mgr->stat.ip4_flow_fail_overlap);
IP_REASSEMBLE_DEBUG("ip4_flow_fail_many_frag : %lu", mgr->stat.ip4_flow_fail_many_frag);
IP_REASSEMBLE_DEBUG("ip4_flow_fail_invalid_length : %lu", mgr->stat.ip4_flow_fail_invalid_length);
IP_REASSEMBLE_DEBUG("ip4_flow_bypass_dup_fist_frag : %lu", mgr->stat.ip4_flow_bypass_dup_fist_frag);
IP_REASSEMBLE_DEBUG("ip4_flow_bypass_dup_last_frag : %lu", mgr->stat.ip4_flow_bypass_dup_last_frag);
IP_REASSEMBLE_DEBUG("ip6_flow_find : %lu", mgr->stat.ip6_flow_find);
IP_REASSEMBLE_DEBUG("ip6_flow_add : %lu", mgr->stat.ip6_flow_add);
IP_REASSEMBLE_DEBUG("ip6_flow_del : %lu", mgr->stat.ip6_flow_del);
IP_REASSEMBLE_DEBUG("ip6_flow_timeout : %lu", mgr->stat.ip6_flow_timeout);
IP_REASSEMBLE_DEBUG("ip6_flow_fail_no_space : %lu", mgr->stat.ip6_flow_fail_no_space);
IP_REASSEMBLE_DEBUG("ip6_flow_fail_overlap : %lu", mgr->stat.ip6_flow_fail_overlap);
IP_REASSEMBLE_DEBUG("ip6_flow_fail_many_frag : %lu", mgr->stat.ip6_flow_fail_many_frag);
IP_REASSEMBLE_DEBUG("ip6_flow_fail_invalid_length : %lu", mgr->stat.ip6_flow_fail_invalid_length);
IP_REASSEMBLE_DEBUG("ip6_flow_bypass_dup_fist_frag : %lu", mgr->stat.ip6_flow_bypass_dup_fist_frag);
IP_REASSEMBLE_DEBUG("ip6_flow_bypass_dup_last_frag : %lu", mgr->stat.ip6_flow_bypass_dup_last_frag);
}
}
struct ip_reassemble_stat *ip_reassemble_manager_get_stat(struct ip_reassemble_manager *mgr)
{
if (mgr)
{
return &(mgr->stat);
}
else
{
return NULL;
}
} }
/* /*
@@ -812,7 +897,7 @@ struct packet *ip_reassemble_packet(struct ip_reassemble_manager *mgr, const str
pkt1 = ipv4_reassemble_packet(mgr, pkt); pkt1 = ipv4_reassemble_packet(mgr, pkt);
if (pkt1 && pkt1->frag_layer) if (pkt1 && pkt1->frag_layer)
{ {
pkt2 = ip_reassemble_packet(mgr, pkt); pkt2 = ip_reassemble_packet(mgr, pkt1);
packet_free(pkt1); packet_free(pkt1);
return pkt2; return pkt2;
} }
@@ -824,7 +909,7 @@ struct packet *ip_reassemble_packet(struct ip_reassemble_manager *mgr, const str
pkt1 = ipv6_reassemble_packet(mgr, pkt); pkt1 = ipv6_reassemble_packet(mgr, pkt);
if (pkt1 && pkt1->frag_layer) if (pkt1 && pkt1->frag_layer)
{ {
pkt2 = ip_reassemble_packet(mgr, pkt); pkt2 = ip_reassemble_packet(mgr, pkt1);
packet_free(pkt1); packet_free(pkt1);
return pkt2; return pkt2;
} }
@@ -839,13 +924,12 @@ struct packet *ip_reassemble_packet(struct ip_reassemble_manager *mgr, const str
struct packet *ipv4_reassemble_packet(struct ip_reassemble_manager *mgr, const struct packet *pkt) struct packet *ipv4_reassemble_packet(struct ip_reassemble_manager *mgr, const struct packet *pkt)
{ {
struct layer_record *layer = pkt->frag_layer; const struct layer_record *layer = pkt->frag_layer;
struct ip *hdr = (struct ip *)layer->hdr_ptr; const struct ip *hdr = (const struct ip *)layer->hdr_ptr;
char *data = (char *)layer->pld_ptr; uint16_t frag_len = ipv4_hdr_get_total_len(hdr) - ipv4_hdr_get_hdr_len(hdr);
uint16_t len = ipv4_hdr_get_total_len(hdr) - ipv4_hdr_get_hdr_len(hdr); if (frag_len > layer->pld_len)
if (len > layer->pld_len)
{ {
IP_REASSEMBLE_ERROR("unexpected header length on fragmented packet, ip_id: %lu", ipv4_hdr_get_ipid(hdr)); IP_REASSEMBLE_ERROR("unexpected header length, ip id: %lu", ipv4_hdr_get_ipid(hdr));
return NULL; return NULL;
} }
@@ -856,18 +940,20 @@ struct packet *ipv4_reassemble_packet(struct ip_reassemble_manager *mgr, const s
key.src_dst_len = IPV4_KEYLEN; key.src_dst_len = IPV4_KEYLEN;
key.ip_id = ipv4_hdr_get_ipid(hdr); key.ip_id = ipv4_hdr_get_ipid(hdr);
key.proto = ipv4_hdr_get_proto(hdr); key.proto = ipv4_hdr_get_proto(hdr);
struct ip_flow *flow = ip_flow_table_update(mgr, &key);
struct ip_flow *flow = ip_reassemble_manager_update_flow(mgr, &key);
if (flow == NULL) if (flow == NULL)
{ {
return NULL; return NULL;
} }
char *frag_data = (char *)layer->pld_ptr;
bool more_frags = ipv4_hdr_get_mf_flag(hdr); bool more_frags = ipv4_hdr_get_mf_flag(hdr);
uint16_t offset = ipv4_hdr_get_frag_offset(hdr); uint16_t frag_offset = ipv4_hdr_get_frag_offset(hdr);
if (ip_flow_update(flow, pkt, data, len, offset, more_frags) != 0) if (ip_flow_update(mgr, flow, pkt, frag_data, frag_len, frag_offset, more_frags) != 0)
{ {
ip_reassemble_manager_del_flow(mgr, flow);
ip_flow_free(flow); ip_flow_free(flow);
ip_flow_table_del(mgr, flow);
return NULL; return NULL;
} }
@@ -876,9 +962,9 @@ struct packet *ipv4_reassemble_packet(struct ip_reassemble_manager *mgr, const s
return NULL; return NULL;
} }
struct packet *new_pkt = ip_frag_reassemble(flow); struct packet *new_pkt = ip_frag_reassemble(mgr, flow);
ip_reassemble_manager_del_flow(mgr, flow);
ip_flow_free(flow); ip_flow_free(flow);
ip_flow_table_del(mgr, flow);
return new_pkt; return new_pkt;
} }
@@ -924,41 +1010,41 @@ struct packet *ipv4_reassemble_packet(struct ip_reassemble_manager *mgr, const s
struct packet *ipv6_reassemble_packet(struct ip_reassemble_manager *mgr, const struct packet *pkt) struct packet *ipv6_reassemble_packet(struct ip_reassemble_manager *mgr, const struct packet *pkt)
{ {
struct layer_record *layer = pkt->frag_layer; const struct layer_record *layer = pkt->frag_layer;
const struct ip6_hdr *hdr = (const struct ip6_hdr *)layer->hdr_ptr; const struct ip6_hdr *hdr = (const struct ip6_hdr *)layer->hdr_ptr;
struct ip6_frag *frag_ext = ipv6_hdr_get_frag_ext(hdr); const struct ip6_frag *frag_hdr = ipv6_hdr_get_frag_ext(hdr);
if (frag_ext == NULL) if (frag_hdr == NULL)
{ {
return NULL; return NULL;
} }
char *frag_data = (char *)frag_hdr + sizeof(struct ip6_frag);
uint16_t frag_len = ipv6_hdr_get_payload_len(hdr) - sizeof(struct ip6_frag);
if (frag_data + frag_len > pkt->data_ptr + pkt->data_len)
{
IP_REASSEMBLE_ERROR("unexpected header length, frag id: %lu", ipv6_frag_get_ident(frag_hdr));
return NULL;
}
struct ip_flow_key key = {0}; struct ip_flow_key key = {0};
memcpy(&key.src_dst_addr[0], hdr->ip6_src.s6_addr, 16); memcpy(&key.src_dst_addr[0], hdr->ip6_src.s6_addr, 16);
memcpy(&key.src_dst_addr[2], hdr->ip6_dst.s6_addr, 16); memcpy(&key.src_dst_addr[2], hdr->ip6_dst.s6_addr, 16);
key.src_dst_len = IPV6_KEYLEN; key.src_dst_len = IPV6_KEYLEN;
key.ip_id = frag_ext->ip6f_ident; key.ip_id = ipv6_frag_get_ident(frag_hdr);
key.proto = 0; // only first fragment has the upper layer protocol key.proto = 0; // only first fragment has the upper layer protocol
struct ip_flow *flow = ip_flow_table_update(mgr, &key); struct ip_flow *flow = ip_reassemble_manager_update_flow(mgr, &key);
if (flow == NULL) if (flow == NULL)
{ {
return NULL; return NULL;
} }
char *data = (char *)layer->hdr_ptr + sizeof(struct ip6_hdr) + sizeof(struct ip6_frag); bool more_frags = ipv6_frag_get_more(frag_hdr);
uint16_t len = ipv6_hdr_get_payload_len(hdr) - sizeof(struct ip6_frag); uint16_t frag_offset = ipv6_frag_get_offset(frag_hdr);
if (ip_flow_update(mgr, flow, pkt, frag_data, frag_len, frag_offset, more_frags) != 0)
if (data + len > pkt->data_ptr + pkt->data_len)
{
IP_REASSEMBLE_ERROR("unexpected header length on fragmented packet, frag_id: %lu", frag_ext->ip6f_ident);
return NULL;
}
bool more_frags = (frag_ext->ip6f_offlg & IP6F_MORE_FRAG);
uint16_t offset = ntohs(frag_ext->ip6f_offlg & IP6F_OFF_MASK);
if (ip_flow_update(flow, pkt, data, len, offset, more_frags) != 0)
{ {
ip_reassemble_manager_del_flow(mgr, flow);
ip_flow_free(flow); ip_flow_free(flow);
ip_flow_table_del(mgr, flow);
return NULL; return NULL;
} }
@@ -967,9 +1053,9 @@ struct packet *ipv6_reassemble_packet(struct ip_reassemble_manager *mgr, const s
return NULL; return NULL;
} }
struct packet *new_pkt = ip_frag_reassemble(flow); struct packet *new_pkt = ip_frag_reassemble(mgr, flow);
ip_reassemble_manager_del_flow(mgr, flow);
ip_flow_free(flow); ip_flow_free(flow);
ip_flow_table_del(mgr, flow);
return new_pkt; return new_pkt;
} }

View File

@@ -16,14 +16,45 @@ struct ip_reassemble_config
{ {
bool enable; bool enable;
uint32_t timeout; uint32_t timeout; // seconds
uint32_t bucket_entries; uint32_t bucket_entries;
uint32_t bucket_num; uint32_t bucket_num;
}; };
struct ip_reassemble_stat
{
// IPv4 flow stat
uint64_t ip4_flow_find;
uint64_t ip4_flow_add;
uint64_t ip4_flow_del;
uint64_t ip4_flow_timeout;
uint64_t ip4_flow_fail_no_space;
uint64_t ip4_flow_fail_overlap;
uint64_t ip4_flow_fail_many_frag;
uint64_t ip4_flow_fail_invalid_length;
uint64_t ip4_flow_bypass_dup_fist_frag;
uint64_t ip4_flow_bypass_dup_last_frag;
// IPv6 flow stat
uint64_t ip6_flow_find;
uint64_t ip6_flow_add;
uint64_t ip6_flow_del;
uint64_t ip6_flow_timeout;
uint64_t ip6_flow_fail_no_space;
uint64_t ip6_flow_fail_overlap;
uint64_t ip6_flow_fail_many_frag;
uint64_t ip6_flow_fail_invalid_length;
uint64_t ip6_flow_bypass_dup_fist_frag;
uint64_t ip6_flow_bypass_dup_last_frag;
};
struct ip_reassemble_manager *ip_reassemble_manager_create(const struct ip_reassemble_config *config); struct ip_reassemble_manager *ip_reassemble_manager_create(const struct ip_reassemble_config *config);
void ip_reassemble_manager_destory(struct ip_reassemble_manager *mgr); void ip_reassemble_manager_destory(struct ip_reassemble_manager *mgr);
void ip_reassemble_manager_stat(struct ip_reassemble_manager *mgr); void ip_reassemble_manager_expire(struct ip_reassemble_manager *mgr);
void ip_reassemble_manager_print_stat(struct ip_reassemble_manager *mgr);
struct ip_reassemble_stat *ip_reassemble_manager_get_stat(struct ip_reassemble_manager *mgr);
/* /*
* Returns the reassembled packet, or NULL if the packet is not reassembled * Returns the reassembled packet, or NULL if the packet is not reassembled

View File

@@ -8,6 +8,10 @@ target_link_libraries(gtest_ipv4_reassemble ip_reassemble gtest)
add_executable(gtest_ipv6_reassemble gtest_ipv6_reassemble.cpp) add_executable(gtest_ipv6_reassemble gtest_ipv6_reassemble.cpp)
target_link_libraries(gtest_ipv6_reassemble ip_reassemble gtest) target_link_libraries(gtest_ipv6_reassemble ip_reassemble gtest)
add_executable(gtest_ip_reassemble gtest_ip_reassemble.cpp)
target_link_libraries(gtest_ip_reassemble ip_reassemble gtest)
include(GoogleTest) include(GoogleTest)
gtest_discover_tests(gtest_ipv4_reassemble) gtest_discover_tests(gtest_ipv4_reassemble)
gtest_discover_tests(gtest_ipv6_reassemble) gtest_discover_tests(gtest_ipv6_reassemble)
gtest_discover_tests(gtest_ip_reassemble)

View File

@@ -0,0 +1,15 @@
#include "gtest_utils.h"
#if 1
TEST(IP_REASSEMBLE, NESTED)
{
// TODO
// IP in IP, both with fragmentation
}
#endif
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -1,17 +1,4 @@
#include <gtest/gtest.h> #include "gtest_utils.h"
#include "timestamp.h"
#include "tcp_utils.h"
#include "ipv4_utils.h"
#include "packet_helpers.h"
#include "ip_reassemble.h"
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1000,
.bucket_entries = 16,
.bucket_num = 8,
};
/* /*
* Frame 4: 60 bytes on wire (480 bits), 60 bytes captured (480 bits) * Frame 4: 60 bytes on wire (480 bits), 60 bytes captured (480 bits)
@@ -204,30 +191,55 @@ unsigned char expect[] = {
0xf4, 0xa5, 0x27, 0x0f, 0x91, 0x07, 0x24, 0x8b, 0x03, 0xd5, 0x18, 0xe7, 0x50, 0x18, 0xff, 0x00, 0x30, 0x16, 0x00, 0x00, 0x61, 0x62, 0x63, 0x0a // data from frag2 0xf4, 0xa5, 0x27, 0x0f, 0x91, 0x07, 0x24, 0x8b, 0x03, 0xd5, 0x18, 0xe7, 0x50, 0x18, 0xff, 0x00, 0x30, 0x16, 0x00, 0x00, 0x61, 0x62, 0x63, 0x0a // data from frag2
}; };
TEST(IPV4_REASSEMBLE, PADDING) #if 1
TEST(IPV4_REASSEMBLE, PADDING_ORDER)
{ {
struct packet pkt; struct packet pkt;
struct packet *new_pkt; struct packet *new_pkt;
const struct layer_record *layer; const struct layer_record *layer;
struct ip_reassemble_manager *mgr; struct ip_reassemble_manager *mgr;
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1,
.bucket_entries = 16,
.bucket_num = 8,
};
timestamp_update(); timestamp_update();
mgr = ip_reassemble_manager_create(&config); mgr = ip_reassemble_manager_create(&config);
EXPECT_TRUE(mgr != NULL); EXPECT_TRUE(mgr != NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag1 // frag1
packet_parse(&pkt, (const char *)frag1, sizeof(frag1)); packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
new_pkt = ip_reassemble_packet(mgr, &pkt); new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL); EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
1, 1, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag2 // frag2
packet_parse(&pkt, (const char *)frag2, sizeof(frag2)); packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
new_pkt = ip_reassemble_packet(mgr, &pkt); new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt); EXPECT_TRUE(new_pkt);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
2, 1, 1, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// check packet // check packet
packet_print(new_pkt); // packet_print(new_pkt);
EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */); EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
EXPECT_TRUE(new_pkt->data_len == sizeof(expect)); EXPECT_TRUE(new_pkt->data_len == sizeof(expect));
EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0); EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0);
@@ -272,26 +284,446 @@ TEST(IPV4_REASSEMBLE, PADDING)
ip_reassemble_manager_destory(mgr); ip_reassemble_manager_destory(mgr);
} }
#endif
#if 1
TEST(IPV4_REASSEMBLE, PADDING_UNORDER)
{
struct packet pkt;
struct packet *new_pkt;
const struct layer_record *layer;
struct ip_reassemble_manager *mgr;
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1,
.bucket_entries = 16,
.bucket_num = 8,
};
timestamp_update();
mgr = ip_reassemble_manager_create(&config);
EXPECT_TRUE(mgr != NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag2
packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
1, 1, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag1
packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
2, 1, 1, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// check packet
// packet_print(new_pkt);
EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
EXPECT_TRUE(new_pkt->data_len == sizeof(expect));
EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0);
// check IPv4
layer = packet_get_innermost_layer(new_pkt, LAYER_TYPE_IPV4);
EXPECT_TRUE(layer);
struct ip *hdr = (struct ip *)layer->hdr_ptr;
EXPECT_TRUE(ipv4_hdr_get_version(hdr) == 4);
EXPECT_TRUE(ipv4_hdr_get_hdr_len(hdr) == 20 /* IPv4 */);
EXPECT_TRUE(ipv4_hdr_get_tos(hdr) == 0);
EXPECT_TRUE(ipv4_hdr_get_total_len(hdr) == 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
EXPECT_TRUE(ipv4_hdr_get_ipid(hdr) == 0xffff);
EXPECT_TRUE(ipv4_hdr_get_flags(hdr) == 0x0);
EXPECT_TRUE(ipv4_hdr_get_frag_offset(hdr) == 0);
EXPECT_TRUE(ipv4_hdr_get_ttl(hdr) == 127);
EXPECT_TRUE(ipv4_hdr_get_proto(hdr) == 6);
EXPECT_TRUE(ipv4_hdr_get_checksum(hdr) == 0x6d73); // NOTE this is correct checksum
EXPECT_TRUE(ipv4_hdr_get_src_addr(hdr) == 0xc0a82467);
EXPECT_TRUE(ipv4_hdr_get_dst_addr(hdr) == 0xc0a82889);
EXPECT_TRUE(ipv4_hdr_get_opt_len(hdr) == 0);
EXPECT_TRUE(ipv4_hdr_get_opt_data(hdr) == NULL);
// check TCP
layer = packet_get_innermost_layer(new_pkt, LAYER_TYPE_TCP);
EXPECT_TRUE(layer);
struct tcphdr *tcp_hdr = (struct tcphdr *)layer->hdr_ptr;
EXPECT_TRUE(tcp_hdr_get_src_port(tcp_hdr) == 62629);
EXPECT_TRUE(tcp_hdr_get_dst_port(tcp_hdr) == 9999);
EXPECT_TRUE(tcp_hdr_get_seq(tcp_hdr) == 2433164423);
EXPECT_TRUE(tcp_hdr_get_ack(tcp_hdr) == 64297191);
EXPECT_TRUE(tcp_hdr_get_hdr_len(tcp_hdr) == 20);
EXPECT_TRUE(tcp_hdr_get_flags(tcp_hdr) == 0x018);
EXPECT_TRUE(tcp_hdr_get_window(tcp_hdr) == 65280);
EXPECT_TRUE(tcp_hdr_get_checksum(tcp_hdr) == 0x5e92);
EXPECT_TRUE(tcp_hdr_get_urg_ptr(tcp_hdr) == 0);
EXPECT_TRUE(tcp_hdr_get_opt_len(tcp_hdr) == 0);
EXPECT_TRUE(tcp_hdr_get_opt_data(tcp_hdr) == NULL);
// free packet
packet_free(new_pkt);
ip_reassemble_manager_destory(mgr);
}
#endif
#if 1
TEST(IPV4_REASSEMBLE, EXPIRE) TEST(IPV4_REASSEMBLE, EXPIRE)
{ {
// TODO struct packet pkt;
} struct packet *new_pkt;
struct ip_reassemble_manager *mgr;
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1,
.bucket_entries = 16,
.bucket_num = 8,
};
timestamp_update();
mgr = ip_reassemble_manager_create(&config);
EXPECT_TRUE(mgr != NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag1
packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
1, 1, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// sleep 1s
sleep(1);
timestamp_update();
// frag2
packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
2, 2, 1, 1, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// free packet
packet_free(new_pkt);
ip_reassemble_manager_destory(mgr);
}
#endif
#if 1
TEST(IPV4_REASSEMBLE, DUP_FIRST_FRAG)
{
struct packet pkt;
struct packet *new_pkt;
const struct layer_record *layer;
struct ip_reassemble_manager *mgr;
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1,
.bucket_entries = 16,
.bucket_num = 8,
};
timestamp_update();
mgr = ip_reassemble_manager_create(&config);
EXPECT_TRUE(mgr != NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag1
packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
1, 1, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag1
packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
2, 1, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 1, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag2
packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
3, 1, 1, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 1, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// check packet
// packet_print(new_pkt);
EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
EXPECT_TRUE(new_pkt->data_len == sizeof(expect));
EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0);
// check IPv4
layer = packet_get_innermost_layer(new_pkt, LAYER_TYPE_IPV4);
EXPECT_TRUE(layer);
struct ip *hdr = (struct ip *)layer->hdr_ptr;
EXPECT_TRUE(ipv4_hdr_get_version(hdr) == 4);
EXPECT_TRUE(ipv4_hdr_get_hdr_len(hdr) == 20 /* IPv4 */);
EXPECT_TRUE(ipv4_hdr_get_tos(hdr) == 0);
EXPECT_TRUE(ipv4_hdr_get_total_len(hdr) == 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
EXPECT_TRUE(ipv4_hdr_get_ipid(hdr) == 0xffff);
EXPECT_TRUE(ipv4_hdr_get_flags(hdr) == 0x0);
EXPECT_TRUE(ipv4_hdr_get_frag_offset(hdr) == 0);
EXPECT_TRUE(ipv4_hdr_get_ttl(hdr) == 127);
EXPECT_TRUE(ipv4_hdr_get_proto(hdr) == 6);
EXPECT_TRUE(ipv4_hdr_get_checksum(hdr) == 0x6d73); // NOTE this is correct checksum
EXPECT_TRUE(ipv4_hdr_get_src_addr(hdr) == 0xc0a82467);
EXPECT_TRUE(ipv4_hdr_get_dst_addr(hdr) == 0xc0a82889);
EXPECT_TRUE(ipv4_hdr_get_opt_len(hdr) == 0);
EXPECT_TRUE(ipv4_hdr_get_opt_data(hdr) == NULL);
// check TCP
layer = packet_get_innermost_layer(new_pkt, LAYER_TYPE_TCP);
EXPECT_TRUE(layer);
struct tcphdr *tcp_hdr = (struct tcphdr *)layer->hdr_ptr;
EXPECT_TRUE(tcp_hdr_get_src_port(tcp_hdr) == 62629);
EXPECT_TRUE(tcp_hdr_get_dst_port(tcp_hdr) == 9999);
EXPECT_TRUE(tcp_hdr_get_seq(tcp_hdr) == 2433164423);
EXPECT_TRUE(tcp_hdr_get_ack(tcp_hdr) == 64297191);
EXPECT_TRUE(tcp_hdr_get_hdr_len(tcp_hdr) == 20);
EXPECT_TRUE(tcp_hdr_get_flags(tcp_hdr) == 0x018);
EXPECT_TRUE(tcp_hdr_get_window(tcp_hdr) == 65280);
EXPECT_TRUE(tcp_hdr_get_checksum(tcp_hdr) == 0x5e92);
EXPECT_TRUE(tcp_hdr_get_urg_ptr(tcp_hdr) == 0);
EXPECT_TRUE(tcp_hdr_get_opt_len(tcp_hdr) == 0);
EXPECT_TRUE(tcp_hdr_get_opt_data(tcp_hdr) == NULL);
// free packet
packet_free(new_pkt);
ip_reassemble_manager_destory(mgr);
}
#endif
#if 1
TEST(IPV4_REASSEMBLE, DUP_LAST_FRAG)
{
struct packet pkt;
struct packet *new_pkt;
const struct layer_record *layer;
struct ip_reassemble_manager *mgr;
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1,
.bucket_entries = 16,
.bucket_num = 8,
};
timestamp_update();
mgr = ip_reassemble_manager_create(&config);
EXPECT_TRUE(mgr != NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag2
packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
1, 1, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag2
packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
2, 1, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 1, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag1
packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
3, 1, 1, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 1, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// check packet
// packet_print(new_pkt);
EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
EXPECT_TRUE(new_pkt->data_len == sizeof(expect));
EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0);
// check IPv4
layer = packet_get_innermost_layer(new_pkt, LAYER_TYPE_IPV4);
EXPECT_TRUE(layer);
struct ip *hdr = (struct ip *)layer->hdr_ptr;
EXPECT_TRUE(ipv4_hdr_get_version(hdr) == 4);
EXPECT_TRUE(ipv4_hdr_get_hdr_len(hdr) == 20 /* IPv4 */);
EXPECT_TRUE(ipv4_hdr_get_tos(hdr) == 0);
EXPECT_TRUE(ipv4_hdr_get_total_len(hdr) == 20 /* IPv4 */ + 20 /* TCP */ + 28 /* DATA */);
EXPECT_TRUE(ipv4_hdr_get_ipid(hdr) == 0xffff);
EXPECT_TRUE(ipv4_hdr_get_flags(hdr) == 0x0);
EXPECT_TRUE(ipv4_hdr_get_frag_offset(hdr) == 0);
EXPECT_TRUE(ipv4_hdr_get_ttl(hdr) == 127);
EXPECT_TRUE(ipv4_hdr_get_proto(hdr) == 6);
EXPECT_TRUE(ipv4_hdr_get_checksum(hdr) == 0x6d73); // NOTE this is correct checksum
EXPECT_TRUE(ipv4_hdr_get_src_addr(hdr) == 0xc0a82467);
EXPECT_TRUE(ipv4_hdr_get_dst_addr(hdr) == 0xc0a82889);
EXPECT_TRUE(ipv4_hdr_get_opt_len(hdr) == 0);
EXPECT_TRUE(ipv4_hdr_get_opt_data(hdr) == NULL);
// check TCP
layer = packet_get_innermost_layer(new_pkt, LAYER_TYPE_TCP);
EXPECT_TRUE(layer);
struct tcphdr *tcp_hdr = (struct tcphdr *)layer->hdr_ptr;
EXPECT_TRUE(tcp_hdr_get_src_port(tcp_hdr) == 62629);
EXPECT_TRUE(tcp_hdr_get_dst_port(tcp_hdr) == 9999);
EXPECT_TRUE(tcp_hdr_get_seq(tcp_hdr) == 2433164423);
EXPECT_TRUE(tcp_hdr_get_ack(tcp_hdr) == 64297191);
EXPECT_TRUE(tcp_hdr_get_hdr_len(tcp_hdr) == 20);
EXPECT_TRUE(tcp_hdr_get_flags(tcp_hdr) == 0x018);
EXPECT_TRUE(tcp_hdr_get_window(tcp_hdr) == 65280);
EXPECT_TRUE(tcp_hdr_get_checksum(tcp_hdr) == 0x5e92);
EXPECT_TRUE(tcp_hdr_get_urg_ptr(tcp_hdr) == 0);
EXPECT_TRUE(tcp_hdr_get_opt_len(tcp_hdr) == 0);
EXPECT_TRUE(tcp_hdr_get_opt_data(tcp_hdr) == NULL);
// free packet
packet_free(new_pkt);
ip_reassemble_manager_destory(mgr);
}
#endif
#if 1
TEST(IPV4_REASSEMBLE, FULL) TEST(IPV4_REASSEMBLE, FULL)
{ {
// TODO struct packet pkt;
} struct packet *new_pkt;
struct ip_reassemble_manager *mgr;
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1,
.bucket_entries = 1,
.bucket_num = 1,
};
TEST(IPV4_REASSEMBLE, HOLE) timestamp_update();
{
// TODO
}
TEST(IPV4_REASSEMBLE, NESTED) mgr = ip_reassemble_manager_create(&config);
{ EXPECT_TRUE(mgr != NULL);
// TODO // ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
char dup_frag[sizeof(frag1)] = {0};
memcpy(dup_frag, frag1, sizeof(frag1));
packet_parse(&pkt, (const char *)dup_frag, sizeof(dup_frag));
// flow1
packet_set_ipv4_src_addr(&pkt, 1);
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
1, 1, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// flow2
packet_set_ipv4_src_addr(&pkt, 2);
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
2, 2, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// flow3
packet_set_ipv4_src_addr(&pkt, 3);
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
3, 2, 0, 0, // ip4: find, add, del, timeout
1, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// free packet
packet_free(new_pkt);
ip_reassemble_manager_destory(mgr);
} }
#endif
#if 1
TEST(IPV4_REASSEMBLE, OVERLAP)
{
// TEST ON IPv6
}
#endif
int main(int argc, char **argv) int main(int argc, char **argv)
{ {

View File

@@ -1,17 +1,4 @@
#include <gtest/gtest.h> #include "gtest_utils.h"
#include "timestamp.h"
#include "udp_utils.h"
#include "ipv6_utils.h"
#include "packet_helpers.h"
#include "ip_reassemble.h"
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1000,
.bucket_entries = 16,
.bucket_num = 8,
};
/* /*
* Frame 3: 1510 bytes on wire (12080 bits), 1510 bytes captured (12080 bits) * Frame 3: 1510 bytes on wire (12080 bits), 1510 bytes captured (12080 bits)
@@ -615,40 +602,77 @@ unsigned char expect[] = {
0x7b, 0x0d, 0x49, 0xe1, 0x76, 0x34, 0x07, 0xf7, 0x9e, 0xe5, 0xb7, 0x66, 0x39, 0xb1, 0xb0, 0xa0, 0x1a, 0x44, 0x90, 0xce, 0x07, 0x03, 0xf2, 0x1b, 0x0e, 0xc6, 0x7b, 0x0d, 0x49, 0xe1, 0x76, 0x34, 0x07, 0xf7, 0x9e, 0xe5, 0xb7, 0x66, 0x39, 0xb1, 0xb0, 0xa0, 0x1a, 0x44, 0x90, 0xce, 0x07, 0x03, 0xf2, 0x1b, 0x0e, 0xc6,
0x17, 0xed, 0xd8, 0x4f, 0x4f}; 0x17, 0xed, 0xd8, 0x4f, 0x4f};
#if 1
TEST(IPV6_REASSEMBLE, NORMAL) TEST(IPV6_REASSEMBLE, NORMAL)
{ {
struct packet pkt; struct packet pkt;
struct packet *new_pkt; struct packet *new_pkt;
const struct layer_record *layer; const struct layer_record *layer;
struct ip_reassemble_manager *mgr; struct ip_reassemble_manager *mgr;
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1,
.bucket_entries = 16,
.bucket_num = 8,
};
timestamp_update(); timestamp_update();
mgr = ip_reassemble_manager_create(&config); mgr = ip_reassemble_manager_create(&config);
EXPECT_TRUE(mgr != NULL); EXPECT_TRUE(mgr != NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag1 // frag1
packet_parse(&pkt, (const char *)frag1, sizeof(frag1)); packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
new_pkt = ip_reassemble_packet(mgr, &pkt); new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL); EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
1, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag2 // frag2
packet_parse(&pkt, (const char *)frag2, sizeof(frag2)); packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
new_pkt = ip_reassemble_packet(mgr, &pkt); new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL); EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
2, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag3 // frag3
packet_parse(&pkt, (const char *)frag3, sizeof(frag3)); packet_parse(&pkt, (const char *)frag3, sizeof(frag3));
new_pkt = ip_reassemble_packet(mgr, &pkt); new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL); EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
3, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag4 // frag4
packet_parse(&pkt, (const char *)frag4, sizeof(frag4)); packet_parse(&pkt, (const char *)frag4, sizeof(frag4));
new_pkt = ip_reassemble_packet(mgr, &pkt); new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt); EXPECT_TRUE(new_pkt);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
4, 1, 1, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// check packet // check packet
packet_print(new_pkt); // packet_print(new_pkt);
EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 40 /* IPv6 */ + 8 /* UDP */ + 5379 /* DATA */); EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 40 /* IPv6 */ + 8 /* UDP */ + 5379 /* DATA */);
EXPECT_TRUE(new_pkt->data_len == sizeof(expect)); EXPECT_TRUE(new_pkt->data_len == sizeof(expect));
EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0); EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0);
@@ -687,26 +711,458 @@ TEST(IPV6_REASSEMBLE, NORMAL)
ip_reassemble_manager_destory(mgr); ip_reassemble_manager_destory(mgr);
} }
#endif
#if 1
TEST(IPV6_REASSEMBLE, EXPIRE) TEST(IPV6_REASSEMBLE, EXPIRE)
{ {
// TODO struct packet pkt;
} struct packet *new_pkt;
struct ip_reassemble_manager *mgr;
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1,
.bucket_entries = 16,
.bucket_num = 8,
};
timestamp_update();
mgr = ip_reassemble_manager_create(&config);
EXPECT_TRUE(mgr != NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag1
packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
1, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// sleep 1
sleep(1);
timestamp_update();
// frag2
packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
2, 2, 1, 1, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// free packet
packet_free(new_pkt);
ip_reassemble_manager_destory(mgr);
}
#endif
#if 1
TEST(IPV6_REASSEMBLE, DUP_FIRST_FRAG)
{
struct packet pkt;
struct packet *new_pkt;
const struct layer_record *layer;
struct ip_reassemble_manager *mgr;
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1,
.bucket_entries = 16,
.bucket_num = 8,
};
timestamp_update();
mgr = ip_reassemble_manager_create(&config);
EXPECT_TRUE(mgr != NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag1
packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
1, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag1
packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
2, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 1, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag2
packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
3, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 1, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag3
packet_parse(&pkt, (const char *)frag3, sizeof(frag3));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
4, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 1, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag4
packet_parse(&pkt, (const char *)frag4, sizeof(frag4));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
5, 1, 1, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 1, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// check packet
// packet_print(new_pkt);
EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 40 /* IPv6 */ + 8 /* UDP */ + 5379 /* DATA */);
EXPECT_TRUE(new_pkt->data_len == sizeof(expect));
EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0);
// check IPv6
layer = packet_get_innermost_layer(new_pkt, LAYER_TYPE_IPV6);
EXPECT_TRUE(layer);
struct ip6_hdr *hdr = (struct ip6_hdr *)layer->hdr_ptr;
EXPECT_TRUE(ipv6_hdr_get_version(hdr) == 6);
EXPECT_TRUE(ipv6_hdr_get_traffic_class(hdr) == 0);
EXPECT_TRUE(ipv6_hdr_get_flow_label(hdr) == 0x21289);
EXPECT_TRUE(ipv6_hdr_get_payload_len(hdr) == 5387);
EXPECT_TRUE(ipv6_hdr_get_next_header(hdr) == 17); // UDP
EXPECT_TRUE(ipv6_hdr_get_hop_limit(hdr) == 64);
char src_str[INET6_ADDRSTRLEN];
char dst_str[INET6_ADDRSTRLEN];
struct in6_addr src_addr = ipv6_hdr_get_src_in6_addr(hdr);
struct in6_addr dst_addr = ipv6_hdr_get_dst_in6_addr(hdr);
inet_ntop(AF_INET6, &src_addr, src_str, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &dst_addr, dst_str, INET6_ADDRSTRLEN);
EXPECT_TRUE(strcmp(src_str, "2607:f010:3f9::1001") == 0);
EXPECT_TRUE(strcmp(dst_str, "2607:f010:3f9::11:0") == 0);
EXPECT_TRUE(ipv6_hdr_get_frag_ext(hdr) == NULL);
// check UDP
layer = packet_get_innermost_layer(new_pkt, LAYER_TYPE_UDP);
EXPECT_TRUE(layer);
struct udphdr *udp_hdr = (struct udphdr *)layer->hdr_ptr;
EXPECT_TRUE(udp_hdr_get_src_port(udp_hdr) == 6363);
EXPECT_TRUE(udp_hdr_get_dst_port(udp_hdr) == 6363);
EXPECT_TRUE(udp_hdr_get_total_len(udp_hdr) == 5387);
EXPECT_TRUE(udp_hdr_get_checksum(udp_hdr) == 0x7916);
// free packet
packet_free(new_pkt);
ip_reassemble_manager_destory(mgr);
}
#endif
#if 1
TEST(IPV6_REASSEMBLE, DUP_LAST_FRAG)
{
struct packet pkt;
struct packet *new_pkt;
const struct layer_record *layer;
struct ip_reassemble_manager *mgr;
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1,
.bucket_entries = 16,
.bucket_num = 8,
};
timestamp_update();
mgr = ip_reassemble_manager_create(&config);
EXPECT_TRUE(mgr != NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag4
packet_parse(&pkt, (const char *)frag4, sizeof(frag4));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
1, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag4
packet_parse(&pkt, (const char *)frag4, sizeof(frag4));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
2, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 1); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag3
packet_parse(&pkt, (const char *)frag3, sizeof(frag3));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
3, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 1); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag2
packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
4, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 1); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag1
packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
5, 1, 1, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 1); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// check packet
// packet_print(new_pkt);
EXPECT_TRUE(new_pkt->data_len == 14 /* ETH */ + 40 /* IPv6 */ + 8 /* UDP */ + 5379 /* DATA */);
EXPECT_TRUE(new_pkt->data_len == sizeof(expect));
EXPECT_TRUE(memcmp(new_pkt->data_ptr, expect, new_pkt->data_len) == 0);
// check IPv6
layer = packet_get_innermost_layer(new_pkt, LAYER_TYPE_IPV6);
EXPECT_TRUE(layer);
struct ip6_hdr *hdr = (struct ip6_hdr *)layer->hdr_ptr;
EXPECT_TRUE(ipv6_hdr_get_version(hdr) == 6);
EXPECT_TRUE(ipv6_hdr_get_traffic_class(hdr) == 0);
EXPECT_TRUE(ipv6_hdr_get_flow_label(hdr) == 0x21289);
EXPECT_TRUE(ipv6_hdr_get_payload_len(hdr) == 5387);
EXPECT_TRUE(ipv6_hdr_get_next_header(hdr) == 17); // UDP
EXPECT_TRUE(ipv6_hdr_get_hop_limit(hdr) == 64);
char src_str[INET6_ADDRSTRLEN];
char dst_str[INET6_ADDRSTRLEN];
struct in6_addr src_addr = ipv6_hdr_get_src_in6_addr(hdr);
struct in6_addr dst_addr = ipv6_hdr_get_dst_in6_addr(hdr);
inet_ntop(AF_INET6, &src_addr, src_str, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &dst_addr, dst_str, INET6_ADDRSTRLEN);
EXPECT_TRUE(strcmp(src_str, "2607:f010:3f9::1001") == 0);
EXPECT_TRUE(strcmp(dst_str, "2607:f010:3f9::11:0") == 0);
EXPECT_TRUE(ipv6_hdr_get_frag_ext(hdr) == NULL);
// check UDP
layer = packet_get_innermost_layer(new_pkt, LAYER_TYPE_UDP);
EXPECT_TRUE(layer);
struct udphdr *udp_hdr = (struct udphdr *)layer->hdr_ptr;
EXPECT_TRUE(udp_hdr_get_src_port(udp_hdr) == 6363);
EXPECT_TRUE(udp_hdr_get_dst_port(udp_hdr) == 6363);
EXPECT_TRUE(udp_hdr_get_total_len(udp_hdr) == 5387);
EXPECT_TRUE(udp_hdr_get_checksum(udp_hdr) == 0x7916);
// free packet
packet_free(new_pkt);
ip_reassemble_manager_destory(mgr);
}
#endif
#if 1
TEST(IPV6_REASSEMBLE, FULL) TEST(IPV6_REASSEMBLE, FULL)
{ {
// TODO struct packet pkt;
} struct packet *new_pkt;
struct in6_addr src_addr;
struct ip_reassemble_manager *mgr;
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1,
.bucket_entries = 1,
.bucket_num = 1,
};
TEST(IPV6_REASSEMBLE, HOLE) timestamp_update();
{
// TODO
}
TEST(IPV6_REASSEMBLE, NESTED) mgr = ip_reassemble_manager_create(&config);
{ EXPECT_TRUE(mgr != NULL);
// TODO // ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
char dup_frag[sizeof(frag1)] = {0};
memcpy(dup_frag, frag1, sizeof(frag1));
packet_parse(&pkt, (const char *)dup_frag, sizeof(dup_frag));
// flow1
memset(&src_addr, 1, sizeof(src_addr));
packet_set_ipv6_src_addr(&pkt, src_addr);
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
1, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// flow2
memset(&src_addr, 2, sizeof(src_addr));
packet_set_ipv6_src_addr(&pkt, src_addr);
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
2, 2, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// flow3
memset(&src_addr, 3, sizeof(src_addr));
packet_set_ipv6_src_addr(&pkt, src_addr);
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
3, 2, 0, 0, // ip6: find, add, del, timeout
1, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// free packet
packet_free(new_pkt);
ip_reassemble_manager_destory(mgr);
} }
#endif
#if 1
TEST(IPV6_REASSEMBLE, OVERLAP)
{
struct packet pkt;
struct packet *new_pkt;
struct ip_reassemble_manager *mgr;
struct ip_reassemble_config config = {
.enable = true,
.timeout = 1,
.bucket_entries = 16,
.bucket_num = 8,
};
timestamp_update();
mgr = ip_reassemble_manager_create(&config);
EXPECT_TRUE(mgr != NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
0, 0, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag1
packet_parse(&pkt, (const char *)frag1, sizeof(frag1));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
1, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag2
packet_parse(&pkt, (const char *)frag2, sizeof(frag2));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
2, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag3 -- overwrite frag offset
char dup_frag[sizeof(frag3)] = {0};
memcpy(dup_frag, frag3, sizeof(frag3));
packet_parse(&pkt, (const char *)dup_frag, sizeof(dup_frag));
packet_set_ipv6_frag_offset(&pkt, 2048);
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
3, 1, 0, 0, // ip6: find, add, del, timeout
0, 0, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// frag4
packet_parse(&pkt, (const char *)frag4, sizeof(frag4));
new_pkt = ip_reassemble_packet(mgr, &pkt);
EXPECT_TRUE(new_pkt == NULL);
// ip_reassemble_manager_print_stat(mgr);
check_stat(ip_reassemble_manager_get_stat(mgr),
0, 0, 0, 0, // ip4: find, add, del, timeout
0, 0, 0, 0, 0, 0, // ip4: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
4, 1, 1, 0, // ip6: find, add, del, timeout
0, 1, 0, 0, 0, 0); // ip6: nospace, overlap, many frag, invalid length, dup first frag, dup last frag
// free packet
packet_free(new_pkt);
ip_reassemble_manager_destory(mgr);
}
#endif
int main(int argc, char **argv) int main(int argc, char **argv)
{ {

View File

@@ -0,0 +1,86 @@
#ifndef _GTEST_UTILS_H
#define _GTEST_UTILS_H
#ifdef __cpluscplus
extern "C"
{
#endif
#include <gtest/gtest.h>
#include "timestamp.h"
#include "udp_utils.h"
#include "tcp_utils.h"
#include "ipv4_utils.h"
#include "ipv6_utils.h"
#include "packet_helpers.h"
#include "ip_reassemble.h"
static inline void packet_set_ipv4_src_addr(struct packet *pkt, uint32_t saddr)
{
const struct layer_record *ipv4_layer = packet_get_innermost_layer(pkt, LAYER_TYPE_IPV4);
EXPECT_TRUE(ipv4_layer);
struct ip *hdr = (struct ip *)ipv4_layer->hdr_ptr;
ipv4_hdr_set_src_addr(hdr, saddr);
}
static inline void packet_set_ipv6_src_addr(struct packet *pkt, struct in6_addr saddr)
{
const struct layer_record *ipv6_layer = packet_get_innermost_layer(pkt, LAYER_TYPE_IPV6);
EXPECT_TRUE(ipv6_layer);
struct ip6_hdr *hdr = (struct ip6_hdr *)ipv6_layer->hdr_ptr;
ipv6_hdr_set_src_in6_addr(hdr, saddr);
}
static inline void packet_set_ipv6_frag_offset(struct packet *pkt, uint16_t offset)
{
const struct layer_record *ipv6_layer = (struct layer_record *)packet_get_innermost_layer(pkt, LAYER_TYPE_IPV6);
EXPECT_TRUE(ipv6_layer);
struct ip6_hdr *hdr = (struct ip6_hdr *)ipv6_layer->hdr_ptr;
struct ip6_frag *frag_hdr = ipv6_hdr_get_frag_ext(hdr);
EXPECT_TRUE(frag_hdr);
ipv6_frag_set_offset(frag_hdr, offset);
}
static inline void check_stat(struct ip_reassemble_stat *stat,
uint64_t ip4_flow_find, uint64_t ip4_flow_add, uint64_t ip4_flow_del, uint64_t ip4_flow_timeout,
uint64_t ip4_flow_fail_no_space, uint64_t ip4_flow_fail_overlap, uint64_t ip4_flow_fail_many_frag,
uint64_t ip4_flow_fail_invalid_length, uint64_t ip4_flow_bypass_dup_fist_frag, uint64_t ip4_flow_bypass_dup_last_frag,
uint64_t ip6_flow_find, uint64_t ip6_flow_add, uint64_t ip6_flow_del, uint64_t ip6_flow_timeout,
uint64_t ip6_flow_fail_no_space, uint64_t ip6_flow_fail_overlap, uint64_t ip6_flow_fail_many_frag,
uint64_t ip6_flow_fail_invalid_length, uint64_t ip6_flow_bypass_dup_fist_frag, uint64_t ip6_flow_bypass_dup_last_frag)
{
EXPECT_TRUE(stat != NULL);
EXPECT_TRUE(stat->ip4_flow_find == ip4_flow_find);
EXPECT_TRUE(stat->ip4_flow_add == ip4_flow_add);
EXPECT_TRUE(stat->ip4_flow_del == ip4_flow_del);
EXPECT_TRUE(stat->ip4_flow_timeout == ip4_flow_timeout);
EXPECT_TRUE(stat->ip4_flow_fail_no_space == ip4_flow_fail_no_space);
EXPECT_TRUE(stat->ip4_flow_fail_overlap == ip4_flow_fail_overlap);
EXPECT_TRUE(stat->ip4_flow_fail_many_frag == ip4_flow_fail_many_frag);
EXPECT_TRUE(stat->ip4_flow_fail_invalid_length == ip4_flow_fail_invalid_length);
EXPECT_TRUE(stat->ip4_flow_bypass_dup_fist_frag == ip4_flow_bypass_dup_fist_frag);
EXPECT_TRUE(stat->ip4_flow_bypass_dup_last_frag == ip4_flow_bypass_dup_last_frag);
EXPECT_TRUE(stat->ip6_flow_find == ip6_flow_find);
EXPECT_TRUE(stat->ip6_flow_add == ip6_flow_add);
EXPECT_TRUE(stat->ip6_flow_del == ip6_flow_del);
EXPECT_TRUE(stat->ip6_flow_timeout == ip6_flow_timeout);
EXPECT_TRUE(stat->ip6_flow_fail_no_space == ip6_flow_fail_no_space);
EXPECT_TRUE(stat->ip6_flow_fail_overlap == ip6_flow_fail_overlap);
EXPECT_TRUE(stat->ip6_flow_fail_many_frag == ip6_flow_fail_many_frag);
EXPECT_TRUE(stat->ip6_flow_fail_invalid_length == ip6_flow_fail_invalid_length);
EXPECT_TRUE(stat->ip6_flow_bypass_dup_fist_frag == ip6_flow_bypass_dup_fist_frag);
EXPECT_TRUE(stat->ip6_flow_bypass_dup_last_frag == ip6_flow_bypass_dup_last_frag);
}
#ifdef __cpluscplus
}
#endif
#endif

View File

@@ -100,8 +100,6 @@ static inline struct ip6_frag *ipv6_hdr_get_frag_ext(const struct ip6_hdr *hdr)
return (struct ip6_frag *)((char *)hdr + sizeof(struct ip6_hdr)); return (struct ip6_frag *)((char *)hdr + sizeof(struct ip6_hdr));
} }
// TODO IPv6 extension headers
/****************************************************************************** /******************************************************************************
* set * set
******************************************************************************/ ******************************************************************************/
@@ -146,7 +144,56 @@ static inline void ipv6_hdr_set_dst_in6_addr(struct ip6_hdr *hdr, struct in6_add
hdr->ip6_dst = dst_addr; hdr->ip6_dst = dst_addr;
} }
// TODO IPv6 extension headers /******************************************************************************
* IPv6 frag extension headers
******************************************************************************/
static inline uint8_t ipv6_frag_get_next_header(const struct ip6_frag *frag)
{
return frag->ip6f_nxt;
}
static inline uint16_t ipv6_frag_get_offset(const struct ip6_frag *frag)
{
return ntohs(frag->ip6f_offlg & IP6F_OFF_MASK);
}
static inline uint32_t ipv6_frag_get_ident(const struct ip6_frag *frag)
{
return ntohl(frag->ip6f_ident);
}
static inline bool ipv6_frag_get_more(const struct ip6_frag *frag)
{
return (frag->ip6f_offlg & IP6F_MORE_FRAG);
}
static inline void ipv6_frag_set_next_header(struct ip6_frag *frag, uint8_t next_header)
{
frag->ip6f_nxt = next_header;
}
static inline void ipv6_frag_set_offset(struct ip6_frag *frag, uint16_t offset)
{
frag->ip6f_offlg = (frag->ip6f_offlg & ~IP6F_OFF_MASK) | htons(offset);
}
static inline void ipv6_frag_set_ident(struct ip6_frag *frag, uint32_t ident)
{
frag->ip6f_ident = htonl(ident);
}
static inline void ipv6_frag_set_more(struct ip6_frag *frag, bool more)
{
if (more)
{
frag->ip6f_offlg |= IP6F_MORE_FRAG;
}
else
{
frag->ip6f_offlg &= ~IP6F_MORE_FRAG;
}
}
#ifdef __cpluscplus #ifdef __cpluscplus
} }

View File

@@ -62,6 +62,41 @@ TEST(IPV6_UTILS, SET)
EXPECT_TRUE(memcmp(buff, data, 40) == 0); EXPECT_TRUE(memcmp(buff, data, 40) == 0);
} }
/*
* Fragment Header for IPv6
* Next header: UDP (17)
* Reserved octet: 0x00
* 0000 0101 1010 1... = Offset: 181 (1448 bytes)
* .... .... .... .00. = Reserved bits: 0
* .... .... .... ...1 = More Fragments: Yes
* Identification: 0xf88eb466
*/
unsigned char frag[] = {
0x11, 0x00, 0x05, 0xa9, 0xf8, 0x8e, 0xb4, 0x66};
TEST(IPV6_FRAG_HDR, GET)
{
const struct ip6_frag *hdr = (struct ip6_frag *)frag;
EXPECT_TRUE(ipv6_frag_get_next_header(hdr) == 17);
EXPECT_TRUE(ipv6_frag_get_offset(hdr) == 1448);
EXPECT_TRUE(ipv6_frag_get_more(hdr) == 1);
EXPECT_TRUE(ipv6_frag_get_ident(hdr) == 0xf88eb466);
}
TEST(IPV6_FRAG_HDR, SET)
{
char buff[8] = {0};
struct ip6_frag *hdr = (struct ip6_frag *)buff;
ipv6_frag_set_next_header(hdr, 17);
ipv6_frag_set_offset(hdr, 1448);
ipv6_frag_set_more(hdr, 1);
ipv6_frag_set_ident(hdr, 0xf88eb466);
EXPECT_TRUE(memcmp(buff, frag, 8) == 0);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);

View File

@@ -98,7 +98,7 @@ TEST(TCP_UTILS, GET)
TEST(TCP_UTILS, SET1) TEST(TCP_UTILS, SET1)
{ {
char buff[40]; char buff[40] = {0};
struct tcphdr *hdr = (struct tcphdr *)buff; struct tcphdr *hdr = (struct tcphdr *)buff;
tcp_hdr_set_src_port(hdr, 55555); tcp_hdr_set_src_port(hdr, 55555);