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