1 /* Copyright (C) 2007-2017 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
22  *
23  * This file provide a set of helper functions for reducing the complexity
24  * when constructing unittests
25  */
26 
27 #include "suricata-common.h"
28 
29 #include "decode.h"
30 
31 #include "flow-private.h"
32 #include "flow-util.h"
33 #include "flow-spare-pool.h"
34 
35 #include "detect.h"
36 #include "detect-parse.h"
37 #include "detect-engine.h"
38 #include "detect-engine-sigorder.h"
39 
40 #include "stream-tcp.h"
41 #include "stream-tcp-private.h"
42 
43 #include "util-debug.h"
44 #include "util-time.h"
45 #include "util-error.h"
46 #include "util-unittest.h"
47 #include "util-unittest-helper.h"
48 
49 #if defined(UNITTESTS) || defined(FUZZ)
TestHelperBuildFlow(int family,const char * src,const char * dst,Port sp,Port dp)50 Flow *TestHelperBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
51 {
52     struct in_addr in;
53 
54     Flow *f = SCMalloc(sizeof(Flow));
55     if (unlikely(f == NULL)) {
56         printf("FlowAlloc failed\n");
57         ;
58         return NULL;
59     }
60     memset(f, 0x00, sizeof(Flow));
61 
62     FLOW_INITIALIZE(f);
63 
64     if (family == AF_INET) {
65         f->flags |= FLOW_IPV4;
66     } else if (family == AF_INET6) {
67         f->flags |= FLOW_IPV6;
68     }
69 
70     if (src != NULL) {
71         if (family == AF_INET) {
72             if (inet_pton(AF_INET, src, &in) != 1) {
73                 printf("invalid address %s\n", src);
74                 SCFree(f);
75                 return NULL;
76             }
77             f->src.addr_data32[0] = in.s_addr;
78         } else {
79             BUG_ON(1);
80         }
81     }
82     if (dst != NULL) {
83         if (family == AF_INET) {
84             if (inet_pton(AF_INET, dst, &in) != 1) {
85                 printf("invalid address %s\n", dst);
86                 SCFree(f);
87                 return NULL;
88             }
89             f->dst.addr_data32[0] = in.s_addr;
90         } else {
91             BUG_ON(1);
92         }
93     }
94 
95     f->sp = sp;
96     f->dp = dp;
97 
98     return f;
99 }
100 /** \brief writes the contents of a buffer into a file */
TestHelperBufferToFile(const char * name,const uint8_t * data,size_t size)101 int TestHelperBufferToFile(const char *name, const uint8_t *data, size_t size)
102 {
103     if (remove(name) != 0) {
104         if (errno != ENOENT) {
105             printf("failed remove, errno=%d\n", errno);
106             return -1;
107         }
108     }
109     FILE *fd = fopen(name, "wb");
110     if (fd == NULL) {
111         printf("failed open, errno=%d\n", errno);
112         return -2;
113     }
114     if (fwrite (data, 1, size, fd) != size) {
115         fclose(fd);
116         return -3;
117     }
118     fclose(fd);
119     return 0;
120 }
121 
122 #endif
123 #ifdef UNITTESTS
124 
125 /**
126  *  \brief return the uint32_t for a ipv4 address string
127  *
128  *  \param str Valid ipaddress in string form (e.g. 1.2.3.4)
129  *
130  *  \retval uint the uin32_t representation
131  */
UTHSetIPv4Address(const char * str)132 uint32_t UTHSetIPv4Address(const char *str)
133 {
134     struct in_addr in;
135     if (inet_pton(AF_INET, str, &in) != 1) {
136         printf("invalid IPv6 address %s\n", str);
137         exit(EXIT_FAILURE);
138     }
139     return (uint32_t)in.s_addr;
140 }
141 
142 /**
143  * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests
144  * specifying ip and port sources and destinations (IPV6)
145  *
146  * \param payload pointer to the payloadd buffer
147  * \param payload_len pointer to the length of the payload
148  * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
149  * \param src pointer to a string containing the ip source
150  * \param dst pointer to a string containing the ip destination
151  * \param sport pointer to a string containing the port source
152  * \param dport pointer to a string containing the port destination
153  *
154  * \retval Packet pointer to the built in packet
155  */
UTHBuildPacketIPV6Real(uint8_t * payload,uint16_t payload_len,uint8_t ipproto,const char * src,const char * dst,uint16_t sport,uint16_t dport)156 Packet *UTHBuildPacketIPV6Real(uint8_t *payload, uint16_t payload_len,
157                            uint8_t ipproto, const char *src, const char *dst,
158                            uint16_t sport, uint16_t dport)
159 {
160     uint32_t in[4];
161 
162     Packet *p = PacketGetFromAlloc();
163     if (unlikely(p == NULL))
164         return NULL;
165 
166     TimeGet(&p->ts);
167 
168     p->src.family = AF_INET6;
169     p->dst.family = AF_INET6;
170     p->payload = payload;
171     p->payload_len = payload_len;
172     p->proto = ipproto;
173 
174     p->ip6h = SCMalloc(sizeof(IPV6Hdr));
175     if (p->ip6h == NULL)
176         goto error;
177     memset(p->ip6h, 0, sizeof(IPV6Hdr));
178     p->ip6h->s_ip6_nxt = ipproto;
179     p->ip6h->s_ip6_plen = htons(payload_len + sizeof(TCPHdr));
180 
181     if (inet_pton(AF_INET6, src, &in) != 1)
182         goto error;
183     p->src.addr_data32[0] = in[0];
184     p->src.addr_data32[1] = in[1];
185     p->src.addr_data32[2] = in[2];
186     p->src.addr_data32[3] = in[3];
187     p->sp = sport;
188     p->ip6h->s_ip6_src[0] = in[0];
189     p->ip6h->s_ip6_src[1] = in[1];
190     p->ip6h->s_ip6_src[2] = in[2];
191     p->ip6h->s_ip6_src[3] = in[3];
192 
193     if (inet_pton(AF_INET6, dst, &in) != 1)
194         goto error;
195     p->dst.addr_data32[0] = in[0];
196     p->dst.addr_data32[1] = in[1];
197     p->dst.addr_data32[2] = in[2];
198     p->dst.addr_data32[3] = in[3];
199     p->dp = dport;
200     p->ip6h->s_ip6_dst[0] = in[0];
201     p->ip6h->s_ip6_dst[1] = in[1];
202     p->ip6h->s_ip6_dst[2] = in[2];
203     p->ip6h->s_ip6_dst[3] = in[3];
204 
205     p->tcph = SCMalloc(sizeof(TCPHdr));
206     if (p->tcph == NULL)
207         goto error;
208     memset(p->tcph, 0, sizeof(TCPHdr));
209     p->tcph->th_sport = htons(sport);
210     p->tcph->th_dport = htons(dport);
211 
212     SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(TCPHdr) + payload_len);
213     return p;
214 
215 error:
216     if (p != NULL) {
217         if (p->ip6h != NULL) {
218             SCFree(p->ip6h);
219         }
220         if (p->tcph != NULL) {
221             SCFree(p->tcph);
222         }
223         SCFree(p);
224     }
225     return NULL;
226 }
227 
228 /**
229  * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests
230  * specifying ip and port sources and destinations
231  *
232  * \param payload pointer to the payloadd buffer
233  * \param payload_len pointer to the length of the payload
234  * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
235  * \param src pointer to a string containing the ip source
236  * \param dst pointer to a string containing the ip destination
237  * \param sport pointer to a string containing the port source
238  * \param dport pointer to a string containing the port destination
239  *
240  * \retval Packet pointer to the built in packet
241  */
UTHBuildPacketReal(uint8_t * payload,uint16_t payload_len,uint8_t ipproto,const char * src,const char * dst,uint16_t sport,uint16_t dport)242 Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len,
243                            uint8_t ipproto, const char *src, const char *dst,
244                            uint16_t sport, uint16_t dport)
245 {
246     struct in_addr in;
247 
248     Packet *p = PacketGetFromAlloc();
249     if (unlikely(p == NULL))
250         return NULL;
251 
252     struct timeval tv;
253     TimeGet(&tv);
254     COPY_TIMESTAMP(&tv, &p->ts);
255 
256     p->src.family = AF_INET;
257     p->dst.family = AF_INET;
258     p->payload = payload;
259     p->payload_len = payload_len;
260     p->proto = ipproto;
261 
262     if (inet_pton(AF_INET, src, &in) != 1)
263         goto error;
264     p->src.addr_data32[0] = in.s_addr;
265     p->sp = sport;
266 
267     if (inet_pton(AF_INET, dst, &in) != 1)
268         goto error;
269     p->dst.addr_data32[0] = in.s_addr;
270     p->dp = dport;
271 
272     p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
273     if (p->ip4h == NULL)
274         goto error;
275 
276     p->ip4h->s_ip_src.s_addr = p->src.addr_data32[0];
277     p->ip4h->s_ip_dst.s_addr = p->dst.addr_data32[0];
278     p->ip4h->ip_proto = ipproto;
279     p->ip4h->ip_verhl = sizeof(IPV4Hdr);
280     p->proto = ipproto;
281 
282     int hdr_offset = sizeof(IPV4Hdr);
283     switch (ipproto) {
284         case IPPROTO_UDP:
285             p->udph = (UDPHdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr));
286             if (p->udph == NULL)
287                 goto error;
288 
289             p->udph->uh_sport = sport;
290             p->udph->uh_dport = dport;
291             hdr_offset += sizeof(UDPHdr);
292             break;
293         case IPPROTO_TCP:
294             p->tcph = (TCPHdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr));
295             if (p->tcph == NULL)
296                 goto error;
297 
298             p->tcph->th_sport = htons(sport);
299             p->tcph->th_dport = htons(dport);
300             hdr_offset += sizeof(TCPHdr);
301             break;
302         case IPPROTO_ICMP:
303             p->icmpv4h = (ICMPV4Hdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr));
304             if (p->icmpv4h == NULL)
305                 goto error;
306 
307             hdr_offset += sizeof(ICMPV4Hdr);
308             break;
309         default:
310             break;
311         /* TODO: Add more protocols */
312     }
313 
314     if (payload && payload_len) {
315         PacketCopyDataOffset(p, hdr_offset, payload, payload_len);
316     }
317     SET_PKT_LEN(p, hdr_offset + payload_len);
318     p->payload = GET_PKT_DATA(p)+hdr_offset;
319 
320     return p;
321 
322 error:
323     SCFree(p);
324     return NULL;
325 }
326 
327 /**
328  * \brief UTHBuildPacket is a wrapper that build packets with default ip
329  * and port fields
330  *
331  * \param payload pointer to the payloadd buffer
332  * \param payload_len pointer to the length of the payload
333  * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
334  *
335  * \retval Packet pointer to the built in packet
336  */
UTHBuildPacket(uint8_t * payload,uint16_t payload_len,uint8_t ipproto)337 Packet *UTHBuildPacket(uint8_t *payload, uint16_t payload_len,
338                            uint8_t ipproto)
339 {
340     return UTHBuildPacketReal(payload, payload_len, ipproto,
341                               "192.168.1.5", "192.168.1.1",
342                               41424, 80);
343 }
344 
345 /**
346  * \brief UTHBuildPacketArrayFromEth is a wrapper that build a packets from an array of
347  *        packets in ethernet rawbytes. Hint: It also share the flows.
348  *
349  * \param raw_eth pointer to the array of ethernet packets in rawbytes
350  * \param pktsize pointer to the array of sizes corresponding to each buffer pointed
351  *                from pktsize.
352  * \param numpkts number of packets in the array
353  *
354  * \retval Packet pointer to the array of built in packets; NULL if something fail
355  */
UTHBuildPacketArrayFromEth(uint8_t * raw_eth[],int * pktsize,int numpkts)356 Packet **UTHBuildPacketArrayFromEth(uint8_t *raw_eth[], int *pktsize, int numpkts)
357 {
358     DecodeThreadVars dtv;
359     ThreadVars th_v;
360     if (raw_eth == NULL || pktsize == NULL || numpkts <= 0) {
361         SCLogError(SC_ERR_INVALID_ARGUMENT, "The arrays cant be null, and the number"
362                                         " of packets should be grater thatn zero");
363         return NULL;
364     }
365     Packet **p = NULL;
366     p = SCMalloc(sizeof(Packet *) * numpkts);
367     if (unlikely(p == NULL))
368         return NULL;
369 
370     memset(&dtv, 0, sizeof(DecodeThreadVars));
371     memset(&th_v, 0, sizeof(th_v));
372 
373     int i = 0;
374     for (; i < numpkts; i++) {
375         p[i] = PacketGetFromAlloc();
376         if (p[i] == NULL) {
377             SCFree(p);
378             return NULL;
379         }
380         DecodeEthernet(&th_v, &dtv, p[i], raw_eth[i], pktsize[i]);
381     }
382     return p;
383 }
384 
385 /**
386  * \brief UTHBuildPacketFromEth is a wrapper that build a packet for the rawbytes
387  *
388  * \param raw_eth pointer to the rawbytes containing an ethernet packet
389  *                    (and any other headers inside)
390  * \param pktsize pointer to the length of the payload
391  *
392  * \retval Packet pointer to the built in packet; NULL if something fail
393  */
UTHBuildPacketFromEth(uint8_t * raw_eth,uint16_t pktsize)394 Packet *UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize)
395 {
396     DecodeThreadVars dtv;
397     ThreadVars th_v;
398     Packet *p = PacketGetFromAlloc();
399     if (unlikely(p == NULL))
400         return NULL;
401     memset(&dtv, 0, sizeof(DecodeThreadVars));
402     memset(&th_v, 0, sizeof(th_v));
403 
404     DecodeEthernet(&th_v, &dtv, p, raw_eth, pktsize);
405     return p;
406 }
407 
408 /**
409  * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs
410  * and defaulting ports
411  *
412  * \param payload pointer to the payloadd buffer
413  * \param payload_len pointer to the length of the payload
414  * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
415  *
416  * \retval Packet pointer to the built in packet
417  */
UTHBuildPacketSrcDst(uint8_t * payload,uint16_t payload_len,uint8_t ipproto,const char * src,const char * dst)418 Packet *UTHBuildPacketSrcDst(uint8_t *payload, uint16_t payload_len,
419                              uint8_t ipproto, const char *src, const char *dst)
420 {
421     return UTHBuildPacketReal(payload, payload_len, ipproto,
422                               src, dst,
423                               41424, 80);
424 }
425 
426 /**
427  * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs
428  * and defaulting ports (IPV6)
429  *
430  * \param payload pointer to the payload buffer
431  * \param payload_len pointer to the length of the payload
432  * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
433  *
434  * \retval Packet pointer to the built in packet
435  */
UTHBuildPacketIPV6SrcDst(uint8_t * payload,uint16_t payload_len,uint8_t ipproto,const char * src,const char * dst)436 Packet *UTHBuildPacketIPV6SrcDst(uint8_t *payload, uint16_t payload_len,
437                            uint8_t ipproto, const char *src, const char *dst)
438 {
439     return UTHBuildPacketIPV6Real(payload, payload_len, ipproto,
440                               src, dst,
441                               41424, 80);
442 }
443 
444 /**
445  * \brief UTHBuildPacketSrcDstPorts is a wrapper that build packets specifying
446  * src and dst ports and defaulting IPs
447  *
448  * \param payload pointer to the payloadd buffer
449  * \param payload_len pointer to the length of the payload
450  * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
451  *
452  * \retval Packet pointer to the built in packet
453  */
UTHBuildPacketSrcDstPorts(uint8_t * payload,uint16_t payload_len,uint8_t ipproto,uint16_t sport,uint16_t dport)454 Packet *UTHBuildPacketSrcDstPorts(uint8_t *payload, uint16_t payload_len,
455                            uint8_t ipproto, uint16_t sport, uint16_t dport)
456 {
457     return UTHBuildPacketReal(payload, payload_len, ipproto,
458                               "192.168.1.5", "192.168.1.1",
459                               sport, dport);
460 }
461 
462 /**
463  * \brief UTHFreePackets: function to release the allocated data
464  * from UTHBuildPacket and the packet itself
465  *
466  * \param p pointer to the Packet
467  */
UTHFreePackets(Packet ** p,int numpkts)468 void UTHFreePackets(Packet **p, int numpkts)
469 {
470     if (p == NULL)
471         return;
472 
473     int i = 0;
474     for (; i < numpkts; i++) {
475         UTHFreePacket(p[i]);
476     }
477 }
478 
479 /**
480  * \brief UTHFreePacket: function to release the allocated data
481  * from UTHBuildPacket and the packet itself
482  *
483  * \param p pointer to the Packet
484  */
UTHFreePacket(Packet * p)485 void UTHFreePacket(Packet *p)
486 {
487     if (p == NULL)
488         return;
489 #if 0 // VJ we now use one buffer
490     switch (p->proto) {
491         case IPPROTO_UDP:
492             if (p->udph != NULL)
493                 SCFree(p->udph);
494             if (p->ip4h != NULL)
495                 SCFree(p->ip4h);
496         break;
497         case IPPROTO_TCP:
498             if (p->tcph != NULL)
499                 SCFree(p->tcph);
500             if (p->ip4h != NULL)
501                 SCFree(p->ip4h);
502         break;
503         case IPPROTO_ICMP:
504             if (p->ip4h != NULL)
505                 SCFree(p->ip4h);
506         break;
507         /* TODO: Add more protocols */
508     }
509 #endif
510     SCFree(p);
511 }
512 
UTHAssignFlow(Packet * p,Flow * f)513 void UTHAssignFlow(Packet *p, Flow *f)
514 {
515     if (p && f) {
516         p->flow = f;
517         p->flags |= PKT_HAS_FLOW;
518     }
519 }
520 
UTHBuildFlow(int family,const char * src,const char * dst,Port sp,Port dp)521 Flow *UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
522 {
523     return TestHelperBuildFlow(family, src, dst, sp, dp);
524 }
525 
UTHFreeFlow(Flow * flow)526 void UTHFreeFlow(Flow *flow)
527 {
528     if (flow != NULL) {
529         SCFree(flow);//FlowFree(flow);
530     }
531 }
532 
UTHAddStreamToFlow(Flow * f,int direction,uint8_t * data,uint32_t data_len)533 int UTHAddStreamToFlow(Flow *f, int direction,
534     uint8_t *data, uint32_t data_len)
535 {
536     FAIL_IF_NULL(f);
537     FAIL_IF_NOT(f->proto == IPPROTO_TCP);
538     FAIL_IF_NULL(f->protoctx);
539     TcpSession *ssn = f->protoctx;
540 
541     StreamingBufferSegment seg;
542     TcpStream *stream = direction == 0 ? &ssn->client : &ssn->server;
543     int r = StreamingBufferAppend(&stream->sb, &seg, data, data_len);
544     FAIL_IF_NOT(r == 0);
545     stream->last_ack += data_len;
546     return 1;
547 }
548 
UTHAddSessionToFlow(Flow * f,uint32_t ts_isn,uint32_t tc_isn)549 int UTHAddSessionToFlow(Flow *f,
550     uint32_t ts_isn,
551     uint32_t tc_isn)
552 {
553     FAIL_IF_NULL(f);
554 
555     TcpSession *ssn = SCCalloc(1, sizeof(*ssn));
556     FAIL_IF_NULL(ssn);
557 
558     StreamingBuffer x = STREAMING_BUFFER_INITIALIZER(&stream_config.sbcnf);
559     ssn->client.sb = x;
560     ssn->server.sb = x;
561 
562     ssn->client.isn = ts_isn;
563     ssn->server.isn = tc_isn;
564 
565     f->protoctx = ssn;
566     return 1;
567 }
568 
UTHRemoveSessionFromFlow(Flow * f)569 int UTHRemoveSessionFromFlow(Flow *f)
570 {
571     FAIL_IF_NULL(f);
572     FAIL_IF_NOT(f->proto == IPPROTO_TCP);
573     TcpSession *ssn = f->protoctx;
574     FAIL_IF_NULL(ssn);
575     StreamTcpSessionCleanup(ssn);
576     SCFree(ssn);
577     f->protoctx = NULL;
578     return 1;
579 }
580 
581 /**
582  * \brief UTHGenericTest: function that perfom a generic check taking care of
583  *                      as maximum common unittest elements as possible.
584  *                      It will create a detection engine, append an array
585  *                      of signatures an check the spected results for each
586  *                      of them, it check matches for an array of packets
587  *
588  * \param pkt pointer to the array of packets
589  * \param numpkts number of packets to match
590  * \param sigs array of char* pointing to signatures to load
591  * \param numsigs number of signatures to load and check
592  * \param results pointer to arrays of numbers, each of them foreach packet
593  *                to check if sids matches that packet as expected with
594  *                that number of times or not. The size of results should be
595  *                numpkts * numsigs * sizeof(uint16_t *)
596  *
597  *                Example:
598  *                result[1][3] would mean the number of times the pkt[1]
599  *                match the sid[3]
600  *
601  * \retval int 1 if the match of all the sids is the specified has the
602  *             specified results; 0 if not
603  */
UTHGenericTest(Packet ** pkt,int numpkts,const char * sigs[],uint32_t sids[],uint32_t * results,int numsigs)604 int UTHGenericTest(Packet **pkt, int numpkts, const char *sigs[], uint32_t sids[], uint32_t *results, int numsigs)
605 {
606 
607     int result = 0;
608     if (pkt == NULL || sigs == NULL || numpkts == 0
609         || sids == NULL || results == NULL || numsigs == 0) {
610         SCLogError(SC_ERR_INVALID_ARGUMENT, "Arguments invalid, that the pointer/arrays are not NULL, and the number of signatures and packets is > 0");
611         goto end;
612     }
613     DetectEngineCtx *de_ctx = DetectEngineCtxInit();
614     if (de_ctx == NULL) {
615         goto end;
616     }
617     de_ctx->flags |= DE_QUIET;
618 
619     if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0)
620         goto cleanup;
621 
622     result = UTHMatchPacketsWithResults(de_ctx, pkt, numpkts, sids, results, numsigs);
623 
624 cleanup:
625     if (de_ctx != NULL) {
626         SigGroupCleanup(de_ctx);
627         SigCleanSignatures(de_ctx);
628         DetectEngineCtxFree(de_ctx);
629     }
630 end:
631     return result;
632 }
633 
634 /**
635  * \brief UTHCheckPacketMatches: function to check if a packet match some sids
636  *
637  *
638  * \param p pointer to the Packet
639  * \param sigs array of char* pointing to signatures to load
640  * \param numsigs number of signatures to load from the array
641  * \param results pointer to an array of numbers to check if sids matches
642  *                that number of times or not.
643  *
644  * \retval int 1 if the match of all the sids is the specified has the
645  *             specified results; 0 if not
646  */
UTHCheckPacketMatchResults(Packet * p,uint32_t sids[],uint32_t results[],int numsids)647 int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[],
648         uint32_t results[], int numsids)
649 {
650     if (p == NULL || sids == NULL) {
651         SCLogError(SC_ERR_INVALID_ARGUMENT, "Arguments invalid, check if the "
652                 "packet is NULL, and if the array contain sids is set");
653         return 0;
654     }
655 
656     int i = 0;
657     int res = 1;
658     for (; i < numsids; i++) {
659         uint16_t r = PacketAlertCheck(p, sids[i]);
660         if (r != results[i]) {
661             SCLogInfo("Sid %"PRIu32" matched %"PRIu16" times, and not %"PRIu32
662                     " as expected", sids[i], r, results[i]);
663             res = 0;
664         } else {
665             SCLogInfo("Sid %"PRIu32" matched %"PRIu16" times, as expected", sids[i], r);
666         }
667     }
668     return res;
669 }
670 
671 /**
672  * \brief UTHAppendSigs: Add sigs to the detection_engine checking for errors
673  *
674  * \param de_ctx pointer to the DetectEngineCtx used
675  * \param sigs array of char* pointing to signatures to load
676  * \param numsigs number of signatures to load from the array
677  *                (size of the array)
678  *
679  * \retval int 0 if we have errors; 1 if all the signatures loaded succesfuly
680  */
UTHAppendSigs(DetectEngineCtx * de_ctx,const char * sigs[],int numsigs)681 int UTHAppendSigs(DetectEngineCtx *de_ctx, const char *sigs[], int numsigs)
682 {
683     if (de_ctx == NULL || numsigs <= 0 || sigs == NULL) {
684         SCLogError(SC_ERR_INVALID_ARGUMENT, "Arguments invalid, check if sigs or de_ctx are NULL, and if the array contain sigs");
685         return 0;
686     }
687     //SCLogDebug("Adding %d signatures for the current unittest", numsigs);
688 
689     Signature *s;
690     int i = 0;
691 
692     for ( ; i < numsigs; i++) {
693         if (sigs[i] == NULL) {
694             SCLogError(SC_ERR_INVALID_ARGUMENT, "Check the signature"
695                        " at position %d", i);
696             return 0;
697         }
698         s = DetectEngineAppendSig(de_ctx, sigs[i]);
699         if (s == NULL) {
700             SCLogError(SC_ERR_INVALID_ARGUMENT, "Check the signature at"
701                        " position %d (%s)", i, sigs[i]);
702             return 0;
703         }
704     }
705     //SCLogDebug("Added %d signatures to the de_ctx of the unittest", i);
706     return 1;
707 }
708 
709 /**
710  * \test UTHMatchPacketsWithResults Match a packet or a array of packets against sigs
711  * of a de_ctx, checking that each signature match match X times for certain packets
712  *
713  * \param de_ctx pointer with the signatures loaded
714  * \param p pointer to the array of packets
715  * \param num_packets number of packets in the array
716  *
717  * \retval return 1 if all goes well
718  * \retval return 0 if something fail
719  */
UTHMatchPacketsWithResults(DetectEngineCtx * de_ctx,Packet ** p,int num_packets,uint32_t sids[],uint32_t * results,int numsigs)720 int UTHMatchPacketsWithResults(DetectEngineCtx *de_ctx, Packet **p, int num_packets, uint32_t sids[], uint32_t *results, int numsigs)
721 {
722     int result = 0;
723 
724     if (de_ctx == NULL || p == NULL) {
725         SCLogError(SC_ERR_INVALID_ARGUMENT, "packet or de_ctx was null");
726         result = 0;
727         goto end;
728     }
729 
730     DecodeThreadVars dtv;
731     ThreadVars th_v;
732     DetectEngineThreadCtx *det_ctx = NULL;
733     memset(&dtv, 0, sizeof(DecodeThreadVars));
734     memset(&th_v, 0, sizeof(th_v));
735 
736     //de_ctx->flags |= DE_QUIET;
737 
738     SigGroupBuild(de_ctx);
739     DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
740 
741     int i = 0;
742     for (; i < num_packets; i++) {
743         SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]);
744         if (UTHCheckPacketMatchResults(p[i], sids, &results[(i * numsigs)], numsigs) == 0)
745             goto cleanup;
746     }
747 
748     /* so far, so good ;) */
749     result = 1;
750 
751 cleanup:
752     if (det_ctx != NULL)
753         DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
754 end:
755     return result;
756 }
757 
758 /**
759  * \test UTHMatchPackets Match a packet or a array of packets against sigs
760  * of a de_ctx, but note that the return value doesn't mean that we have a
761  * match, we have to check it later with PacketAlertCheck()
762  *
763  * \param de_ctx pointer with the signatures loaded
764  * \param p pointer to the array of packets
765  * \param num_packets number of packets in the array
766  *
767  * \retval return 1 if all goes well
768  * \retval return 0 if something fail
769  */
UTHMatchPackets(DetectEngineCtx * de_ctx,Packet ** p,int num_packets)770 int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets)
771 {
772     int result = 1;
773 
774     if (de_ctx == NULL || p == NULL) {
775         SCLogError(SC_ERR_INVALID_ARGUMENT, "packet or de_ctx was null");
776         result = 0;
777         goto end;
778     }
779 
780     DecodeThreadVars dtv;
781     ThreadVars th_v;
782     DetectEngineThreadCtx *det_ctx = NULL;
783     memset(&dtv, 0, sizeof(DecodeThreadVars));
784     memset(&th_v, 0, sizeof(th_v));
785 
786     //de_ctx->flags |= DE_QUIET;
787 
788     SCSigRegisterSignatureOrderingFuncs(de_ctx);
789     SCSigOrderSignatures(de_ctx);
790     SCSigSignatureOrderingModuleCleanup(de_ctx);
791     SigGroupBuild(de_ctx);
792     DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
793 
794     int i = 0;
795     for (; i < num_packets; i++)
796         SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]);
797 
798     /* Here we don't check if the packet matched or not, because
799      * the de_ctx can have multiple signatures, and some of them may match
800      * and others may not. That check will be outside
801      */
802     if (det_ctx != NULL) {
803         DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
804     }
805 end:
806     if (de_ctx != NULL) SigGroupCleanup(de_ctx);
807 
808     return result;
809 }
810 
811 /**
812  * \test Test if a packet match a signature given as string and a mpm_type
813  * Hint: Useful for unittests with only one packet and one signature
814  *
815  * \param sig pointer to the string signature to test
816  * \param sid sid number of the signature
817  *
818  * \retval return 1 if match
819  * \retval return 0 if not
820  */
UTHPacketMatchSigMpm(Packet * p,char * sig,uint16_t mpm_type)821 int UTHPacketMatchSigMpm(Packet *p, char *sig, uint16_t mpm_type)
822 {
823     SCEnter();
824 
825     int result = 0;
826 
827     DecodeThreadVars dtv;
828     ThreadVars th_v;
829     DetectEngineThreadCtx *det_ctx = NULL;
830 
831     memset(&dtv, 0, sizeof(DecodeThreadVars));
832     memset(&th_v, 0, sizeof(th_v));
833 
834     DetectEngineCtx *de_ctx = DetectEngineCtxInit();
835     if (de_ctx == NULL) {
836         printf("de_ctx == NULL: ");
837         goto end;
838     }
839 
840     de_ctx->flags |= DE_QUIET;
841     de_ctx->mpm_matcher = mpm_type;
842 
843     de_ctx->sig_list = SigInit(de_ctx, sig);
844     if (de_ctx->sig_list == NULL) {
845         printf("signature == NULL: ");
846         goto end;
847     }
848 
849     SigGroupBuild(de_ctx);
850     DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
851 
852     SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
853     if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) {
854         printf("signature didn't alert: ");
855         goto end;
856     }
857 
858     result = 1;
859 end:
860     SigGroupCleanup(de_ctx);
861     SigCleanSignatures(de_ctx);
862 
863     if (det_ctx != NULL)
864         DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
865 
866     if (de_ctx != NULL)
867         DetectEngineCtxFree(de_ctx);
868 
869     SCReturnInt(result);
870 }
871 
872 /**
873  * \test Test if a packet match a signature given as string
874  * Hint: Useful for unittests with only one packet and one signature
875  *
876  * \param sig pointer to the string signature to test
877  * \param sid sid number of the signature
878  *
879  * \retval return 1 if match
880  * \retval return 0 if not
881  */
UTHPacketMatchSig(Packet * p,const char * sig)882 int UTHPacketMatchSig(Packet *p, const char *sig)
883 {
884     int result = 1;
885 
886     DecodeThreadVars dtv;
887 
888     ThreadVars th_v;
889     DetectEngineThreadCtx *det_ctx = NULL;
890 
891     memset(&dtv, 0, sizeof(DecodeThreadVars));
892     memset(&th_v, 0, sizeof(th_v));
893 
894     DetectEngineCtx *de_ctx = DetectEngineCtxInit();
895     if (de_ctx == NULL) {
896         result=0;
897         goto end;
898     }
899 
900     de_ctx->flags |= DE_QUIET;
901 
902     de_ctx->sig_list = SigInit(de_ctx, sig);
903     if (de_ctx->sig_list == NULL) {
904         result = 0;
905         goto end;
906     }
907 
908     SigGroupBuild(de_ctx);
909     DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
910 
911     SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
912     if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) {
913         result = 0;
914         goto end;
915     }
916 
917 end:
918     if (de_ctx) {
919 	SigGroupCleanup(de_ctx);
920 	SigCleanSignatures(de_ctx);
921     }
922 
923     if (det_ctx != NULL)
924         DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
925     if (de_ctx != NULL)
926         DetectEngineCtxFree(de_ctx);
927 
928     return result;
929 }
930 
UTHBuildPacketOfFlows(uint32_t start,uint32_t end,uint8_t dir)931 uint32_t UTHBuildPacketOfFlows(uint32_t start, uint32_t end, uint8_t dir)
932 {
933     FlowLookupStruct fls;
934     memset(&fls, 0, sizeof(fls));
935 
936     uint32_t i = start;
937     uint8_t payload[] = "Payload";
938     for (; i < end; i++) {
939         Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP);
940         if (dir == 0) {
941             p->src.addr_data32[0] = i;
942             p->dst.addr_data32[0] = i + 1;
943         } else {
944             p->src.addr_data32[0] = i + 1;
945             p->dst.addr_data32[0] = i;
946         }
947         FlowHandlePacket(NULL, &fls, p);
948         if (p->flow != NULL) {
949             p->flow->use_cnt = 0;
950             FLOWLOCK_UNLOCK(p->flow);
951         }
952 
953         /* Now the queues shoul be updated */
954         UTHFreePacket(p);
955     }
956 
957     Flow *f;
958     while ((f = FlowQueuePrivateGetFromTop(&fls.spare_queue))) {
959         FlowFree(f);
960     }
961     while ((f = FlowQueuePrivateGetFromTop(&fls.work_queue))) {
962         FlowFree(f);
963     }
964 
965     return i;
966 }
967 
968 /** \brief parser a sig and see if the expected result is correct */
UTHParseSignature(const char * str,bool expect)969 int UTHParseSignature(const char *str, bool expect)
970 {
971     DetectEngineCtx *de_ctx = DetectEngineCtxInit();
972     FAIL_IF_NULL(de_ctx);
973     de_ctx->flags |= DE_QUIET;
974 
975     Signature *s = DetectEngineAppendSig(de_ctx, str);
976     if (expect)
977         FAIL_IF_NULL(s);
978     else
979         FAIL_IF_NOT_NULL(s);
980 
981     DetectEngineCtxFree(de_ctx);
982     PASS;
983 }
984 
985 /*
986  * unittests for the unittest helpers
987  */
988 
989 /**
990  * \brief CheckUTHTestPacket wrapper to check packets for unittests
991  */
CheckUTHTestPacket(Packet * p,uint8_t ipproto)992 static int CheckUTHTestPacket(Packet *p, uint8_t ipproto)
993 {
994     uint16_t sport = 41424;
995     uint16_t dport = 80;
996     uint8_t payload[] = "Payload";
997 
998     uint8_t len = sizeof(payload);
999 
1000     if (p == NULL)
1001         return 0;
1002 
1003     if (p->payload_len != len)
1004         return 0;
1005 
1006     if (strncmp((char *)payload, (char *)p->payload, len) != 0)
1007         return 0;
1008 
1009     if (p->src.family != AF_INET)
1010         return 0;
1011     if (p->dst.family != AF_INET)
1012         return 0;
1013     if (p->proto != ipproto)
1014         return 0;
1015 
1016     switch(ipproto) {
1017         case IPPROTO_UDP:
1018             if (p->udph == NULL)
1019                 return 0;
1020             if (p->udph->uh_sport != sport)
1021                 return 0;
1022             if (p->udph->uh_dport != dport)
1023                 return 0;
1024         break;
1025         case IPPROTO_TCP:
1026             if (p->tcph == NULL)
1027                 return 0;
1028             if (SCNtohs(p->tcph->th_sport) != sport)
1029                 return 0;
1030             if (SCNtohs(p->tcph->th_dport) != dport)
1031                 return 0;
1032         break;
1033     }
1034     return 1;
1035 }
1036 
1037 #ifdef HAVE_MEMMEM
1038 #include <string.h>
UTHmemsearch(const void * big,size_t big_len,const void * little,size_t little_len)1039 void * UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len) {
1040     return memmem(big, big_len, little, little_len);
1041 }
1042 #else
1043 #include "util-spm-bs.h"
UTHmemsearch(const void * big,size_t big_len,const void * little,size_t little_len)1044 void * UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len) {
1045     return BasicSearch(big, big_len, little, little_len);
1046 }
1047 #endif //HAVE_MEMMEM
1048 
1049 /**
1050  * \brief UTHBuildPacketRealTest01 wrapper to check packets for unittests
1051  */
UTHBuildPacketRealTest01(void)1052 static int UTHBuildPacketRealTest01(void)
1053 {
1054     uint8_t payload[] = "Payload";
1055 
1056     Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_TCP,
1057                                    "192.168.1.5", "192.168.1.1", 41424, 80);
1058 
1059     int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
1060     UTHFreePacket(p);
1061 
1062     return ret;
1063 }
1064 
1065 /**
1066  * \brief UTHBuildPacketRealTest02 wrapper to check packets for unittests
1067  */
UTHBuildPacketRealTest02(void)1068 static int UTHBuildPacketRealTest02(void)
1069 {
1070     uint8_t payload[] = "Payload";
1071 
1072     Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_UDP,
1073                                    "192.168.1.5", "192.168.1.1", 41424, 80);
1074 
1075     int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
1076     UTHFreePacket(p);
1077     return ret;
1078 }
1079 
1080 /**
1081  * \brief UTHBuildPacketTest01 wrapper to check packets for unittests
1082  */
UTHBuildPacketTest01(void)1083 static int UTHBuildPacketTest01(void)
1084 {
1085     uint8_t payload[] = "Payload";
1086 
1087     Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP);
1088 
1089     int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
1090     UTHFreePacket(p);
1091 
1092     return ret;
1093 }
1094 
1095 /**
1096  * \brief UTHBuildPacketTest02 wrapper to check packets for unittests
1097  */
UTHBuildPacketTest02(void)1098 static int UTHBuildPacketTest02(void)
1099 {
1100     uint8_t payload[] = "Payload";
1101 
1102     Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_UDP);
1103 
1104     int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
1105     UTHFreePacket(p);
1106 
1107     return ret;
1108 }
1109 
1110 /**
1111  * \brief UTHBuildPacketOfFlowsTest01 wrapper to check packets for unittests
1112  */
UTHBuildPacketOfFlowsTest01(void)1113 static int UTHBuildPacketOfFlowsTest01(void)
1114 {
1115     int result = 0;
1116 
1117     FlowInitConfig(FLOW_QUIET);
1118     uint32_t flow_spare_q_len = FlowSpareGetPoolSize();
1119 
1120     UTHBuildPacketOfFlows(0, 100, 0);
1121 
1122     if (FlowSpareGetPoolSize() != flow_spare_q_len - 100)
1123         result = 0;
1124     else
1125         result = 1;
1126     FlowShutdown();
1127 
1128     return result;
1129 }
1130 
1131 
1132 /**
1133  * \brief UTHBuildPacketSrcDstTest01 wrapper to check packets for unittests
1134  */
UTHBuildPacketSrcDstTest01(void)1135 static int UTHBuildPacketSrcDstTest01(void)
1136 {
1137     uint8_t payload[] = "Payload";
1138 
1139     Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_TCP,
1140                                      "192.168.1.5", "192.168.1.1");
1141 
1142     int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
1143     UTHFreePacket(p);
1144 
1145     return ret;
1146 }
1147 
1148 /**
1149  * \brief UTHBuildPacketSrcDstTest02 wrapper to check packets for unittests
1150  */
UTHBuildPacketSrcDstTest02(void)1151 static int UTHBuildPacketSrcDstTest02(void)
1152 {
1153     uint8_t payload[] = "Payload";
1154 
1155     Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_UDP,
1156                                      "192.168.1.5", "192.168.1.1");
1157 
1158     int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
1159     UTHFreePacket(p);
1160 
1161     return ret;
1162 }
1163 
1164 /**
1165  * \brief UTHBuildPacketSrcDstPortsTest01 wrapper to check packets for unittests
1166  */
UTHBuildPacketSrcDstPortsTest01(void)1167 static int UTHBuildPacketSrcDstPortsTest01(void)
1168 {
1169     uint8_t payload[] = "Payload";
1170 
1171     Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_TCP,
1172                                           41424, 80);
1173 
1174     int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
1175     UTHFreePacket(p);
1176 
1177     return ret;
1178 }
1179 
1180 /**
1181  * \brief UTHBuildPacketSrcDstPortsTest02 wrapper to check packets for unittests
1182  */
UTHBuildPacketSrcDstPortsTest02(void)1183 static int UTHBuildPacketSrcDstPortsTest02(void)
1184 {
1185     uint8_t payload[] = "Payload";
1186 
1187     Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_UDP,
1188                                           41424, 80);
1189 
1190     int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
1191     UTHFreePacket(p);
1192 
1193     return ret;
1194 }
1195 
1196 #endif /* UNITTESTS */
1197 
UTHRegisterTests(void)1198 void UTHRegisterTests(void)
1199 {
1200 #ifdef UNITTESTS
1201     UtRegisterTest("UTHBuildPacketRealTest01", UTHBuildPacketRealTest01);
1202     UtRegisterTest("UTHBuildPacketRealTest02", UTHBuildPacketRealTest02);
1203     UtRegisterTest("UTHBuildPacketTest01", UTHBuildPacketTest01);
1204     UtRegisterTest("UTHBuildPacketTest02", UTHBuildPacketTest02);
1205     UtRegisterTest("UTHBuildPacketSrcDstTest01", UTHBuildPacketSrcDstTest01);
1206     UtRegisterTest("UTHBuildPacketSrcDstTest02", UTHBuildPacketSrcDstTest02);
1207     UtRegisterTest("UTHBuildPacketSrcDstPortsTest01",
1208                    UTHBuildPacketSrcDstPortsTest01);
1209     UtRegisterTest("UTHBuildPacketSrcDstPortsTest02",
1210                    UTHBuildPacketSrcDstPortsTest02);
1211     UtRegisterTest("UTHBuildPacketOfFlowsTest01", UTHBuildPacketOfFlowsTest01);
1212 
1213 #endif /* UNITTESTS */
1214 }
1215 
1216