aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/util-unittest-helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/util-unittest-helper.c')
-rw-r--r--framework/src/suricata/src/util-unittest-helper.c1081
1 files changed, 1081 insertions, 0 deletions
diff --git a/framework/src/suricata/src/util-unittest-helper.c b/framework/src/suricata/src/util-unittest-helper.c
new file mode 100644
index 00000000..a318205d
--- /dev/null
+++ b/framework/src/suricata/src/util-unittest-helper.c
@@ -0,0 +1,1081 @@
+/* Copyright (C) 2007-2013 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
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
+ *
+ * This file provide a set of helper functions for reducing the complexity
+ * when constructing unittests
+ */
+
+#include "suricata-common.h"
+
+#include "decode.h"
+
+#include "flow-private.h"
+#include "flow-util.h"
+
+#include "detect.h"
+#include "detect-parse.h"
+#include "detect-engine.h"
+#include "detect-engine-sigorder.h"
+
+#include "util-debug.h"
+#include "util-time.h"
+#include "util-error.h"
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+
+#ifdef UNITTESTS
+
+/**
+ * \brief return the uint32_t for a ipv4 address string
+ *
+ * \param str Valid ipaddress in string form (e.g. 1.2.3.4)
+ *
+ * \retval uint the uin32_t representation
+ */
+uint32_t UTHSetIPv4Address(char *str)
+{
+ struct in_addr in;
+ if (inet_pton(AF_INET, str, &in) != 1) {
+ printf("invalid IPv6 address %s\n", str);
+ exit(EXIT_FAILURE);
+ }
+ return (uint32_t)in.s_addr;
+}
+
+/**
+ * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests
+ * specifying ip and port sources and destinations (IPV6)
+ *
+ * \param payload pointer to the payloadd buffer
+ * \param payload_len pointer to the length of the payload
+ * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
+ * \param src pointer to a string containing the ip source
+ * \param dst pointer to a string containing the ip destination
+ * \param sport pointer to a string containing the port source
+ * \param dport pointer to a string containing the port destination
+ *
+ * \retval Packet pointer to the built in packet
+ */
+Packet *UTHBuildPacketIPV6Real(uint8_t *payload, uint16_t payload_len,
+ uint8_t ipproto, char *src, char *dst,
+ uint16_t sport, uint16_t dport)
+{
+ uint32_t in[4];
+
+ Packet *p = PacketGetFromAlloc();
+ if (unlikely(p == NULL))
+ return NULL;
+
+ TimeSet(&p->ts);
+
+ p->src.family = AF_INET6;
+ p->dst.family = AF_INET6;
+ p->payload = payload;
+ p->payload_len = payload_len;
+ p->proto = ipproto;
+
+ p->ip6h = SCMalloc(sizeof(IPV6Hdr));
+ if (p->ip6h == NULL)
+ goto error;
+ memset(p->ip6h, 0, sizeof(IPV6Hdr));
+ p->ip6h->s_ip6_nxt = ipproto;
+ p->ip6h->s_ip6_plen = htons(payload_len + sizeof(TCPHdr));
+
+ if (inet_pton(AF_INET6, src, &in) != 1)
+ goto error;
+ p->src.addr_data32[0] = in[0];
+ p->src.addr_data32[1] = in[1];
+ p->src.addr_data32[2] = in[2];
+ p->src.addr_data32[3] = in[3];
+ p->sp = sport;
+ p->ip6h->s_ip6_src[0] = in[0];
+ p->ip6h->s_ip6_src[1] = in[1];
+ p->ip6h->s_ip6_src[2] = in[2];
+ p->ip6h->s_ip6_src[3] = in[3];
+
+ if (inet_pton(AF_INET6, dst, &in) != 1)
+ goto error;
+ p->dst.addr_data32[0] = in[0];
+ p->dst.addr_data32[1] = in[1];
+ p->dst.addr_data32[2] = in[2];
+ p->dst.addr_data32[3] = in[3];
+ p->dp = dport;
+ p->ip6h->s_ip6_dst[0] = in[0];
+ p->ip6h->s_ip6_dst[1] = in[1];
+ p->ip6h->s_ip6_dst[2] = in[2];
+ p->ip6h->s_ip6_dst[3] = in[3];
+
+ p->tcph = SCMalloc(sizeof(TCPHdr));
+ if (p->tcph == NULL)
+ goto error;
+ memset(p->tcph, 0, sizeof(TCPHdr));
+ p->tcph->th_sport = htons(sport);
+ p->tcph->th_dport = htons(dport);
+
+ SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(TCPHdr) + payload_len);
+ return p;
+
+error:
+ if (p != NULL) {
+ if (p->ip6h != NULL) {
+ SCFree(p->ip6h);
+ }
+ if (p->tcph != NULL) {
+ SCFree(p->tcph);
+ }
+ SCFree(p);
+ }
+ return NULL;
+}
+
+/**
+ * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests
+ * specifying ip and port sources and destinations
+ *
+ * \param payload pointer to the payloadd buffer
+ * \param payload_len pointer to the length of the payload
+ * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
+ * \param src pointer to a string containing the ip source
+ * \param dst pointer to a string containing the ip destination
+ * \param sport pointer to a string containing the port source
+ * \param dport pointer to a string containing the port destination
+ *
+ * \retval Packet pointer to the built in packet
+ */
+Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len,
+ uint8_t ipproto, char *src, char *dst,
+ uint16_t sport, uint16_t dport)
+{
+ struct in_addr in;
+
+ Packet *p = PacketGetFromAlloc();
+ if (unlikely(p == NULL))
+ return NULL;
+
+ struct timeval tv;
+ TimeGet(&tv);
+ COPY_TIMESTAMP(&tv, &p->ts);
+
+ p->src.family = AF_INET;
+ p->dst.family = AF_INET;
+ p->payload = payload;
+ p->payload_len = payload_len;
+ p->proto = ipproto;
+
+ if (inet_pton(AF_INET, src, &in) != 1)
+ goto error;
+ p->src.addr_data32[0] = in.s_addr;
+ p->sp = sport;
+
+ if (inet_pton(AF_INET, dst, &in) != 1)
+ goto error;
+ p->dst.addr_data32[0] = in.s_addr;
+ p->dp = dport;
+
+ p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
+ if (p->ip4h == NULL)
+ goto error;
+
+ p->ip4h->s_ip_src.s_addr = p->src.addr_data32[0];
+ p->ip4h->s_ip_dst.s_addr = p->dst.addr_data32[0];
+ p->ip4h->ip_proto = ipproto;
+ p->ip4h->ip_verhl = sizeof(IPV4Hdr);
+ p->proto = ipproto;
+
+ int hdr_offset = sizeof(IPV4Hdr);
+ switch (ipproto) {
+ case IPPROTO_UDP:
+ p->udph = (UDPHdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr));
+ if (p->udph == NULL)
+ goto error;
+
+ p->udph->uh_sport = sport;
+ p->udph->uh_dport = dport;
+ hdr_offset += sizeof(UDPHdr);
+ break;
+ case IPPROTO_TCP:
+ p->tcph = (TCPHdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr));
+ if (p->tcph == NULL)
+ goto error;
+
+ p->tcph->th_sport = htons(sport);
+ p->tcph->th_dport = htons(dport);
+ hdr_offset += sizeof(TCPHdr);
+ break;
+ case IPPROTO_ICMP:
+ p->icmpv4h = (ICMPV4Hdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr));
+ if (p->icmpv4h == NULL)
+ goto error;
+
+ hdr_offset += sizeof(ICMPV4Hdr);
+ break;
+ default:
+ break;
+ /* TODO: Add more protocols */
+ }
+
+ PacketCopyDataOffset(p, hdr_offset, payload, payload_len);
+ SET_PKT_LEN(p, hdr_offset + payload_len);
+ p->payload = GET_PKT_DATA(p)+hdr_offset;
+
+ return p;
+
+error:
+ SCFree(p);
+ return NULL;
+}
+
+/**
+ * \brief UTHBuildPacket is a wrapper that build packets with default ip
+ * and port fields
+ *
+ * \param payload pointer to the payloadd buffer
+ * \param payload_len pointer to the length of the payload
+ * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
+ *
+ * \retval Packet pointer to the built in packet
+ */
+Packet *UTHBuildPacket(uint8_t *payload, uint16_t payload_len,
+ uint8_t ipproto)
+{
+ return UTHBuildPacketReal(payload, payload_len, ipproto,
+ "192.168.1.5", "192.168.1.1",
+ 41424, 80);
+}
+
+/**
+ * \brief UTHBuildPacketArrayFromEth is a wrapper that build a packets from an array of
+ * packets in ethernet rawbytes. Hint: It also share the flows.
+ *
+ * \param raw_eth pointer to the array of ethernet packets in rawbytes
+ * \param pktsize pointer to the array of sizes corresponding to each buffer pointed
+ * from pktsize.
+ * \param numpkts number of packets in the array
+ *
+ * \retval Packet pointer to the array of built in packets; NULL if something fail
+ */
+Packet **UTHBuildPacketArrayFromEth(uint8_t *raw_eth[], int *pktsize, int numpkts)
+{
+ DecodeThreadVars dtv;
+ ThreadVars th_v;
+ if (raw_eth == NULL || pktsize == NULL || numpkts <= 0) {
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "The arrays cant be null, and the number"
+ " of packets should be grater thatn zero");
+ return NULL;
+ }
+ Packet **p = NULL;
+ p = SCMalloc(sizeof(Packet *) * numpkts);
+ if (unlikely(p == NULL))
+ return NULL;
+
+ memset(&dtv, 0, sizeof(DecodeThreadVars));
+ memset(&th_v, 0, sizeof(th_v));
+
+ int i = 0;
+ for (; i < numpkts; i++) {
+ p[i] = PacketGetFromAlloc();
+ if (p[i] == NULL) {
+ SCFree(p);
+ return NULL;
+ }
+ DecodeEthernet(&th_v, &dtv, p[i], raw_eth[i], pktsize[i], NULL);
+ }
+ return p;
+}
+
+/**
+ * \brief UTHBuildPacketFromEth is a wrapper that build a packet for the rawbytes
+ *
+ * \param raw_eth pointer to the rawbytes containing an ethernet packet
+ * (and any other headers inside)
+ * \param pktsize pointer to the length of the payload
+ *
+ * \retval Packet pointer to the built in packet; NULL if something fail
+ */
+Packet *UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize)
+{
+ DecodeThreadVars dtv;
+ ThreadVars th_v;
+ Packet *p = PacketGetFromAlloc();
+ if (unlikely(p == NULL))
+ return NULL;
+ memset(&dtv, 0, sizeof(DecodeThreadVars));
+ memset(&th_v, 0, sizeof(th_v));
+
+ DecodeEthernet(&th_v, &dtv, p, raw_eth, pktsize, NULL);
+ return p;
+}
+
+/**
+ * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs
+ * and defaulting ports
+ *
+ * \param payload pointer to the payloadd buffer
+ * \param payload_len pointer to the length of the payload
+ * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
+ *
+ * \retval Packet pointer to the built in packet
+ */
+Packet *UTHBuildPacketSrcDst(uint8_t *payload, uint16_t payload_len,
+ uint8_t ipproto, char *src, char *dst)
+{
+ return UTHBuildPacketReal(payload, payload_len, ipproto,
+ src, dst,
+ 41424, 80);
+}
+
+/**
+ * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs
+ * and defaulting ports (IPV6)
+ *
+ * \param payload pointer to the payloadd buffer
+ * \param payload_len pointer to the length of the payload
+ * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
+ *
+ * \retval Packet pointer to the built in packet
+ */
+Packet *UTHBuildPacketIPV6SrcDst(uint8_t *payload, uint16_t payload_len,
+ uint8_t ipproto, char *src, char *dst)
+{
+ return UTHBuildPacketIPV6Real(payload, payload_len, ipproto,
+ src, dst,
+ 41424, 80);
+}
+
+/**
+ * \brief UTHBuildPacketSrcDstPorts is a wrapper that build packets specifying
+ * src and dst ports and defaulting IPs
+ *
+ * \param payload pointer to the payloadd buffer
+ * \param payload_len pointer to the length of the payload
+ * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
+ *
+ * \retval Packet pointer to the built in packet
+ */
+Packet *UTHBuildPacketSrcDstPorts(uint8_t *payload, uint16_t payload_len,
+ uint8_t ipproto, uint16_t sport, uint16_t dport)
+{
+ return UTHBuildPacketReal(payload, payload_len, ipproto,
+ "192.168.1.5", "192.168.1.1",
+ sport, dport);
+}
+
+/**
+ * \brief UTHFreePackets: function to release the allocated data
+ * from UTHBuildPacket and the packet itself
+ *
+ * \param p pointer to the Packet
+ */
+void UTHFreePackets(Packet **p, int numpkts)
+{
+ if (p == NULL)
+ return;
+
+ int i = 0;
+ for (; i < numpkts; i++) {
+ UTHFreePacket(p[i]);
+ }
+}
+
+/**
+ * \brief UTHFreePacket: function to release the allocated data
+ * from UTHBuildPacket and the packet itself
+ *
+ * \param p pointer to the Packet
+ */
+void UTHFreePacket(Packet *p)
+{
+ if (p == NULL)
+ return;
+#if 0 // VJ we now use one buffer
+ switch (p->proto) {
+ case IPPROTO_UDP:
+ if (p->udph != NULL)
+ SCFree(p->udph);
+ if (p->ip4h != NULL)
+ SCFree(p->ip4h);
+ break;
+ case IPPROTO_TCP:
+ if (p->tcph != NULL)
+ SCFree(p->tcph);
+ if (p->ip4h != NULL)
+ SCFree(p->ip4h);
+ break;
+ case IPPROTO_ICMP:
+ if (p->ip4h != NULL)
+ SCFree(p->ip4h);
+ break;
+ /* TODO: Add more protocols */
+ }
+#endif
+ SCFree(p);
+}
+
+Flow *UTHBuildFlow(int family, char *src, char *dst, Port sp, Port dp)
+{
+ struct in_addr in;
+
+ Flow *f = SCMalloc(sizeof(Flow));
+ if (unlikely(f == NULL)) {
+ printf("FlowAlloc failed\n");
+ ;
+ return NULL;
+ }
+ memset(f, 0x00, sizeof(Flow));
+
+ FLOW_INITIALIZE(f);
+
+ if (family == AF_INET) {
+ f->flags |= FLOW_IPV4;
+ } else if (family == AF_INET6) {
+ f->flags |= FLOW_IPV6;
+ }
+
+ if (src != NULL) {
+ if (family == AF_INET) {
+ if (inet_pton(AF_INET, src, &in) != 1) {
+ printf("invalid address %s\n", src);
+ SCFree(f);
+ return NULL;
+ }
+ f->src.addr_data32[0] = in.s_addr;
+ } else {
+ BUG_ON(1);
+ }
+ }
+ if (dst != NULL) {
+ if (family == AF_INET) {
+ if (inet_pton(AF_INET, dst, &in) != 1) {
+ printf("invalid address %s\n", dst);
+ SCFree(f);
+ return NULL;
+ }
+ f->dst.addr_data32[0] = in.s_addr;
+ } else {
+ BUG_ON(1);
+ }
+ }
+
+ f->sp = sp;
+ f->dp = dp;
+
+ return f;
+}
+
+void UTHFreeFlow(Flow *flow)
+{
+ if (flow != NULL) {
+ FlowFree(flow);
+ }
+}
+
+/**
+ * \brief UTHGenericTest: function that perfom a generic check taking care of
+ * as maximum common unittest elements as possible.
+ * It will create a detection engine, append an array
+ * of signatures an check the spected results for each
+ * of them, it check matches for an array of packets
+ *
+ * \param pkt pointer to the array of packets
+ * \param numpkts number of packets to match
+ * \param sigs array of char* pointing to signatures to load
+ * \param numsigs number of signatures to load and check
+ * \param results pointer to arrays of numbers, each of them foreach packet
+ * to check if sids matches that packet as expected with
+ * that number of times or not. The size of results should be
+ * numpkts * numsigs * sizeof(uint16_t *)
+ *
+ * Example:
+ * result[1][3] would mean the number of times the pkt[1]
+ * match the sid[3]
+ *
+ * \retval int 1 if the match of all the sids is the specified has the
+ * specified results; 0 if not
+ */
+int UTHGenericTest(Packet **pkt, int numpkts, char *sigs[], uint32_t sids[], uint32_t *results, int numsigs)
+{
+
+ int result = 0;
+ if (pkt == NULL || sigs == NULL || numpkts == 0
+ || sids == NULL || results == NULL || numsigs == 0) {
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "Arguments invalid, that the pointer/arrays are not NULL, and the number of signatures and packets is > 0");
+ goto end;
+ }
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL) {
+ goto end;
+ }
+ de_ctx->flags |= DE_QUIET;
+
+ if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0)
+ goto cleanup;
+
+ result = UTHMatchPacketsWithResults(de_ctx, pkt, numpkts, sids, results, numsigs);
+
+cleanup:
+ if (de_ctx != NULL) {
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ }
+end:
+ return result;
+}
+
+/**
+ * \brief UTHCheckPacketMatches: function to check if a packet match some sids
+ *
+ *
+ * \param p pointer to the Packet
+ * \param sigs array of char* pointing to signatures to load
+ * \param numsigs number of signatures to load from the array
+ * \param results pointer to an array of numbers to check if sids matches
+ * that number of times or not.
+ *
+ * \retval int 1 if the match of all the sids is the specified has the
+ * specified results; 0 if not
+ */
+int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[],
+ uint32_t results[], int numsids)
+{
+ if (p == NULL || sids == NULL) {
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "Arguments invalid, check if the "
+ "packet is NULL, and if the array contain sids is set");
+ return 0;
+ }
+
+ int i = 0;
+ int res = 1;
+ for (; i < numsids; i++) {
+ uint16_t r = PacketAlertCheck(p, sids[i]);
+ if (r != results[i]) {
+ SCLogInfo("Sid %"PRIu32" matched %"PRIu16" times, and not %"PRIu16
+ " as expected", sids[i], r, results[i]);
+ res = 0;
+ } else {
+ SCLogInfo("Sid %"PRIu32" matched %"PRIu16" times, as expected", sids[i], r);
+ }
+ }
+ return res;
+}
+
+/**
+ * \brief UTHAppendSigs: Add sigs to the detection_engine checking for errors
+ *
+ * \param de_ctx pointer to the DetectEngineCtx used
+ * \param sigs array of char* pointing to signatures to load
+ * \param numsigs number of signatures to load from the array
+ * (size of the array)
+ *
+ * \retval int 0 if we have errors; 1 if all the signatures loaded succesfuly
+ */
+int UTHAppendSigs(DetectEngineCtx *de_ctx, char *sigs[], int numsigs)
+{
+ if (de_ctx == NULL || numsigs <= 0 || sigs == NULL) {
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "Arguments invalid, check if sigs or de_ctx are NULL, and if the array contain sigs");
+ return 0;
+ }
+ //SCLogDebug("Adding %d signatures for the current unittest", numsigs);
+
+ Signature *s;
+ int i = 0;
+
+ for ( ; i < numsigs; i++) {
+ if (sigs[i] == NULL) {
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "Check the signature"
+ " at position %d", i);
+ return 0;
+ }
+ s = DetectEngineAppendSig(de_ctx, sigs[i]);
+ if (s == NULL) {
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "Check the signature at"
+ " position %d (%s)", i, sigs[i]);
+ return 0;
+ }
+ }
+ //SCLogDebug("Added %d signatures to the de_ctx of the unittest", i);
+ return 1;
+}
+
+/**
+ * \test UTHMatchPacketsWithResults Match a packet or a array of packets against sigs
+ * of a de_ctx, checking that each signature match match X times for certain packets
+ *
+ * \param de_ctx pointer with the signatures loaded
+ * \param p pointer to the array of packets
+ * \param num_packets number of packets in the array
+ *
+ * \retval return 1 if all goes well
+ * \retval return 0 if something fail
+ */
+int UTHMatchPacketsWithResults(DetectEngineCtx *de_ctx, Packet **p, int num_packets, uint32_t sids[], uint32_t *results, int numsigs)
+{
+ int result = 0;
+
+ if (de_ctx == NULL || p == NULL) {
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "packet or de_ctx was null");
+ result = 0;
+ goto end;
+ }
+
+ DecodeThreadVars dtv;
+ ThreadVars th_v;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ memset(&dtv, 0, sizeof(DecodeThreadVars));
+ memset(&th_v, 0, sizeof(th_v));
+
+ //de_ctx->flags |= DE_QUIET;
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
+
+ int i = 0;
+ for (; i < num_packets; i++) {
+ SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]);
+ if (UTHCheckPacketMatchResults(p[i], sids, &results[(i * numsigs)], numsigs) == 0)
+ goto cleanup;
+ }
+
+ /* so far, so good ;) */
+ result = 1;
+
+cleanup:
+ if (det_ctx != NULL)
+ DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
+end:
+ return result;
+}
+
+/**
+ * \test UTHMatchPackets Match a packet or a array of packets against sigs
+ * of a de_ctx, but note that the return value doesn't mean that we have a
+ * match, we have to check it later with PacketAlertCheck()
+ *
+ * \param de_ctx pointer with the signatures loaded
+ * \param p pointer to the array of packets
+ * \param num_packets number of packets in the array
+ *
+ * \retval return 1 if all goes well
+ * \retval return 0 if something fail
+ */
+int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets)
+{
+ int result = 1;
+
+ if (de_ctx == NULL || p == NULL) {
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "packet or de_ctx was null");
+ result = 0;
+ goto end;
+ }
+
+ DecodeThreadVars dtv;
+ ThreadVars th_v;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ memset(&dtv, 0, sizeof(DecodeThreadVars));
+ memset(&th_v, 0, sizeof(th_v));
+
+ //de_ctx->flags |= DE_QUIET;
+
+ SCSigRegisterSignatureOrderingFuncs(de_ctx);
+ SCSigOrderSignatures(de_ctx);
+ SCSigSignatureOrderingModuleCleanup(de_ctx);
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
+
+ int i = 0;
+ for (; i < num_packets; i++)
+ SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]);
+
+ /* Here we don't check if the packet matched or not, because
+ * the de_ctx can have multiple signatures, and some of them may match
+ * and others may not. That check will be outside
+ */
+ if (det_ctx != NULL) {
+ DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
+ }
+end:
+ if (de_ctx != NULL) SigGroupCleanup(de_ctx);
+
+ return result;
+}
+
+/**
+ * \test Test if a packet match a signature given as string and a mpm_type
+ * Hint: Useful for unittests with only one packet and one signature
+ *
+ * \param sig pointer to the string signature to test
+ * \param sid sid number of the signature
+ *
+ * \retval return 1 if match
+ * \retval return 0 if not
+ */
+int UTHPacketMatchSigMpm(Packet *p, char *sig, uint16_t mpm_type)
+{
+ SCEnter();
+
+ int result = 0;
+
+ DecodeThreadVars dtv;
+ ThreadVars th_v;
+ DetectEngineThreadCtx *det_ctx = NULL;
+
+ memset(&dtv, 0, sizeof(DecodeThreadVars));
+ memset(&th_v, 0, sizeof(th_v));
+
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL) {
+ printf("de_ctx == NULL: ");
+ goto end;
+ }
+
+ de_ctx->flags |= DE_QUIET;
+ de_ctx->mpm_matcher = mpm_type;
+
+ de_ctx->sig_list = SigInit(de_ctx, sig);
+ if (de_ctx->sig_list == NULL) {
+ printf("signature == NULL: ");
+ goto end;
+ }
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
+
+ SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
+ if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) {
+ printf("signature didn't alert: ");
+ goto end;
+ }
+
+ result = 1;
+end:
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+
+ if (det_ctx != NULL)
+ DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
+
+ if (de_ctx != NULL)
+ DetectEngineCtxFree(de_ctx);
+
+ SCReturnInt(result);
+}
+
+/**
+ * \test Test if a packet match a signature given as string
+ * Hint: Useful for unittests with only one packet and one signature
+ *
+ * \param sig pointer to the string signature to test
+ * \param sid sid number of the signature
+ *
+ * \retval return 1 if match
+ * \retval return 0 if not
+ */
+int UTHPacketMatchSig(Packet *p, char *sig)
+{
+ int result = 1;
+
+ DecodeThreadVars dtv;
+
+ ThreadVars th_v;
+ DetectEngineThreadCtx *det_ctx = NULL;
+
+ memset(&dtv, 0, sizeof(DecodeThreadVars));
+ memset(&th_v, 0, sizeof(th_v));
+
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL) {
+ result=0;
+ goto end;
+ }
+
+ de_ctx->flags |= DE_QUIET;
+
+ de_ctx->sig_list = SigInit(de_ctx, sig);
+ if (de_ctx->sig_list == NULL) {
+ result = 0;
+ goto end;
+ }
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
+
+ SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
+ if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) {
+ result = 0;
+ goto end;
+ }
+
+end:
+ if (de_ctx) {
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+ }
+
+ if (det_ctx != NULL)
+ DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
+ if (de_ctx != NULL)
+ DetectEngineCtxFree(de_ctx);
+
+ return result;
+}
+
+uint32_t UTHBuildPacketOfFlows(uint32_t start, uint32_t end, uint8_t dir)
+{
+ uint32_t i = start;
+ uint8_t payload[] = "Payload";
+ for (; i < end; i++) {
+ Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP);
+ if (dir == 0) {
+ p->src.addr_data32[0] = i;
+ p->dst.addr_data32[0] = i + 1;
+ } else {
+ p->src.addr_data32[0] = i + 1;
+ p->dst.addr_data32[0] = i;
+ }
+ FlowHandlePacket(NULL, NULL, p);
+ if (p->flow != NULL)
+ SC_ATOMIC_RESET(p->flow->use_cnt);
+
+ /* Now the queues shoul be updated */
+ UTHFreePacket(p);
+ }
+
+ return i;
+}
+
+/*
+ * unittests for the unittest helpers
+ */
+
+/**
+ * \brief CheckUTHTestPacket wrapper to check packets for unittests
+ */
+int CheckUTHTestPacket(Packet *p, uint8_t ipproto)
+{
+ uint16_t sport = 41424;
+ uint16_t dport = 80;
+ uint8_t payload[] = "Payload";
+
+ uint8_t len = sizeof(payload);
+
+ if (p == NULL)
+ return 0;
+
+ if (p->payload_len != len)
+ return 0;
+
+ if (strncmp((char *)payload, (char *)p->payload, len) != 0)
+ return 0;
+
+ if (p->src.family != AF_INET)
+ return 0;
+ if (p->dst.family != AF_INET)
+ return 0;
+ if (p->proto != ipproto)
+ return 0;
+
+ switch(ipproto) {
+ case IPPROTO_UDP:
+ if (p->udph == NULL)
+ return 0;
+ if (p->udph->uh_sport != sport)
+ return 0;
+ if (p->udph->uh_dport != dport)
+ return 0;
+ break;
+ case IPPROTO_TCP:
+ if (p->tcph == NULL)
+ return 0;
+ if (ntohs(p->tcph->th_sport) != sport)
+ return 0;
+ if (ntohs(p->tcph->th_dport) != dport)
+ return 0;
+ break;
+ }
+ return 1;
+}
+
+/**
+ * \brief UTHBuildPacketRealTest01 wrapper to check packets for unittests
+ */
+int UTHBuildPacketRealTest01(void)
+{
+ uint8_t payload[] = "Payload";
+
+ Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_TCP,
+ "192.168.1.5", "192.168.1.1", 41424, 80);
+
+ int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
+ UTHFreePacket(p);
+
+ return ret;
+}
+
+/**
+ * \brief UTHBuildPacketRealTest02 wrapper to check packets for unittests
+ */
+int UTHBuildPacketRealTest02(void)
+{
+ uint8_t payload[] = "Payload";
+
+ Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_UDP,
+ "192.168.1.5", "192.168.1.1", 41424, 80);
+
+ int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
+ UTHFreePacket(p);
+ return ret;
+}
+
+/**
+ * \brief UTHBuildPacketTest01 wrapper to check packets for unittests
+ */
+int UTHBuildPacketTest01(void)
+{
+ uint8_t payload[] = "Payload";
+
+ Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP);
+
+ int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
+ UTHFreePacket(p);
+
+ return ret;
+}
+
+/**
+ * \brief UTHBuildPacketTest02 wrapper to check packets for unittests
+ */
+int UTHBuildPacketTest02(void)
+{
+ uint8_t payload[] = "Payload";
+
+ Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_UDP);
+
+ int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
+ UTHFreePacket(p);
+
+ return ret;
+}
+
+/**
+ * \brief UTHBuildPacketOfFlowsTest01 wrapper to check packets for unittests
+ */
+int UTHBuildPacketOfFlowsTest01(void)
+{
+ int result = 0;
+
+ FlowInitConfig(FLOW_QUIET);
+ uint32_t flow_spare_q_len = flow_spare_q.len;
+
+ UTHBuildPacketOfFlows(0, 100, 0);
+
+ if (flow_spare_q.len != flow_spare_q_len - 100)
+ result = 0;
+ else
+ result = 1;
+ FlowShutdown();
+
+ return result;
+}
+
+
+/**
+ * \brief UTHBuildPacketSrcDstTest01 wrapper to check packets for unittests
+ */
+int UTHBuildPacketSrcDstTest01(void)
+{
+ uint8_t payload[] = "Payload";
+
+ Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_TCP,
+ "192.168.1.5", "192.168.1.1");
+
+ int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
+ UTHFreePacket(p);
+
+ return ret;
+}
+
+/**
+ * \brief UTHBuildPacketSrcDstTest02 wrapper to check packets for unittests
+ */
+int UTHBuildPacketSrcDstTest02(void)
+{
+ uint8_t payload[] = "Payload";
+
+ Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_UDP,
+ "192.168.1.5", "192.168.1.1");
+
+ int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
+ UTHFreePacket(p);
+
+ return ret;
+}
+
+/**
+ * \brief UTHBuildPacketSrcDstPortsTest01 wrapper to check packets for unittests
+ */
+int UTHBuildPacketSrcDstPortsTest01(void)
+{
+ uint8_t payload[] = "Payload";
+
+ Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_TCP,
+ 41424, 80);
+
+ int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
+ UTHFreePacket(p);
+
+ return ret;
+}
+
+/**
+ * \brief UTHBuildPacketSrcDstPortsTest02 wrapper to check packets for unittests
+ */
+int UTHBuildPacketSrcDstPortsTest02(void)
+{
+ uint8_t payload[] = "Payload";
+
+ Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_UDP,
+ 41424, 80);
+
+ int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
+ UTHFreePacket(p);
+
+ return ret;
+}
+
+#endif /* UNITTESTS */
+
+void UTHRegisterTests(void)
+{
+#ifdef UNITTESTS
+ UtRegisterTest("UTHBuildPacketRealTest01", UTHBuildPacketRealTest01, 1);
+ UtRegisterTest("UTHBuildPacketRealTest02", UTHBuildPacketRealTest02, 1);
+ UtRegisterTest("UTHBuildPacketTest01", UTHBuildPacketTest01, 1);
+ UtRegisterTest("UTHBuildPacketTest02", UTHBuildPacketTest02, 1);
+ UtRegisterTest("UTHBuildPacketSrcDstTest01", UTHBuildPacketSrcDstTest01, 1);
+ UtRegisterTest("UTHBuildPacketSrcDstTest02", UTHBuildPacketSrcDstTest02, 1);
+ UtRegisterTest("UTHBuildPacketSrcDstPortsTest01", UTHBuildPacketSrcDstPortsTest01, 1);
+ UtRegisterTest("UTHBuildPacketSrcDstPortsTest02", UTHBuildPacketSrcDstPortsTest02, 1);
+ UtRegisterTest("UTHBuildPacketOfFlowsTest01", UTHBuildPacketOfFlowsTest01, 1);
+
+#endif /* UNITTESTS */
+}
+