diff --git a/src/ip_fragment/ip_fragment.cpp b/src/ip_fragment/ip_fragment.cpp deleted file mode 100644 index 1286b84..0000000 --- a/src/ip_fragment/ip_fragment.cpp +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/src/ip_fragment/ip_fragment.h b/src/ip_fragment/ip_fragment.h deleted file mode 100644 index fead52d..0000000 --- a/src/ip_fragment/ip_fragment.h +++ /dev/null @@ -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 diff --git a/src/ip_reassemble/ip_reassemble.cpp b/src/ip_reassemble/ip_reassemble.cpp index 1fbc068..670fb43 100644 --- a/src/ip_reassemble/ip_reassemble.cpp +++ b/src/ip_reassemble/ip_reassemble.cpp @@ -12,39 +12,45 @@ #include "packet_helpers.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 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, ...) \ - do \ - { \ - if ((key)->src_dst_len == IPV4_KEYLEN) \ - { \ - IP_REASSEMBLE_DEBUG(desc, "key <%lu, %#x>", (key)->src_dst_addr[0], (key)->ip_id); \ - } \ - else \ - { \ - IP_REASSEMBLE_DEBUG(desc, "key <%08lu%08lu%08lu%08lu, %#x>", IPv6_KEY_BYTES((key)->src_dst_addr), (key)->ip_id); \ - } \ +#define KEY_TO_STR(key, str_str, dst_str) \ + do \ + { \ + if ((key)->src_dst_len == IPV4_KEYLEN) \ + { \ + uint32_t src_addr = (key)->src_dst_addr[0] >> 32; \ + uint32_t dst_addr = (key)->src_dst_addr[0] & 0xffffffff; \ + inet_ntop(AF_INET, &src_addr, src_str, INET6_ADDRSTRLEN); \ + inet_ntop(AF_INET, &dst_addr, dst_str, INET6_ADDRSTRLEN); \ + } \ + 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) -#define IP_REASSEMBLE_ERROR_ARG1(desc, key, ...) \ - do \ - { \ - if ((key)->src_dst_len == IPV4_KEYLEN) \ - { \ - IP_REASSEMBLE_ERROR(desc, "key <%lu, %#x>", (key)->src_dst_addr[0], (key)->ip_id); \ - } \ - else \ - { \ - IP_REASSEMBLE_ERROR(desc, "key <%08lu%08lu%08lu%08lu, %#x>", IPv6_KEY_BYTES((key)->src_dst_addr), (key)->ip_id); \ - } \ +#define IP_REASSEMBLE_DEBUG1(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_DEBUG("%s (%s->%s 0x%0x)", desc, src_str, dst_str, (key)->ip_id); \ + } while (0) + +#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) /****************************************************************************** @@ -61,18 +67,21 @@ enum struct ip_frag_hdr { + void *hdr_data; // need be freed + uint16_t hdr_len; + uint16_t l3_offset; uint16_t l3_len; - uint16_t hdr_len; + uint8_t next_proto; - void *hdr_data; // need be freed }; struct ip_frag_pkt { - uint16_t offset; - uint16_t len; void *data; // need be freed + uint16_t len; + + uint16_t offset; }; 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_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 { // config @@ -131,13 +131,40 @@ struct ip_reassemble_manager struct ip_flow **tqh_last; } lru; 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) { 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) @@ -267,27 +294,13 @@ static inline void ip_flow_key_zero(struct ip_flow_key *key) key->src_dst_len = 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) { 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 const struct ip_frag_pkt zero_frag = { - .offset = 0, - .len = 0, .data = NULL, + .len = 0, + .offset = 0, }; flow->lru.tqe_next = NULL; flow->lru.tqe_prev = NULL; flow->key = *key; - flow->create_time = timestamp_get_msec(); + flow->create_time = timestamp_get_sec(); flow->expected_total_size = UINT32_MAX; flow->received_frag_size = 0; 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++) { struct ip_frag_pkt *frag = &flow->frags[i]; - frag->offset = 0; - frag->len = 0; - if (frag->data != NULL) - { - free(frag->data); - frag->data = NULL; - } + ip_frag_pkt_free(frag); } ip_flow_key_zero(&flow->key); 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 -1 : failed -static inline int ip_flow_update(struct ip_flow *flow, const struct packet *pkt, - char *data, uint16_t len, uint16_t offset, bool more_frags) +static inline int ip_flow_update(struct ip_reassemble_manager *mgr, + 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; - - if (offset == 0) + struct ip_frag_pkt *frag_pkt; + /* + * 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) { - IP_REASSEMBLE_ERROR_ARG1("duplicate first fragment encountered: ", &flow->key); - return -1; + IP_REASSEMBLE_DEBUG1("duplicate first fragment bypass", &flow->key); + ip_reassemble_stat_inc(mgr, bypass_dup_fist_frag, &flow->key); + return 0; } idx = IP_FIRST_FRAG_IDX; 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) { - IP_REASSEMBLE_ERROR_ARG1("duplicate last fragment encountered: ", &flow->key); - return -1; + IP_REASSEMBLE_DEBUG1("duplicate last fragment bypass", &flow->key); + ip_reassemble_stat_inc(mgr, bypass_dup_last_frag, &flow->key); + return 0; } idx = IP_LAST_FRAG_IDX; - flow->expected_total_size = offset + len; + flow->expected_total_size = frag_offset + frag_len; } else { 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; } idx = flow->next_fill_idx; flow->next_fill_idx++; } - flow->received_frag_size += len; - flow->frags[idx].data = memdup(data, len); - flow->frags[idx].offset = offset; - flow->frags[idx].len = len; + flow->received_frag_size += frag_len; + frag_pkt = &flow->frags[idx]; + ip_frag_pkt_init(frag_pkt, frag_data, frag_len, frag_offset); 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); 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); 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_flow_table_add(mgr, flow); + ip_reassemble_manager_del_flow(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 * 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) { @@ -455,10 +504,6 @@ static struct ip_flow *ip_flow_table_find(struct ip_reassemble_manager *mgr, con uint32_t sig1 = 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) { 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 struct ip_flow *old = 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++) { 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; } - else if (timeout + p1[i].create_time < tms) + else if (timeout + p1[i].create_time <= tms) { 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; } - else if (timeout + p2[i].create_time < tms) + else if (timeout + p2[i].create_time <= tms) { 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; } -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 *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 (expired) { - IP_REASSEMBLE_DEBUG_ARG1("ip flow new (use expired iterm): ", key); - ip_flow_free(expired); - ip_flow_init(expired, key); - ip_flow_table_reuse(mgr, expired); + IP_REASSEMBLE_DEBUG1("add ip flow success: reuse expired entry", key); + ip_reassemble_manager_reuse_flow(mgr, expired, key); + ip_reassemble_stat_inc(mgr, timeout, key); mgr->last = expired; return expired; @@ -536,28 +582,27 @@ static struct ip_flow *ip_flow_table_update(struct ip_reassemble_manager *mgr, c 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_table_add(mgr, free); + ip_reassemble_manager_add_flow(mgr, free); mgr->last = free; return free; } // no space - IP_REASSEMBLE_DEBUG_ARG1("bucket full discarding new fragmented packets: ", key); - mgr->stat.fail_nospace++; + IP_REASSEMBLE_ERROR1("add ip flow failed: bucket full", key); + ip_reassemble_stat_inc(mgr, fail_no_space, key); return NULL; } else { // 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_flow_free(flow); - ip_flow_init(flow, key); - ip_flow_table_reuse(mgr, flow); + IP_REASSEMBLE_DEBUG1("add ip flow success: reuse expired entry", key); + ip_reassemble_manager_reuse_flow(mgr, flow, key); + ip_reassemble_stat_inc(mgr, timeout, key); mgr->last = flow; return flow; @@ -565,41 +610,33 @@ static struct ip_flow *ip_flow_table_update(struct ip_reassemble_manager *mgr, c // not expired else { - IP_REASSEMBLE_DEBUG_ARG1("ip flow find, not expired: ", key); + IP_REASSEMBLE_DEBUG1("find ip flow success: not expire", key); + mgr->last = 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 ******************************************************************************/ -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 *last = &flow->frags[IP_LAST_FRAG_IDX]; 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 - uint32_t buff_len = flow->expected_total_size + flow->hdr.hdr_len; - char *buff = (char *)calloc(1, buff_len + sizeof(struct packet)); + uint32_t packet_len = flow->expected_total_size + flow->hdr.hdr_len; + char *buff = (char *)calloc(1, packet_len + sizeof(struct packet)); if (buff == NULL) { 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 *end = ptr + buff_len; + char *end = ptr + packet_len; // copy last frag if (last->len > end - ptr) { - IP_REASSEMBLE_ERROR_ARG1("last packet length is greater than the expected reassembled length: ", &flow->key); - free(buff); - return NULL; + IP_REASSEMBLE_ERROR1("last frag length not match expected reassembled length", &flow->key); + goto error_out_invalid_length; } end -= last->len; memcpy(end, last->data, last->len); - uint32_t loop = 0; - uint16_t last_offset = 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 * datagram delivered. */ - 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]; if (temp->offset + temp->len == last_offset) { if (temp->len > end - ptr) { - IP_REASSEMBLE_ERROR_ARG1("middle fragment packet length doesn't match last fragment packet offset: ", &flow->key); - free(buff); - return NULL; + IP_REASSEMBLE_ERROR1("middle frag length not match expected reassembled length", &flow->key); + goto error_out_invalid_length; } 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); - free(buff); - return NULL; + IP_REASSEMBLE_ERROR1("overlap appear during frag reassemble", &flow->key); + goto error_out_overlap; } loop++; @@ -669,9 +695,8 @@ static struct packet *ip_frag_reassemble(struct ip_flow *flow) // copy fist fragment data if (first->len > end - ptr) { - IP_REASSEMBLE_ERROR_ARG1("last packet length is greater than the expected reassembled length: ", &flow->key); - free(buff); - return NULL; + IP_REASSEMBLE_ERROR1("first frag length not match expected reassembled length", &flow->key); + goto error_out_invalid_length; } end -= 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 if (flow->hdr.hdr_len > end - ptr) { - IP_REASSEMBLE_ERROR_ARG1("hdr length is greater than the expected reassembled length: ", &flow->key); - free(buff); - return NULL; + IP_REASSEMBLE_ERROR1("packet header length not match expected reassembled length", &flow->key); + goto error_out_invalid_length; } end -= flow->hdr.hdr_len; memcpy(end, flow->hdr.hdr_data, flow->hdr.hdr_len); + + // assert assert(ptr == end); if (flow->key.src_dst_len == IPV4_KEYLEN) { // update ip total length & ip checksum - struct ip *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_mf_flag(hdr, false); // update more fragment flag - ipv4_hdr_set_frag_offset(hdr, 0); // update fragment offset - hdr->ip_sum = 0; // update checksum - hdr->ip_sum = checksum((char *)hdr, flow->hdr.l3_len); + ip4_hdr = (struct ip *)(ptr + flow->hdr.l3_offset); + ipv4_hdr_set_total_len(ip4_hdr, packet_len - flow->hdr.l3_offset); // update total length + ipv4_hdr_set_mf_flag(ip4_hdr, false); // update more fragment flag + ipv4_hdr_set_frag_offset(ip4_hdr, 0); // update fragment offset + ip4_hdr->ip_sum = 0; // update checksum + ip4_hdr->ip_sum = checksum((char *)ip4_hdr, flow->hdr.l3_len); } else { // update ipv6 payload length & next header - struct ip6_hdr *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_next_header(hdr, flow->hdr.next_proto); // update next header + ip6_hdr = (struct ip6_hdr *)(ptr + flow->hdr.l3_offset); + ipv6_hdr_set_payload_len(ip6_hdr, flow->expected_total_size); // update payload length + ipv6_hdr_set_next_header(ip6_hdr, flow->hdr.next_proto); // update next header } // create a new packet - struct packet *new_pkt = (struct packet *)buff; - packet_parse(new_pkt, buff + sizeof(struct packet), buff_len); + packet_parse((struct packet *)buff, buff + sizeof(struct packet), packet_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); if (pkt1 && pkt1->frag_layer) { - pkt2 = ip_reassemble_packet(mgr, pkt); + pkt2 = ip_reassemble_packet(mgr, pkt1); packet_free(pkt1); return pkt2; } @@ -824,7 +909,7 @@ struct packet *ip_reassemble_packet(struct ip_reassemble_manager *mgr, const str pkt1 = ipv6_reassemble_packet(mgr, pkt); if (pkt1 && pkt1->frag_layer) { - pkt2 = ip_reassemble_packet(mgr, pkt); + pkt2 = ip_reassemble_packet(mgr, pkt1); packet_free(pkt1); 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 layer_record *layer = pkt->frag_layer; - struct ip *hdr = (struct ip *)layer->hdr_ptr; - char *data = (char *)layer->pld_ptr; - uint16_t len = ipv4_hdr_get_total_len(hdr) - ipv4_hdr_get_hdr_len(hdr); - if (len > layer->pld_len) + const struct layer_record *layer = pkt->frag_layer; + const struct ip *hdr = (const struct ip *)layer->hdr_ptr; + uint16_t frag_len = ipv4_hdr_get_total_len(hdr) - ipv4_hdr_get_hdr_len(hdr); + if (frag_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; } @@ -856,18 +940,20 @@ struct packet *ipv4_reassemble_packet(struct ip_reassemble_manager *mgr, const s key.src_dst_len = IPV4_KEYLEN; key.ip_id = ipv4_hdr_get_ipid(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) { return NULL; } + char *frag_data = (char *)layer->pld_ptr; bool more_frags = ipv4_hdr_get_mf_flag(hdr); - uint16_t offset = ipv4_hdr_get_frag_offset(hdr); - if (ip_flow_update(flow, pkt, data, len, offset, more_frags) != 0) + uint16_t frag_offset = ipv4_hdr_get_frag_offset(hdr); + 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_table_del(mgr, flow); return NULL; } @@ -876,9 +962,9 @@ struct packet *ipv4_reassemble_packet(struct ip_reassemble_manager *mgr, const s 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_table_del(mgr, flow); 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 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; - struct ip6_frag *frag_ext = ipv6_hdr_get_frag_ext(hdr); - if (frag_ext == NULL) + const struct ip6_frag *frag_hdr = ipv6_hdr_get_frag_ext(hdr); + if (frag_hdr == 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}; memcpy(&key.src_dst_addr[0], hdr->ip6_src.s6_addr, 16); memcpy(&key.src_dst_addr[2], hdr->ip6_dst.s6_addr, 16); 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 - struct ip_flow *flow = ip_flow_table_update(mgr, &key); + struct ip_flow *flow = ip_reassemble_manager_update_flow(mgr, &key); if (flow == NULL) { return NULL; } - char *data = (char *)layer->hdr_ptr + sizeof(struct ip6_hdr) + sizeof(struct ip6_frag); - uint16_t len = ipv6_hdr_get_payload_len(hdr) - sizeof(struct ip6_frag); - - 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) + bool more_frags = ipv6_frag_get_more(frag_hdr); + 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) { + ip_reassemble_manager_del_flow(mgr, flow); ip_flow_free(flow); - ip_flow_table_del(mgr, flow); return NULL; } @@ -967,9 +1053,9 @@ struct packet *ipv6_reassemble_packet(struct ip_reassemble_manager *mgr, const s 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_table_del(mgr, flow); return new_pkt; } diff --git a/src/ip_reassemble/ip_reassemble.h b/src/ip_reassemble/ip_reassemble.h index 5147e57..fcd5413 100644 --- a/src/ip_reassemble/ip_reassemble.h +++ b/src/ip_reassemble/ip_reassemble.h @@ -16,14 +16,45 @@ struct ip_reassemble_config { bool enable; - uint32_t timeout; + uint32_t timeout; // seconds uint32_t bucket_entries; 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); 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 diff --git a/src/ip_reassemble/test/CMakeLists.txt b/src/ip_reassemble/test/CMakeLists.txt index 4465f60..e115854 100644 --- a/src/ip_reassemble/test/CMakeLists.txt +++ b/src/ip_reassemble/test/CMakeLists.txt @@ -8,6 +8,10 @@ target_link_libraries(gtest_ipv4_reassemble ip_reassemble gtest) add_executable(gtest_ipv6_reassemble gtest_ipv6_reassemble.cpp) 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) gtest_discover_tests(gtest_ipv4_reassemble) -gtest_discover_tests(gtest_ipv6_reassemble) \ No newline at end of file +gtest_discover_tests(gtest_ipv6_reassemble) +gtest_discover_tests(gtest_ip_reassemble) \ No newline at end of file diff --git a/src/ip_reassemble/test/gtest_ip_reassemble.cpp b/src/ip_reassemble/test/gtest_ip_reassemble.cpp new file mode 100644 index 0000000..18e4c87 --- /dev/null +++ b/src/ip_reassemble/test/gtest_ip_reassemble.cpp @@ -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(); +} diff --git a/src/ip_reassemble/test/gtest_ipv4_reassemble.cpp b/src/ip_reassemble/test/gtest_ipv4_reassemble.cpp index 8ce9809..40551aa 100644 --- a/src/ip_reassemble/test/gtest_ipv4_reassemble.cpp +++ b/src/ip_reassemble/test/gtest_ipv4_reassemble.cpp @@ -1,17 +1,4 @@ -#include - -#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, -}; +#include "gtest_utils.h" /* * 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 }; -TEST(IPV4_REASSEMBLE, PADDING) +#if 1 +TEST(IPV4_REASSEMBLE, PADDING_ORDER) { 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 // 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), + 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); + // 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); @@ -272,26 +284,446 @@ TEST(IPV4_REASSEMBLE, PADDING) 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) { - // 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) { - // 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) -{ - // TODO -} + timestamp_update(); -TEST(IPV4_REASSEMBLE, NESTED) -{ - // TODO + 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 + + 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) { diff --git a/src/ip_reassemble/test/gtest_ipv6_reassemble.cpp b/src/ip_reassemble/test/gtest_ipv6_reassemble.cpp index 90951d3..38dbc46 100644 --- a/src/ip_reassemble/test/gtest_ipv6_reassemble.cpp +++ b/src/ip_reassemble/test/gtest_ipv6_reassemble.cpp @@ -1,17 +1,4 @@ -#include - -#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, -}; +#include "gtest_utils.h" /* * 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, 0x17, 0xed, 0xd8, 0x4f, 0x4f}; +#if 1 TEST(IPV6_REASSEMBLE, NORMAL) { 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 // 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 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, 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 + 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 - 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 == sizeof(expect)); 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); } +#endif +#if 1 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) { - // 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) -{ - // TODO -} + timestamp_update(); -TEST(IPV6_REASSEMBLE, NESTED) -{ - // TODO + 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 + + 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) { diff --git a/src/ip_reassemble/test/gtest_utils.h b/src/ip_reassemble/test/gtest_utils.h new file mode 100644 index 0000000..e4659d1 --- /dev/null +++ b/src/ip_reassemble/test/gtest_utils.h @@ -0,0 +1,86 @@ +#ifndef _GTEST_UTILS_H +#define _GTEST_UTILS_H + +#ifdef __cpluscplus +extern "C" +{ +#endif + +#include + +#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 diff --git a/src/packet/ipv6_utils.h b/src/packet/ipv6_utils.h index 0d3b2e4..29b94da 100644 --- a/src/packet/ipv6_utils.h +++ b/src/packet/ipv6_utils.h @@ -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)); } -// TODO IPv6 extension headers - /****************************************************************************** * 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; } -// 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 } diff --git a/src/packet/test/gtest_ipv6_utils.cpp b/src/packet/test/gtest_ipv6_utils.cpp index ec0b6c0..57a76e1 100644 --- a/src/packet/test/gtest_ipv6_utils.cpp +++ b/src/packet/test/gtest_ipv6_utils.cpp @@ -62,6 +62,41 @@ TEST(IPV6_UTILS, SET) 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) { ::testing::InitGoogleTest(&argc, argv); diff --git a/src/packet/test/gtest_tcp_utils.cpp b/src/packet/test/gtest_tcp_utils.cpp index 2e46c67..fd13102 100644 --- a/src/packet/test/gtest_tcp_utils.cpp +++ b/src/packet/test/gtest_tcp_utils.cpp @@ -98,7 +98,7 @@ TEST(TCP_UTILS, GET) TEST(TCP_UTILS, SET1) { - char buff[40]; + char buff[40] = {0}; struct tcphdr *hdr = (struct tcphdr *)buff; tcp_hdr_set_src_port(hdr, 55555);