Project

General

Profile

Unittest Helper Functions

UTHBuildPacket Functions

Helper functions that return a generic packet to use on the unittests. If something fail, they will return NULL.

Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len,
uint16_t ipproto, char *src, char *dst,
uint16_t sport, uint16_t dport);

This function create a generic packet with the arguments of payload, payload_len, protocol (TCP/UDP/ICMP at the moment), source/dest IP addresses in ascii format, and ports. The rest of the functions with the prefix UTHBuildPacket are wrappers that call this function with some generic values.

Packet *UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint16_t ipproto);

For example, UTHBuildPacket() is the most complete and faster to use. It receive as argument the payload, payload_len and protocol. It will fill the ip addresses and ports with default values.

Packet *UTHBuildPacketSrcDst(uint8_t *payload, uint16_t payload_len, uint16_t ipproto, char *src_ip, char *dst_ip);

Another one is UTHBuildPacketSrcDst() that works similar to UTHBuildPacket() but you have to specify the IP src and dst addresses.

Packet *UTHBuildPacketSrcDstPorts(uint8_t *payload, uint16_t payload len, uint16_t ipproto, uint16_t src_port, uint16_t dst_port);

The same apply to UTHBuildPacketSrcDstPorts() but you have to specify ports instead of IP addresses.

void UTHFreePacket(Packet *);

This function is used to free packets created by the UTHBuildPacket*() family functions.

Other functions for building packets

Packet **UTHBuildPacketArrayFromEth(uint8_t *raw_eth[], int *pktsize, int numpkts);

UTHBuildPacketArrayFromEth is a wrapper that builds a packet from an array of packets in ethernet rawbytes. Hint: It also shares the flows.
As argument it takes an array of pointers to ethernet raw buffers, another array of sizes for each of the packets, and the total number of packets in the array. If fail, it will return NULL.

Packet *UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize);

UTHBuildPacketFromEth is a wrapper that build a packet from the raw bytes of an ethernet buffer. raw_eth is the pointer to the rawbytes containing an ethernet level packet.
pktsize holds the length used by the ethernet packet in the buffer. If fail, it will return NULL.

void UTHFreePackets(Packet **pkts, int numpkts);

This function will iterate the pkts array and free each of them. The number of packets at the array should be numpkts.

Matching Process

int UTHAppendSigs(DetectEngineCtx *de_ctx, char **sigs, int numsigs);

Before matching, you'll need to add some signatures to the Detection Engine Context. With this function, you can pass an array of signatures in the format char *sigs[numsigs]. sigs should be the array, and numsigs the number of signatures. This number should be equal to the number of sids (you should not repeat them because this is what results testing functions expect).

int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **pkts, int numpkts);

This function will try to match an array of packets with the signatures loaded at the Detection Engine Context(de_ctx). Note that the return value doesn't mean that we have a match, we have to check it later with PacketAlertCheck()

int UTHPacketMatchSig(Packet *p, char *sig);

This function try to match the signature sig with only one packet p. It will return 1 if match, 0 if not. It is useful when you want to match only one signature.

int UTHPacketMatchSigMpm(Packet *p, char *sig, uint16_t mpm_type);

Similar to UTHPacketMatchSig() but you can specify the Pattern Matcher type (b2g, b3g, wumanber).

int UTHCheckPacketMatchResults(Packet *p, uint32_t *sids, uint32_t *results, int numsids);

This function check if a packet p matched an array of sid numbers as expected. So you need to build an array of sids and an array of expected results, both of them with size of numsids. As an example, the results expected will be checked as follows:

sids[1] = 10;
if this sid should match, results[1] should be equal to 1, if not, it should be 0
results[1] = 1;
sigs[2] = 20;
if this sid should match, results[1] should be equal to 1, if not, it should be 0
results[2] = 0;

This function will return 1 only if all the signatures matches as expected. And 0 otherwise.
Note, be careful because this function just look at the packet, and it does no match, it's just a check. If you want to directly match and test, use UTHMatchPacketsWithResults()

int UTHMatchPacketsWithResults(DetectEngineCtx *de_ctx, Packet **pkts, int num_packets, uint32_t sids[], uint32_t *results, int numsigs);

This function will Match a packet or a array of packets against sigs of a de_ctx, checking that each signature match for certain packets.
de_ctx is the pointer to the Detection Engine with the signatures loaded before (for example with UTHAppendSigs() ). pkts is a pointer to the array of pointers to packets. num_packets is the number of packets in the array pkts. Then you need to specify the results with sids[] and results[]. But, if you have more than one packet, the results array become a matrix that a row for each packet represents all the sids match result. Like

pkts \ sids 1 2 3
p1 0 1 0 * For the packet 1 we expect to match only the sid 2
p2 1 0 1 *
For the packet 2 we expect to match sids 1 and 3
p3 0 0 1 ** For the packet 3 we expect to match only the sid 3

This function will return 1 only if all the signatures matches as expected. And 0 otherwise.

Generic test (all in one...)

int UTHGenericTest(Packet **pkts, int numpkts, char *sigs[], uint32_t sids[], uint32_t *results, int numsigs);

UTHGenericTest perfoms a generic check taking care of as maximum common unittest elements as possible. It will create a detection engine, append an array of signatures and check the expected results for each of them, it checks matches for an array of packets.
pkts is a pointer to the array of packets; numpkts is the number of packets to match; sigs points to an array of signatures to load; numsigs should be the number of signatures to load and check. This number will give the dimensions of results, sigs, and sids arrays; results is a pointer to an array of expected results, each of them (of the rows) corresponds to packets.
The size of results should be numpkts * numsigs * sizeof(uint16_t *)
Example:
result1[3] would mean if the pkt1 match the sid3
A table of results should be like the following:

pkts \ sids 1 2 3
p1 0 1 0 * For the packet 1 we expect to match only the sid 2
p2 1 0 1 *
For the packet 2 we expect to match sids 1 and 3
p3 0 0 1 ** For the packet 3 we expect to match only the sid 3

This function will return 1 only if all the signatures matches as expected. And 0 otherwise.

For a complete example of this function, have a look at DetectIdTestMatch01() located in the file detect-id.c