suricata
util-unittest-helper.c
Go to the documentation of this file.
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-alert.h"
40#include "detect-engine-build.h"
41
42#include "stream-tcp.h"
43#include "stream-tcp-private.h"
44
45#include "util-debug.h"
46#include "util-time.h"
47#include "util-error.h"
48#include "util-unittest.h"
50
51#if defined(UNITTESTS) || defined(FUZZ)
52Flow *TestHelperBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
53{
54 struct in_addr in;
55
56 Flow *f = SCMalloc(sizeof(Flow));
57 if (unlikely(f == NULL)) {
58 printf("FlowAlloc failed\n");
59 ;
60 return NULL;
61 }
62 memset(f, 0x00, sizeof(Flow));
63
65
66 if (family == AF_INET) {
67 f->flags |= FLOW_IPV4;
68 } else if (family == AF_INET6) {
69 f->flags |= FLOW_IPV6;
70 }
71
72 if (src != NULL) {
73 if (family == AF_INET) {
74 if (inet_pton(AF_INET, src, &in) != 1) {
75 printf("invalid address %s\n", src);
76 SCFree(f);
77 return NULL;
78 }
79 f->src.addr_data32[0] = in.s_addr;
80 } else {
81 BUG_ON(1);
82 }
83 }
84 if (dst != NULL) {
85 if (family == AF_INET) {
86 if (inet_pton(AF_INET, dst, &in) != 1) {
87 printf("invalid address %s\n", dst);
88 SCFree(f);
89 return NULL;
90 }
91 f->dst.addr_data32[0] = in.s_addr;
92 } else {
93 BUG_ON(1);
94 }
95 }
96
97 f->sp = sp;
98 f->dp = dp;
99
100 return f;
101}
102/** \brief writes the contents of a buffer into a file */
103int TestHelperBufferToFile(const char *name, const uint8_t *data, size_t size)
104{
105 if (remove(name) != 0) {
106 if (errno != ENOENT) {
107 printf("failed remove, errno=%d\n", errno);
108 return -1;
109 }
110 }
111 FILE *fd = fopen(name, "wb");
112 if (fd == NULL) {
113 printf("failed open, errno=%d\n", errno);
114 return -2;
115 }
116 if (fwrite (data, 1, size, fd) != size) {
117 fclose(fd);
118 return -3;
119 }
120 fclose(fd);
121 return 0;
122}
123
124#endif
125#ifdef UNITTESTS
127{
128 PacketSetIPV4(p, (uint8_t *)ip4h);
129}
130
132{
133 PacketSetIPV6(p, (uint8_t *)ip6h);
134}
135
137{
138 PacketSetTCP(p, (uint8_t *)tcph);
139}
140
141/**
142 * \brief return the uint32_t for a ipv4 address string
143 *
144 * \param str Valid ipaddress in string form (e.g. 1.2.3.4)
145 *
146 * \retval uint the uin32_t representation
147 */
148uint32_t UTHSetIPv4Address(const char *str)
149{
150 struct in_addr in;
151 if (inet_pton(AF_INET, str, &in) != 1) {
152 printf("invalid IPv6 address %s\n", str);
153 exit(EXIT_FAILURE);
154 }
155 return (uint32_t)in.s_addr;
156}
157
158/**
159 * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests
160 * specifying ip and port sources and destinations (IPV6)
161 *
162 * \param payload pointer to the payload buffer
163 * \param payload_len pointer to the length of the payload
164 * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
165 * \param src pointer to a string containing the ip source
166 * \param dst pointer to a string containing the ip destination
167 * \param sport pointer to a string containing the port source
168 * \param dport pointer to a string containing the port destination
169 *
170 * \retval Packet pointer to the built in packet
171 */
172Packet *UTHBuildPacketIPV6Real(uint8_t *payload, uint16_t payload_len,
173 uint8_t ipproto, const char *src, const char *dst,
174 uint16_t sport, uint16_t dport)
175{
176 uint32_t in[4];
177 TCPHdr *tcph = NULL;
178
180 if (unlikely(p == NULL))
181 return NULL;
182
183 p->ts = TimeGet();
184
185 p->src.family = AF_INET6;
186 p->dst.family = AF_INET6;
187 p->payload = payload;
189 p->proto = ipproto;
190
191 IPV6Hdr *ip6h = SCCalloc(1, sizeof(IPV6Hdr));
192 if (ip6h == NULL)
193 goto error;
194 ip6h->s_ip6_nxt = ipproto;
195 ip6h->s_ip6_plen = htons(payload_len + sizeof(TCPHdr));
196 UTHSetIPV6Hdr(p, ip6h);
197
198 if (inet_pton(AF_INET6, src, &in) != 1)
199 goto error;
200 p->src.addr_data32[0] = in[0];
201 p->src.addr_data32[1] = in[1];
202 p->src.addr_data32[2] = in[2];
203 p->src.addr_data32[3] = in[3];
204 p->sp = sport;
205 ip6h->s_ip6_src[0] = in[0];
206 ip6h->s_ip6_src[1] = in[1];
207 ip6h->s_ip6_src[2] = in[2];
208 ip6h->s_ip6_src[3] = in[3];
209
210 if (inet_pton(AF_INET6, dst, &in) != 1)
211 goto error;
212 p->dst.addr_data32[0] = in[0];
213 p->dst.addr_data32[1] = in[1];
214 p->dst.addr_data32[2] = in[2];
215 p->dst.addr_data32[3] = in[3];
216 p->dp = dport;
217 ip6h->s_ip6_dst[0] = in[0];
218 ip6h->s_ip6_dst[1] = in[1];
219 ip6h->s_ip6_dst[2] = in[2];
220 ip6h->s_ip6_dst[3] = in[3];
221
222 tcph = SCMalloc(sizeof(TCPHdr));
223 if (tcph == NULL)
224 goto error;
225 memset(tcph, 0, sizeof(TCPHdr));
226 tcph->th_sport = htons(sport);
227 tcph->th_dport = htons(dport);
228 UTHSetTCPHdr(p, tcph);
229
230 SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(TCPHdr) + payload_len);
231 return p;
232
233error:
234 if (p != NULL) {
235 if (ip6h != NULL) {
236 SCFree(ip6h);
237 }
238 if (tcph != NULL) {
239 SCFree(tcph);
240 }
241 SCFree(p);
242 }
243 return NULL;
244}
245
246/**
247 * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests
248 * specifying ip and port sources and destinations
249 *
250 * \param payload pointer to the payload buffer
251 * \param payload_len pointer to the length of the payload
252 * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
253 * \param src pointer to a string containing the ip source
254 * \param dst pointer to a string containing the ip destination
255 * \param sport pointer to a string containing the port source
256 * \param dport pointer to a string containing the port destination
257 *
258 * \retval Packet pointer to the built in packet
259 */
260Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len,
261 uint8_t ipproto, const char *src, const char *dst,
262 uint16_t sport, uint16_t dport)
263{
264 struct in_addr in;
265
267 if (unlikely(p == NULL))
268 return NULL;
269
270 p->ts = TimeGet();
271
272 p->src.family = AF_INET;
273 p->dst.family = AF_INET;
274 p->payload = payload;
275 p->payload_len = payload_len;
276 p->proto = ipproto;
277
278 if (inet_pton(AF_INET, src, &in) != 1)
279 goto error;
280 p->src.addr_data32[0] = in.s_addr;
281 if (ipproto == IPPROTO_TCP || ipproto == IPPROTO_UDP || ipproto == IPPROTO_SCTP)
282 p->sp = sport;
283
284 if (inet_pton(AF_INET, dst, &in) != 1)
285 goto error;
286 p->dst.addr_data32[0] = in.s_addr;
287 if (ipproto == IPPROTO_TCP || ipproto == IPPROTO_UDP || ipproto == IPPROTO_SCTP)
288 p->dp = dport;
289
290 IPV4Hdr *ip4h = PacketSetIPV4(p, GET_PKT_DATA(p));
291 if (ip4h == NULL)
292 goto error;
293
294 ip4h->s_ip_src.s_addr = p->src.addr_data32[0];
295 ip4h->s_ip_dst.s_addr = p->dst.addr_data32[0];
296 ip4h->ip_proto = ipproto;
297 ip4h->ip_verhl = 0x40 | (sizeof(IPV4Hdr) / 4);
298 p->proto = ipproto;
299
300 int hdr_offset = sizeof(IPV4Hdr);
301 switch (ipproto) {
302 case IPPROTO_UDP: {
303 UDPHdr *udph = PacketSetUDP(p, (GET_PKT_DATA(p) + hdr_offset));
304 if (udph == NULL)
305 goto error;
306
307 udph->uh_sport = htons(sport);
308 udph->uh_dport = htons(dport);
309 udph->uh_len = htons(payload_len + sizeof(UDPHdr));
310 ip4h->ip_len = htons(payload_len + sizeof(IPV4Hdr) + sizeof(UDPHdr));
311 hdr_offset += sizeof(UDPHdr);
312 break;
313 }
314 case IPPROTO_TCP: {
315 TCPHdr *tcph = PacketSetTCP(p, GET_PKT_DATA(p) + hdr_offset);
316 if (tcph == NULL)
317 goto error;
318
319 tcph->th_sport = htons(sport);
320 tcph->th_dport = htons(dport);
321 tcph->th_offx2 = (sizeof(TCPHdr) / 4) << 4;
322 tcph->th_win = 0x4444; // non-zero window
323 tcph->th_flags = TH_ACK;
324 ip4h->ip_len = htons(payload_len + sizeof(IPV4Hdr) + sizeof(TCPHdr));
325 hdr_offset += sizeof(TCPHdr);
326 break;
327 }
328 case IPPROTO_ICMP: {
329 ICMPV4Hdr *icmpv4h = PacketSetICMPv4(p, (GET_PKT_DATA(p) + hdr_offset));
330 if (icmpv4h == NULL)
331 goto error;
332
333 hdr_offset += sizeof(ICMPV4Hdr);
334 break;
335 }
336 default:
337 break;
338 /* TODO: Add more protocols */
339 }
340
341 if (payload && payload_len) {
342 PacketCopyDataOffset(p, hdr_offset, payload, payload_len);
343 }
344 SET_PKT_LEN(p, hdr_offset + payload_len);
345 p->payload = GET_PKT_DATA(p)+hdr_offset;
346 p->app_update_direction = UPDATE_DIR_BOTH;
347
348 return p;
349
350error:
351 SCFree(p);
352 return NULL;
353}
354
355/**
356 * \brief UTHBuildPacket is a wrapper that build packets with default ip
357 * and port fields
358 *
359 * \param payload pointer to the payload buffer
360 * \param payload_len pointer to the length of the payload
361 * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
362 *
363 * \retval Packet pointer to the built in packet
364 */
365Packet *UTHBuildPacket(uint8_t *payload, uint16_t payload_len,
366 uint8_t ipproto)
367{
368 return UTHBuildPacketReal(payload, payload_len, ipproto,
369 "192.168.1.5", "192.168.1.1",
370 41424, 80);
371}
372
373/**
374 * \brief UTHBuildPacketFromEth is a wrapper that build a packet for the rawbytes
375 *
376 * \param raw_eth pointer to the rawbytes containing an ethernet packet
377 * (and any other headers inside)
378 * \param pktsize pointer to the length of the payload
379 *
380 * \retval Packet pointer to the built in packet; NULL if something fail
381 */
382Packet *UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize)
383{
385 ThreadVars th_v;
387 if (unlikely(p == NULL))
388 return NULL;
389 memset(&dtv, 0, sizeof(DecodeThreadVars));
390 memset(&th_v, 0, sizeof(th_v));
391
392 DecodeEthernet(&th_v, &dtv, p, raw_eth, pktsize);
393 return p;
394}
395
396/**
397 * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs
398 * and defaulting ports
399 *
400 * \param payload pointer to the payload buffer
401 * \param payload_len pointer to the length of the payload
402 * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
403 *
404 * \retval Packet pointer to the built in packet
405 */
406Packet *UTHBuildPacketSrcDst(uint8_t *payload, uint16_t payload_len,
407 uint8_t ipproto, const char *src, const char *dst)
408{
409 return UTHBuildPacketReal(payload, payload_len, ipproto,
410 src, dst,
411 41424, 80);
412}
413
414/**
415 * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs
416 * and defaulting ports (IPV6)
417 *
418 * \param payload pointer to the payload buffer
419 * \param payload_len pointer to the length of the payload
420 * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
421 *
422 * \retval Packet pointer to the built in packet
423 */
424Packet *UTHBuildPacketIPV6SrcDst(uint8_t *payload, uint16_t payload_len,
425 uint8_t ipproto, const char *src, const char *dst)
426{
427 return UTHBuildPacketIPV6Real(payload, payload_len, ipproto,
428 src, dst,
429 41424, 80);
430}
431
432/**
433 * \brief UTHBuildPacketSrcDstPorts is a wrapper that build packets specifying
434 * src and dst ports and defaulting IPs
435 *
436 * \param payload pointer to the payload buffer
437 * \param payload_len pointer to the length of the payload
438 * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
439 *
440 * \retval Packet pointer to the built in packet
441 */
442Packet *UTHBuildPacketSrcDstPorts(uint8_t *payload, uint16_t payload_len,
443 uint8_t ipproto, uint16_t sport, uint16_t dport)
444{
445 return UTHBuildPacketReal(payload, payload_len, ipproto,
446 "192.168.1.5", "192.168.1.1",
447 sport, dport);
448}
449
450/**
451 * \brief UTHFreePackets: function to release the allocated data
452 * from UTHBuildPacket and the packet itself
453 *
454 * \param p pointer to the Packet
455 */
456void UTHFreePackets(Packet **p, int numpkts)
457{
458 if (p == NULL)
459 return;
460
461 int i = 0;
462 for (; i < numpkts; i++) {
463 UTHFreePacket(p[i]);
464 }
465}
466
467/**
468 * \brief UTHFreePacket: function to release the allocated data
469 * from UTHBuildPacket and the packet itself
470 *
471 * \param p pointer to the Packet
472 */
474{
475 if (p == NULL)
476 return;
477 PacketFree(p);
478}
479
481{
482 if (p && f) {
483 p->flow = f;
484 p->flags |= PKT_HAS_FLOW;
485 }
486}
487
488Flow *UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
489{
490 return TestHelperBuildFlow(family, src, dst, sp, dp);
491}
492
493void UTHFreeFlow(Flow *flow)
494{
495 if (flow != NULL) {
496 SCFree(flow);//FlowFree(flow);
497 }
498}
499
500int UTHAddStreamToFlow(Flow *f, int direction,
501 uint8_t *data, uint32_t data_len)
502{
503 FAIL_IF_NULL(f);
504 FAIL_IF_NOT(f->proto == IPPROTO_TCP);
506 TcpSession *ssn = f->protoctx;
507
508 StreamingBufferSegment seg;
509 TcpStream *stream = direction == 0 ? &ssn->client : &ssn->server;
510 int r = StreamingBufferAppend(&stream->sb, &stream_config.sbcnf, &seg, data, data_len);
511 FAIL_IF_NOT(r == 0);
512 stream->last_ack += data_len;
513 return 1;
514}
515
517 uint32_t ts_isn,
518 uint32_t tc_isn)
519{
520 FAIL_IF_NULL(f);
521
522 TcpSession *ssn = SCCalloc(1, sizeof(*ssn));
523 FAIL_IF_NULL(ssn);
524
526 ssn->client.sb = x;
527 ssn->server.sb = x;
528
529 ssn->client.isn = ts_isn;
530 ssn->server.isn = tc_isn;
531
532 f->protoctx = ssn;
533 return 1;
534}
535
537{
538 FAIL_IF_NULL(f);
539 FAIL_IF_NOT(f->proto == IPPROTO_TCP);
540 TcpSession *ssn = f->protoctx;
541 FAIL_IF_NULL(ssn);
543 SCFree(ssn);
544 f->protoctx = NULL;
545 return 1;
546}
547
548/**
549 * \brief UTHGenericTest: function that perform a generic check taking care of
550 * as maximum common unittest elements as possible.
551 * It will create a detection engine, append an array
552 * of signatures an check the expected results for each
553 * of them, it check matches for an array of packets
554 *
555 * \param pkt pointer to the array of packets
556 * \param numpkts number of packets to match
557 * \param sigs array of char* pointing to signatures to load
558 * \param numsigs number of signatures to load and check
559 * \param results pointer to arrays of numbers, each of them foreach packet
560 * to check if sids matches that packet as expected with
561 * that number of times or not. The size of results should be
562 * numpkts * numsigs * sizeof(uint16_t *)
563 *
564 * Example:
565 * result[1][3] would mean the number of times the pkt[1]
566 * match the sid[3]
567 *
568 * \retval int 1 if the match of all the sids is the specified has the
569 * specified results; 0 if not
570 */
571int UTHGenericTest(Packet **pkt, int numpkts, const char *sigs[], uint32_t sids[], uint32_t *results, int numsigs)
572{
573
574 int result = 0;
575 if (pkt == NULL || sigs == NULL || numpkts == 0
576 || sids == NULL || results == NULL || numsigs == 0) {
577 SCLogError("Arguments invalid, that the pointer/arrays are not NULL, and the number of "
578 "signatures and packets is > 0");
579 goto end;
580 }
582 if (de_ctx == NULL) {
583 goto end;
584 }
586
587 if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0)
588 goto cleanup;
589
590 result = UTHMatchPacketsWithResults(de_ctx, pkt, numpkts, sids, results, numsigs);
591
592cleanup:
594end:
595 return result;
596}
597
598/**
599 * \brief UTHCheckPacketMatches: function to check if a packet match some sids
600 *
601 *
602 * \param p pointer to the Packet
603 * \param sigs array of char* pointing to signatures to load
604 * \param numsigs number of signatures to load from the array
605 * \param results pointer to an array of numbers to check if sids matches
606 * that number of times or not.
607 *
608 * \retval int 1 if the match of all the sids is the specified has the
609 * specified results; 0 if not
610 */
611int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[], uint32_t results[], int numsigs)
612{
613 if (p == NULL || sids == NULL) {
614 SCLogError("Arguments invalid, check if the "
615 "packet is NULL, and if the array contain sids is set");
616 return 0;
617 }
618
619 int i = 0;
620 int res = 1;
621 for (; i < numsigs; i++) {
622 uint32_t r = PacketAlertCheck(p, sids[i]);
623 if (r != results[i]) {
624 SCLogInfo("Sid %" PRIu32 " matched %" PRIu32 " times, and not %" PRIu32 " as expected",
625 sids[i], r, results[i]);
626 res = 0;
627 } else {
628 SCLogInfo("Sid %" PRIu32 " matched %" PRIu32 " times, as expected", sids[i], r);
629 }
630 }
631 return res;
632}
633
634/**
635 * \brief UTHAppendSigs: Add sigs to the detection_engine checking for errors
636 *
637 * \param de_ctx pointer to the DetectEngineCtx used
638 * \param sigs array of char* pointing to signatures to load
639 * \param numsigs number of signatures to load from the array
640 * (size of the array)
641 *
642 * \retval int 0 if we have errors; 1 if all the signatures loaded successfully
643 */
644int UTHAppendSigs(DetectEngineCtx *de_ctx, const char *sigs[], int numsigs)
645{
646 BUG_ON(de_ctx == NULL);
647 BUG_ON(numsigs <= 0);
648 BUG_ON(sigs == NULL);
649
650 for (int i = 0; i < numsigs; i++) {
651 if (sigs[i] == NULL) {
652 SCLogError("Check the signature"
653 " at position %d",
654 i);
655 return 0;
656 }
658 if (s == NULL) {
659 SCLogError("Check the signature at"
660 " position %d (%s)",
661 i, sigs[i]);
662 return 0;
663 }
664 }
665 return 1;
666}
667
668/**
669 * \test UTHMatchPacketsWithResults Match a packet or a array of packets against sigs
670 * of a de_ctx, checking that each signature matches X times for certain packets
671 *
672 * \param de_ctx pointer with the signatures loaded
673 * \param p pointer to the array of packets
674 * \param num_packets number of packets in the array
675 *
676 * \retval return 1 if all goes well
677 * \retval return 0 if something fail
678 */
679int UTHMatchPacketsWithResults(DetectEngineCtx *de_ctx, Packet **p, int num_packets, uint32_t sids[], uint32_t *results, int numsigs)
680{
681 BUG_ON(de_ctx == NULL);
682 BUG_ON(p == NULL);
683
684 int result = 0;
686 ThreadVars th_v;
687 DetectEngineThreadCtx *det_ctx = NULL;
688 memset(&dtv, 0, sizeof(DecodeThreadVars));
689 memset(&th_v, 0, sizeof(th_v));
690
692 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
693
694 for (int i = 0; i < num_packets; i++) {
695 SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]);
696 if (UTHCheckPacketMatchResults(p[i], sids, &results[(i * numsigs)], numsigs) == 0)
697 goto cleanup;
698 }
699
700 result = 1;
701cleanup:
702 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
703 return result;
704}
705
706/**
707 * \test UTHMatchPackets Match a packet or a array of packets against sigs
708 * of a de_ctx, but note that the return value doesn't mean that we have a
709 * match, we have to check it later with PacketAlertCheck()
710 *
711 * \param de_ctx pointer with the signatures loaded
712 * \param p pointer to the array of packets
713 * \param num_packets number of packets in the array
714 *
715 * \retval return 1 if all goes well
716 * \retval return 0 if something fail
717 */
718int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets)
719{
720 BUG_ON(de_ctx == NULL);
721 BUG_ON(p == NULL);
722 int result = 1;
724 ThreadVars th_v;
725 DetectEngineThreadCtx *det_ctx = NULL;
726 memset(&dtv, 0, sizeof(DecodeThreadVars));
727 memset(&th_v, 0, sizeof(th_v));
732 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
733
734 for (int i = 0; i < num_packets; i++)
735 SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]);
736
737 /* Here we don't check if the packet matched or not, because
738 * the de_ctx can have multiple signatures, and some of them may match
739 * and others may not. That check will be outside
740 */
741 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
742 if (de_ctx != NULL) SigGroupCleanup(de_ctx);
743 return result;
744}
745
746/**
747 * \test Test if a packet match a signature given as string and a mpm_type
748 * Hint: Useful for unittests with only one packet and one signature
749 *
750 * \param sig pointer to the string signature to test
751 * \param sid sid number of the signature
752 *
753 * \retval return 1 if match
754 * \retval return 0 if not
755 */
756int UTHPacketMatchSigMpm(Packet *p, char *sig, uint16_t mpm_type)
757{
758 SCEnter();
759
760 int result = 0;
761
763 ThreadVars th_v;
764 DetectEngineThreadCtx *det_ctx = NULL;
765
766 memset(&dtv, 0, sizeof(DecodeThreadVars));
767 memset(&th_v, 0, sizeof(th_v));
768
770 if (de_ctx == NULL) {
771 printf("de_ctx == NULL: ");
772 goto end;
773 }
774
776 de_ctx->mpm_matcher = mpm_type;
777
778 de_ctx->sig_list = SigInit(de_ctx, sig);
779 if (de_ctx->sig_list == NULL) {
780 printf("signature == NULL: ");
781 goto end;
782 }
783
785 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
786
787 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
788 if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) {
789 printf("signature didn't alert: ");
790 goto end;
791 }
792
793 result = 1;
794end:
795 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
797 SCReturnInt(result);
798}
799
800/**
801 * \test Test if a packet match a signature given as string
802 * Hint: Useful for unittests with only one packet and one signature
803 *
804 * \param sig pointer to the string signature to test
805 * \param sid sid number of the signature
806 *
807 * \retval return 1 if match
808 * \retval return 0 if not
809 */
810int UTHPacketMatchSig(Packet *p, const char *sig)
811{
812 int result = 1;
813
815
816 ThreadVars th_v;
817 DetectEngineThreadCtx *det_ctx = NULL;
818
819 memset(&dtv, 0, sizeof(DecodeThreadVars));
820 memset(&th_v, 0, sizeof(th_v));
821
823 if (de_ctx == NULL) {
824 result=0;
825 goto end;
826 }
827
829
830 de_ctx->sig_list = SigInit(de_ctx, sig);
831 if (de_ctx->sig_list == NULL) {
832 result = 0;
833 goto end;
834 }
835
837 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
838
839 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
840 if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) {
841 result = 0;
842 goto end;
843 }
844
845end:
846 if (de_ctx) {
849 }
850
851 if (det_ctx != NULL)
852 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
853 if (de_ctx != NULL)
855
856 return result;
857}
858
859uint32_t UTHBuildPacketOfFlows(uint32_t start, uint32_t end, uint8_t dir)
860{
862 memset(&fls, 0, sizeof(fls));
864 memset(&tv, 0, sizeof(tv));
865
866 uint32_t i = start;
867 uint8_t payload[] = "Payload";
868 for (; i < end; i++) {
869 Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP);
870 if (dir == 0) {
871 p->src.addr_data32[0] = i;
872 p->dst.addr_data32[0] = i + 1;
873 } else {
874 p->src.addr_data32[0] = i + 1;
875 p->dst.addr_data32[0] = i;
876 }
877 FlowHandlePacket(&tv, &fls, p);
878 if (p->flow != NULL) {
880 }
881
882 /* Now the queues should be updated */
883 UTHFreePacket(p);
884 }
885
886 Flow *f;
887 while ((f = FlowQueuePrivateGetFromTop(&fls.spare_queue))) {
888 FlowFree(f);
889 }
890 while ((f = FlowQueuePrivateGetFromTop(&fls.work_queue))) {
891 FlowFree(f);
892 }
893
894 return i;
895}
896
897/** \brief parser a sig and see if the expected result is correct */
898int UTHParseSignature(const char *str, bool expect)
899{
903
905 if (expect)
906 FAIL_IF_NULL(s);
907 else
909
911 PASS;
912}
913
914/*
915 * unittests for the unittest helpers
916 */
917
918/**
919 * \brief CheckUTHTestPacket wrapper to check packets for unittests
920 */
921static int CheckUTHTestPacket(Packet *p, uint8_t ipproto)
922{
923 uint16_t sport = 41424;
924 uint16_t dport = 80;
925 uint8_t payload[] = "Payload";
926
927 uint8_t len = sizeof(payload);
928
929 if (p == NULL)
930 return 0;
931
932 if (p->payload_len != len)
933 return 0;
934
935 if (strncmp((char *)payload, (char *)p->payload, len) != 0)
936 return 0;
937
938 if (p->src.family != AF_INET)
939 return 0;
940 if (p->dst.family != AF_INET)
941 return 0;
942 if (p->proto != ipproto)
943 return 0;
944
945 switch(ipproto) {
946 case IPPROTO_UDP: {
947 const UDPHdr *udph = PacketGetUDP(p);
948 if (udph == NULL)
949 return 0;
950 if (SCNtohs(udph->uh_sport) != sport)
951 return 0;
952 if (SCNtohs(udph->uh_dport) != dport)
953 return 0;
954 break;
955 }
956 case IPPROTO_TCP: {
957 const TCPHdr *tcph = PacketGetTCP(p);
958 if (tcph == NULL)
959 return 0;
960 if (SCNtohs(tcph->th_sport) != sport)
961 return 0;
962 if (SCNtohs(tcph->th_dport) != dport)
963 return 0;
964 break;
965 }
966 }
967 return 1;
968}
969
970#ifdef HAVE_MEMMEM
971#include <string.h>
972void * UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len) {
973 return memmem(big, big_len, little, little_len);
974}
975#else
976#include "util-spm-bs.h"
977void * UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len) {
978 return BasicSearch(big, big_len, little, little_len);
979}
980#endif //HAVE_MEMMEM
981
982/**
983 * \brief UTHBuildPacketRealTest01 wrapper to check packets for unittests
984 */
985static int UTHBuildPacketRealTest01(void)
986{
987 uint8_t payload[] = "Payload";
988
989 Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_TCP,
990 "192.168.1.5", "192.168.1.1", 41424, 80);
991
992 int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
993 UTHFreePacket(p);
994
995 return ret;
996}
997
998/**
999 * \brief UTHBuildPacketRealTest02 wrapper to check packets for unittests
1000 */
1001static int UTHBuildPacketRealTest02(void)
1002{
1003 uint8_t payload[] = "Payload";
1004
1005 Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_UDP,
1006 "192.168.1.5", "192.168.1.1", 41424, 80);
1007
1008 int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
1009 UTHFreePacket(p);
1010 return ret;
1011}
1012
1013/**
1014 * \brief UTHBuildPacketTest01 wrapper to check packets for unittests
1015 */
1016static int UTHBuildPacketTest01(void)
1017{
1018 uint8_t payload[] = "Payload";
1019
1020 Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP);
1021
1022 int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
1023 UTHFreePacket(p);
1024
1025 return ret;
1026}
1027
1028/**
1029 * \brief UTHBuildPacketTest02 wrapper to check packets for unittests
1030 */
1031static int UTHBuildPacketTest02(void)
1032{
1033 uint8_t payload[] = "Payload";
1034
1035 Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_UDP);
1036
1037 int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
1038 UTHFreePacket(p);
1039
1040 return ret;
1041}
1042
1043/**
1044 * \brief UTHBuildPacketOfFlowsTest01 wrapper to check packets for unittests
1045 */
1046static int UTHBuildPacketOfFlowsTest01(void)
1047{
1048 int result = 0;
1049
1051 uint32_t flow_spare_q_len = FlowSpareGetPoolSize();
1052
1053 UTHBuildPacketOfFlows(0, 100, 0);
1054
1055 if (FlowSpareGetPoolSize() != flow_spare_q_len - 100)
1056 result = 0;
1057 else
1058 result = 1;
1059 FlowShutdown();
1060
1061 return result;
1062}
1063
1064
1065/**
1066 * \brief UTHBuildPacketSrcDstTest01 wrapper to check packets for unittests
1067 */
1068static int UTHBuildPacketSrcDstTest01(void)
1069{
1070 uint8_t payload[] = "Payload";
1071
1072 Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_TCP,
1073 "192.168.1.5", "192.168.1.1");
1074
1075 int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
1076 UTHFreePacket(p);
1077
1078 return ret;
1079}
1080
1081/**
1082 * \brief UTHBuildPacketSrcDstTest02 wrapper to check packets for unittests
1083 */
1084static int UTHBuildPacketSrcDstTest02(void)
1085{
1086 uint8_t payload[] = "Payload";
1087
1088 Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_UDP,
1089 "192.168.1.5", "192.168.1.1");
1090
1091 int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
1092 UTHFreePacket(p);
1093
1094 return ret;
1095}
1096
1097/**
1098 * \brief UTHBuildPacketSrcDstPortsTest01 wrapper to check packets for unittests
1099 */
1100static int UTHBuildPacketSrcDstPortsTest01(void)
1101{
1102 uint8_t payload[] = "Payload";
1103
1104 Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_TCP,
1105 41424, 80);
1106
1107 int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
1108 UTHFreePacket(p);
1109
1110 return ret;
1111}
1112
1113/**
1114 * \brief UTHBuildPacketSrcDstPortsTest02 wrapper to check packets for unittests
1115 */
1116static int UTHBuildPacketSrcDstPortsTest02(void)
1117{
1118 uint8_t payload[] = "Payload";
1119
1120 Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_UDP,
1121 41424, 80);
1122
1123 int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
1124 UTHFreePacket(p);
1125
1126 return ret;
1127}
1128
1129#endif /* UNITTESTS */
1130
1132{
1133#ifdef UNITTESTS
1134 UtRegisterTest("UTHBuildPacketRealTest01", UTHBuildPacketRealTest01);
1135 UtRegisterTest("UTHBuildPacketRealTest02", UTHBuildPacketRealTest02);
1136 UtRegisterTest("UTHBuildPacketTest01", UTHBuildPacketTest01);
1137 UtRegisterTest("UTHBuildPacketTest02", UTHBuildPacketTest02);
1138 UtRegisterTest("UTHBuildPacketSrcDstTest01", UTHBuildPacketSrcDstTest01);
1139 UtRegisterTest("UTHBuildPacketSrcDstTest02", UTHBuildPacketSrcDstTest02);
1140 UtRegisterTest("UTHBuildPacketSrcDstPortsTest01",
1141 UTHBuildPacketSrcDstPortsTest01);
1142 UtRegisterTest("UTHBuildPacketSrcDstPortsTest02",
1143 UTHBuildPacketSrcDstPortsTest02);
1144 UtRegisterTest("UTHBuildPacketOfFlowsTest01", UTHBuildPacketOfFlowsTest01);
1145
1146#endif /* UNITTESTS */
1147}
1148
uint8_t len
uint16_t dst
uint16_t src
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
struct ICMPV4Hdr_ ICMPV4Hdr
struct IPV4Hdr_ IPV4Hdr
#define TH_ACK
Definition decode-tcp.h:38
struct TCPHdr_ TCPHdr
struct UDPHdr_ UDPHdr
#define PKT_HAS_FLOW
Definition decode.h:1266
#define SET_PKT_LEN(p, len)
Definition decode.h:213
#define GET_PKT_DATA(p)
Definition decode.h:209
uint16_t Port
Definition decode.h:218
#define IPPROTO_SCTP
Definition decode.h:1228
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
void SigCleanSignatures(DetectEngineCtx *de_ctx)
int SigGroupCleanup(DetectEngineCtx *de_ctx)
void SCSigOrderSignatures(DetectEngineCtx *de_ctx)
Orders the signatures.
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
void SCSigSignatureOrderingModuleCleanup(DetectEngineCtx *de_ctx)
De-registers all the signature ordering functions registered.
void SCSigRegisterSignatureOrderingFuncs(DetectEngineCtx *de_ctx)
Lets you register the Signature ordering functions. The order in which the functions are registered s...
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition detect.c:2420
#define DE_QUIET
Definition detect.h:330
TcpStreamCnf stream_config
Definition stream-tcp.c:219
Flow * FlowQueuePrivateGetFromTop(FlowQueuePrivate *fqc)
Definition flow-queue.c:151
uint32_t FlowSpareGetPoolSize(void)
void FlowFree(Flow *f)
cleanup & free the memory of a flow
Definition flow-util.c:84
#define FLOW_INITIALIZE(f)
Definition flow-util.h:38
void FlowHandlePacket(ThreadVars *tv, FlowLookupStruct *fls, Packet *p)
Entry point for packet flow handling.
Definition flow.c:533
void FlowInitConfig(bool quiet)
initialize the configuration
Definition flow.c:547
void FlowShutdown(void)
shutdown the flow engine
Definition flow.c:691
#define FLOW_QUIET
Definition flow.h:43
#define FLOW_IPV6
Definition flow.h:102
#define FLOW_IPV4
Definition flow.h:100
#define FLOWLOCK_UNLOCK(fb)
Definition flow.h:273
DecodeThreadVars * dtv
ThreadVars * tv
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
int PacketCopyDataOffset(Packet *p, uint32_t offset, const uint8_t *data, uint32_t datalen)
Copy data to Packet payload at given offset.
Definition decode.c:335
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition decode.c:258
void PacketFree(Packet *p)
Return a malloced packet.
Definition decode.c:219
uint16_t payload_len
@ UPDATE_DIR_BOTH
void StreamTcpSessionCleanup(TcpSession *ssn)
Session cleanup function. Does not free the ssn.
Definition stream-tcp.c:327
char family
Definition decode.h:113
Structure to hold thread specific data for all decode modules.
Definition decode.h:963
main detection engine ctx
Definition detect.h:932
uint8_t mpm_matcher
Definition detect.h:935
uint8_t flags
Definition detect.h:934
Signature * sig_list
Definition detect.h:941
FlowQueuePrivate spare_queue
Definition flow.h:544
FlowQueuePrivate work_queue
Definition flow.h:546
Flow data structure.
Definition flow.h:356
uint8_t proto
Definition flow.h:378
void * protoctx
Definition flow.h:441
uint8_t ip_verhl
Definition decode-ipv4.h:73
uint8_t ip_proto
Definition decode-ipv4.h:79
uint16_t ip_len
Definition decode-ipv4.h:75
SCTime_t ts
Definition decode.h:555
Address src
Definition decode.h:505
Port sp
Definition decode.h:508
struct Flow_ * flow
Definition decode.h:546
uint8_t * payload
Definition decode.h:605
uint16_t payload_len
Definition decode.h:606
uint32_t flags
Definition decode.h:544
Address dst
Definition decode.h:506
uint8_t proto
Definition decode.h:523
Port dp
Definition decode.h:516
Signature container.
Definition detect.h:668
uint32_t id
Definition detect.h:713
uint16_t th_win
Definition decode-tcp.h:156
uint8_t th_offx2
Definition decode-tcp.h:154
uint16_t th_dport
Definition decode-tcp.h:151
uint8_t th_flags
Definition decode-tcp.h:155
uint16_t th_sport
Definition decode-tcp.h:150
StreamingBufferConfig sbcnf
Definition stream-tcp.h:89
StreamingBuffer sb
Per thread variable structure.
Definition threadvars.h:58
uint16_t uh_len
Definition decode-udp.h:45
uint16_t uh_dport
Definition decode-udp.h:44
uint16_t uh_sport
Definition decode-udp.h:43
#define SCNtohs(x)
#define BUG_ON(x)
#define str(s)
const char * name
#define SCEnter(...)
Definition util-debug.h:277
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition util-debug.h:225
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define unlikely(expr)
uint8_t * BasicSearch(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, uint16_t needle_len)
Basic search improved. Limits are better handled, so it doesn't start searches that wont fit in the r...
Definition util-spm-bs.c:47
int StreamingBufferAppend(StreamingBuffer *sb, const StreamingBufferConfig *cfg, StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len)
#define STREAMING_BUFFER_INITIALIZER
SCTime_t TimeGet(void)
Definition util-time.c:152
int TestHelperBufferToFile(const char *name, const uint8_t *data, size_t size)
writes the contents of a buffer into a file
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Packet * UTHBuildPacketIPV6Real(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst, uint16_t sport, uint16_t dport)
UTHBuildPacketReal is a function that create tcp/udp packets for unittests specifying ip and port sou...
int UTHPacketMatchSig(Packet *p, const char *sig)
int UTHRemoveSessionFromFlow(Flow *f)
void * UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len)
int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets)
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
int UTHAddSessionToFlow(Flow *f, uint32_t ts_isn, uint32_t tc_isn)
void UTHSetIPV4Hdr(Packet *p, IPV4Hdr *ip4h)
Packet * UTHBuildPacketSrcDstPorts(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, uint16_t sport, uint16_t dport)
UTHBuildPacketSrcDstPorts is a wrapper that build packets specifying src and dst ports and defaulting...
Packet * UTHBuildPacketSrcDst(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst)
UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs and defaulting ports.
int UTHAppendSigs(DetectEngineCtx *de_ctx, const char *sigs[], int numsigs)
UTHAppendSigs: Add sigs to the detection_engine checking for errors.
int UTHMatchPacketsWithResults(DetectEngineCtx *de_ctx, Packet **p, int num_packets, uint32_t sids[], uint32_t *results, int numsigs)
void UTHAssignFlow(Packet *p, Flow *f)
Packet * UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst, uint16_t sport, uint16_t dport)
UTHBuildPacketReal is a function that create tcp/udp packets for unittests specifying ip and port sou...
int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[], uint32_t results[], int numsigs)
UTHCheckPacketMatches: function to check if a packet match some sids.
void UTHFreeFlow(Flow *flow)
Flow * TestHelperBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
int UTHGenericTest(Packet **pkt, int numpkts, const char *sigs[], uint32_t sids[], uint32_t *results, int numsigs)
UTHGenericTest: function that perform a generic check taking care of as maximum common unittest eleme...
void UTHRegisterTests(void)
Packet * UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize)
UTHBuildPacketFromEth is a wrapper that build a packet for the rawbytes.
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself.
int UTHAddStreamToFlow(Flow *f, int direction, uint8_t *data, uint32_t data_len)
Packet * UTHBuildPacketIPV6SrcDst(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst)
UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs and defaulting ports (IPV6)
int UTHParseSignature(const char *str, bool expect)
parser a sig and see if the expected result is correct
int UTHPacketMatchSigMpm(Packet *p, char *sig, uint16_t mpm_type)
void UTHSetTCPHdr(Packet *p, TCPHdr *tcph)
void UTHSetIPV6Hdr(Packet *p, IPV6Hdr *ip6h)
uint32_t UTHBuildPacketOfFlows(uint32_t start, uint32_t end, uint8_t dir)
uint32_t UTHSetIPv4Address(const char *str)
return the uint32_t for a ipv4 address string
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)