summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in1
-rw-r--r--src/autoconf.h8
-rw-r--r--src/conf-yaml-loader.c15
-rw-r--r--src/datasets.c5
-rw-r--r--src/decode-ipv4.h26
-rw-r--r--src/decode.c1
-rw-r--r--src/decode.h1
-rw-r--r--src/defrag.c1620
-rw-r--r--src/defrag.h1
-rw-r--r--src/detect-dataset.c4
-rw-r--r--src/detect-fast-pattern.c3
-rw-r--r--src/detect-http-server-body.c3
-rw-r--r--src/detect-ipopts.c75
-rw-r--r--src/detect-parse.c12
-rw-r--r--src/flow-timeout.c10
-rw-r--r--src/flow.c2
-rw-r--r--src/output-json-stats.c34
-rw-r--r--src/runmode-af-packet.c6
-rw-r--r--src/runmode-dpdk.c42
-rw-r--r--src/runmode-dpdk.h1
-rw-r--r--src/runmode-netmap.c6
-rw-r--r--src/runmodes.c11
-rw-r--r--src/source-dpdk.c73
-rw-r--r--src/source-dpdk.h1
-rw-r--r--src/source-pcap-file-helper.c1
-rw-r--r--src/tests/detect-http-client-body.c1
-rw-r--r--src/tests/detect-http-server-body.c1
-rw-r--r--src/tests/output-json-stats.c69
-rw-r--r--src/util-base64.c6
-rw-r--r--src/util-dpdk-ice.c12
-rw-r--r--src/util-dpdk-ice.h4
-rw-r--r--src/util-host-info.c36
-rw-r--r--src/util-streaming-buffer.c63
33 files changed, 1528 insertions, 626 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index 4f15923..229aaef 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1233,6 +1233,7 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POW_LIB = @POW_LIB@
RANLIB = @RANLIB@
+RELEASE_DATE = @RELEASE_DATE@
RUSTC = @RUSTC@
RUSTUP_HOME_PATH = @RUSTUP_HOME_PATH@
RUST_FEATURES = @RUST_FEATURES@
diff --git a/src/autoconf.h b/src/autoconf.h
index 336c550..457a903 100644
--- a/src/autoconf.h
+++ b/src/autoconf.h
@@ -696,7 +696,7 @@
#define PACKAGE_NAME "suricata"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "suricata 7.0.4"
+#define PACKAGE_STRING "suricata 7.0.5"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "suricata"
@@ -705,7 +705,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "7.0.4"
+#define PACKAGE_VERSION "7.0.5"
/* Pcre code unit width is 8 bits */
#define PCRE2_CODE_UNIT_WIDTH 8
@@ -723,7 +723,7 @@
/* #undef PROFILING */
/* Git revision */
-#define REVISION d8bad3b1a 2024-03-19
+#define REVISION c4cf7b09f 2024-04-23
/* Define to 1 if all of the C90 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
@@ -743,7 +743,7 @@
/* #undef UNITTESTS */
/* Version number of package */
-#define VERSION "7.0.4"
+#define VERSION "7.0.5"
/* Enable Windows WinDivert support for inline IDP */
/* #undef WINDIVERT */
diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c
index ea64563..463eb2e 100644
--- a/src/conf-yaml-loader.c
+++ b/src/conf-yaml-loader.c
@@ -394,8 +394,19 @@ static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int
if (inseq) {
char sequence_node_name[DEFAULT_NAME_LEN];
snprintf(sequence_node_name, DEFAULT_NAME_LEN, "%d", seq_idx++);
- ConfNode *seq_node = ConfNodeLookupChild(node,
- sequence_node_name);
+ ConfNode *seq_node = NULL;
+ if (was_empty < 0) {
+ // initialize was_empty
+ if (TAILQ_EMPTY(&node->head)) {
+ was_empty = 1;
+ } else {
+ was_empty = 0;
+ }
+ }
+ // we only check if the node's list was not empty at first
+ if (was_empty == 0) {
+ seq_node = ConfNodeLookupChild(node, sequence_node_name);
+ }
if (seq_node != NULL) {
/* The sequence node has already been set, probably
* from the command line. Remove it so it gets
diff --git a/src/datasets.c b/src/datasets.c
index d89ed8d..01ef5bb 100644
--- a/src/datasets.c
+++ b/src/datasets.c
@@ -746,6 +746,11 @@ Dataset *DatasetGet(const char *name, enum DatasetTypes type, const char *save,
break;
}
+ if (set->hash && SC_ATOMIC_GET(set->hash->memcap_reached)) {
+ SCLogError("dataset too large for set memcap");
+ goto out_err;
+ }
+
SCLogDebug("set %p/%s type %u save %s load %s",
set, set->name, set->type, set->save, set->load);
diff --git a/src/decode-ipv4.h b/src/decode-ipv4.h
index d247fa9..a825007 100644
--- a/src/decode-ipv4.h
+++ b/src/decode-ipv4.h
@@ -154,20 +154,18 @@ typedef struct IPV4Hdr_
memset(&p->ip4vars, 0x00, sizeof(p->ip4vars)); \
} while (0)
-enum IPV4OptionFlags {
- IPV4_OPT_FLAG_EOL = 0,
- IPV4_OPT_FLAG_NOP,
- IPV4_OPT_FLAG_RR,
- IPV4_OPT_FLAG_TS,
- IPV4_OPT_FLAG_QS,
- IPV4_OPT_FLAG_LSRR,
- IPV4_OPT_FLAG_SSRR,
- IPV4_OPT_FLAG_SID,
- IPV4_OPT_FLAG_SEC,
- IPV4_OPT_FLAG_CIPSO,
- IPV4_OPT_FLAG_RTRALT,
- IPV4_OPT_FLAG_ESEC,
-};
+#define IPV4_OPT_FLAG_EOL BIT_U16(1)
+#define IPV4_OPT_FLAG_NOP BIT_U16(2)
+#define IPV4_OPT_FLAG_RR BIT_U16(3)
+#define IPV4_OPT_FLAG_TS BIT_U16(4)
+#define IPV4_OPT_FLAG_QS BIT_U16(5)
+#define IPV4_OPT_FLAG_LSRR BIT_U16(6)
+#define IPV4_OPT_FLAG_SSRR BIT_U16(7)
+#define IPV4_OPT_FLAG_SID BIT_U16(8)
+#define IPV4_OPT_FLAG_SEC BIT_U16(9)
+#define IPV4_OPT_FLAG_CIPSO BIT_U16(10)
+#define IPV4_OPT_FLAG_RTRALT BIT_U16(11)
+#define IPV4_OPT_FLAG_ESEC BIT_U16(12)
/* helper structure with parsed ipv4 info */
typedef struct IPV4Vars_
diff --git a/src/decode.c b/src/decode.c
index 5cdeeea..13c6541 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -408,7 +408,6 @@ Packet *PacketDefragPktSetup(Packet *parent, const uint8_t *pkt, uint32_t len, u
}
p->recursion_level = parent->recursion_level; /* NOT incremented */
p->ts = parent->ts;
- p->datalink = DLT_RAW;
p->tenant_id = parent->tenant_id;
/* tell new packet it's part of a tunnel */
SET_TUNNEL_PKT(p);
diff --git a/src/decode.h b/src/decode.h
index dedfbb0..4516d37 100644
--- a/src/decode.h
+++ b/src/decode.h
@@ -974,6 +974,7 @@ void DecodeUnregisterCounters(void);
* Libpcap on at least OpenBSD returns 101 as datalink type for RAW pcaps though. */
#define LINKTYPE_RAW2 101
#define LINKTYPE_IPV4 228
+#define LINKTYPE_IPV6 229
#define LINKTYPE_GRE_OVER_IP 778
#define LINKTYPE_CISCO_HDLC DLT_C_HDLC
#define PPP_OVER_GRE 11
diff --git a/src/defrag.c b/src/defrag.c
index 71cf420..4596d72 100644
--- a/src/defrag.c
+++ b/src/defrag.c
@@ -104,26 +104,6 @@ static DefragContext *defrag_context;
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
/**
- * Utility/debugging function to dump the frags associated with a
- * tracker. Only enable when unit tests are enabled.
- */
-#if 0
-#ifdef UNITTESTS
-static void
-DumpFrags(DefragTracker *tracker)
-{
- Frag *frag;
-
- printf("Dumping frags for packet: ID=%d\n", tracker->id);
- TAILQ_FOREACH(frag, &tracker->frags, next) {
- printf("-> Frag: frag_offset=%d, frag_len=%d, data_len=%d, ltrim=%d, skip=%d\n", frag->offset, frag->len, frag->data_len, frag->ltrim, frag->skip);
- PrintRawDataFp(stdout, frag->pkt, frag->len);
- }
-}
-#endif /* UNITTESTS */
-#endif
-
-/**
* \brief Reset a frag for reuse in a pool.
*/
static void
@@ -266,7 +246,7 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
}
/* Check that we have all the data. Relies on the fact that
- * fragments are inserted if frag_offset order. */
+ * fragments are inserted in frag_offset order. */
Frag *frag = NULL;
size_t len = 0;
RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
@@ -276,7 +256,8 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
goto done;
}
else {
- len += frag->data_len;
+ /* Update the packet length to the largest known data offset. */
+ len = MAX(len, frag->offset + frag->data_len);
}
}
@@ -288,17 +269,27 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
}
PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
rp->flags |= PKT_REBUILT_FRAGMENT;
- rp->recursion_level = p->recursion_level;
+ rp->datalink = tracker->datalink;
int fragmentable_offset = 0;
uint16_t fragmentable_len = 0;
uint16_t hlen = 0;
int ip_hdr_offset = 0;
+ /* Assume more frags. */
+ uint16_t prev_offset = 0;
+ bool more_frags = 1;
+
RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
frag, frag->data_len, frag->offset, frag->pcap_cnt);
+ /* Previous fragment has no more fragments, and this packet
+ * doesn't overlap. We're done. */
+ if (!more_frags && frag->offset > prev_offset) {
+ break;
+ }
+
if (frag->skip)
continue;
if (frag->ltrim >= frag->data_len)
@@ -339,9 +330,16 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
fragmentable_len = frag->offset + frag->data_len;
}
- if (!frag->more_frags) {
- break;
- }
+ /* Even if this fragment is flagged as having no more
+ * fragments, still continue. The next fragment may have the
+ * same offset with data that is preferred.
+ *
+ * For example, DefragBsdFragmentAfterNoMfIpv{4,6}Test
+ *
+ * This is due to not all fragments being completely trimmed,
+ * but relying on the copy ordering. */
+ more_frags = frag->more_frags;
+ prev_offset = frag->offset;
}
SCLogDebug("ip_hdr_offset %u, hlen %" PRIu16 ", fragmentable_len %" PRIu16, ip_hdr_offset, hlen,
@@ -417,7 +415,7 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
goto done;
}
else {
- len += frag->data_len;
+ len = MAX(len, frag->offset + frag->data_len);
}
}
}
@@ -430,13 +428,23 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
goto error_remove_tracker;
}
PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
+ rp->flags |= PKT_REBUILT_FRAGMENT;
+ rp->datalink = tracker->datalink;
uint16_t unfragmentable_len = 0;
int fragmentable_offset = 0;
uint16_t fragmentable_len = 0;
int ip_hdr_offset = 0;
uint8_t next_hdr = 0;
+
+ /* Assume more frags. */
+ uint16_t prev_offset = 0;
+ bool more_frags = 1;
+
RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
+ if (!more_frags && frag->offset > prev_offset) {
+ break;
+ }
if (frag->skip)
continue;
if (frag->data_len - frag->ltrim <= 0)
@@ -481,9 +489,16 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
fragmentable_len = frag->offset + frag->data_len;
}
- if (!frag->more_frags) {
- break;
- }
+ /* Even if this fragment is flagged as having no more
+ * fragments, still continue. The next fragment may have the
+ * same offset with data that is preferred.
+ *
+ * For example, DefragBsdFragmentAfterNoMfIpv{4,6}Test
+ *
+ * This is due to not all fragments being completely trimmed,
+ * but relying on the copy ordering. */
+ more_frags = frag->more_frags;
+ prev_offset = frag->offset;
}
rp->ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
@@ -660,16 +675,45 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker,
switch (tracker->policy) {
case DEFRAG_POLICY_BSD:
if (frag_offset < prev->offset + prev->data_len) {
- if (frag_offset >= prev->offset) {
- ltrim = prev->offset + prev->data_len - frag_offset;
+ if (prev->offset <= frag_offset) {
+ /* We prefer the data from the previous
+ * fragment, so trim off the data in the new
+ * fragment that exists in the previous
+ * fragment. */
+ uint16_t prev_end = prev->offset + prev->data_len;
+ if (prev_end > frag_end) {
+ /* Just skip. */
+ /* TODO: Set overlap flag. */
+ goto done;
+ }
+ ltrim = prev_end - frag_offset;
+
+ if ((next != NULL) && (frag_end > next->offset)) {
+ next->ltrim = frag_end - next->offset;
+ }
+
+ goto insert;
}
+
+ /* If the end of this fragment overlaps the start
+ * of the previous fragment, then trim up the
+ * start of previous fragment so this fragment is
+ * used.
+ *
+ * See:
+ * DefragBsdSubsequentOverlapsStartOfOriginal.
+ */
+ if (frag_offset <= prev->offset && frag_end > prev->offset + prev->ltrim) {
+ uint16_t prev_ltrim = frag_end - prev->offset;
+ if (prev_ltrim > prev->ltrim) {
+ prev->ltrim = prev_ltrim;
+ }
+ }
+
if ((next != NULL) && (frag_end > next->offset)) {
next->ltrim = frag_end - next->offset;
}
- if ((frag_offset < prev->offset) &&
- (frag_end >= prev->offset + prev->data_len)) {
- prev->skip = 1;
- }
+
goto insert;
}
break;
@@ -861,6 +905,9 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker,
#ifdef DEBUG
new->pcap_cnt = pcap_cnt;
#endif
+ if (frag_offset == 0) {
+ tracker->datalink = p->datalink;
+ }
IP_FRAGMENTS_RB_INSERT(&tracker->fragment_tree, new);
@@ -1093,8 +1140,8 @@ void DefragDestroy(void)
* Allocate a test packet. Nothing to fancy, just a simple IP packet
* with some payload of no particular protocol.
*/
-static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf,
- const char content, int content_len)
+static Packet *BuildIpv4TestPacket(
+ uint8_t proto, uint16_t id, uint16_t off, int mf, const char content, int content_len)
{
Packet *p = NULL;
int hlen = 20;
@@ -1167,8 +1214,79 @@ error:
return NULL;
}
-static Packet *IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off,
- int mf, const char content, int content_len)
+/**
+ * Allocate a test packet, much like BuildIpv4TestPacket, but with
+ * the full content provided by the caller.
+ */
+static Packet *BuildIpv4TestPacketWithContent(
+ uint8_t proto, uint16_t id, uint16_t off, int mf, const uint8_t *content, int content_len)
+{
+ Packet *p = NULL;
+ int hlen = 20;
+ int ttl = 64;
+ IPV4Hdr ip4h;
+
+ p = SCCalloc(1, sizeof(*p) + default_packet_size);
+ if (unlikely(p == NULL))
+ return NULL;
+
+ PacketInit(p);
+
+ struct timeval tval;
+ gettimeofday(&tval, NULL);
+ p->ts = SCTIME_FROM_TIMEVAL(&tval);
+ ip4h.ip_verhl = 4 << 4;
+ ip4h.ip_verhl |= hlen >> 2;
+ ip4h.ip_len = htons(hlen + content_len);
+ ip4h.ip_id = htons(id);
+ if (mf)
+ ip4h.ip_off = htons(IP_MF | off);
+ else
+ ip4h.ip_off = htons(off);
+ ip4h.ip_ttl = ttl;
+ ip4h.ip_proto = proto;
+
+ ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
+ ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
+
+ /* copy content_len crap, we need full length */
+ PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
+ p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
+ SET_IPV4_SRC_ADDR(p, &p->src);
+ SET_IPV4_DST_ADDR(p, &p->dst);
+
+ PacketCopyDataOffset(p, hlen, content, content_len);
+ SET_PKT_LEN(p, hlen + content_len);
+
+ p->ip4h->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
+
+ /* Self test. */
+ if (IPV4_GET_VER(p) != 4)
+ goto error;
+ if (IPV4_GET_HLEN(p) != hlen)
+ goto error;
+ if (IPV4_GET_IPLEN(p) != hlen + content_len)
+ goto error;
+ if (IPV4_GET_IPID(p) != id)
+ goto error;
+ if (IPV4_GET_IPOFFSET(p) != off)
+ goto error;
+ if (IPV4_GET_MF(p) != mf)
+ goto error;
+ if (IPV4_GET_IPTTL(p) != ttl)
+ goto error;
+ if (IPV4_GET_IPPROTO(p) != proto)
+ goto error;
+
+ return p;
+error:
+ if (p != NULL)
+ SCFree(p);
+ return NULL;
+}
+
+static Packet *BuildIpv6TestPacket(
+ uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t content, int content_len)
{
Packet *p = NULL;
uint8_t *pcontent;
@@ -1238,6 +1356,71 @@ error:
return NULL;
}
+static Packet *BuildIpv6TestPacketWithContent(
+ uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t *content, int content_len)
+{
+ Packet *p = NULL;
+ IPV6Hdr ip6h;
+
+ p = SCCalloc(1, sizeof(*p) + default_packet_size);
+ if (unlikely(p == NULL))
+ return NULL;
+
+ PacketInit(p);
+
+ struct timeval tval;
+ gettimeofday(&tval, NULL);
+ p->ts = SCTIME_FROM_TIMEVAL(&tval);
+
+ ip6h.s_ip6_nxt = 44;
+ ip6h.s_ip6_hlim = 2;
+
+ /* Source and dest address - very bogus addresses. */
+ ip6h.s_ip6_src[0] = 0x01010101;
+ ip6h.s_ip6_src[1] = 0x01010101;
+ ip6h.s_ip6_src[2] = 0x01010101;
+ ip6h.s_ip6_src[3] = 0x01010101;
+ ip6h.s_ip6_dst[0] = 0x02020202;
+ ip6h.s_ip6_dst[1] = 0x02020202;
+ ip6h.s_ip6_dst[2] = 0x02020202;
+ ip6h.s_ip6_dst[3] = 0x02020202;
+
+ /* copy content_len crap, we need full length */
+ PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
+
+ p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
+ IPV6_SET_RAW_VER(p->ip6h, 6);
+ /* Fragmentation header. */
+ IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
+ fh->ip6fh_nxt = proto;
+ fh->ip6fh_ident = htonl(id);
+ fh->ip6fh_offlg = htons((off << 3) | mf);
+
+ DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
+
+ PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), content, content_len);
+ SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
+
+ p->ip6h->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
+
+ SET_IPV6_SRC_ADDR(p, &p->src);
+ SET_IPV6_DST_ADDR(p, &p->dst);
+
+ /* Self test. */
+ if (IPV6_GET_VER(p) != 6)
+ goto error;
+ if (IPV6_GET_NH(p) != 44)
+ goto error;
+ if (IPV6_GET_PLEN(p) != sizeof(IPV6FragHdr) + content_len)
+ goto error;
+
+ return p;
+error:
+ if (p != NULL)
+ SCFree(p);
+ return NULL;
+}
+
/**
* Test the simplest possible re-assembly scenario. All packet in
* order and no overlaps.
@@ -1251,11 +1434,11 @@ static int DefragInOrderSimpleTest(void)
DefragInit();
- p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
+ p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
+ p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
FAIL_IF_NULL(p2);
- p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
+ p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
FAIL_IF_NULL(p3);
FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
@@ -1303,11 +1486,11 @@ static int DefragReverseSimpleTest(void)
DefragInit();
- p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
+ p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
+ p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
FAIL_IF_NULL(p2);
- p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
+ p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
FAIL_IF_NULL(p3);
FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
@@ -1347,7 +1530,7 @@ static int DefragReverseSimpleTest(void)
* Test the simplest possible re-assembly scenario. All packet in
* order and no overlaps.
*/
-static int IPV6DefragInOrderSimpleTest(void)
+static int DefragInOrderSimpleIpv6Test(void)
{
Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
Packet *reassembled = NULL;
@@ -1356,11 +1539,11 @@ static int IPV6DefragInOrderSimpleTest(void)
DefragInit();
- p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
+ p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
+ p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
FAIL_IF_NULL(p2);
- p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
+ p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
FAIL_IF_NULL(p3);
FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
@@ -1394,7 +1577,7 @@ static int IPV6DefragInOrderSimpleTest(void)
PASS;
}
-static int IPV6DefragReverseSimpleTest(void)
+static int DefragReverseSimpleIpv6Test(void)
{
DefragContext *dc = NULL;
Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
@@ -1407,11 +1590,11 @@ static int IPV6DefragReverseSimpleTest(void)
dc = DefragContextNew();
FAIL_IF_NULL(dc);
- p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
+ p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
+ p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
FAIL_IF_NULL(p2);
- p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
+ p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
FAIL_IF_NULL(p3);
FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
@@ -1444,8 +1627,7 @@ static int IPV6DefragReverseSimpleTest(void)
PASS;
}
-static int DefragDoSturgesNovakTest(int policy, u_char *expected,
- size_t expected_len)
+static int DefragDoSturgesNovakTest(int policy, uint8_t *expected, size_t expected_len)
{
int i;
@@ -1463,60 +1645,60 @@ static int DefragDoSturgesNovakTest(int policy, u_char *expected,
* Original fragments.
*/
- /* A*24 at 0. */
- packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
+ /* <1> A*24 at 0. */
+ packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
- /* B*15 at 32. */
- packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
+ /* <2> B*16 at 32. */
+ packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
- /* C*24 at 48. */
- packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
+ /* <3> C*24 at 48. */
+ packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
- /* D*8 at 80. */
- packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
+ /* <3_1> D*8 at 80. */
+ packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
- /* E*16 at 104. */
- packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
+ /* <3_2> E*16 at 104. */
+ packets[4] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
- /* F*24 at 120. */
- packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
+ /* <3_3> F*24 at 120. */
+ packets[5] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
- /* G*16 at 144. */
- packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
+ /* <3_4> G*16 at 144. */
+ packets[6] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
- /* H*16 at 160. */
- packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
+ /* <3_5> H*16 at 160. */
+ packets[7] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
- /* I*8 at 176. */
- packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
+ /* <3_6> I*8 at 176. */
+ packets[8] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
/*
* Overlapping subsequent fragments.
*/
- /* J*32 at 8. */
- packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
+ /* <4> J*32 at 8. */
+ packets[9] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
- /* K*24 at 48. */
- packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
+ /* <5> K*24 at 48. */
+ packets[10] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
- /* L*24 at 72. */
- packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
+ /* <6> L*24 at 72. */
+ packets[11] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
- /* M*24 at 96. */
- packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
+ /* <7> M*24 at 96. */
+ packets[12] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
- /* N*8 at 128. */
- packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
+ /* <8> N*8 at 128. */
+ packets[13] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
- /* O*8 at 152. */
- packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
+ /* <9> O*8 at 152. */
+ packets[14] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
- /* P*8 at 160. */
- packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
+ /* <10> P*8 at 160. */
+ packets[15] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
- /* Q*16 at 176. */
- packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
+ /* <11> Q*16 at 176. */
+ packets[16] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
default_policy = policy;
@@ -1542,8 +1724,15 @@ static int DefragDoSturgesNovakTest(int policy, u_char *expected,
FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
FAIL_IF(IPV4_GET_IPLEN(reassembled) != 20 + 192);
-
- FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0);
+ FAIL_IF(expected_len != 192);
+
+ if (memcmp(expected, GET_PKT_DATA(reassembled) + 20, expected_len) != 0) {
+ printf("Expected:\n");
+ PrintRawDataFp(stdout, expected, expected_len);
+ printf("Got:\n");
+ PrintRawDataFp(stdout, GET_PKT_DATA(reassembled) + 20, GET_PKT_LEN(reassembled) - 20);
+ FAIL;
+ }
SCFree(reassembled);
/* Make sure all frags were returned back to the pool. */
@@ -1556,8 +1745,7 @@ static int DefragDoSturgesNovakTest(int policy, u_char *expected,
PASS;
}
-static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected,
- size_t expected_len)
+static int DefragDoSturgesNovakIpv6Test(int policy, uint8_t *expected, size_t expected_len)
{
int i;
@@ -1575,60 +1763,60 @@ static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected,
* Original fragments.
*/
- /* A*24 at 0. */
- packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
+ /* <1> A*24 at 0. */
+ packets[0] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
- /* B*15 at 32. */
- packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
+ /* <2> B*16 at 32. */
+ packets[1] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
- /* C*24 at 48. */
- packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
+ /* <3> C*24 at 48. */
+ packets[2] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
- /* D*8 at 80. */
- packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
+ /* <3_1> D*8 at 80. */
+ packets[3] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
- /* E*16 at 104. */
- packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
+ /* <3_2> E*16 at 104. */
+ packets[4] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
- /* F*24 at 120. */
- packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
+ /* <3_3> F*24 at 120. */
+ packets[5] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
- /* G*16 at 144. */
- packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
+ /* <3_4> G*16 at 144. */
+ packets[6] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
- /* H*16 at 160. */
- packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
+ /* <3_5> H*16 at 160. */
+ packets[7] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
- /* I*8 at 176. */
- packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
+ /* <3_6> I*8 at 176. */
+ packets[8] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
/*
* Overlapping subsequent fragments.
*/
- /* J*32 at 8. */
- packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
+ /* <4> J*32 at 8. */
+ packets[9] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
- /* K*24 at 48. */
- packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
+ /* <5> K*24 at 48. */
+ packets[10] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
- /* L*24 at 72. */
- packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
+ /* <6> L*24 at 72. */
+ packets[11] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
- /* M*24 at 96. */
- packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
+ /* <7> M*24 at 96. */
+ packets[12] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
- /* N*8 at 128. */
- packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
+ /* <8> N*8 at 128. */
+ packets[13] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
- /* O*8 at 152. */
- packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
+ /* <9> O*8 at 152. */
+ packets[14] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
- /* P*8 at 160. */
- packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
+ /* <10> P*8 at 160. */
+ packets[15] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
- /* Q*16 at 176. */
- packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
+ /* <11> Q*16 at 176. */
+ packets[16] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
default_policy = policy;
@@ -1667,35 +1855,61 @@ static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected,
PASS;
}
+/* Define data that matches the naming "Target-Based Fragmentation
+ * Reassembly".
+ *
+ * For example, the data refers to a fragment of data as <1>, or <3_6>
+ * and uses these to diagram the input fragments and the resulting
+ * policies. We build test cases for the papers scenario but assign
+ * specific values to each segment.
+ */
+#define D_1 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'
+#define D_2 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B'
+#define D_3 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C'
+#define D_3_1 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D'
+#define D_3_2 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E'
+#define D_3_3 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F'
+#define D_3_4 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G'
+#define D_3_5 'H', 'H', 'H', 'H', 'H', 'H', 'H', 'H'
+#define D_3_6 'I', 'I', 'I', 'I', 'I', 'I', 'I', 'I'
+#define D_4 'J', 'J', 'J', 'J', 'J', 'J', 'J', 'J'
+#define D_5 'K', 'K', 'K', 'K', 'K', 'K', 'K', 'K'
+#define D_6 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
+#define D_7 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M'
+#define D_8 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'
+#define D_9 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'
+#define D_10 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'
+#define D_11 'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q'
+
static int
DefragSturgesNovakBsdTest(void)
{
/* Expected data. */
- u_char expected[] = {
- "AAAAAAAA"
- "AAAAAAAA"
- "AAAAAAAA"
- "JJJJJJJJ"
- "JJJJJJJJ"
- "BBBBBBBB"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "LLLLLLLL"
- "LLLLLLLL"
- "LLLLLLLL"
- "MMMMMMMM"
- "MMMMMMMM"
- "MMMMMMMM"
- "FFFFFFFF"
- "FFFFFFFF"
- "FFFFFFFF"
- "GGGGGGGG"
- "GGGGGGGG"
- "HHHHHHHH"
- "HHHHHHHH"
- "IIIIIIII"
- "QQQQQQQQ"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_4,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
@@ -1703,69 +1917,68 @@ DefragSturgesNovakBsdTest(void)
PASS;
}
-static int IPV6DefragSturgesNovakBsdTest(void)
+static int DefragSturgesNovakBsdIpv6Test(void)
{
/* Expected data. */
- u_char expected[] = {
- "AAAAAAAA"
- "AAAAAAAA"
- "AAAAAAAA"
- "JJJJJJJJ"
- "JJJJJJJJ"
- "BBBBBBBB"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "LLLLLLLL"
- "LLLLLLLL"
- "LLLLLLLL"
- "MMMMMMMM"
- "MMMMMMMM"
- "MMMMMMMM"
- "FFFFFFFF"
- "FFFFFFFF"
- "FFFFFFFF"
- "GGGGGGGG"
- "GGGGGGGG"
- "HHHHHHHH"
- "HHHHHHHH"
- "IIIIIIII"
- "QQQQQQQQ"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_4,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
- FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
- sizeof(expected)));
+ FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_BSD, expected, sizeof(expected)));
PASS;
}
static int DefragSturgesNovakLinuxIpv4Test(void)
{
/* Expected data. */
- u_char expected[] = {
- "AAAAAAAA"
- "AAAAAAAA"
- "AAAAAAAA"
- "JJJJJJJJ"
- "JJJJJJJJ"
- "BBBBBBBB"
- "KKKKKKKK"
- "KKKKKKKK"
- "KKKKKKKK"
- "LLLLLLLL"
- "LLLLLLLL"
- "LLLLLLLL"
- "MMMMMMMM"
- "MMMMMMMM"
- "MMMMMMMM"
- "FFFFFFFF"
- "FFFFFFFF"
- "FFFFFFFF"
- "GGGGGGGG"
- "GGGGGGGG"
- "PPPPPPPP"
- "HHHHHHHH"
- "QQQQQQQQ"
- "QQQQQQQQ"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_4,
+ D_2,
+ D_5,
+ D_5,
+ D_5,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_10,
+ D_3_5,
+ D_11,
+ D_11,
};
FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
@@ -1773,69 +1986,68 @@ static int DefragSturgesNovakLinuxIpv4Test(void)
PASS;
}
-static int IPV6DefragSturgesNovakLinuxTest(void)
+static int DefragSturgesNovakLinuxIpv6Test(void)
{
/* Expected data. */
- u_char expected[] = {
- "AAAAAAAA"
- "AAAAAAAA"
- "AAAAAAAA"
- "JJJJJJJJ"
- "JJJJJJJJ"
- "BBBBBBBB"
- "KKKKKKKK"
- "KKKKKKKK"
- "KKKKKKKK"
- "LLLLLLLL"
- "LLLLLLLL"
- "LLLLLLLL"
- "MMMMMMMM"
- "MMMMMMMM"
- "MMMMMMMM"
- "FFFFFFFF"
- "FFFFFFFF"
- "FFFFFFFF"
- "GGGGGGGG"
- "GGGGGGGG"
- "PPPPPPPP"
- "HHHHHHHH"
- "QQQQQQQQ"
- "QQQQQQQQ"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_4,
+ D_2,
+ D_5,
+ D_5,
+ D_5,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_10,
+ D_3_5,
+ D_11,
+ D_11,
};
- FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
- sizeof(expected)));
+ FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LINUX, expected, sizeof(expected)));
PASS;
}
static int DefragSturgesNovakWindowsIpv4Test(void)
{
/* Expected data. */
- u_char expected[] = {
- "AAAAAAAA"
- "AAAAAAAA"
- "AAAAAAAA"
- "JJJJJJJJ"
- "BBBBBBBB"
- "BBBBBBBB"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "LLLLLLLL"
- "LLLLLLLL"
- "LLLLLLLL"
- "MMMMMMMM"
- "EEEEEEEE"
- "EEEEEEEE"
- "FFFFFFFF"
- "FFFFFFFF"
- "FFFFFFFF"
- "GGGGGGGG"
- "GGGGGGGG"
- "HHHHHHHH"
- "HHHHHHHH"
- "IIIIIIII"
- "QQQQQQQQ"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_2,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_3_2,
+ D_3_2,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
@@ -1843,69 +2055,68 @@ static int DefragSturgesNovakWindowsIpv4Test(void)
PASS;
}
-static int IPV6DefragSturgesNovakWindowsTest(void)
+static int DefragSturgesNovakWindowsIpv6Test(void)
{
/* Expected data. */
- u_char expected[] = {
- "AAAAAAAA"
- "AAAAAAAA"
- "AAAAAAAA"
- "JJJJJJJJ"
- "BBBBBBBB"
- "BBBBBBBB"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "LLLLLLLL"
- "LLLLLLLL"
- "LLLLLLLL"
- "MMMMMMMM"
- "EEEEEEEE"
- "EEEEEEEE"
- "FFFFFFFF"
- "FFFFFFFF"
- "FFFFFFFF"
- "GGGGGGGG"
- "GGGGGGGG"
- "HHHHHHHH"
- "HHHHHHHH"
- "IIIIIIII"
- "QQQQQQQQ"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_2,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_3_2,
+ D_3_2,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
- FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
- sizeof(expected)));
+ FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected)));
PASS;
}
static int DefragSturgesNovakSolarisTest(void)
{
/* Expected data. */
- u_char expected[] = {
- "AAAAAAAA"
- "AAAAAAAA"
- "AAAAAAAA"
- "JJJJJJJJ"
- "BBBBBBBB"
- "BBBBBBBB"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "LLLLLLLL"
- "LLLLLLLL"
- "LLLLLLLL"
- "MMMMMMMM"
- "MMMMMMMM"
- "MMMMMMMM"
- "FFFFFFFF"
- "FFFFFFFF"
- "FFFFFFFF"
- "GGGGGGGG"
- "GGGGGGGG"
- "HHHHHHHH"
- "HHHHHHHH"
- "IIIIIIII"
- "QQQQQQQQ"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_2,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
@@ -1913,69 +2124,68 @@ static int DefragSturgesNovakSolarisTest(void)
PASS;
}
-static int IPV6DefragSturgesNovakSolarisTest(void)
+static int DefragSturgesNovakSolarisIpv6Test(void)
{
/* Expected data. */
- u_char expected[] = {
- "AAAAAAAA"
- "AAAAAAAA"
- "AAAAAAAA"
- "JJJJJJJJ"
- "BBBBBBBB"
- "BBBBBBBB"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "LLLLLLLL"
- "LLLLLLLL"
- "LLLLLLLL"
- "MMMMMMMM"
- "MMMMMMMM"
- "MMMMMMMM"
- "FFFFFFFF"
- "FFFFFFFF"
- "FFFFFFFF"
- "GGGGGGGG"
- "GGGGGGGG"
- "HHHHHHHH"
- "HHHHHHHH"
- "IIIIIIII"
- "QQQQQQQQ"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_2,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
- FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
- sizeof(expected)));
+ FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected)));
PASS;
}
static int DefragSturgesNovakFirstTest(void)
{
/* Expected data. */
- u_char expected[] = {
- "AAAAAAAA"
- "AAAAAAAA"
- "AAAAAAAA"
- "JJJJJJJJ"
- "BBBBBBBB"
- "BBBBBBBB"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "LLLLLLLL"
- "DDDDDDDD"
- "LLLLLLLL"
- "MMMMMMMM"
- "EEEEEEEE"
- "EEEEEEEE"
- "FFFFFFFF"
- "FFFFFFFF"
- "FFFFFFFF"
- "GGGGGGGG"
- "GGGGGGGG"
- "HHHHHHHH"
- "HHHHHHHH"
- "IIIIIIII"
- "QQQQQQQQ"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_2,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_3_1,
+ D_6,
+ D_7,
+ D_3_2,
+ D_3_2,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
@@ -1983,69 +2193,68 @@ static int DefragSturgesNovakFirstTest(void)
PASS;
}
-static int IPV6DefragSturgesNovakFirstTest(void)
+static int DefragSturgesNovakFirstIpv6Test(void)
{
/* Expected data. */
- u_char expected[] = {
- "AAAAAAAA"
- "AAAAAAAA"
- "AAAAAAAA"
- "JJJJJJJJ"
- "BBBBBBBB"
- "BBBBBBBB"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "LLLLLLLL"
- "DDDDDDDD"
- "LLLLLLLL"
- "MMMMMMMM"
- "EEEEEEEE"
- "EEEEEEEE"
- "FFFFFFFF"
- "FFFFFFFF"
- "FFFFFFFF"
- "GGGGGGGG"
- "GGGGGGGG"
- "HHHHHHHH"
- "HHHHHHHH"
- "IIIIIIII"
- "QQQQQQQQ"
+ uint8_t expected[] = {
+ D_1,
+ D_1,
+ D_1,
+ D_4,
+ D_2,
+ D_2,
+ D_3,
+ D_3,
+ D_3,
+ D_6,
+ D_3_1,
+ D_6,
+ D_7,
+ D_3_2,
+ D_3_2,
+ D_3_3,
+ D_3_3,
+ D_3_3,
+ D_3_4,
+ D_3_4,
+ D_3_5,
+ D_3_5,
+ D_3_6,
+ D_11,
};
- return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
- sizeof(expected));
+ return DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_FIRST, expected, sizeof(expected));
}
static int
DefragSturgesNovakLastTest(void)
{
/* Expected data. */
- u_char expected[] = {
- "AAAAAAAA"
- "JJJJJJJJ"
- "JJJJJJJJ"
- "JJJJJJJJ"
- "JJJJJJJJ"
- "BBBBBBBB"
- "KKKKKKKK"
- "KKKKKKKK"
- "KKKKKKKK"
- "LLLLLLLL"
- "LLLLLLLL"
- "LLLLLLLL"
- "MMMMMMMM"
- "MMMMMMMM"
- "MMMMMMMM"
- "FFFFFFFF"
- "NNNNNNNN"
- "FFFFFFFF"
- "GGGGGGGG"
- "OOOOOOOO"
- "PPPPPPPP"
- "HHHHHHHH"
- "QQQQQQQQ"
- "QQQQQQQQ"
+ uint8_t expected[] = {
+ D_1,
+ D_4,
+ D_4,
+ D_4,
+ D_4,
+ D_2,
+ D_5,
+ D_5,
+ D_5,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_8,
+ D_3_3,
+ D_3_4,
+ D_9,
+ D_10,
+ D_3_5,
+ D_11,
+ D_11,
};
FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
@@ -2053,38 +2262,37 @@ DefragSturgesNovakLastTest(void)
PASS;
}
-static int IPV6DefragSturgesNovakLastTest(void)
+static int DefragSturgesNovakLastIpv6Test(void)
{
/* Expected data. */
- u_char expected[] = {
- "AAAAAAAA"
- "JJJJJJJJ"
- "JJJJJJJJ"
- "JJJJJJJJ"
- "JJJJJJJJ"
- "BBBBBBBB"
- "KKKKKKKK"
- "KKKKKKKK"
- "KKKKKKKK"
- "LLLLLLLL"
- "LLLLLLLL"
- "LLLLLLLL"
- "MMMMMMMM"
- "MMMMMMMM"
- "MMMMMMMM"
- "FFFFFFFF"
- "NNNNNNNN"
- "FFFFFFFF"
- "GGGGGGGG"
- "OOOOOOOO"
- "PPPPPPPP"
- "HHHHHHHH"
- "QQQQQQQQ"
- "QQQQQQQQ"
+ uint8_t expected[] = {
+ D_1,
+ D_4,
+ D_4,
+ D_4,
+ D_4,
+ D_2,
+ D_5,
+ D_5,
+ D_5,
+ D_6,
+ D_6,
+ D_6,
+ D_7,
+ D_7,
+ D_7,
+ D_3_3,
+ D_8,
+ D_3_3,
+ D_3_4,
+ D_9,
+ D_10,
+ D_3_5,
+ D_11,
+ D_11,
};
- FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
- sizeof(expected)));
+ FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LAST, expected, sizeof(expected)));
PASS;
}
@@ -2099,7 +2307,7 @@ static int DefragTimeoutTest(void)
/* Load in 16 packets. */
for (i = 0; i < 16; i++) {
- Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16);
+ Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, i, 0, 1, 'A' + i, 16);
FAIL_IF_NULL(p);
Packet *tp = Defrag(NULL, NULL, p);
@@ -2109,7 +2317,7 @@ static int DefragTimeoutTest(void)
/* Build a new packet but push the timestamp out by our timeout.
* This should force our previous fragments to be timed out. */
- Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
+ Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
FAIL_IF_NULL(p);
p->ts = SCTIME_ADD_SECS(p->ts, defrag_context->timeout + 1);
@@ -2134,7 +2342,7 @@ static int DefragTimeoutTest(void)
* fail. The fix was simple, but this unit test is just to make sure
* its not introduced.
*/
-static int DefragIPv4NoDataTest(void)
+static int DefragNoDataIpv4Test(void)
{
DefragContext *dc = NULL;
Packet *p = NULL;
@@ -2146,7 +2354,7 @@ static int DefragIPv4NoDataTest(void)
FAIL_IF_NULL(dc);
/* This packet has an offset > 0, more frags set to 0 and no data. */
- p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
+ p = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
FAIL_IF_NULL(p);
/* We do not expect a packet returned. */
@@ -2163,7 +2371,7 @@ static int DefragIPv4NoDataTest(void)
PASS;
}
-static int DefragIPv4TooLargeTest(void)
+static int DefragTooLargeIpv4Test(void)
{
DefragContext *dc = NULL;
Packet *p = NULL;
@@ -2175,7 +2383,7 @@ static int DefragIPv4TooLargeTest(void)
/* Create a fragment that would extend past the max allowable size
* for an IPv4 packet. */
- p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
+ p = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
FAIL_IF_NULL(p);
/* We do not expect a packet returned. */
@@ -2206,9 +2414,9 @@ static int DefragVlanTest(void)
DefragInit();
- p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
+ p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
+ p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
FAIL_IF_NULL(p2);
/* With no VLAN IDs set, packets should re-assemble. */
@@ -2238,9 +2446,9 @@ static int DefragVlanQinQTest(void)
DefragInit();
- p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
+ p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
+ p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
FAIL_IF_NULL(p2);
/* With no VLAN IDs set, packets should re-assemble. */
@@ -2272,9 +2480,9 @@ static int DefragVlanQinQinQTest(void)
DefragInit();
- Packet *p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
+ Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- Packet *p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
+ Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
FAIL_IF_NULL(p2);
/* With no VLAN IDs set, packets should re-assemble. */
@@ -2308,7 +2516,7 @@ static int DefragTrackerReuseTest(void)
/* Build a packet, its not a fragment but shouldn't matter for
* this test. */
- p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
+ p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
FAIL_IF_NULL(p1);
/* Get a tracker. It shouldn't look like its already in use. */
@@ -2355,9 +2563,9 @@ static int DefragMfIpv4Test(void)
DefragInit();
- Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
- Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
- Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
+ Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
+ Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
+ Packet *p3 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
p = Defrag(NULL, NULL, p1);
@@ -2374,6 +2582,10 @@ static int DefragMfIpv4Test(void)
* fragments should be in the re-assembled packet. */
FAIL_IF(IPV4_GET_IPLEN(p) != 36);
+ /* Verify the payload of the IPv4 packet. */
+ uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
+ FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV4Hdr), expected_payload, sizeof(expected_payload)));
+
SCFree(p1);
SCFree(p2);
SCFree(p3);
@@ -2398,9 +2610,9 @@ static int DefragMfIpv6Test(void)
DefragInit();
- Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
- Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
- Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
+ Packet *p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
+ Packet *p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
+ Packet *p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
p = Defrag(NULL, NULL, p1);
@@ -2417,6 +2629,10 @@ static int DefragMfIpv6Test(void)
* of 2 fragments, so 16. */
FAIL_IF(IPV6_GET_PLEN(p) != 16);
+ /* Verify the payload of the IPv4 packet. */
+ uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
+ FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV6Hdr), expected_payload, sizeof(expected_payload)));
+
SCFree(p1);
SCFree(p2);
SCFree(p3);
@@ -2436,11 +2652,11 @@ static int DefragTestBadProto(void)
DefragInit();
- p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
+ p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
FAIL_IF_NULL(p1);
- p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
+ p2 = BuildIpv4TestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
FAIL_IF_NULL(p2);
- p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
+ p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
FAIL_IF_NULL(p3);
FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1));
@@ -2461,19 +2677,19 @@ static int DefragTestBadProto(void)
*/
static int DefragTestJeremyLinux(void)
{
- char expected[] = "AAAAAAAA"
- "AAAAAAAA"
- "AAAAAAAA"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "CCCCCCCC"
- "BBBBBBBB"
- "BBBBBBBB"
- "DDDDDDDD"
- "DDDDDD";
+ uint8_t expected[] = "AAAAAAAA"
+ "AAAAAAAA"
+ "AAAAAAAA"
+ "CCCCCCCC"
+ "CCCCCCCC"
+ "CCCCCCCC"
+ "CCCCCCCC"
+ "CCCCCCCC"
+ "CCCCCCCC"
+ "BBBBBBBB"
+ "BBBBBBBB"
+ "DDDDDDDD"
+ "DDDDDD";
DefragInit();
default_policy = DEFRAG_POLICY_LINUX;
@@ -2482,10 +2698,10 @@ static int DefragTestJeremyLinux(void)
Packet *packets[4];
int i = 0;
- packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
- packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
- packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
- packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
+ packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
+ packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
+ packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
+ packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
Packet *r = Defrag(NULL, NULL, packets[0]);
FAIL_IF_NOT_NULL(r);
@@ -2510,6 +2726,401 @@ static int DefragTestJeremyLinux(void)
PASS;
}
+/**
+ * | 0 | 8 | 16 | 24 | 32 |
+ * |----------|----------|----------|----------|----------|
+ * | AAAAAAAA | AAAAAAAA |
+ * | | BBBBBBBB | BBBBBBBB | | |
+ * | | | CCCCCCCC | CCCCCCCC | |
+ * | DDDDDDDD | | | | |
+ *
+ * | DDDDDDDD | BBBBBBBB | BBBBBBBB | CCCCCCCC | AAAAAAAA |
+ */
+static int DefragBsdFragmentAfterNoMfIpv4Test(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[4];
+
+ packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
+ packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
+ packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
+ packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[2]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[3]);
+ FAIL_IF_NULL(r);
+
+ // clang-format off
+ uint8_t expected[] = {
+ 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
+ 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
+ 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
+ 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
+ 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
+ };
+ // clang-format on
+
+ if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
+ printf("Expected:\n");
+ PrintRawDataFp(stdout, expected, sizeof(expected));
+ printf("Got:\n");
+ PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
+ FAIL;
+ }
+
+ DefragDestroy();
+ PASS;
+}
+
+static int DefragBsdFragmentAfterNoMfIpv6Test(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[4];
+
+ packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
+ packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
+ packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
+ packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[2]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[3]);
+ FAIL_IF_NULL(r);
+
+ // clang-format off
+ uint8_t expected[] = {
+ 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
+ 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
+ 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
+ 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
+ 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
+ };
+ // clang-format on
+
+ if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
+ printf("Expected:\n");
+ PrintRawDataFp(stdout, expected, sizeof(expected));
+ printf("Got:\n");
+ PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
+ FAIL;
+ }
+
+ DefragDestroy();
+ PASS;
+}
+
+static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[4];
+
+ /* Packet 1: off=16, mf=1 */
+ packets[0] = BuildIpv4TestPacketWithContent(
+ IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
+
+ /* Packet 2: off=8, mf=1 */
+ packets[1] = BuildIpv4TestPacketWithContent(
+ IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16);
+
+ /* Packet 3: off=0, mf=1: IP and ICMP header. */
+ packets[2] = BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
+
+ /* Packet 4: off=8, mf=1 */
+ packets[3] =
+ BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[2]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[3]);
+ FAIL_IF_NULL(r);
+
+ // clang-format off
+ const uint8_t expected[] = {
+ // AACCBBDD
+ // AACCDDBB
+ // AABBDDCC
+ // DDCCBBAA
+ 'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
+ 'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
+ 'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
+ 'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
+ };
+ // clang-format on
+
+ FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20 + 8, sizeof(expected)) != 0);
+
+ DefragDestroy();
+ PASS;
+}
+
+static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[4];
+
+ /* Packet 1: off=16, mf=1 */
+ packets[0] = BuildIpv6TestPacketWithContent(
+ IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
+
+ /* Packet 2: off=8, mf=1 */
+ packets[1] = BuildIpv6TestPacketWithContent(
+ IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16);
+
+ /* Packet 3: off=0, mf=1: IP and ICMP header. */
+ packets[2] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
+
+ /* Packet 4: off=8, mf=1 */
+ packets[3] =
+ BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[2]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[3]);
+ FAIL_IF_NULL(r);
+
+ // clang-format off
+ const uint8_t expected[] = {
+ // AACCBBDD
+ // AACCDDBB
+ // AABBDDCC
+ // DDCCBBAA
+ 'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
+ 'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
+ 'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
+ 'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
+ };
+ // clang-format on
+
+ FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 40 + 8, sizeof(expected)) != 0);
+
+ DefragDestroy();
+ PASS;
+}
+
+/**
+ * #### Input
+ *
+ * | 96 (0) | 104 (8) | 112 (16) | 120 (24) |
+ * |----------|----------|----------|----------|
+ * | | EEEEEEEE | EEEEEEEE | EEEEEEEE |
+ * | MMMMMMMM | MMMMMMMM | MMMMMMMM | |
+ *
+ * #### Expected Output
+ *
+ * | MMMMMMMM | MMMMMMMM | MMMMMMMM | EEEEEEEE |
+ */
+static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[2];
+
+ packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
+ packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NULL(r);
+
+ // clang-format off
+ const uint8_t expected[] = {
+ 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
+ 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
+ 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
+ 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
+ };
+ // clang-format on
+
+ if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
+ printf("Expected:\n");
+ PrintRawDataFp(stdout, expected, sizeof(expected));
+ printf("Got:\n");
+ PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
+ FAIL;
+ }
+
+ PASS;
+}
+
+static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[2];
+
+ packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
+ packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NULL(r);
+
+ // clang-format off
+ const uint8_t expected[] = {
+ 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
+ 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
+ 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
+ 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
+ };
+ // clang-format on
+
+ if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
+ printf("Expected:\n");
+ PrintRawDataFp(stdout, expected, sizeof(expected));
+ printf("Got:\n");
+ PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
+ FAIL;
+ }
+
+ PASS;
+}
+
+/**
+ * Reassembly should fail.
+ *
+ * |0 |8 |16 |24 |32 |40 |48 |
+ * |========|========|========|========|========|========|========|
+ * | | |AABBCCDD|AABBDDCC| | | |
+ * | | | | | |AACCBBDD| |
+ * | |AACCDDBB|AADDBBCC| | | | |
+ * |ZZZZZZZZ| | | | | | |
+ * | | | | | | |DDCCBBAA|
+ */
+static int DefragBsdMissingFragmentIpv4Test(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[5];
+
+ packets[0] = BuildIpv4TestPacketWithContent(
+ IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
+
+ packets[1] =
+ BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8);
+
+ packets[2] = BuildIpv4TestPacketWithContent(
+ IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16);
+
+ /* ICMP header. */
+ packets[3] = BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
+
+ packets[4] =
+ BuildIpv4TestPacketWithContent(IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[2]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[3]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[4]);
+ FAIL_IF_NOT_NULL(r);
+
+#if 0
+ PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
+#endif
+
+ for (int i = 0; i < 5; i++) {
+ SCFree(packets[i]);
+ }
+
+ DefragDestroy();
+
+ PASS;
+}
+
+static int DefragBsdMissingFragmentIpv6Test(void)
+{
+ DefragInit();
+ default_policy = DEFRAG_POLICY_BSD;
+ Packet *packets[5];
+
+ packets[0] = BuildIpv6TestPacketWithContent(
+ IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
+
+ packets[1] =
+ BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8);
+
+ packets[2] = BuildIpv6TestPacketWithContent(
+ IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16);
+
+ /* ICMP header. */
+ packets[3] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
+
+ packets[4] =
+ BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
+
+ Packet *r = Defrag(NULL, NULL, packets[0]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[1]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[2]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[3]);
+ FAIL_IF_NOT_NULL(r);
+
+ r = Defrag(NULL, NULL, packets[4]);
+ FAIL_IF_NOT_NULL(r);
+
+#if 0
+ PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
+#endif
+
+ for (int i = 0; i < 5; i++) {
+ SCFree(packets[i]);
+ }
+
+ DefragDestroy();
+
+ PASS;
+}
+
#endif /* UNITTESTS */
void DefragRegisterTests(void)
@@ -2527,23 +3138,17 @@ void DefragRegisterTests(void)
UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
- UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest);
- UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest);
-
- UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest);
- UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest);
- UtRegisterTest("IPV6DefragSturgesNovakBsdTest",
- IPV6DefragSturgesNovakBsdTest);
- UtRegisterTest("IPV6DefragSturgesNovakLinuxTest",
- IPV6DefragSturgesNovakLinuxTest);
- UtRegisterTest("IPV6DefragSturgesNovakWindowsTest",
- IPV6DefragSturgesNovakWindowsTest);
- UtRegisterTest("IPV6DefragSturgesNovakSolarisTest",
- IPV6DefragSturgesNovakSolarisTest);
- UtRegisterTest("IPV6DefragSturgesNovakFirstTest",
- IPV6DefragSturgesNovakFirstTest);
- UtRegisterTest("IPV6DefragSturgesNovakLastTest",
- IPV6DefragSturgesNovakLastTest);
+ UtRegisterTest("DefragNoDataIpv4Test", DefragNoDataIpv4Test);
+ UtRegisterTest("DefragTooLargeIpv4Test", DefragTooLargeIpv4Test);
+
+ UtRegisterTest("DefragInOrderSimpleIpv6Test", DefragInOrderSimpleIpv6Test);
+ UtRegisterTest("DefragReverseSimpleIpv6Test", DefragReverseSimpleIpv6Test);
+ UtRegisterTest("DefragSturgesNovakBsdIpv6Test", DefragSturgesNovakBsdIpv6Test);
+ UtRegisterTest("DefragSturgesNovakLinuxIpv6Test", DefragSturgesNovakLinuxIpv6Test);
+ UtRegisterTest("DefragSturgesNovakWindowsIpv6Test", DefragSturgesNovakWindowsIpv6Test);
+ UtRegisterTest("DefragSturgesNovakSolarisIpv6Test", DefragSturgesNovakSolarisIpv6Test);
+ UtRegisterTest("DefragSturgesNovakFirstIpv6Test", DefragSturgesNovakFirstIpv6Test);
+ UtRegisterTest("DefragSturgesNovakLastIpv6Test", DefragSturgesNovakLastIpv6Test);
UtRegisterTest("DefragVlanTest", DefragVlanTest);
UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
@@ -2555,5 +3160,16 @@ void DefragRegisterTests(void)
UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
+
+ UtRegisterTest("DefragBsdFragmentAfterNoMfIpv4Test", DefragBsdFragmentAfterNoMfIpv4Test);
+ UtRegisterTest("DefragBsdFragmentAfterNoMfIpv6Test", DefragBsdFragmentAfterNoMfIpv6Test);
+ UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test",
+ DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test);
+ UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test",
+ DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test);
+ UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2", DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2);
+ UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2", DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2);
+ UtRegisterTest("DefragBsdMissingFragmentIpv4Test", DefragBsdMissingFragmentIpv4Test);
+ UtRegisterTest("DefragBsdMissingFragmentIpv6Test", DefragBsdMissingFragmentIpv6Test);
#endif /* UNITTESTS */
}
diff --git a/src/defrag.h b/src/defrag.h
index 11e6a61..93fe872 100644
--- a/src/defrag.h
+++ b/src/defrag.h
@@ -106,6 +106,7 @@ typedef struct DefragTracker_ {
Address src_addr; /**< Source address for this tracker. */
Address dst_addr; /**< Destination address for this tracker. */
+ int datalink; /**< datalink for reassembled packet, set by first fragment */
SCTime_t timeout; /**< When this tracker will timeout. */
uint32_t host_timeout; /**< Host timeout, statically assigned from the yaml */
diff --git a/src/detect-dataset.c b/src/detect-dataset.c
index 3d29646..69eaf81 100644
--- a/src/detect-dataset.c
+++ b/src/detect-dataset.c
@@ -407,10 +407,6 @@ int DetectDatasetSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawst
SCLogError("failed to set up dataset '%s'.", name);
return -1;
}
- if (set->hash && SC_ATOMIC_GET(set->hash->memcap_reached)) {
- SCLogError("dataset too large for set memcap");
- return -1;
- }
cd = SCCalloc(1, sizeof(DetectDatasetData));
if (unlikely(cd == NULL))
diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c
index b82f327..ef6007a 100644
--- a/src/detect-fast-pattern.c
+++ b/src/detect-fast-pattern.c
@@ -274,6 +274,9 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const c
}
}
}
+ if (SigMatchListSMBelongsTo(s, pm) == DETECT_SM_LIST_BASE64_DATA) {
+ SCLogInfo("fast_pattern is ineffective with base64_data");
+ }
cd->flags |= DETECT_CONTENT_FAST_PATTERN;
return 0;
}
diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c
index 98f0ec5..28833a8 100644
--- a/src/detect-http-server-body.c
+++ b/src/detect-http-server-body.c
@@ -124,6 +124,9 @@ static int DetectHttpServerBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0)
return -1;
+ // file data is on both directions, but we only take the one to client here
+ s->flags |= SIG_FLAG_TOCLIENT;
+ s->flags &= ~SIG_FLAG_TOSERVER;
return 0;
}
diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c
index 105751c..01b4712 100644
--- a/src/detect-ipopts.c
+++ b/src/detect-ipopts.c
@@ -25,23 +25,13 @@
#include "suricata-common.h"
#include "suricata.h"
-#include "decode.h"
#include "detect.h"
#include "detect-parse.h"
-#include "flow-var.h"
-#include "decode-events.h"
-
-#include "util-debug.h"
-
#include "detect-ipopts.h"
#include "util-unittest.h"
-#define PARSE_REGEX "\\S[A-z]"
-
-static DetectParseRegex parse_regex;
-
static int DetectIpOptsMatch (DetectEngineThreadCtx *, Packet *,
const Signature *, const SigMatchCtx *);
static int DetectIpOptsSetup (DetectEngineCtx *, Signature *, const char *);
@@ -64,7 +54,6 @@ void DetectIpOptsRegister (void)
#ifdef UNITTESTS
sigmatch_table[DETECT_IPOPTS].RegisterTests = IpOptsRegisterTests;
#endif
- DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
}
/**
@@ -173,11 +162,7 @@ static int DetectIpOptsMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
if (!de || !PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p))
return 0;
- if (p->ip4vars.opts_set & de->ipopt) {
- return 1;
- }
-
- return 0;
+ return (p->ip4vars.opts_set & de->ipopt) == de->ipopt;
}
/**
@@ -191,42 +176,30 @@ static int DetectIpOptsMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
*/
static DetectIpOptsData *DetectIpOptsParse (const char *rawstr)
{
- int i;
- DetectIpOptsData *de = NULL;
- int found = 0;
-
- pcre2_match_data *match = NULL;
- int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0);
- if (ret < 1) {
- SCLogError("pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr);
- goto error;
- }
+ if (rawstr == NULL || strlen(rawstr) == 0)
+ return NULL;
+ int i;
+ bool found = false;
for(i = 0; ipopts[i].ipopt_name != NULL; i++) {
if((strcasecmp(ipopts[i].ipopt_name,rawstr)) == 0) {
- found = 1;
+ found = true;
break;
}
}
- if(found == 0)
- goto error;
+ if (!found) {
+ SCLogError("unknown IP option specified \"%s\"", rawstr);
+ return NULL;
+ }
- de = SCMalloc(sizeof(DetectIpOptsData));
+ DetectIpOptsData *de = SCMalloc(sizeof(DetectIpOptsData));
if (unlikely(de == NULL))
- goto error;
+ return NULL;
de->ipopt = ipopts[i].code;
- pcre2_match_data_free(match);
return de;
-
-error:
- if (match) {
- pcre2_match_data_free(match);
- }
- if (de) SCFree(de);
- return NULL;
}
/**
@@ -242,10 +215,8 @@ error:
*/
static int DetectIpOptsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
- DetectIpOptsData *de = NULL;
SigMatch *sm = NULL;
-
- de = DetectIpOptsParse(rawstr);
+ DetectIpOptsData *de = DetectIpOptsParse(rawstr);
if (de == NULL)
goto error;
@@ -275,8 +246,9 @@ error:
*/
void DetectIpOptsFree(DetectEngineCtx *de_ctx, void *de_ptr)
{
- DetectIpOptsData *de = (DetectIpOptsData *)de_ptr;
- if(de) SCFree(de);
+ if (de_ptr) {
+ SCFree(de_ptr);
+ }
}
/*
@@ -381,6 +353,20 @@ static int IpOptsTestParse04 (void)
}
/**
+ * \test IpOptsTestParse05 tests the NULL and empty string
+ */
+static int IpOptsTestParse05(void)
+{
+ DetectIpOptsData *de = DetectIpOptsParse("");
+ FAIL_IF_NOT_NULL(de);
+
+ de = DetectIpOptsParse(NULL);
+ FAIL_IF_NOT_NULL(de);
+
+ PASS;
+}
+
+/**
* \brief this function registers unit tests for IpOpts
*/
void IpOptsRegisterTests(void)
@@ -389,5 +375,6 @@ void IpOptsRegisterTests(void)
UtRegisterTest("IpOptsTestParse02", IpOptsTestParse02);
UtRegisterTest("IpOptsTestParse03", IpOptsTestParse03);
UtRegisterTest("IpOptsTestParse04", IpOptsTestParse04);
+ UtRegisterTest("IpOptsTestParse05", IpOptsTestParse05);
}
#endif /* UNITTESTS */
diff --git a/src/detect-parse.c b/src/detect-parse.c
index c3232b9..5dee7e6 100644
--- a/src/detect-parse.c
+++ b/src/detect-parse.c
@@ -2701,7 +2701,7 @@ int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match,
*match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
if (*match)
return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
- *match, NULL);
+ *match, parse_regex->context);
return -1;
}
@@ -2761,8 +2761,16 @@ bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect
parse_str, en, errbuffer);
return false;
}
- detect_parse->match = pcre2_match_data_create_from_pattern(detect_parse->regex, NULL);
+ detect_parse->context = pcre2_match_context_create(NULL);
+ if (detect_parse->context == NULL) {
+ SCLogError("pcre2 could not create match context");
+ pcre2_code_free(detect_parse->regex);
+ detect_parse->regex = NULL;
+ return false;
+ }
+ pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
+ pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
DetectParseRegexAddToFreeList(detect_parse);
return true;
diff --git a/src/flow-timeout.c b/src/flow-timeout.c
index e5d2794..6efa382 100644
--- a/src/flow-timeout.c
+++ b/src/flow-timeout.c
@@ -341,14 +341,20 @@ int FlowForceReassemblyNeedReassembly(Flow *f)
*
* The function requires flow to be locked beforehand.
*
+ * Normally, the first thread_id value should be used. This is when the flow is
+ * created on seeing the first packet to the server; when the flow's reversed
+ * flag is set, choose the second thread_id (to client/source).
+ *
* \param f Pointer to the flow.
*
* \retval 0 This flow doesn't need any reassembly processing; 1 otherwise.
*/
void FlowForceReassemblyForFlow(Flow *f)
{
- const int thread_id = (int)f->thread_id[0];
- TmThreadsInjectFlowById(f, thread_id);
+ // Choose the thread_id based on whether the flow has been
+ // reversed.
+ int idx = f->flags & FLOW_DIR_REVERSED ? 1 : 0;
+ TmThreadsInjectFlowById(f, (const int)f->thread_id[idx]);
}
/**
diff --git a/src/flow.c b/src/flow.c
index 9783b78..b61823e 100644
--- a/src/flow.c
+++ b/src/flow.c
@@ -291,6 +291,8 @@ void FlowSwap(Flow *f)
FlowSwapFlags(f);
FlowSwapFileFlags(f);
+ SWAP_VARS(FlowThreadId, f->thread_id[0], f->thread_id[1]);
+
if (f->proto == IPPROTO_TCP) {
TcpStreamFlowSwap(f);
}
diff --git a/src/output-json-stats.c b/src/output-json-stats.c
index 33f98af..7cc8807 100644
--- a/src/output-json-stats.c
+++ b/src/output-json-stats.c
@@ -265,23 +265,30 @@ json_t *StatsToJSON(const StatsTable *st, uint8_t flags)
uint32_t x;
for (x = 0; x < st->ntstats; x++) {
uint32_t offset = x * st->nstats;
-
- // Stats for for this thread.
- json_t *thread = json_object();
- if (unlikely(thread == NULL)) {
- json_decref(js_stats);
- json_decref(threads);
- return NULL;
- }
+ const char *tm_name = NULL;
+ json_t *thread = NULL;
/* for each counter */
for (u = offset; u < (offset + st->nstats); u++) {
if (st->tstats[u].name == NULL)
continue;
- // Seems this holds, but assert in debug builds.
- DEBUG_VALIDATE_BUG_ON(
- strcmp(st->tstats[offset].tm_name, st->tstats[u].tm_name) != 0);
+ DEBUG_VALIDATE_BUG_ON(st->tstats[u].tm_name == NULL);
+
+ if (tm_name == NULL) {
+ // First time we see a set tm_name. Remember it
+ // and allocate the stats object for this thread.
+ tm_name = st->tstats[u].tm_name;
+ thread = json_object();
+ if (unlikely(thread == NULL)) {
+ json_decref(js_stats);
+ json_decref(threads);
+ return NULL;
+ }
+ } else {
+ DEBUG_VALIDATE_BUG_ON(strcmp(tm_name, st->tstats[u].tm_name) != 0);
+ DEBUG_VALIDATE_BUG_ON(thread == NULL);
+ }
json_t *js_type = NULL;
const char *stat_name = st->tstats[u].short_name;
@@ -303,7 +310,10 @@ json_t *StatsToJSON(const StatsTable *st, uint8_t flags)
}
}
}
- json_object_set_new(threads, st->tstats[offset].tm_name, thread);
+ if (tm_name != NULL) {
+ DEBUG_VALIDATE_BUG_ON(thread == NULL);
+ json_object_set_new(threads, tm_name, thread);
+ }
}
json_object_set_new(js_stats, "threads", threads);
}
diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c
index b8ad0bf..742d968 100644
--- a/src/runmode-af-packet.c
+++ b/src/runmode-af-packet.c
@@ -90,7 +90,6 @@ static int AFPRunModeIsIPS(void)
SCLogError("Problem with config file");
return 0;
}
- const char *copymodestr = NULL;
if_root = ConfFindDeviceConfig(af_packet_node, live_dev);
if (if_root == NULL) {
@@ -101,7 +100,10 @@ static int AFPRunModeIsIPS(void)
if_root = if_default;
}
- if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
+ const char *copymodestr = NULL;
+ const char *copyifacestr = NULL;
+ if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1 &&
+ ConfGetChildValue(if_root, "copy-iface", &copyifacestr) == 1) {
if (strcmp(copymodestr, "ips") == 0) {
has_ips = 1;
} else {
diff --git a/src/runmode-dpdk.c b/src/runmode-dpdk.c
index 1a240aa..fb49d6e 100644
--- a/src/runmode-dpdk.c
+++ b/src/runmode-dpdk.c
@@ -54,9 +54,12 @@
#define RSS_HKEY_LEN 40
// General purpose RSS key for symmetric bidirectional flow distribution
-uint8_t rss_hkey[] = { 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D,
- 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D,
- 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A };
+uint8_t rss_hkey[] = {
+ 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
+ 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
+ 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, // 40
+ 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, // 52
+};
// Calculates the closest multiple of y from x
#define ROUNDUP(x, y) ((((x) + ((y)-1)) / (y)) * (y))
@@ -111,6 +114,7 @@ static void *ParseDpdkConfigAndConfigureDevice(const char *iface);
static void DPDKDerefConfig(void *conf);
#define DPDK_CONFIG_DEFAULT_THREADS "auto"
+#define DPDK_CONFIG_DEFAULT_INTERRUPT_MODE false
#define DPDK_CONFIG_DEFAULT_MEMPOOL_SIZE 65535
#define DPDK_CONFIG_DEFAULT_MEMPOOL_CACHE_SIZE "auto"
#define DPDK_CONFIG_DEFAULT_RX_DESCRIPTORS 1024
@@ -126,6 +130,7 @@ static void DPDKDerefConfig(void *conf);
DPDKIfaceConfigAttributes dpdk_yaml = {
.threads = "threads",
+ .irq_mode = "interrupt-mode",
.promisc = "promisc",
.multicast = "multicast",
.checksum_checks = "checksum-checks",
@@ -434,6 +439,15 @@ static int ConfigSetThreads(DPDKIfaceConfig *iconf, const char *entry_str)
SCReturnInt(0);
}
+static bool ConfigSetInterruptMode(DPDKIfaceConfig *iconf, bool enable)
+{
+ SCEnter();
+ if (enable)
+ iconf->flags |= DPDK_IRQ_MODE;
+
+ SCReturnBool(true);
+}
+
static int ConfigSetRxQueues(DPDKIfaceConfig *iconf, uint16_t nb_queues)
{
SCEnter();
@@ -704,6 +718,17 @@ static int ConfigLoad(DPDKIfaceConfig *iconf, const char *iface)
if (retval < 0)
SCReturnInt(retval);
+ bool irq_enable;
+ retval = ConfGetChildValueBoolWithDefault(if_root, if_default, dpdk_yaml.irq_mode, &entry_bool);
+ if (retval != 1) {
+ irq_enable = DPDK_CONFIG_DEFAULT_INTERRUPT_MODE;
+ } else {
+ irq_enable = entry_bool ? true : false;
+ }
+ retval = ConfigSetInterruptMode(iconf, irq_enable);
+ if (retval != true)
+ SCReturnInt(-EINVAL);
+
// currently only mapping "1 thread == 1 RX (and 1 TX queue in IPS mode)" is supported
retval = ConfigSetRxQueues(iconf, (uint16_t)iconf->threads);
if (retval < 0)
@@ -846,7 +871,7 @@ static void DeviceSetPMDSpecificRSS(struct rte_eth_rss_conf *rss_conf, const cha
if (strcmp(driver_name, "net_i40e") == 0)
i40eDeviceSetRSSConf(rss_conf);
if (strcmp(driver_name, "net_ice") == 0)
- iceDeviceSetRSSHashFunction(&rss_conf->rss_hf);
+ iceDeviceSetRSSConf(rss_conf);
if (strcmp(driver_name, "net_ixgbe") == 0)
ixgbeDeviceSetRSSHashFunction(&rss_conf->rss_hf);
if (strcmp(driver_name, "net_e1000_igb") == 0)
@@ -1115,6 +1140,11 @@ static void DeviceInitPortConf(const DPDKIfaceConfig *iconf,
},
};
+ SCLogConfig("%s: interrupt mode is %s", iconf->iface,
+ iconf->flags & DPDK_IRQ_MODE ? "enabled" : "disabled");
+ if (iconf->flags & DPDK_IRQ_MODE)
+ port_conf->intr_conf.rxq = 1;
+
// configure RX offloads
if (dev_info->rx_offload_capa & RTE_ETH_RX_OFFLOAD_RSS_HASH) {
if (iconf->nb_rx_queues > 1) {
@@ -1616,7 +1646,9 @@ static int DPDKRunModeIsIPS(void)
}
const char *copymodestr = NULL;
- if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
+ const char *copyifacestr = NULL;
+ if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1 &&
+ ConfGetChildValue(if_root, "copy-iface", &copyifacestr) == 1) {
if (strcmp(copymodestr, "ips") == 0) {
has_ips = true;
} else {
diff --git a/src/runmode-dpdk.h b/src/runmode-dpdk.h
index a00327b..152c1d6 100644
--- a/src/runmode-dpdk.h
+++ b/src/runmode-dpdk.h
@@ -25,6 +25,7 @@
typedef struct DPDKIfaceConfigAttributes_ {
const char *threads;
+ const char *irq_mode;
const char *promisc;
const char *multicast;
const char *checksum_checks;
diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c
index e207cf0..947b381 100644
--- a/src/runmode-netmap.c
+++ b/src/runmode-netmap.c
@@ -81,7 +81,6 @@ static int NetmapRunModeIsIPS(void)
SCLogError("Problem with config file");
return 0;
}
- const char *copymodestr = NULL;
if_root = ConfNodeLookupKeyValue(netmap_node, "interface", live_dev);
if (if_root == NULL) {
@@ -92,7 +91,10 @@ static int NetmapRunModeIsIPS(void)
if_root = if_default;
}
- if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
+ const char *copymodestr = NULL;
+ const char *copyifacestr = NULL;
+ if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1 &&
+ ConfGetChildValue(if_root, "copy-iface", &copyifacestr) == 1) {
if (strcmp(copymodestr, "ips") == 0) {
has_ips = 1;
} else {
diff --git a/src/runmodes.c b/src/runmodes.c
index 348adfa..d4b57df 100644
--- a/src/runmodes.c
+++ b/src/runmodes.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2022 Open Information Security Foundation
+/* Copyright (C) 2007-2024 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@@ -70,6 +70,7 @@
#include "counters.h"
#include "suricata-plugin.h"
+#include "util-device.h"
int debuglog_enabled = 0;
int threading_set_cpu_affinity = FALSE;
@@ -408,6 +409,14 @@ void RunModeEngineIsIPS(int capture_mode, const char *runmode, const char *captu
if (mode->RunModeIsIPSEnabled != NULL) {
mode->RunModeIsIPSEnabled();
+
+ if (EngineModeIsIPS()) {
+ extern uint16_t g_livedev_mask;
+ if (g_livedev_mask != 0 && LiveGetDeviceCount() > 0) {
+ SCLogWarning("disabling livedev.use-for-tracking with IPS mode. See ticket #6726.");
+ g_livedev_mask = 0;
+ }
+ }
}
}
diff --git a/src/source-dpdk.c b/src/source-dpdk.c
index cf26af5..6a7833e 100644
--- a/src/source-dpdk.c
+++ b/src/source-dpdk.c
@@ -93,6 +93,13 @@ TmEcode NoDPDKSupportExit(ThreadVars *tv, const void *initdata, void **data)
#define BURST_SIZE 32
static struct timeval machine_start_time = { 0, 0 };
+// interrupt mode constants
+#define MIN_ZERO_POLL_COUNT 10U
+#define MIN_ZERO_POLL_COUNT_TO_SLEEP 10U
+#define MINIMUM_SLEEP_TIME_US 1U
+#define STANDARD_SLEEP_TIME_US 100U
+#define MAX_EPOLL_TIMEOUT_MS 500U
+static rte_spinlock_t intr_lock[RTE_MAX_ETHPORTS];
/**
* \brief Structure to hold thread specific variables.
@@ -104,6 +111,7 @@ typedef struct DPDKThreadVars_ {
TmSlot *slot;
LiveDevice *livedev;
ChecksumValidationMode checksum_mode;
+ bool intr_enabled;
/* references to packet and drop counters */
uint16_t capture_dpdk_packets;
uint16_t capture_dpdk_rx_errs;
@@ -142,6 +150,40 @@ static uint64_t CyclesToSeconds(uint64_t cycles);
static void DPDKFreeMbufArray(struct rte_mbuf **mbuf_array, uint16_t mbuf_cnt, uint16_t offset);
static uint64_t DPDKGetSeconds(void);
+static bool InterruptsRXEnable(uint16_t port_id, uint16_t queue_id)
+{
+ uint32_t event_data = port_id << UINT16_WIDTH | queue_id;
+ int32_t ret = rte_eth_dev_rx_intr_ctl_q(port_id, queue_id, RTE_EPOLL_PER_THREAD,
+ RTE_INTR_EVENT_ADD, (void *)((uintptr_t)event_data));
+
+ if (ret != 0) {
+ SCLogError("%s-Q%d: failed to enable interrupt mode: %s", DPDKGetPortNameByPortID(port_id),
+ queue_id, rte_strerror(-ret));
+ return false;
+ }
+ return true;
+}
+
+static inline uint32_t InterruptsSleepHeuristic(uint32_t no_pkt_polls_count)
+{
+ if (no_pkt_polls_count < MIN_ZERO_POLL_COUNT_TO_SLEEP)
+ return MINIMUM_SLEEP_TIME_US;
+
+ return STANDARD_SLEEP_TIME_US;
+}
+
+static inline void InterruptsTurnOnOff(uint16_t port_id, uint16_t queue_id, bool on)
+{
+ rte_spinlock_lock(&(intr_lock[port_id]));
+
+ if (on)
+ rte_eth_dev_rx_intr_enable(port_id, queue_id);
+ else
+ rte_eth_dev_rx_intr_disable(port_id, queue_id);
+
+ rte_spinlock_unlock(&(intr_lock[port_id]));
+}
+
static void DPDKFreeMbufArray(struct rte_mbuf **mbuf_array, uint16_t mbuf_cnt, uint16_t offset)
{
for (int i = offset; i < mbuf_cnt; i++) {
@@ -377,6 +419,11 @@ static TmEcode ReceiveDPDKLoop(ThreadVars *tv, void *data, void *slot)
rte_eth_stats_reset(ptv->port_id);
rte_eth_xstats_reset(ptv->port_id);
+
+ uint32_t pwd_zero_rx_packet_polls_count = 0;
+ if (ptv->intr_enabled && !InterruptsRXEnable(ptv->port_id, ptv->queue_id))
+ SCReturnInt(TM_ECODE_FAILED);
+
while (1) {
if (unlikely(suricata_ctl_flags != 0)) {
SCLogDebug("Stopping Suricata!");
@@ -398,7 +445,27 @@ static TmEcode ReceiveDPDKLoop(ThreadVars *tv, void *data, void *slot)
TmThreadsCaptureHandleTimeout(tv, NULL);
last_timeout_msec = msecs;
}
- continue;
+
+ if (!ptv->intr_enabled)
+ continue;
+
+ pwd_zero_rx_packet_polls_count++;
+ if (pwd_zero_rx_packet_polls_count <= MIN_ZERO_POLL_COUNT)
+ continue;
+
+ uint32_t pwd_idle_hint = InterruptsSleepHeuristic(pwd_zero_rx_packet_polls_count);
+
+ if (pwd_idle_hint < STANDARD_SLEEP_TIME_US) {
+ rte_delay_us(pwd_idle_hint);
+ } else {
+ InterruptsTurnOnOff(ptv->port_id, ptv->queue_id, true);
+ struct rte_epoll_event event;
+ rte_epoll_wait(RTE_EPOLL_PER_THREAD, &event, 1, MAX_EPOLL_TIMEOUT_MS);
+ InterruptsTurnOnOff(ptv->port_id, ptv->queue_id, false);
+ continue;
+ }
+ } else if (ptv->intr_enabled && pwd_zero_rx_packet_polls_count) {
+ pwd_zero_rx_packet_polls_count = 0;
}
ptv->pkts += (uint64_t)nb_rx;
@@ -522,6 +589,7 @@ static TmEcode ReceiveDPDKThreadInit(ThreadVars *tv, const void *initdata, void
ptv->checksum_mode = dpdk_config->checksum_mode;
ptv->threads = dpdk_config->threads;
+ ptv->intr_enabled = (dpdk_config->flags & DPDK_IRQ_MODE) ? true : false;
ptv->port_id = dpdk_config->port_id;
ptv->out_port_id = dpdk_config->out_port_id;
ptv->port_socket_id = dpdk_config->socket_id;
@@ -569,6 +637,9 @@ static TmEcode ReceiveDPDKThreadInit(ThreadVars *tv, const void *initdata, void
"%s: unable to determine NIC's NUMA node, degraded performance can be expected",
dpdk_config->iface);
}
+ if (ptv->intr_enabled) {
+ rte_spinlock_init(&intr_lock[ptv->port_id]);
+ }
}
*data = (void *)ptv;
diff --git a/src/source-dpdk.h b/src/source-dpdk.h
index 3fdb63c..b962d86 100644
--- a/src/source-dpdk.h
+++ b/src/source-dpdk.h
@@ -38,6 +38,7 @@ typedef enum { DPDK_COPY_MODE_NONE, DPDK_COPY_MODE_TAP, DPDK_COPY_MODE_IPS } Dpd
// General flags
#define DPDK_PROMISC (1 << 0) /**< Promiscuous mode */
#define DPDK_MULTICAST (1 << 1) /**< Enable multicast packets */
+#define DPDK_IRQ_MODE (1 << 2) /**< Interrupt mode */
// Offloads
#define DPDK_RX_CHECKSUM_OFFLOAD (1 << 4) /**< Enable chsum offload */
diff --git a/src/source-pcap-file-helper.c b/src/source-pcap-file-helper.c
index 936b65f..4984a44 100644
--- a/src/source-pcap-file-helper.c
+++ b/src/source-pcap-file-helper.c
@@ -251,6 +251,7 @@ TmEcode ValidateLinkType(int datalink, DecoderFunc *DecoderFn)
*DecoderFn = DecodePPP;
break;
case LINKTYPE_IPV4:
+ case LINKTYPE_IPV6:
case LINKTYPE_RAW:
case LINKTYPE_RAW2:
case LINKTYPE_GRE_OVER_IP:
diff --git a/src/tests/detect-http-client-body.c b/src/tests/detect-http-client-body.c
index c87d667..bbeb4d3 100644
--- a/src/tests/detect-http-client-body.c
+++ b/src/tests/detect-http-client-body.c
@@ -157,6 +157,7 @@ static int RunTest (struct TestSteps *steps, const char *sig, const char *yaml)
int i = 0;
while (b->input != NULL) {
SCLogDebug("chunk %p %d", b, i);
+ (void)i;
Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FAIL_IF_NULL(p);
p->flow = &f;
diff --git a/src/tests/detect-http-server-body.c b/src/tests/detect-http-server-body.c
index 29340fb..d9723d4 100644
--- a/src/tests/detect-http-server-body.c
+++ b/src/tests/detect-http-server-body.c
@@ -119,6 +119,7 @@ static int RunTest(struct TestSteps *steps, const char *sig, const char *yaml)
int i = 0;
while (b->input != NULL) {
SCLogDebug("chunk %p %d", b, i);
+ (void)i;
Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FAIL_IF_NULL(p);
p->flow = &f;
diff --git a/src/tests/output-json-stats.c b/src/tests/output-json-stats.c
index ac1336e..332a819 100644
--- a/src/tests/output-json-stats.c
+++ b/src/tests/output-json-stats.c
@@ -23,7 +23,7 @@
static int OutputJsonStatsTest01(void)
{
- StatsRecord global_records[] = { { 0 }, { 0 } };
+ StatsRecord total_records[] = { { 0 }, { 0 } };
StatsRecord thread_records[2];
thread_records[0].name = "capture.kernel_packets";
thread_records[0].short_name = "kernel_packets";
@@ -36,7 +36,7 @@ static int OutputJsonStatsTest01(void)
StatsTable table = {
.nstats = 2,
- .stats = &global_records[0],
+ .stats = &total_records[0],
.ntstats = 1,
.tstats = &thread_records[0],
};
@@ -64,7 +64,72 @@ static int OutputJsonStatsTest01(void)
return cmp_result == 0;
}
+static int OutputJsonStatsTest02(void)
+{
+ StatsRecord total_records[4] = { 0 };
+ StatsRecord thread_records[8] = { 0 };
+
+ // Totals
+ total_records[0].name = "tcp.syn";
+ total_records[0].short_name = "syn";
+ total_records[0].tm_name = NULL;
+ total_records[0].value = 1234;
+
+ // Worker
+ // thread_records[0] is a global counter
+ thread_records[1].name = "capture.kernel_packets";
+ thread_records[1].short_name = "kernel_packets";
+ thread_records[1].tm_name = "W#01-bond0.30";
+ thread_records[1].value = 42;
+ thread_records[2].name = "capture.kernel_drops";
+ thread_records[2].short_name = "kernel_drops";
+ thread_records[2].tm_name = "W#01-bond0.30";
+ thread_records[2].value = 4711;
+ // thread_records[3] is a FM specific counter
+
+ // Flow manager
+ // thread_records[4] is a global counter
+ // thread_records[5] is a worker specific counter
+ // thread_records[6] is a worker specific counter
+ thread_records[7].name = "flow.mgr.full_hash_passes";
+ thread_records[7].short_name = "full_hash_passes";
+ thread_records[7].tm_name = "FM#01";
+ thread_records[7].value = 10;
+
+ StatsTable table = {
+ .nstats = 4,
+ .stats = &total_records[0],
+ .ntstats = 2,
+ .tstats = &thread_records[0],
+ };
+
+ json_t *r = StatsToJSON(&table, JSON_STATS_TOTALS | JSON_STATS_THREADS);
+ if (!r)
+ return 0;
+
+ // Remove variable content
+ json_object_del(r, "uptime");
+
+ char *serialized = json_dumps(r, 0);
+
+ // Cheesy comparison
+ const char *expected = "{\"tcp\": {\"syn\": 1234}, \"threads\": {\"W#01-bond0.30\": "
+ "{\"capture\": {\"kernel_packets\": "
+ "42, \"kernel_drops\": 4711}}, \"FM#01\": {\"flow\": {\"mgr\": "
+ "{\"full_hash_passes\": 10}}}}}";
+
+ int cmp_result = strcmp(expected, serialized);
+ if (cmp_result != 0)
+ printf("unexpected result\nexpected=%s\ngot=%s\n", expected, serialized);
+
+ free(serialized);
+ json_decref(r);
+
+ return cmp_result == 0;
+}
+
void OutputJsonStatsRegisterTests(void)
{
UtRegisterTest("OutputJsonStatsTest01", OutputJsonStatsTest01);
+ UtRegisterTest("OutputJsonStatsTest02", OutputJsonStatsTest02);
}
diff --git a/src/util-base64.c b/src/util-base64.c
index 4a4a5d1..d973f0e 100644
--- a/src/util-base64.c
+++ b/src/util-base64.c
@@ -156,6 +156,8 @@ Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src,
ecode = BASE64_ECODE_BUF;
break;
}
+ if (dest_size - *decoded_bytes < ASCII_BLOCK)
+ return BASE64_ECODE_BUF;
/* Decode base-64 block into ascii block and move pointer */
DecodeBase64Block(dptr, b64);
@@ -183,7 +185,7 @@ Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src,
/* if the destination size is not at least 3 Bytes long, it'll give a dynamic
* buffer overflow while decoding, so, return and let the caller take care of the
* remaining bytes to be decoded which should always be < 4 at this stage */
- if (dest_size - *decoded_bytes < 3)
+ if (dest_size - *decoded_bytes < ASCII_BLOCK)
return BASE64_ECODE_BUF;
*decoded_bytes += numDecoded_blk;
DecodeBase64Block(dptr, b64);
@@ -193,6 +195,8 @@ Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src,
/* Finish remaining b64 bytes by padding */
if (valid && bbidx > 0 && (mode != BASE64_MODE_RFC2045)) {
/* Decode remaining */
+ if (dest_size - *decoded_bytes < ASCII_BLOCK)
+ return BASE64_ECODE_BUF;
*decoded_bytes += ASCII_BLOCK - (B64_BLOCK - bbidx);
DecodeBase64Block(dptr, b64);
}
diff --git a/src/util-dpdk-ice.c b/src/util-dpdk-ice.c
index 36f4481..4b714d8 100644
--- a/src/util-dpdk-ice.c
+++ b/src/util-dpdk-ice.c
@@ -35,7 +35,7 @@
#ifdef HAVE_DPDK
-void iceDeviceSetRSSHashFunction(uint64_t *rss_hf)
+static void iceDeviceSetRSSHashFunction(uint64_t *rss_hf)
{
#if RTE_VERSION < RTE_VERSION_NUM(20, 0, 0, 0)
*rss_hf = RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | RTE_ETH_RSS_FRAG_IPV6 |
@@ -46,6 +46,16 @@ void iceDeviceSetRSSHashFunction(uint64_t *rss_hf)
#endif
}
+void iceDeviceSetRSSConf(struct rte_eth_rss_conf *rss_conf)
+{
+ iceDeviceSetRSSHashFunction(&rss_conf->rss_hf);
+#if RTE_VERSION < RTE_VERSION_NUM(23, 11, 0, 0)
+ rss_conf->rss_key_len = 40;
+#else
+ rss_conf->rss_key_len = 52;
+#endif
+}
+
#endif /* HAVE_DPDK */
/**
* @}
diff --git a/src/util-dpdk-ice.h b/src/util-dpdk-ice.h
index cdc2185..d535fa0 100644
--- a/src/util-dpdk-ice.h
+++ b/src/util-dpdk-ice.h
@@ -28,7 +28,9 @@
#ifdef HAVE_DPDK
-void iceDeviceSetRSSHashFunction(uint64_t *rss_conf);
+#include "util-dpdk.h"
+
+void iceDeviceSetRSSConf(struct rte_eth_rss_conf *rss_conf);
#endif /* HAVE_DPDK */
diff --git a/src/util-host-info.c b/src/util-host-info.c
index c0dd93b..282b2fb 100644
--- a/src/util-host-info.c
+++ b/src/util-host-info.c
@@ -44,7 +44,6 @@ int SCKernelVersionIsAtLeast(int major, int minor)
PCRE2_SIZE eo;
int ret;
int kmajor, kminor;
- PCRE2_UCHAR **list;
/* get local version */
if (uname(&kuname) != 0) {
@@ -79,25 +78,36 @@ int SCKernelVersionIsAtLeast(int major, int minor)
goto error;
}
- pcre2_substring_list_get(version_regex_match, &list, NULL);
+ char majorstr[32];
+ size_t pcre2len = sizeof(majorstr);
+ ret = pcre2_substring_copy_bynumber(
+ version_regex_match, 1, (PCRE2_UCHAR8 *)majorstr, &pcre2len);
+ if (ret < 0) {
+ SCLogError("pcre2_substring_copy_bynumber failed");
+ goto error;
+ }
- bool err = false;
- if (StringParseInt32(&kmajor, 10, 0, (const char *)list[1]) < 0) {
- SCLogError("Invalid value for kmajor: '%s'", list[1]);
- err = true;
+ char minorstr[32];
+ pcre2len = sizeof(majorstr);
+ ret = pcre2_substring_copy_bynumber(
+ version_regex_match, 2, (PCRE2_UCHAR8 *)minorstr, &pcre2len);
+ if (ret < 0) {
+ SCLogError("pcre2_substring_copy_bynumber failed");
+ goto error;
}
- if (StringParseInt32(&kminor, 10, 0, (const char *)list[2]) < 0) {
- SCLogError("Invalid value for kminor: '%s'", list[2]);
- err = true;
+
+ if (StringParseInt32(&kmajor, 10, 0, (const char *)majorstr) < 0) {
+ SCLogError("Invalid value for kmajor: '%s'", minorstr);
+ goto error;
+ }
+ if (StringParseInt32(&kminor, 10, 0, (const char *)minorstr) < 0) {
+ SCLogError("Invalid value for kminor: '%s'", minorstr);
+ goto error;
}
- pcre2_substring_list_free((PCRE2_SPTR *)list);
pcre2_match_data_free(version_regex_match);
pcre2_code_free(version_regex);
- if (err)
- goto error;
-
if (kmajor > major)
return 1;
if (kmajor == major && kminor >= minor)
diff --git a/src/util-streaming-buffer.c b/src/util-streaming-buffer.c
index 6ff4f43..204ef2e 100644
--- a/src/util-streaming-buffer.c
+++ b/src/util-streaming-buffer.c
@@ -1064,7 +1064,15 @@ void StreamingBufferSlideToOffset(
DEBUG_VALIDATE_BUG_ON(sb->region.stream_offset < offset);
}
-#define DATA_FITS(sb, len) ((sb)->region.buf_offset + (len) <= (sb)->region.buf_size)
+static int DataFits(const StreamingBuffer *sb, const uint32_t len)
+{
+ uint64_t buf_offset64 = sb->region.buf_offset;
+ uint64_t len64 = len;
+ if (len64 + buf_offset64 > UINT32_MAX) {
+ return -1;
+ }
+ return sb->region.buf_offset + len <= sb->region.buf_size;
+}
int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len)
@@ -1076,7 +1084,11 @@ int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
return -1;
}
- if (!DATA_FITS(sb, data_len)) {
+ int r = DataFits(sb, data_len);
+ if (r < 0) {
+ DEBUG_VALIDATE_BUG_ON(1);
+ return -1;
+ } else if (r == 0) {
if (sb->region.buf_size == 0) {
if (GrowToSize(sb, cfg, data_len) != SC_OK)
return -1;
@@ -1085,7 +1097,7 @@ int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
return -1;
}
}
- DEBUG_VALIDATE_BUG_ON(!DATA_FITS(sb, data_len));
+ DEBUG_VALIDATE_BUG_ON(DataFits(sb, data_len) != 1);
memcpy(sb->region.buf + sb->region.buf_offset, data, data_len);
seg->stream_offset = sb->region.stream_offset + sb->region.buf_offset;
@@ -1111,7 +1123,11 @@ int StreamingBufferAppendNoTrack(StreamingBuffer *sb, const StreamingBufferConfi
return -1;
}
- if (!DATA_FITS(sb, data_len)) {
+ int r = DataFits(sb, data_len);
+ if (r < 0) {
+ DEBUG_VALIDATE_BUG_ON(1);
+ return -1;
+ } else if (r == 0) {
if (sb->region.buf_size == 0) {
if (GrowToSize(sb, cfg, data_len) != SC_OK)
return -1;
@@ -1120,7 +1136,7 @@ int StreamingBufferAppendNoTrack(StreamingBuffer *sb, const StreamingBufferConfi
return -1;
}
}
- DEBUG_VALIDATE_BUG_ON(!DATA_FITS(sb, data_len));
+ DEBUG_VALIDATE_BUG_ON(DataFits(sb, data_len) != 1);
memcpy(sb->region.buf + sb->region.buf_offset, data, data_len);
uint32_t rel_offset = sb->region.buf_offset;
@@ -1133,7 +1149,15 @@ int StreamingBufferAppendNoTrack(StreamingBuffer *sb, const StreamingBufferConfi
}
}
-#define DATA_FITS_AT_OFFSET(region, len, offset) ((offset) + (len) <= (region)->buf_size)
+static int DataFitsAtOffset(
+ const StreamingBufferRegion *region, const uint32_t len, const uint32_t offset)
+{
+ const uint64_t offset64 = offset;
+ const uint64_t len64 = len;
+ if (offset64 + len64 > UINT32_MAX)
+ return -1;
+ return (offset + len <= region->buf_size);
+}
#if defined(DEBUG) || defined(DEBUG_VALIDATION)
static void Validate(const StreamingBuffer *sb)
@@ -1477,8 +1501,6 @@ static StreamingBufferRegion *BufferInsertAtRegion(StreamingBuffer *sb,
int StreamingBufferInsertAt(StreamingBuffer *sb, const StreamingBufferConfig *cfg,
StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len, uint64_t offset)
{
- int r;
-
DEBUG_VALIDATE_BUG_ON(seg == NULL);
DEBUG_VALIDATE_BUG_ON(offset < sb->region.stream_offset);
if (offset < sb->region.stream_offset) {
@@ -1496,11 +1518,15 @@ int StreamingBufferInsertAt(StreamingBuffer *sb, const StreamingBufferConfig *cf
region == &sb->region ? "main" : "aux", region);
uint32_t rel_offset = offset - region->stream_offset;
- if (!DATA_FITS_AT_OFFSET(region, data_len, rel_offset)) {
+ int r = DataFitsAtOffset(region, data_len, rel_offset);
+ if (r < 0) {
+ DEBUG_VALIDATE_BUG_ON(1);
+ return SC_ELIMIT;
+ } else if (r == 0) {
if ((r = GrowToSize(sb, cfg, (rel_offset + data_len))) != SC_OK)
return r;
}
- DEBUG_VALIDATE_BUG_ON(!DATA_FITS_AT_OFFSET(region, data_len, rel_offset));
+ DEBUG_VALIDATE_BUG_ON(DataFitsAtOffset(region, data_len, rel_offset) != 1);
SCLogDebug("offset %" PRIu64 " data_len %u, rel_offset %u into region offset %" PRIu64
", buf_offset %u, buf_size %u",
@@ -2320,6 +2346,22 @@ static int StreamingBufferTest10(void)
PASS;
}
+static int StreamingBufferTest11(void)
+{
+ StreamingBufferConfig cfg = { 24, 1, STREAMING_BUFFER_REGION_GAP_DEFAULT, NULL, NULL, NULL };
+ StreamingBuffer *sb = StreamingBufferInit(&cfg);
+ FAIL_IF(sb == NULL);
+
+ StreamingBufferSegment seg1;
+ FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0);
+ StreamingBufferSegment seg2;
+ unsigned int data_len = 0xffffffff;
+ FAIL_IF(StreamingBufferAppend(sb, &cfg, &seg2, (const uint8_t *)"unused", data_len) != -1);
+ FAIL_IF(StreamingBufferInsertAt(
+ sb, &cfg, &seg2, (const uint8_t *)"abcdefghij", data_len, 100000) != SC_ELIMIT);
+ StreamingBufferFree(sb, &cfg);
+ PASS;
+}
#endif
void StreamingBufferRegisterTests(void)
@@ -2333,5 +2375,6 @@ void StreamingBufferRegisterTests(void)
UtRegisterTest("StreamingBufferTest08", StreamingBufferTest08);
UtRegisterTest("StreamingBufferTest09", StreamingBufferTest09);
UtRegisterTest("StreamingBufferTest10", StreamingBufferTest10);
+ UtRegisterTest("StreamingBufferTest11 Bug 6903", StreamingBufferTest11);
#endif
}