summaryrefslogtreecommitdiffstats
path: root/src/detect-engine-iponly.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/detect-engine-iponly.c')
-rw-r--r--src/detect-engine-iponly.c2453
1 files changed, 2453 insertions, 0 deletions
diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c
new file mode 100644
index 0000000..03b4649
--- /dev/null
+++ b/src/detect-engine-iponly.c
@@ -0,0 +1,2453 @@
+/* Copyright (C) 2007-2022 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Victor Julien <victor@inliniac.net>
+ * \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
+ *
+ * Signatures that only inspect IP addresses are processed here
+ * We use radix trees for src dst ipv4 and ipv6 addresses
+ * This radix trees hold information for subnets and hosts in a
+ * hierarchical distribution
+ */
+
+#include "suricata-common.h"
+#include "detect.h"
+#include "decode.h"
+#include "flow.h"
+
+#include "detect-parse.h"
+#include "detect-engine.h"
+
+#include "detect-engine-siggroup.h"
+#include "detect-engine-address.h"
+#include "detect-engine-proto.h"
+#include "detect-engine-port.h"
+#include "detect-engine-mpm.h"
+#include "detect-engine-build.h"
+
+#include "detect-engine-threshold.h"
+#include "detect-engine-iponly.h"
+#include "detect-threshold.h"
+#include "util-classification-config.h"
+#include "util-rule-vars.h"
+
+#include "flow-util.h"
+#include "util-debug.h"
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+#include "util-print.h"
+#include "util-byte.h"
+#include "util-profiling.h"
+#include "util-validate.h"
+#include "util-cidr.h"
+
+#ifdef OS_WIN32
+#include <winsock.h>
+#else
+#include <netinet/in.h>
+#endif /* OS_WIN32 */
+
+/**
+ * \brief This function creates a new IPOnlyCIDRItem
+ *
+ * \retval IPOnlyCIDRItem address of the new instance
+ */
+static IPOnlyCIDRItem *IPOnlyCIDRItemNew(void)
+{
+ SCEnter();
+ IPOnlyCIDRItem *item = NULL;
+
+ item = SCMalloc(sizeof(IPOnlyCIDRItem));
+ if (unlikely(item == NULL))
+ SCReturnPtr(NULL, "IPOnlyCIDRItem");
+ memset(item, 0, sizeof(IPOnlyCIDRItem));
+
+ SCReturnPtr(item, "IPOnlyCIDRItem");
+}
+
+static uint8_t IPOnlyCIDRItemCompare(IPOnlyCIDRItem *head,
+ IPOnlyCIDRItem *item)
+{
+ uint8_t i = 0;
+ for (; i < head->netmask / 32 || i < 1; i++) {
+ if (item->ip[i] < head->ip[i])
+ //if (*(uint8_t *)(item->ip + i) < *(uint8_t *)(head->ip + i))
+ return 1;
+ }
+ return 0;
+}
+
+//declaration for using it already
+static IPOnlyCIDRItem *IPOnlyCIDRItemInsert(IPOnlyCIDRItem *head,
+ IPOnlyCIDRItem *item);
+
+static int InsertRange(
+ IPOnlyCIDRItem **pdd, IPOnlyCIDRItem *dd, const uint32_t first_in, const uint32_t last_in)
+{
+ DEBUG_VALIDATE_BUG_ON(dd == NULL);
+ DEBUG_VALIDATE_BUG_ON(pdd == NULL);
+
+ uint32_t first = first_in;
+ uint32_t last = last_in;
+
+ dd->netmask = 32;
+ /* Find the maximum netmask starting from current address first
+ * and not crossing last.
+ * To extend the mask, we need to start from a power of 2.
+ * And we need to pay attention to unsigned overflow back to 0.0.0.0
+ */
+ while (dd->netmask > 0 && (first & (1UL << (32 - dd->netmask))) == 0 &&
+ first + (1UL << (32 - (dd->netmask - 1))) - 1 <= last) {
+ dd->netmask--;
+ }
+ dd->ip[0] = htonl(first);
+ first += 1UL << (32 - dd->netmask);
+ // case whatever-255.255.255.255 looping to 0.0.0.0/0
+ while (first <= last && first != 0) {
+ IPOnlyCIDRItem *new = IPOnlyCIDRItemNew();
+ if (new == NULL)
+ goto error;
+ new->negated = dd->negated;
+ new->family = dd->family;
+ new->netmask = 32;
+ while (new->netmask > 0 && (first & (1UL << (32 - new->netmask))) == 0 &&
+ first + (1UL << (32 - (new->netmask - 1))) - 1 <= last) {
+ new->netmask--;
+ }
+ new->ip[0] = htonl(first);
+ first += 1UL << (32 - new->netmask);
+ dd = IPOnlyCIDRItemInsert(dd, new);
+ }
+ // update head of list
+ *pdd = dd;
+ return 0;
+error:
+ return -1;
+}
+
+/**
+ * \internal
+ * \brief Parses an ipv4/ipv6 address string and updates the result into the
+ * IPOnlyCIDRItem instance sent as the argument.
+ *
+ * \param pdd Double pointer to the IPOnlyCIDRItem instance which should be updated
+ * with the address (in cidr) details from the parsed ip string.
+ * \param str Pointer to address string that has to be parsed.
+ *
+ * \retval 0 On successfully parsing the address string.
+ * \retval -1 On failure.
+ */
+static int IPOnlyCIDRItemParseSingle(IPOnlyCIDRItem **pdd, const char *str)
+{
+ char buf[256] = "";
+ char *ip = NULL, *ip2 = NULL;
+ char *mask = NULL;
+ int r = 0;
+ IPOnlyCIDRItem *dd = *pdd;
+
+ while (*str != '\0' && *str == ' ')
+ str++;
+
+ SCLogDebug("str %s", str);
+ strlcpy(buf, str, sizeof(buf));
+ ip = buf;
+
+ /* first handle 'any' */
+ if (strcasecmp(str, "any") == 0) {
+ /* if any, insert 0.0.0.0/0 and ::/0 as well */
+ SCLogDebug("adding 0.0.0.0/0 and ::/0 as we\'re handling \'any\'");
+
+ IPOnlyCIDRItemParseSingle(&dd, "0.0.0.0/0");
+ BUG_ON(dd->family == 0);
+
+ dd->next = IPOnlyCIDRItemNew();
+ if (dd->next == NULL)
+ goto error;
+
+ IPOnlyCIDRItemParseSingle(&dd->next, "::/0");
+ BUG_ON(dd->family == 0);
+
+ SCLogDebug("address is \'any\'");
+ return 0;
+ }
+
+ /* handle the negation case */
+ if (ip[0] == '!') {
+ dd->negated = (dd->negated)? 0 : 1;
+ ip++;
+ }
+
+ /* see if the address is an ipv4 or ipv6 address */
+ if ((strchr(str, ':')) == NULL) {
+ /* IPv4 Address */
+ struct in_addr in;
+
+ dd->family = AF_INET;
+
+ if ((mask = strchr(ip, '/')) != NULL) {
+ /* 1.2.3.4/xxx format (either dotted or cidr notation */
+ ip[mask - ip] = '\0';
+ mask++;
+ uint32_t netmask = 0;
+ size_t u = 0;
+
+ if ((strchr (mask, '.')) == NULL) {
+ /* 1.2.3.4/24 format */
+
+ for (u = 0; u < strlen(mask); u++) {
+ if(!isdigit((unsigned char)mask[u]))
+ goto error;
+ }
+
+ uint8_t cidr;
+ if (StringParseU8RangeCheck(&cidr, 10, 0, (const char *)mask, 0, 32) < 0)
+ goto error;
+
+ dd->netmask = cidr;
+ netmask = CIDRGet(cidr);
+ } else {
+ /* 1.2.3.4/255.255.255.0 format */
+ r = inet_pton(AF_INET, mask, &in);
+ if (r <= 0)
+ goto error;
+
+ int cidr = CIDRFromMask(in.s_addr);
+ if (cidr < 0)
+ goto error;
+
+ dd->netmask = (uint8_t)cidr;
+ }
+
+ r = inet_pton(AF_INET, ip, &in);
+ if (r <= 0)
+ goto error;
+
+ dd->ip[0] = in.s_addr & netmask;
+
+ } else if ((ip2 = strchr(ip, '-')) != NULL) {
+ /* 1.2.3.4-1.2.3.6 range format */
+ ip[ip2 - ip] = '\0';
+ ip2++;
+
+ uint32_t first, last;
+
+ r = inet_pton(AF_INET, ip, &in);
+ if (r <= 0)
+ goto error;
+ first = SCNtohl(in.s_addr);
+
+ r = inet_pton(AF_INET, ip2, &in);
+ if (r <= 0)
+ goto error;
+ last = SCNtohl(in.s_addr);
+
+ /* a > b is illegal, a = b is ok */
+ if (first > last)
+ goto error;
+
+ SCLogDebug("Creating CIDR range for [%s - %s]", ip, ip2);
+ return InsertRange(pdd, dd, first, last);
+ } else {
+ /* 1.2.3.4 format */
+ r = inet_pton(AF_INET, ip, &in);
+ if (r <= 0)
+ goto error;
+
+ /* single host */
+ dd->ip[0] = in.s_addr;
+ dd->netmask = 32;
+ }
+ } else {
+ /* IPv6 Address */
+ struct in6_addr in6, mask6;
+ uint32_t ip6addr[4], netmask[4];
+
+ dd->family = AF_INET6;
+
+ if ((mask = strchr(ip, '/')) != NULL) {
+ mask[0] = '\0';
+ mask++;
+
+ r = inet_pton(AF_INET6, ip, &in6);
+ if (r <= 0)
+ goto error;
+
+ /* Format is cidr val */
+ if (StringParseU8RangeCheck(&dd->netmask, 10, 0,
+ (const char *)mask, 0, 128) < 0) {
+ goto error;
+ }
+
+ memcpy(&ip6addr, &in6.s6_addr, sizeof(ip6addr));
+ CIDRGetIPv6(dd->netmask, &mask6);
+ memcpy(&netmask, &mask6.s6_addr, sizeof(netmask));
+
+ dd->ip[0] = ip6addr[0] & netmask[0];
+ dd->ip[1] = ip6addr[1] & netmask[1];
+ dd->ip[2] = ip6addr[2] & netmask[2];
+ dd->ip[3] = ip6addr[3] & netmask[3];
+ } else {
+ r = inet_pton(AF_INET6, ip, &in6);
+ if (r <= 0)
+ goto error;
+
+ memcpy(dd->ip, &in6.s6_addr, sizeof(dd->ip));
+ dd->netmask = 128;
+ }
+
+ }
+
+ BUG_ON(dd->family == 0);
+ return 0;
+
+error:
+ return -1;
+}
+
+/**
+ * \brief Setup a single address string, parse it and add the resulting
+ * Address items in cidr format to the list of gh
+ *
+ * \param gh Pointer to the IPOnlyCIDRItem list Head to which the
+ * resulting Address-Range(s) from the parsed ip string has to
+ * be added.
+ * \param s Pointer to the ip address string to be parsed.
+ *
+ * \retval 0 On success.
+ * \retval -1 On failure.
+ */
+static int IPOnlyCIDRItemSetup(IPOnlyCIDRItem **gh, char *s)
+{
+ SCLogDebug("gh %p, s %s", *gh, s);
+
+ /* parse the address */
+ if (IPOnlyCIDRItemParseSingle(gh, s) == -1) {
+ SCLogError("address parsing error \"%s\"", s);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+
+
+/**
+ * \brief This function insert a IPOnlyCIDRItem
+ * to a list of IPOnlyCIDRItems sorted by netmask
+ * ascending
+ * \param head Pointer to the head of IPOnlyCIDRItems list
+ * \param item Pointer to the item to insert in the list
+ *
+ * \retval IPOnlyCIDRItem address of the new head if apply
+ */
+static IPOnlyCIDRItem *IPOnlyCIDRItemInsertReal(IPOnlyCIDRItem *head,
+ IPOnlyCIDRItem *item)
+{
+ IPOnlyCIDRItem *it, *prev = NULL;
+
+ if (item == NULL)
+ return head;
+
+ /* Compare with the head */
+ if (item->netmask < head->netmask || (item->netmask == head->netmask && IPOnlyCIDRItemCompare(head, item))) {
+ item->next = head;
+ return item;
+ }
+
+ if (item->netmask == head->netmask && !IPOnlyCIDRItemCompare(head, item)) {
+ item->next = head->next;
+ head->next = item;
+ return head;
+ }
+
+ for (prev = it = head;
+ it != NULL && it->netmask < item->netmask;
+ it = it->next)
+ prev = it;
+
+ if (it == NULL) {
+ prev->next = item;
+ item->next = NULL;
+ } else {
+ item->next = it;
+ prev->next = item;
+ }
+
+ return head;
+}
+
+/**
+ * \brief This function insert a IPOnlyCIDRItem list
+ * to a list of IPOnlyCIDRItems sorted by netmask
+ * ascending
+ * \param head Pointer to the head of IPOnlyCIDRItems list
+ * \param item Pointer to the list of items to insert in the list
+ *
+ * \retval IPOnlyCIDRItem address of the new head if apply
+ */
+static IPOnlyCIDRItem *IPOnlyCIDRItemInsert(IPOnlyCIDRItem *head,
+ IPOnlyCIDRItem *item)
+{
+ IPOnlyCIDRItem *it, *prev = NULL;
+
+ /* The first element */
+ if (head == NULL) {
+ SCLogDebug("Head is NULL to insert item (%p)",item);
+ return item;
+ }
+
+ if (item == NULL) {
+ SCLogDebug("Item is NULL");
+ return head;
+ }
+
+ SCLogDebug("Inserting item(%p)->netmask %u head %p", item, item->netmask, head);
+
+ prev = item;
+ while (prev != NULL) {
+ it = prev->next;
+
+ /* Separate from the item list */
+ prev->next = NULL;
+
+ //SCLogDebug("Before:");
+ //IPOnlyCIDRListPrint(head);
+ head = IPOnlyCIDRItemInsertReal(head, prev);
+ //SCLogDebug("After:");
+ //IPOnlyCIDRListPrint(head);
+ prev = it;
+ }
+
+ return head;
+}
+
+/**
+ * \brief This function free a IPOnlyCIDRItem list
+ * \param tmphead Pointer to the list
+ */
+void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead)
+{
+ SCEnter();
+#ifdef DEBUG
+ uint32_t i = 0;
+#endif
+ IPOnlyCIDRItem *it, *next = NULL;
+
+ if (tmphead == NULL) {
+ SCLogDebug("temphead is NULL");
+ return;
+ }
+
+ it = tmphead;
+ next = it->next;
+
+ while (it != NULL) {
+#ifdef DEBUG
+ i++;
+ SCLogDebug("Item(%p) %"PRIu32" removed", it, i);
+#endif
+ SCFree(it);
+ it = next;
+
+ if (next != NULL)
+ next = next->next;
+ }
+ SCReturn;
+}
+
+/**
+ * \brief This function update a list of IPOnlyCIDRItems
+ * setting the signature internal id (signum) to "i"
+ *
+ * \param tmphead Pointer to the list
+ * \param i number of signature internal id
+ */
+static void IPOnlyCIDRListSetSigNum(IPOnlyCIDRItem *tmphead, SigIntId i)
+{
+ while (tmphead != NULL) {
+ tmphead->signum = i;
+ tmphead = tmphead->next;
+ }
+}
+
+#ifdef UNITTESTS
+/**
+ * \brief This function print a IPOnlyCIDRItem list
+ * \param tmphead Pointer to the head of IPOnlyCIDRItems list
+ */
+static void IPOnlyCIDRListPrint(IPOnlyCIDRItem *tmphead)
+{
+#ifdef DEBUG
+ uint32_t i = 0;
+
+ while (tmphead != NULL) {
+ i++;
+ SCLogDebug("Item %"PRIu32" has netmask %"PRIu8" negated:"
+ " %s; IP: %s; signum: %"PRIu32, i, tmphead->netmask,
+ (tmphead->negated) ? "yes":"no",
+ inet_ntoa(*(struct in_addr*)&tmphead->ip[0]),
+ tmphead->signum);
+ tmphead = tmphead->next;
+ }
+#endif
+}
+#endif
+
+/** \brief user data for storing signature id's in the radix tree
+ *
+ * Bit array representing signature internal id's (Signature::num).
+ */
+typedef struct SigNumArray_ {
+ uint8_t *array; /* bit array of sig nums */
+ uint32_t size; /* size in bytes of the array */
+} SigNumArray;
+
+/**
+ * \brief This function print a SigNumArray, it's used with the
+ * radix tree print function to help debugging
+ * \param tmp Pointer to the head of SigNumArray
+ */
+static void SigNumArrayPrint(void *tmp)
+{
+ SigNumArray *sna = (SigNumArray *)tmp;
+ for (uint32_t u = 0; u < sna->size; u++) {
+ uint8_t bitarray = sna->array[u];
+ for (uint8_t i = 0; i < 8; i++) {
+ if (bitarray & 0x01)
+ printf("%" PRIu32 " ", u * 8 + i);
+ bitarray = bitarray >> 1;
+ }
+ }
+}
+
+/**
+ * \brief This function creates a new SigNumArray with the
+ * size fixed to the io_ctx->max_idx
+ * \param de_ctx Pointer to the current detection context
+ * \param io_ctx Pointer to the current ip only context
+ *
+ * \retval SigNumArray address of the new instance
+ */
+static SigNumArray *SigNumArrayNew(DetectEngineCtx *de_ctx,
+ DetectEngineIPOnlyCtx *io_ctx)
+{
+ SigNumArray *new = SCMalloc(sizeof(SigNumArray));
+
+ if (unlikely(new == NULL)) {
+ FatalError("Fatal error encountered in SigNumArrayNew. Exiting...");
+ }
+ memset(new, 0, sizeof(SigNumArray));
+
+ new->array = SCMalloc(io_ctx->max_idx / 8 + 1);
+ if (new->array == NULL) {
+ exit(EXIT_FAILURE);
+ }
+
+ memset(new->array, 0, io_ctx->max_idx / 8 + 1);
+ new->size = io_ctx->max_idx / 8 + 1;
+
+ SCLogDebug("max idx= %u", io_ctx->max_idx);
+
+ return new;
+}
+
+/**
+ * \brief This function creates a new SigNumArray with the
+ * same data as the argument
+ *
+ * \param orig Pointer to the original SigNumArray to copy
+ *
+ * \retval SigNumArray address of the new instance
+ */
+static SigNumArray *SigNumArrayCopy(SigNumArray *orig)
+{
+ SigNumArray *new = SCMalloc(sizeof(SigNumArray));
+
+ if (unlikely(new == NULL)) {
+ FatalError("Fatal error encountered in SigNumArrayCopy. Exiting...");
+ }
+
+ memset(new, 0, sizeof(SigNumArray));
+ new->size = orig->size;
+
+ new->array = SCMalloc(orig->size);
+ if (new->array == NULL) {
+ exit(EXIT_FAILURE);
+ }
+
+ memcpy(new->array, orig->array, orig->size);
+ return new;
+}
+
+/**
+ * \brief This function free() a SigNumArray
+ * \param orig Pointer to the original SigNumArray to copy
+ */
+static void SigNumArrayFree(void *tmp)
+{
+ SigNumArray *sna = (SigNumArray *)tmp;
+
+ if (sna == NULL)
+ return;
+
+ if (sna->array != NULL)
+ SCFree(sna->array);
+
+ SCFree(sna);
+}
+
+/**
+ * \brief This function parses and return a list of IPOnlyCIDRItem
+ *
+ * \param s Pointer to the string of the addresses
+ * (in the format of signatures)
+ * \param negate flag to indicate if all this string is negated or not
+ *
+ * \retval 0 if success
+ * \retval -1 if fails
+ */
+static IPOnlyCIDRItem *IPOnlyCIDRListParse2(
+ const DetectEngineCtx *de_ctx, const char *s, int negate)
+{
+ size_t x = 0;
+ size_t u = 0;
+ int o_set = 0, n_set = 0, d_set = 0;
+ int depth = 0;
+ size_t size = strlen(s);
+ char address[8196] = "";
+ const char *rule_var_address = NULL;
+ char *temp_rule_var_address = NULL;
+ IPOnlyCIDRItem *head;
+ IPOnlyCIDRItem *subhead;
+ head = subhead = NULL;
+
+ SCLogDebug("s %s negate %s", s, negate ? "true" : "false");
+
+ for (u = 0, x = 0; u < size && x < sizeof(address); u++) {
+ address[x] = s[u];
+ x++;
+
+ if (!o_set && s[u] == '!') {
+ n_set = 1;
+ x--;
+ } else if (s[u] == '[') {
+ if (!o_set) {
+ o_set = 1;
+ x = 0;
+ }
+ depth++;
+ } else if (s[u] == ']') {
+ if (depth == 1) {
+ address[x - 1] = '\0';
+ x = 0;
+
+ if ( (subhead = IPOnlyCIDRListParse2(de_ctx, address,
+ (negate + n_set) % 2)) == NULL)
+ goto error;
+
+ head = IPOnlyCIDRItemInsert(head, subhead);
+ n_set = 0;
+ }
+ depth--;
+ } else if (depth == 0 && s[u] == ',') {
+ if (o_set == 1) {
+ o_set = 0;
+ } else if (d_set == 1) {
+ address[x - 1] = '\0';
+
+ rule_var_address = SCRuleVarsGetConfVar(de_ctx, address,
+ SC_RULE_VARS_ADDRESS_GROUPS);
+ if (rule_var_address == NULL)
+ goto error;
+
+ if ((negate + n_set) % 2) {
+ temp_rule_var_address = SCMalloc(strlen(rule_var_address) + 3);
+ if (unlikely(temp_rule_var_address == NULL)) {
+ goto error;
+ }
+
+ snprintf(temp_rule_var_address, strlen(rule_var_address) + 3,
+ "[%s]", rule_var_address);
+ } else {
+ temp_rule_var_address = SCStrdup(rule_var_address);
+ if (unlikely(temp_rule_var_address == NULL)) {
+ goto error;
+ }
+ }
+
+ subhead = IPOnlyCIDRListParse2(de_ctx, temp_rule_var_address,
+ (negate + n_set) % 2);
+ head = IPOnlyCIDRItemInsert(head, subhead);
+
+ d_set = 0;
+ n_set = 0;
+
+ SCFree(temp_rule_var_address);
+
+ } else {
+ address[x - 1] = '\0';
+
+ subhead = IPOnlyCIDRItemNew();
+ if (subhead == NULL)
+ goto error;
+
+ if (!((negate + n_set) % 2))
+ subhead->negated = 0;
+ else
+ subhead->negated = 1;
+
+ if (IPOnlyCIDRItemSetup(&subhead, address) < 0) {
+ IPOnlyCIDRListFree(subhead);
+ subhead = NULL;
+ goto error;
+ }
+ head = IPOnlyCIDRItemInsert(head, subhead);
+
+ n_set = 0;
+ }
+ x = 0;
+ } else if (depth == 0 && s[u] == '$') {
+ d_set = 1;
+ } else if (depth == 0 && u == size - 1) {
+ if (x == sizeof(address)) {
+ address[x - 1] = '\0';
+ } else {
+ address[x] = '\0';
+ }
+ x = 0;
+
+ if (d_set == 1) {
+ rule_var_address = SCRuleVarsGetConfVar(de_ctx, address,
+ SC_RULE_VARS_ADDRESS_GROUPS);
+ if (rule_var_address == NULL)
+ goto error;
+
+ if ((negate + n_set) % 2) {
+ temp_rule_var_address = SCMalloc(strlen(rule_var_address) + 3);
+ if (unlikely(temp_rule_var_address == NULL)) {
+ goto error;
+ }
+ snprintf(temp_rule_var_address, strlen(rule_var_address) + 3,
+ "[%s]", rule_var_address);
+ } else {
+ temp_rule_var_address = SCStrdup(rule_var_address);
+ if (unlikely(temp_rule_var_address == NULL)) {
+ goto error;
+ }
+ }
+ subhead = IPOnlyCIDRListParse2(de_ctx, temp_rule_var_address,
+ (negate + n_set) % 2);
+ head = IPOnlyCIDRItemInsert(head, subhead);
+
+ d_set = 0;
+
+ SCFree(temp_rule_var_address);
+ } else {
+ subhead = IPOnlyCIDRItemNew();
+ if (subhead == NULL)
+ goto error;
+
+ if (!((negate + n_set) % 2))
+ subhead->negated = 0;
+ else
+ subhead->negated = 1;
+
+ if (IPOnlyCIDRItemSetup(&subhead, address) < 0) {
+ IPOnlyCIDRListFree(subhead);
+ subhead = NULL;
+ goto error;
+ }
+ head = IPOnlyCIDRItemInsert(head, subhead);
+ }
+ n_set = 0;
+ }
+ }
+
+ return head;
+
+error:
+ SCLogError("Error parsing addresses");
+ return head;
+}
+
+
+/**
+ * \brief Parses an address group sent as a character string and updates the
+ * IPOnlyCIDRItem list
+ *
+ * \param gh Pointer to the IPOnlyCIDRItem list
+ * \param str Pointer to the character string containing the address group
+ * that has to be parsed.
+ *
+ * \retval 0 On success.
+ * \retval -1 On failure.
+ */
+static int IPOnlyCIDRListParse(const DetectEngineCtx *de_ctx, IPOnlyCIDRItem **gh, const char *str)
+{
+ SCLogDebug("gh %p, str %s", gh, str);
+
+ if (gh == NULL)
+ goto error;
+
+ *gh = IPOnlyCIDRListParse2(de_ctx, str, 0);
+ if (*gh == NULL) {
+ SCLogDebug("IPOnlyCIDRListParse2 returned null");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+
+/**
+ * \brief Parses an address group sent as a character string and updates the
+ * IPOnlyCIDRItem lists src and dst of the Signature *s
+ *
+ * \param s Pointer to the signature structure
+ * \param addrstr Pointer to the character string containing the address group
+ * that has to be parsed.
+ * \param flag to indicate if we are parsing the src string or the dst string
+ *
+ * \retval 0 On success.
+ * \retval -1 On failure.
+ */
+int IPOnlySigParseAddress(const DetectEngineCtx *de_ctx,
+ Signature *s, const char *addrstr, char flag)
+{
+ SCLogDebug("Address Group \"%s\" to be parsed now", addrstr);
+
+ /* pass on to the address(list) parser */
+ if (flag == 0) {
+ if (strcasecmp(addrstr, "any") == 0) {
+ s->flags |= SIG_FLAG_SRC_ANY;
+ if (IPOnlyCIDRListParse(de_ctx, &s->cidr_src, "[0.0.0.0/0,::/0]") < 0)
+ goto error;
+
+ } else if (IPOnlyCIDRListParse(de_ctx, &s->cidr_src, (char *)addrstr) < 0) {
+ goto error;
+ }
+
+ /* IPOnlyCIDRListPrint(s->CidrSrc); */
+ } else {
+ if (strcasecmp(addrstr, "any") == 0) {
+ s->flags |= SIG_FLAG_DST_ANY;
+ if (IPOnlyCIDRListParse(de_ctx, &s->cidr_dst, "[0.0.0.0/0,::/0]") < 0)
+ goto error;
+
+ } else if (IPOnlyCIDRListParse(de_ctx, &s->cidr_dst, (char *)addrstr) < 0) {
+ goto error;
+ }
+
+ /* IPOnlyCIDRListPrint(s->CidrDst); */
+ }
+
+ return 0;
+
+error:
+ SCLogError("failed to parse addresses");
+ return -1;
+}
+
+/**
+ * \brief Setup the IP Only detection engine context
+ *
+ * \param de_ctx Pointer to the current detection engine
+ * \param io_ctx Pointer to the current ip only detection engine
+ */
+void IPOnlyInit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx)
+{
+ io_ctx->tree_ipv4src = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint);
+ io_ctx->tree_ipv4dst = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint);
+ io_ctx->tree_ipv6src = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint);
+ io_ctx->tree_ipv6dst = SCRadixCreateRadixTree(SigNumArrayFree, SigNumArrayPrint);
+
+ io_ctx->sig_mapping = SCCalloc(1, de_ctx->sig_array_len * sizeof(uint32_t));
+ if (io_ctx->sig_mapping == NULL) {
+ FatalError("Unable to allocate iponly signature tracking area");
+ }
+ io_ctx->sig_mapping_size = 0;
+}
+
+SigIntId IPOnlyTrackSigNum(DetectEngineIPOnlyCtx *io_ctx, SigIntId signum)
+{
+ SigIntId loc = io_ctx->sig_mapping_size;
+ io_ctx->sig_mapping[loc] = signum;
+ io_ctx->sig_mapping_size++;
+ return loc;
+}
+
+/**
+ * \brief Print stats of the IP Only engine
+ *
+ * \param de_ctx Pointer to the current detection engine
+ * \param io_ctx Pointer to the current ip only detection engine
+ */
+void IPOnlyPrint(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx)
+{
+ /* XXX: how are we going to print the stats now? */
+}
+
+/**
+ * \brief Deinitialize the IP Only detection engine context
+ *
+ * \param de_ctx Pointer to the current detection engine
+ * \param io_ctx Pointer to the current ip only detection engine
+ */
+void IPOnlyDeinit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx)
+{
+
+ if (io_ctx == NULL)
+ return;
+
+ if (io_ctx->tree_ipv4src != NULL)
+ SCRadixReleaseRadixTree(io_ctx->tree_ipv4src);
+ io_ctx->tree_ipv4src = NULL;
+
+ if (io_ctx->tree_ipv4dst != NULL)
+ SCRadixReleaseRadixTree(io_ctx->tree_ipv4dst);
+ io_ctx->tree_ipv4dst = NULL;
+
+ if (io_ctx->tree_ipv6src != NULL)
+ SCRadixReleaseRadixTree(io_ctx->tree_ipv6src);
+ io_ctx->tree_ipv6src = NULL;
+
+ if (io_ctx->tree_ipv6dst != NULL)
+ SCRadixReleaseRadixTree(io_ctx->tree_ipv6dst);
+ io_ctx->tree_ipv6dst = NULL;
+
+ if (io_ctx->sig_mapping != NULL)
+ SCFree(io_ctx->sig_mapping);
+ io_ctx->sig_mapping = NULL;
+}
+
+static inline
+int IPOnlyMatchCompatSMs(ThreadVars *tv,
+ DetectEngineThreadCtx *det_ctx,
+ Signature *s, Packet *p)
+{
+ KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH);
+ SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH];
+ if (smd) {
+ while (1) {
+ DEBUG_VALIDATE_BUG_ON(!(sigmatch_table[smd->type].flags & SIGMATCH_IPONLY_COMPAT));
+ KEYWORD_PROFILING_START;
+ if (sigmatch_table[smd->type].Match(det_ctx, p, s, smd->ctx) > 0) {
+ KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
+ if (smd->is_last)
+ break;
+ smd++;
+ continue;
+ }
+ KEYWORD_PROFILING_END(det_ctx, smd->type, 0);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/**
+ * \brief Match a packet against the IP Only detection engine contexts
+ *
+ * \param de_ctx Pointer to the current detection engine
+ * \param io_ctx Pointer to the current ip only detection engine
+ * \param io_ctx Pointer to the current ip only thread detection engine
+ * \param p Pointer to the Packet to match against
+ */
+void IPOnlyMatchPacket(ThreadVars *tv, const DetectEngineCtx *de_ctx,
+ DetectEngineThreadCtx *det_ctx, const DetectEngineIPOnlyCtx *io_ctx, Packet *p)
+{
+ SigNumArray *src = NULL;
+ SigNumArray *dst = NULL;
+ void *user_data_src = NULL, *user_data_dst = NULL;
+
+ SCEnter();
+
+ if (p->src.family == AF_INET) {
+ (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)&GET_IPV4_SRC_ADDR_U32(p),
+ io_ctx->tree_ipv4src, &user_data_src);
+ } else if (p->src.family == AF_INET6) {
+ (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_SRC_ADDR(p),
+ io_ctx->tree_ipv6src, &user_data_src);
+ }
+
+ if (p->dst.family == AF_INET) {
+ (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)&GET_IPV4_DST_ADDR_U32(p),
+ io_ctx->tree_ipv4dst, &user_data_dst);
+ } else if (p->dst.family == AF_INET6) {
+ (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_DST_ADDR(p),
+ io_ctx->tree_ipv6dst, &user_data_dst);
+ }
+
+ src = user_data_src;
+ dst = user_data_dst;
+
+ if (src == NULL || dst == NULL)
+ SCReturn;
+
+ uint32_t u;
+ for (u = 0; u < src->size; u++) {
+ SCLogDebug("And %"PRIu8" & %"PRIu8, src->array[u], dst->array[u]);
+
+ uint8_t bitarray = dst->array[u] & src->array[u];
+
+ /* We have to move the logic of the signature checking
+ * to the main detect loop, in order to apply the
+ * priority of actions (pass, drop, reject, alert) */
+ if (bitarray) {
+ /* We have a match :) Let's see from which signum's */
+ uint8_t i = 0;
+
+ for (; i < 8; i++, bitarray = bitarray >> 1) {
+ if (bitarray & 0x01) {
+ Signature *s = de_ctx->sig_array[io_ctx->sig_mapping[u * 8 + i]];
+
+ if ((s->proto.flags & DETECT_PROTO_IPV4) && !PKT_IS_IPV4(p)) {
+ SCLogDebug("ip version didn't match");
+ continue;
+ }
+ if ((s->proto.flags & DETECT_PROTO_IPV6) && !PKT_IS_IPV6(p)) {
+ SCLogDebug("ip version didn't match");
+ continue;
+ }
+
+ if (DetectProtoContainsProto(&s->proto, IP_GET_IPPROTO(p)) == 0) {
+ SCLogDebug("proto didn't match");
+ continue;
+ }
+
+ /* check the source & dst port in the sig */
+ if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) {
+ if (!(s->flags & SIG_FLAG_DP_ANY)) {
+ if (p->flags & PKT_IS_FRAGMENT)
+ continue;
+
+ DetectPort *dport = DetectPortLookupGroup(s->dp,p->dp);
+ if (dport == NULL) {
+ SCLogDebug("dport didn't match.");
+ continue;
+ }
+ }
+ if (!(s->flags & SIG_FLAG_SP_ANY)) {
+ if (p->flags & PKT_IS_FRAGMENT)
+ continue;
+
+ DetectPort *sport = DetectPortLookupGroup(s->sp,p->sp);
+ if (sport == NULL) {
+ SCLogDebug("sport didn't match.");
+ continue;
+ }
+ }
+ } else if ((s->flags & (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) != (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) {
+ SCLogDebug("port-less protocol and sig needs ports");
+ continue;
+ }
+
+ if (!IPOnlyMatchCompatSMs(tv, det_ctx, s, p)) {
+ continue;
+ }
+
+ SCLogDebug("Signum %"PRIu32" match (sid: %"PRIu32", msg: %s)",
+ u * 8 + i, s->id, s->msg);
+
+ if (s->sm_arrays[DETECT_SM_LIST_POSTMATCH] != NULL) {
+ KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_POSTMATCH);
+ SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_POSTMATCH];
+
+ SCLogDebug("running match functions, sm %p", smd);
+
+ if (smd != NULL) {
+ while (1) {
+ KEYWORD_PROFILING_START;
+ (void)sigmatch_table[smd->type].Match(det_ctx, p, s, smd->ctx);
+ KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
+ if (smd->is_last)
+ break;
+ smd++;
+ }
+ }
+ }
+ AlertQueueAppend(det_ctx, s, p, 0, 0);
+ }
+ }
+ }
+ }
+ SCReturn;
+}
+
+/**
+ * \brief Build the radix trees from the lists of parsed addresses in CIDR format
+ * the result should be 4 radix trees: src/dst ipv4 and src/dst ipv6
+ * holding SigNumArrays, each of them with a hierarchical relation
+ * of subnets and hosts
+ *
+ * \param de_ctx Pointer to the current detection engine
+ */
+void IPOnlyPrepare(DetectEngineCtx *de_ctx)
+{
+ SCLogDebug("Preparing Final Lists");
+
+ /*
+ IPOnlyCIDRListPrint((de_ctx->io_ctx).ip_src);
+ IPOnlyCIDRListPrint((de_ctx->io_ctx).ip_dst);
+ */
+
+ IPOnlyCIDRItem *src, *dst;
+ SCRadixNode *node = NULL;
+
+ /* Prepare Src radix trees */
+ for (src = (de_ctx->io_ctx).ip_src; src != NULL; ) {
+ if (src->family == AF_INET) {
+ /*
+ SCLogDebug("To IPv4");
+ SCLogDebug("Item has netmask %"PRIu16" negated: %s; IP: %s; "
+ "signum: %"PRIu16, src->netmask,
+ (src->negated) ? "yes":"no",
+ inet_ntoa( *(struct in_addr*)&src->ip[0]),
+ src->signum);
+ */
+
+ void *user_data = NULL;
+ if (src->netmask == 32)
+ (void)SCRadixFindKeyIPV4ExactMatch((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv4src,
+ &user_data);
+ else
+ (void)SCRadixFindKeyIPV4Netblock((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv4src,
+ src->netmask, &user_data);
+ if (user_data == NULL) {
+ SCLogDebug("Exact match not found");
+
+ /** Not found, look if there's a subnet of this range with
+ * bigger netmask */
+ (void)SCRadixFindKeyIPV4BestMatch((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv4src,
+ &user_data);
+ if (user_data == NULL) {
+ SCLogDebug("best match not found");
+
+ /* Not found, insert a new one */
+ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx);
+
+ /* Update the sig */
+ uint8_t tmp = (uint8_t)(1 << (src->signum % 8));
+
+ if (src->negated > 0)
+ /* Unset it */
+ sna->array[src->signum / 8] &= ~tmp;
+ else
+ /* Set it */
+ sna->array[src->signum / 8] |= tmp;
+
+ if (src->netmask == 32)
+ node = SCRadixAddKeyIPV4((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv4src, sna);
+ else
+ node = SCRadixAddKeyIPV4Netblock((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv4src,
+ sna, src->netmask);
+
+ if (node == NULL)
+ SCLogError("Error inserting in the "
+ "src ipv4 radix tree");
+ } else {
+ SCLogDebug("Best match found");
+
+ /* Found, copy the sig num table, add this signum and insert */
+ SigNumArray *sna = NULL;
+ sna = SigNumArrayCopy((SigNumArray *) user_data);
+
+ /* Update the sig */
+ uint8_t tmp = (uint8_t)(1 << (src->signum % 8));
+
+ if (src->negated > 0)
+ /* Unset it */
+ sna->array[src->signum / 8] &= ~tmp;
+ else
+ /* Set it */
+ sna->array[src->signum / 8] |= tmp;
+
+ if (src->netmask == 32)
+ node = SCRadixAddKeyIPV4((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv4src, sna);
+ else
+ node = SCRadixAddKeyIPV4Netblock((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv4src, sna,
+ src->netmask);
+
+ if (node == NULL) {
+ char tmpstr[64];
+ PrintInet(src->family, &src->ip[0], tmpstr, sizeof(tmpstr));
+ SCLogError("Error inserting in the"
+ " src ipv4 radix tree ip %s netmask %" PRIu8,
+ tmpstr, src->netmask);
+ //SCRadixPrintTree((de_ctx->io_ctx).tree_ipv4src);
+ exit(-1);
+ }
+ }
+ } else {
+ SCLogDebug("Exact match found");
+
+ /* it's already inserted. Update it */
+ SigNumArray *sna = (SigNumArray *)user_data;
+
+ /* Update the sig */
+ uint8_t tmp = (uint8_t)(1 << (src->signum % 8));
+
+ if (src->negated > 0)
+ /* Unset it */
+ sna->array[src->signum / 8] &= ~tmp;
+ else
+ /* Set it */
+ sna->array[src->signum / 8] |= tmp;
+ }
+ } else if (src->family == AF_INET6) {
+ SCLogDebug("To IPv6");
+
+ void *user_data = NULL;
+ if (src->netmask == 128)
+ (void)SCRadixFindKeyIPV6ExactMatch((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv6src,
+ &user_data);
+ else
+ (void)SCRadixFindKeyIPV6Netblock((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv6src,
+ src->netmask, &user_data);
+
+ if (user_data == NULL) {
+ /* Not found, look if there's a subnet of this range with bigger netmask */
+ (void)SCRadixFindKeyIPV6BestMatch((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv6src,
+ &user_data);
+
+ if (user_data == NULL) {
+ /* Not found, insert a new one */
+ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx);
+
+ /* Update the sig */
+ uint8_t tmp = (uint8_t)(1 << (src->signum % 8));
+
+ if (src->negated > 0)
+ /* Unset it */
+ sna->array[src->signum / 8] &= ~tmp;
+ else
+ /* Set it */
+ sna->array[src->signum / 8] |= tmp;
+
+ if (src->netmask == 128)
+ node = SCRadixAddKeyIPV6((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv6src, sna);
+ else
+ node = SCRadixAddKeyIPV6Netblock((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv6src,
+ sna, src->netmask);
+ if (node == NULL)
+ SCLogError("Error inserting in the src "
+ "ipv6 radix tree");
+ } else {
+ /* Found, copy the sig num table, add this signum and insert */
+ SigNumArray *sna = NULL;
+ sna = SigNumArrayCopy((SigNumArray *)user_data);
+
+ /* Update the sig */
+ uint8_t tmp = (uint8_t)(1 << (src->signum % 8));
+ if (src->negated > 0)
+ /* Unset it */
+ sna->array[src->signum / 8] &= ~tmp;
+ else
+ /* Set it */
+ sna->array[src->signum / 8] |= tmp;
+
+ if (src->netmask == 128)
+ node = SCRadixAddKeyIPV6((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv6src, sna);
+ else
+ node = SCRadixAddKeyIPV6Netblock((uint8_t *)&src->ip[0],
+ (de_ctx->io_ctx).tree_ipv6src,
+ sna, src->netmask);
+ if (node == NULL)
+ SCLogError("Error inserting in the src "
+ "ipv6 radix tree");
+ }
+ } else {
+ /* it's already inserted. Update it */
+ SigNumArray *sna = (SigNumArray *)user_data;
+
+ /* Update the sig */
+ uint8_t tmp = (uint8_t)(1 << (src->signum % 8));
+ if (src->negated > 0)
+ /* Unset it */
+ sna->array[src->signum / 8] &= ~tmp;
+ else
+ /* Set it */
+ sna->array[src->signum / 8] |= tmp;
+ }
+ }
+ IPOnlyCIDRItem *tmpaux = src;
+ src = src->next;
+ SCFree(tmpaux);
+ }
+
+ SCLogDebug("dsts:");
+
+ /* Prepare Dst radix trees */
+ for (dst = (de_ctx->io_ctx).ip_dst; dst != NULL; ) {
+ if (dst->family == AF_INET) {
+
+ SCLogDebug("To IPv4");
+ SCLogDebug("Item has netmask %"PRIu8" negated: %s; IP: %s; signum:"
+ " %"PRIu32"", dst->netmask, (dst->negated)?"yes":"no",
+ inet_ntoa(*(struct in_addr*)&dst->ip[0]), dst->signum);
+
+ void *user_data = NULL;
+ if (dst->netmask == 32)
+ (void) SCRadixFindKeyIPV4ExactMatch((uint8_t *) &dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv4dst,
+ &user_data);
+ else
+ (void) SCRadixFindKeyIPV4Netblock((uint8_t *) &dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv4dst,
+ dst->netmask,
+ &user_data);
+
+ if (user_data == NULL) {
+ SCLogDebug("Exact match not found");
+
+ /**
+ * Not found, look if there's a subnet of this range
+ * with bigger netmask
+ */
+ (void) SCRadixFindKeyIPV4BestMatch((uint8_t *)&dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv4dst,
+ &user_data);
+ if (user_data == NULL) {
+ SCLogDebug("Best match not found");
+
+ /** Not found, insert a new one */
+ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx);
+
+ /** Update the sig */
+ uint8_t tmp = (uint8_t)(1 << (dst->signum % 8));
+ if (dst->negated > 0)
+ /** Unset it */
+ sna->array[dst->signum / 8] &= ~tmp;
+ else
+ /** Set it */
+ sna->array[dst->signum / 8] |= tmp;
+
+ if (dst->netmask == 32)
+ node = SCRadixAddKeyIPV4((uint8_t *)&dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv4dst, sna);
+ else
+ node = SCRadixAddKeyIPV4Netblock((uint8_t *)&dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv4dst,
+ sna, dst->netmask);
+
+ if (node == NULL)
+ SCLogError("Error inserting in the dst "
+ "ipv4 radix tree");
+ } else {
+ SCLogDebug("Best match found");
+
+ /* Found, copy the sig num table, add this signum and insert */
+ SigNumArray *sna = NULL;
+ sna = SigNumArrayCopy((SigNumArray *) user_data);
+
+ /* Update the sig */
+ uint8_t tmp = (uint8_t)(1 << (dst->signum % 8));
+ if (dst->negated > 0)
+ /* Unset it */
+ sna->array[dst->signum / 8] &= ~tmp;
+ else
+ /* Set it */
+ sna->array[dst->signum / 8] |= tmp;
+
+ if (dst->netmask == 32)
+ node = SCRadixAddKeyIPV4((uint8_t *)&dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv4dst, sna);
+ else
+ node = SCRadixAddKeyIPV4Netblock((uint8_t *)&dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv4dst,
+ sna, dst->netmask);
+
+ if (node == NULL)
+ SCLogError("Error inserting in the dst "
+ "ipv4 radix tree");
+ }
+ } else {
+ SCLogDebug("Exact match found");
+
+ /* it's already inserted. Update it */
+ SigNumArray *sna = (SigNumArray *)user_data;
+
+ /* Update the sig */
+ uint8_t tmp = (uint8_t)(1 << (dst->signum % 8));
+ if (dst->negated > 0)
+ /* Unset it */
+ sna->array[dst->signum / 8] &= ~tmp;
+ else
+ /* Set it */
+ sna->array[dst->signum / 8] |= tmp;
+ }
+ } else if (dst->family == AF_INET6) {
+ SCLogDebug("To IPv6");
+
+ void *user_data = NULL;
+ if (dst->netmask == 128)
+ (void) SCRadixFindKeyIPV6ExactMatch((uint8_t *)&dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv6dst,
+ &user_data);
+ else
+ (void) SCRadixFindKeyIPV6Netblock((uint8_t *)&dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv6dst,
+ dst->netmask, &user_data);
+
+ if (user_data == NULL) {
+ /** Not found, look if there's a subnet of this range with
+ * bigger netmask
+ */
+ (void) SCRadixFindKeyIPV6BestMatch((uint8_t *)&dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv6dst,
+ &user_data);
+
+ if (user_data == NULL) {
+ /* Not found, insert a new one */
+ SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx);
+
+ /* Update the sig */
+ uint8_t tmp = (uint8_t)(1 << (dst->signum % 8));
+ if (dst->negated > 0)
+ /* Unset it */
+ sna->array[dst->signum / 8] &= ~tmp;
+ else
+ /* Set it */
+ sna->array[dst->signum / 8] |= tmp;
+
+ if (dst->netmask == 128)
+ node = SCRadixAddKeyIPV6((uint8_t *)&dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv6dst, sna);
+ else
+ node = SCRadixAddKeyIPV6Netblock((uint8_t *)&dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv6dst,
+ sna, dst->netmask);
+
+ if (node == NULL)
+ SCLogError("Error inserting in the dst "
+ "ipv6 radix tree");
+ } else {
+ /* Found, copy the sig num table, add this signum and insert */
+ SigNumArray *sna = NULL;
+ sna = SigNumArrayCopy((SigNumArray *)user_data);
+
+ /* Update the sig */
+ uint8_t tmp = (uint8_t)(1 << (dst->signum % 8));
+ if (dst->negated > 0)
+ /* Unset it */
+ sna->array[dst->signum / 8] &= ~tmp;
+ else
+ /* Set it */
+ sna->array[dst->signum / 8] |= tmp;
+
+ if (dst->netmask == 128)
+ node = SCRadixAddKeyIPV6((uint8_t *)&dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv6dst, sna);
+ else
+ node = SCRadixAddKeyIPV6Netblock((uint8_t *)&dst->ip[0],
+ (de_ctx->io_ctx).tree_ipv6dst,
+ sna, dst->netmask);
+
+ if (node == NULL)
+ SCLogError("Error inserting in the dst "
+ "ipv6 radix tree");
+ }
+ } else {
+ /* it's already inserted. Update it */
+ SigNumArray *sna = (SigNumArray *)user_data;
+
+ /* Update the sig */
+ uint8_t tmp = (uint8_t)(1 << (dst->signum % 8));
+ if (dst->negated > 0)
+ /* Unset it */
+ sna->array[dst->signum / 8] &= ~tmp;
+ else
+ /* Set it */
+ sna->array[dst->signum / 8] |= tmp;
+ }
+ }
+ IPOnlyCIDRItem *tmpaux = dst;
+ dst = dst->next;
+ SCFree(tmpaux);
+ }
+
+ /* print all the trees: for debugging it might print too much info
+ SCLogDebug("Radix tree src ipv4:");
+ SCRadixPrintTree((de_ctx->io_ctx).tree_ipv4src);
+ SCLogDebug("Radix tree src ipv6:");
+ SCRadixPrintTree((de_ctx->io_ctx).tree_ipv6src);
+ SCLogDebug("__________________");
+
+ SCLogDebug("Radix tree dst ipv4:");
+ SCRadixPrintTree((de_ctx->io_ctx).tree_ipv4dst);
+ SCLogDebug("Radix tree dst ipv6:");
+ SCRadixPrintTree((de_ctx->io_ctx).tree_ipv6dst);
+ SCLogDebug("__________________");
+ */
+}
+
+/**
+ * \brief Add a signature to the lists of Addresses in CIDR format (sorted)
+ * this step is necessary to build the radix tree with a hierarchical
+ * relation between nodes
+ * \param de_ctx Pointer to the current detection engine context
+ * \param de_ctx Pointer to the current ip only detection engine contest
+ * \param s Pointer to the current signature
+ */
+void IPOnlyAddSignature(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx,
+ Signature *s)
+{
+ if (!(s->type == SIG_TYPE_IPONLY))
+ return;
+
+ SigIntId mapped_signum = IPOnlyTrackSigNum(io_ctx, s->num);
+ SCLogDebug("Adding IPs from rule: %" PRIu32 " (%s) as %" PRIu32 " mapped to %" PRIu32 "\n",
+ s->id, s->msg, s->num, mapped_signum);
+ /* Set the internal signum to the list before merging */
+ IPOnlyCIDRListSetSigNum(s->cidr_src, mapped_signum);
+
+ IPOnlyCIDRListSetSigNum(s->cidr_dst, mapped_signum);
+
+ /**
+ * ipv4 and ipv6 are mixed, but later we will separate them into
+ * different trees
+ */
+ io_ctx->ip_src = IPOnlyCIDRItemInsert(io_ctx->ip_src, s->cidr_src);
+ io_ctx->ip_dst = IPOnlyCIDRItemInsert(io_ctx->ip_dst, s->cidr_dst);
+
+ if (mapped_signum > io_ctx->max_idx)
+ io_ctx->max_idx = mapped_signum;
+
+ /** no longer ref to this, it's in the table now */
+ s->cidr_src = NULL;
+ s->cidr_dst = NULL;
+}
+
+#ifdef UNITTESTS
+/**
+ * \test check that we set a Signature as IPOnly because it has no rule
+ * option appending a SigMatch and no port is fixed
+ */
+
+static int IPOnlyTestSig01(void)
+{
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+ FAIL_IF(de_ctx == NULL);
+ de_ctx->flags |= DE_QUIET;
+
+ Signature *s = SigInit(de_ctx,"alert tcp any any -> any any (sid:400001; rev:1;)");
+ FAIL_IF(s == NULL);
+
+ FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0);
+ SigFree(de_ctx, s);
+ DetectEngineCtxFree(de_ctx);
+ PASS;
+}
+
+/**
+ * \test check that we don't set a Signature as IPOnly because it has no rule
+ * option appending a SigMatch but a port is fixed
+ */
+
+static int IPOnlyTestSig02 (void)
+{
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+ FAIL_IF(de_ctx == NULL);
+ de_ctx->flags |= DE_QUIET;
+
+ Signature *s = SigInit(de_ctx,"alert tcp any any -> any 80 (sid:400001; rev:1;)");
+ FAIL_IF(s == NULL);
+
+ FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0);
+ SigFree(de_ctx, s);
+ DetectEngineCtxFree(de_ctx);
+ PASS;
+}
+
+/**
+ * \test check that we set don't set a Signature as IPOnly
+ * because it has rule options appending a SigMatch like content, and pcre
+ */
+
+static int IPOnlyTestSig03 (void)
+{
+ int result = 1;
+ DetectEngineCtx *de_ctx;
+ Signature *s=NULL;
+
+ de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL)
+ goto end;
+ de_ctx->flags |= DE_QUIET;
+
+ /* combination of pcre and content */
+ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pcre and content) \"; content:\"php\"; pcre:\"/require(_once)?/i\"; classtype:misc-activity; sid:400001; rev:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+ if(SignatureIsIPOnly(de_ctx, s))
+ {
+ printf("got a IPOnly signature (content): ");
+ result=0;
+ }
+ SigFree(de_ctx, s);
+
+ /* content */
+ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (content) \"; content:\"match something\"; classtype:misc-activity; sid:400001; rev:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+ if(SignatureIsIPOnly(de_ctx, s))
+ {
+ printf("got a IPOnly signature (content): ");
+ result=0;
+ }
+ SigFree(de_ctx, s);
+
+ /* uricontent */
+ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (uricontent) \"; uricontent:\"match something\"; classtype:misc-activity; sid:400001; rev:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+ if(SignatureIsIPOnly(de_ctx, s))
+ {
+ printf("got a IPOnly signature (uricontent): ");
+ result=0;
+ }
+ SigFree(de_ctx, s);
+
+ /* pcre */
+ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pcre) \"; pcre:\"/e?idps rule[sz]/i\"; classtype:misc-activity; sid:400001; rev:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+ if(SignatureIsIPOnly(de_ctx, s))
+ {
+ printf("got a IPOnly signature (pcre): ");
+ result=0;
+ }
+ SigFree(de_ctx, s);
+
+ /* flow */
+ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flow) \"; flow:to_server; classtype:misc-activity; sid:400001; rev:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+ if(SignatureIsIPOnly(de_ctx, s))
+ {
+ printf("got a IPOnly signature (flow): ");
+ result=0;
+ }
+ SigFree(de_ctx, s);
+
+ /* dsize */
+ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (dsize) \"; dsize:100; classtype:misc-activity; sid:400001; rev:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+ if(SignatureIsIPOnly(de_ctx, s))
+ {
+ printf("got a IPOnly signature (dsize): ");
+ result=0;
+ }
+ SigFree(de_ctx, s);
+
+ /* flowbits */
+ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flowbits) \"; flowbits:unset; classtype:misc-activity; sid:400001; rev:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+ if(SignatureIsIPOnly(de_ctx, s))
+ {
+ printf("got a IPOnly signature (flowbits): ");
+ result=0;
+ }
+ SigFree(de_ctx, s);
+
+ /* flowvar */
+ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flowvar) \"; pcre:\"/(?<flow_var>.*)/i\"; flowvar:var,\"str\"; classtype:misc-activity; sid:400001; rev:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+ if(SignatureIsIPOnly(de_ctx, s))
+ {
+ printf("got a IPOnly signature (flowvar): ");
+ result=0;
+ }
+ SigFree(de_ctx, s);
+
+ /* pktvar */
+ s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pktvar) \"; pcre:\"/(?<pkt_var>.*)/i\"; pktvar:var,\"str\"; classtype:misc-activity; sid:400001; rev:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+ if(SignatureIsIPOnly(de_ctx, s))
+ {
+ printf("got a IPOnly signature (pktvar): ");
+ result=0;
+ }
+ SigFree(de_ctx, s);
+
+end:
+ if (de_ctx != NULL)
+ DetectEngineCtxFree(de_ctx);
+ return result;
+}
+
+/**
+ * \test
+ */
+static int IPOnlyTestSig04 (void)
+{
+ int result = 1;
+
+ IPOnlyCIDRItem *head = NULL;
+ IPOnlyCIDRItem *new;
+
+ new = IPOnlyCIDRItemNew();
+ new->netmask= 10;
+
+ head = IPOnlyCIDRItemInsert(head, new);
+
+ new = IPOnlyCIDRItemNew();
+ new->netmask= 11;
+
+ head = IPOnlyCIDRItemInsert(head, new);
+
+ new = IPOnlyCIDRItemNew();
+ new->netmask= 9;
+
+ head = IPOnlyCIDRItemInsert(head, new);
+
+ new = IPOnlyCIDRItemNew();
+ new->netmask= 10;
+
+ head = IPOnlyCIDRItemInsert(head, new);
+
+ new = IPOnlyCIDRItemNew();
+ new->netmask= 10;
+
+ head = IPOnlyCIDRItemInsert(head, new);
+
+ IPOnlyCIDRListPrint(head);
+ new = head;
+ if (new->netmask != 9) {
+ result = 0;
+ goto end;
+ }
+ new = new->next;
+ if (new->netmask != 10) {
+ result = 0;
+ goto end;
+ }
+ new = new->next;
+ if (new->netmask != 10) {
+ result = 0;
+ goto end;
+ }
+ new = new->next;
+ if (new->netmask != 10) {
+ result = 0;
+ goto end;
+ }
+ new = new->next;
+ if (new->netmask != 11) {
+ result = 0;
+ goto end;
+ }
+
+end:
+ IPOnlyCIDRListFree(head);
+ return result;
+}
+
+/**
+ * \test Test a set of ip only signatures making use a lot of
+ * addresses for src and dst (all should match)
+ */
+static int IPOnlyTestSig05(void)
+{
+ int result = 0;
+ uint8_t *buf = (uint8_t *)"Hi all!";
+ uint16_t buflen = strlen((char *)buf);
+
+ uint8_t numpkts = 1;
+ uint8_t numsigs = 7;
+
+ Packet *p[1];
+
+ p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
+
+ const char *sigs[numsigs];
+ sigs[0]= "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)";
+ sigs[1]= "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)";
+ sigs[2]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
+ sigs[3]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
+ sigs[4]= "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
+ sigs[5]= "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
+ sigs[6]= "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)";
+
+ /* Sid numbers (we could extract them from the sig) */
+ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
+ uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1};
+
+ result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
+
+ UTHFreePackets(p, numpkts);
+
+ return result;
+}
+
+/**
+ * \test Test a set of ip only signatures making use a lot of
+ * addresses for src and dst (none should match)
+ */
+static int IPOnlyTestSig06(void)
+{
+ int result = 0;
+ uint8_t *buf = (uint8_t *)"Hi all!";
+ uint16_t buflen = strlen((char *)buf);
+
+ uint8_t numpkts = 1;
+ uint8_t numsigs = 7;
+
+ Packet *p[1];
+
+ p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "80.58.0.33", "195.235.113.3");
+
+ const char *sigs[numsigs];
+ sigs[0]= "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)";
+ sigs[1]= "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)";
+ sigs[2]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
+ sigs[3]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
+ sigs[4]= "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
+ sigs[5]= "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
+ sigs[6]= "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)";
+
+ /* Sid numbers (we could extract them from the sig) */
+ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
+ uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0};
+
+ result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
+
+ UTHFreePackets(p, numpkts);
+
+ return result;
+}
+
+/* \todo fix it. We have disabled this unittest because 599 exposes 608,
+ * which is why these unittests fail. When we fix 608, we need to renable
+ * these sigs */
+#if 0
+/**
+ * \test Test a set of ip only signatures making use a lot of
+ * addresses for src and dst (all should match)
+ */
+static int IPOnlyTestSig07(void)
+{
+ int result = 0;
+ uint8_t *buf = (uint8_t *)"Hi all!";
+ uint16_t buflen = strlen((char *)buf);
+
+ uint8_t numpkts = 1;
+ uint8_t numsigs = 7;
+
+ Packet *p[1];
+
+ p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
+
+ char *sigs[numsigs];
+ sigs[0]= "alert tcp 192.168.1.5 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)";
+ sigs[1]= "alert tcp [192.168.1.2,192.168.1.5,192.168.1.4] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)";
+ sigs[2]= "alert tcp [192.168.1.0/24,!192.168.1.1] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
+ sigs[3]= "alert tcp [192.0.0.0/8,!192.168.0.0/16,192.168.1.0/24,!192.168.1.1] any -> [192.168.1.0/24,!192.168.1.5] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
+ sigs[4]= "alert tcp any any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
+ sigs[5]= "alert tcp any any -> [192.168.0.0/16,!192.168.1.0/24,192.168.1.1] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
+ sigs[6]= "alert tcp [78.129.202.0/24,192.168.1.5,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> 192.168.1.1 any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */
+
+ /* Sid numbers (we could extract them from the sig) */
+ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
+ uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1};
+
+ result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
+
+ UTHFreePackets(p, numpkts);
+
+ return result;
+}
+#endif
+
+/**
+ * \test Test a set of ip only signatures making use a lot of
+ * addresses for src and dst (none should match)
+ */
+static int IPOnlyTestSig08(void)
+{
+ int result = 0;
+ uint8_t *buf = (uint8_t *)"Hi all!";
+ uint16_t buflen = strlen((char *)buf);
+
+ uint8_t numpkts = 1;
+ uint8_t numsigs = 7;
+
+ Packet *p[1];
+
+ p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"192.168.1.1","192.168.1.5");
+
+ const char *sigs[numsigs];
+ sigs[0]= "alert tcp 192.168.1.5 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)";
+ sigs[1]= "alert tcp [192.168.1.2,192.168.1.5,192.168.1.4] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)";
+ sigs[2]= "alert tcp [192.168.1.0/24,!192.168.1.1] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
+ sigs[3]= "alert tcp [192.0.0.0/8,!192.168.0.0/16,192.168.1.0/24,!192.168.1.1] any -> [192.168.1.0/24,!192.168.1.5] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
+ sigs[4]= "alert tcp any any -> !192.168.1.5 any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
+ sigs[5]= "alert tcp any any -> [192.168.0.0/16,!192.168.1.0/24,192.168.1.1] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
+ sigs[6]= "alert tcp [78.129.202.0/24,192.168.1.5,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> 192.168.1.1 any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */
+
+ /* Sid numbers (we could extract them from the sig) */
+ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
+ uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0};
+
+ result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
+
+ UTHFreePackets(p, numpkts);
+
+ return result;
+}
+
+/**
+ * \test Test a set of ip only signatures making use a lot of
+ * addresses for src and dst (all should match)
+ */
+static int IPOnlyTestSig09(void)
+{
+ int result = 0;
+ uint8_t *buf = (uint8_t *)"Hi all!";
+ uint16_t buflen = strlen((char *)buf);
+
+ uint8_t numpkts = 1;
+ uint8_t numsigs = 7;
+
+ Packet *p[1];
+
+ p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562");
+
+ const char *sigs[numsigs];
+ sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)";
+ sigs[1]= "alert tcp any any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)";
+ sigs[2]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
+ sigs[3]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:0/96 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
+ sigs[4]= "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
+ sigs[5]= "alert tcp any any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
+ sigs[6]= "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)";
+
+ /* Sid numbers (we could extract them from the sig) */
+ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
+ uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1};
+
+ result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
+
+ UTHFreePackets(p, numpkts);
+
+ return result;
+}
+
+/**
+ * \test Test a set of ip only signatures making use a lot of
+ * addresses for src and dst (none should match)
+ */
+static int IPOnlyTestSig10(void)
+{
+ int result = 0;
+ uint8_t *buf = (uint8_t *)"Hi all!";
+ uint16_t buflen = strlen((char *)buf);
+
+ uint8_t numpkts = 1;
+ uint8_t numsigs = 7;
+
+ Packet *p[1];
+
+ p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565");
+
+ const char *sigs[numsigs];
+ sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)";
+ sigs[1]= "alert tcp any any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)";
+ sigs[2]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
+ sigs[3]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> !3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562/96 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
+ sigs[4]= "alert tcp !3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
+ sigs[5]= "alert tcp any any -> !3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
+ sigs[6]= "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> 3FFE:FFFF:7654:FEDB:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)";
+
+ /* Sid numbers (we could extract them from the sig) */
+ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
+ uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0};
+
+ result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
+
+ UTHFreePackets(p, numpkts);
+
+ return result;
+}
+
+/* \todo fix it. We have disabled this unittest because 599 exposes 608,
+ * which is why these unittests fail. When we fix 608, we need to renable
+ * these sigs */
+#if 0
+/**
+ * \test Test a set of ip only signatures making use a lot of
+ * addresses for src and dst (all should match) with ipv4 and ipv6 mixed
+ */
+static int IPOnlyTestSig11(void)
+{
+ int result = 0;
+ uint8_t *buf = (uint8_t *)"Hi all!";
+ uint16_t buflen = strlen((char *)buf);
+
+ uint8_t numpkts = 2;
+ uint8_t numsigs = 7;
+
+ Packet *p[2];
+
+ p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562");
+ p[1] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"192.168.1.1","192.168.1.5");
+
+ char *sigs[numsigs];
+ sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1 any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.5 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)";
+ sigs[1]= "alert tcp [192.168.1.1,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.4,192.168.1.5,!192.168.1.0/24] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.0/24] any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)";
+ sigs[2]= "alert tcp [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
+ sigs[3]= "alert tcp [3FFE:FFFF:0:0:0:0:0:0/32,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.0/24,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
+ sigs[4]= "alert tcp any any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
+ sigs[5]= "alert tcp any any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
+ sigs[6]= "alert tcp [78.129.202.0/24,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.0.0.0/8] any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */
+
+ /* Sid numbers (we could extract them from the sig) */
+ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
+ uint32_t results[2][7] = {{ 1, 1, 1, 1, 1, 1, 1}, { 1, 1, 1, 1, 1, 1, 1}};
+
+ result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
+
+ UTHFreePackets(p, numpkts);
+
+ return result;
+}
+#endif
+
+/**
+ * \test Test a set of ip only signatures making use a lot of
+ * addresses for src and dst (none should match) with ipv4 and ipv6 mixed
+ */
+static int IPOnlyTestSig12(void)
+{
+ int result = 0;
+ uint8_t *buf = (uint8_t *)"Hi all!";
+ uint16_t buflen = strlen((char *)buf);
+
+ uint8_t numpkts = 2;
+ uint8_t numsigs = 7;
+
+ Packet *p[2];
+
+ p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"3FBE:FFFF:7654:FEDA:1245:BA98:3210:4562","3FBE:FFFF:7654:FEDA:1245:BA98:3210:4565");
+ p[1] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"195.85.1.1","80.198.1.5");
+
+ const char *sigs[numsigs];
+ sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1 any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.5 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)";
+ sigs[1]= "alert tcp [192.168.1.1,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.4,192.168.1.5,!192.168.1.0/24] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.0/24] any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)";
+ sigs[2]= "alert tcp [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
+ sigs[3]= "alert tcp [3FFE:FFFF:0:0:0:0:0:0/32,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.0/24,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
+ sigs[4]= "alert tcp any any -> [!3FBE:FFFF:7654:FEDA:1245:BA98:3210:4565,!80.198.1.5] any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
+ sigs[5]= "alert tcp any any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
+ sigs[6]= "alert tcp [78.129.202.0/24,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.0.0.0/8] any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */
+
+ /* Sid numbers (we could extract them from the sig) */
+ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
+ uint32_t results[2][7] = {{ 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}};
+
+ result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
+
+ UTHFreePackets(p, numpkts);
+
+ return result;
+}
+
+static int IPOnlyTestSig13(void)
+{
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+ FAIL_IF(de_ctx == NULL);
+ de_ctx->flags |= DE_QUIET;
+
+ Signature *s = SigInit(de_ctx,
+ "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; "
+ "flowbits:set,myflow1; sid:1; rev:1;)");
+ FAIL_IF(s == NULL);
+
+ FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0);
+ SigFree(de_ctx, s);
+ DetectEngineCtxFree(de_ctx);
+ PASS;
+}
+
+static int IPOnlyTestSig14(void)
+{
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+ FAIL_IF(de_ctx == NULL);
+ de_ctx->flags |= DE_QUIET;
+
+ Signature *s = SigInit(de_ctx,
+ "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; "
+ "flowbits:set,myflow1; flowbits:isset,myflow2; sid:1; rev:1;)");
+ FAIL_IF(s == NULL);
+
+ FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 1);
+ SigFree(de_ctx, s);
+ DetectEngineCtxFree(de_ctx);
+ PASS;
+}
+
+static int IPOnlyTestSig15(void)
+{
+ int result = 0;
+ uint8_t *buf = (uint8_t *)"Hi all!";
+ uint16_t buflen = strlen((char *)buf);
+
+ uint8_t numpkts = 1;
+ uint8_t numsigs = 7;
+
+ Packet *p[1];
+ Flow f;
+ GenericVar flowvar;
+ memset(&f, 0, sizeof(Flow));
+ memset(&flowvar, 0, sizeof(GenericVar));
+ FLOW_INITIALIZE(&f);
+
+ p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
+
+ p[0]->flow = &f;
+ p[0]->flow->flowvar = &flowvar;
+ p[0]->flags |= PKT_HAS_FLOW;
+ p[0]->flowflags |= FLOW_PKT_TOSERVER;
+
+ const char *sigs[numsigs];
+ sigs[0]= "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; "
+ "flowbits:set,one; sid:1;)";
+ sigs[1]= "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; "
+ "flowbits:set,two; sid:2;)";
+ sigs[2]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; "
+ "flowbits:set,three; sid:3;)";
+ sigs[3]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; "
+ "flowbits:set,four; sid:4;)";
+ sigs[4]= "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; "
+ "flowbits:set,five; sid:5;)";
+ sigs[5]= "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; "
+ "flowbits:set,six; sid:6;)";
+ sigs[6]= "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 7)\"; "
+ "flowbits:set,seven; content:\"Hi all\"; sid:7;)";
+
+ /* Sid numbers (we could extract them from the sig) */
+ uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
+ uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1};
+
+ result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
+
+ UTHFreePackets(p, numpkts);
+
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+/**
+ * \brief Unittest to show #599. We fail to match if we have negated addresses.
+ */
+static int IPOnlyTestSig16(void)
+{
+ int result = 0;
+ uint8_t *buf = (uint8_t *)"Hi all!";
+ uint16_t buflen = strlen((char *)buf);
+
+ uint8_t numpkts = 1;
+ uint8_t numsigs = 2;
+
+ Packet *p[1];
+
+ p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "100.100.0.0", "50.0.0.0");
+
+ const char *sigs[numsigs];
+ sigs[0]= "alert tcp !100.100.0.1 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)";
+ sigs[1]= "alert tcp any any -> !50.0.0.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)";
+
+ /* Sid numbers (we could extract them from the sig) */
+ uint32_t sid[2] = { 1, 2};
+ uint32_t results[2] = { 1, 1};
+
+ result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
+
+ UTHFreePackets(p, numpkts);
+
+ return result;
+}
+
+/**
+ * \brief Unittest to show #611. Ports on portless protocols.
+ */
+static int IPOnlyTestSig17(void)
+{
+ int result = 0;
+ uint8_t *buf = (uint8_t *)"Hi all!";
+ uint16_t buflen = strlen((char *)buf);
+
+ uint8_t numpkts = 1;
+ uint8_t numsigs = 2;
+
+ Packet *p[1];
+
+ p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_ICMP, "100.100.0.0", "50.0.0.0");
+
+ const char *sigs[numsigs];
+ sigs[0]= "alert ip 100.100.0.0 80 -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)";
+ sigs[1]= "alert ip any any -> 50.0.0.0 123 (msg:\"Testing dst ip (sid 2)\"; sid:2;)";
+
+ uint32_t sid[2] = { 1, 2};
+ uint32_t results[2] = { 0, 0}; /* neither should match */
+
+ result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
+
+ UTHFreePackets(p, numpkts);
+
+ return result;
+}
+
+/**
+ * \brief Unittest to show #3568 -- IP address range handling
+ */
+static int IPOnlyTestSig18(void)
+{
+ int result = 0;
+ uint8_t *buf = (uint8_t *)"Hi all!";
+ uint16_t buflen = strlen((char *)buf);
+
+ uint8_t numpkts = 4;
+ uint8_t numsigs = 4;
+
+ Packet *p[4];
+
+ p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "10.10.10.1", "50.0.0.1");
+ p[1] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "220.10.10.1", "5.0.0.1");
+ p[2] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "0.0.0.1", "50.0.0.1");
+ p[3] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "255.255.255.254", "5.0.0.1");
+
+ const char *sigs[numsigs];
+ // really many IP addresses
+ sigs[0]= "alert ip 1.2.3.4-219.6.7.8 any -> any any (sid:1;)";
+ sigs[1]= "alert ip 51.2.3.4-253.1.2.3 any -> any any (sid:2;)";
+ sigs[2]= "alert ip 0.0.0.0-50.0.0.2 any -> any any (sid:3;)";
+ sigs[3]= "alert ip 50.0.0.0-255.255.255.255 any -> any any (sid:4;)";
+
+ uint32_t sid[4] = { 1, 2, 3, 4, };
+ uint32_t results[4][4] = {
+ { 1, 0, 1, 0, }, { 0, 1, 0, 1}, { 0, 0, 1, 0 }, { 0, 0, 0, 1}};
+
+ result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
+
+ UTHFreePackets(p, numpkts);
+
+ FAIL_IF(result != 1);
+
+ PASS;
+}
+
+/** \test build IP-only tree */
+static int IPOnlyTestBug5066v1(void)
+{
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+ FAIL_IF(de_ctx == NULL);
+ de_ctx->flags |= DE_QUIET;
+
+ Signature *s = DetectEngineAppendSig(
+ de_ctx, "alert ip [1.2.3.4/24,1.2.3.64/27] any -> any any (sid:1;)");
+ FAIL_IF_NULL(s);
+ s = DetectEngineAppendSig(de_ctx, "alert ip [1.2.3.4/24] any -> any any (sid:2;)");
+ FAIL_IF_NULL(s);
+
+ SigGroupBuild(de_ctx);
+
+ DetectEngineCtxFree(de_ctx);
+ PASS;
+}
+
+static int IPOnlyTestBug5066v2(void)
+{
+ IPOnlyCIDRItem *x = IPOnlyCIDRItemNew();
+ FAIL_IF_NULL(x);
+
+ FAIL_IF(IPOnlyCIDRItemParseSingle(&x, "1.2.3.4/24") != 0);
+
+ char ip[16];
+ PrintInet(AF_INET, (const void *)&x->ip[0], ip, sizeof(ip));
+ SCLogDebug("ip %s netmask %d", ip, x->netmask);
+
+ FAIL_IF_NOT(strcmp(ip, "1.2.3.0") == 0);
+ FAIL_IF_NOT(x->netmask == 24);
+
+ IPOnlyCIDRListFree(x);
+ PASS;
+}
+
+static int IPOnlyTestBug5066v3(void)
+{
+ IPOnlyCIDRItem *x = IPOnlyCIDRItemNew();
+ FAIL_IF_NULL(x);
+
+ FAIL_IF(IPOnlyCIDRItemParseSingle(&x, "1.2.3.64/26") != 0);
+
+ char ip[16];
+ PrintInet(AF_INET, (const void *)&x->ip[0], ip, sizeof(ip));
+ SCLogDebug("ip %s netmask %d", ip, x->netmask);
+
+ FAIL_IF_NOT(strcmp(ip, "1.2.3.64") == 0);
+ FAIL_IF_NOT(x->netmask == 26);
+
+ IPOnlyCIDRListFree(x);
+ PASS;
+}
+
+static int IPOnlyTestBug5066v4(void)
+{
+ IPOnlyCIDRItem *x = IPOnlyCIDRItemNew();
+ FAIL_IF_NULL(x);
+
+ FAIL_IF(IPOnlyCIDRItemParseSingle(&x, "2000::1:1/122") != 0);
+
+ char ip[64];
+ PrintInet(AF_INET6, (const void *)&x->ip, ip, sizeof(ip));
+ SCLogDebug("ip %s netmask %d", ip, x->netmask);
+
+ FAIL_IF_NOT(strcmp(ip, "2000:0000:0000:0000:0000:0000:0001:0000") == 0);
+ FAIL_IF_NOT(x->netmask == 122);
+
+ IPOnlyCIDRListFree(x);
+ PASS;
+}
+
+static int IPOnlyTestBug5066v5(void)
+{
+ IPOnlyCIDRItem *x = IPOnlyCIDRItemNew();
+ FAIL_IF_NULL(x);
+
+ FAIL_IF(IPOnlyCIDRItemParseSingle(&x, "2000::1:40/122") != 0);
+
+ char ip[64];
+ PrintInet(AF_INET6, (const void *)&x->ip, ip, sizeof(ip));
+ SCLogDebug("ip %s netmask %d", ip, x->netmask);
+
+ FAIL_IF_NOT(strcmp(ip, "2000:0000:0000:0000:0000:0000:0001:0040") == 0);
+ FAIL_IF_NOT(x->netmask == 122);
+
+ IPOnlyCIDRListFree(x);
+ PASS;
+}
+
+static int IPOnlyTestBug5168v1(void)
+{
+ IPOnlyCIDRItem *x = IPOnlyCIDRItemNew();
+ FAIL_IF_NULL(x);
+
+ FAIL_IF(IPOnlyCIDRItemParseSingle(&x, "1.2.3.64/0.0.0.0") != 0);
+
+ char ip[16];
+ PrintInet(AF_INET, (const void *)&x->ip[0], ip, sizeof(ip));
+ SCLogDebug("ip %s netmask %d", ip, x->netmask);
+
+ FAIL_IF_NOT(strcmp(ip, "0.0.0.0") == 0);
+ FAIL_IF_NOT(x->netmask == 0);
+
+ IPOnlyCIDRListFree(x);
+ PASS;
+}
+
+static int IPOnlyTestBug5168v2(void)
+{
+ IPOnlyCIDRItem *x = IPOnlyCIDRItemNew();
+ FAIL_IF_NULL(x);
+ FAIL_IF(IPOnlyCIDRItemParseSingle(&x, "0.0.0.5/0.0.0.5") != -1);
+ IPOnlyCIDRListFree(x);
+ PASS;
+}
+
+#endif /* UNITTESTS */
+
+void IPOnlyRegisterTests(void)
+{
+#ifdef UNITTESTS
+ UtRegisterTest("IPOnlyTestSig01", IPOnlyTestSig01);
+ UtRegisterTest("IPOnlyTestSig02", IPOnlyTestSig02);
+ UtRegisterTest("IPOnlyTestSig03", IPOnlyTestSig03);
+ UtRegisterTest("IPOnlyTestSig04", IPOnlyTestSig04);
+
+ UtRegisterTest("IPOnlyTestSig05", IPOnlyTestSig05);
+ UtRegisterTest("IPOnlyTestSig06", IPOnlyTestSig06);
+/* \todo fix it. We have disabled this unittest because 599 exposes 608,
+ * which is why these unittests fail. When we fix 608, we need to renable
+ * these sigs */
+#if 0
+ UtRegisterTest("IPOnlyTestSig07", IPOnlyTestSig07, 1);
+#endif
+ UtRegisterTest("IPOnlyTestSig08", IPOnlyTestSig08);
+
+ UtRegisterTest("IPOnlyTestSig09", IPOnlyTestSig09);
+ UtRegisterTest("IPOnlyTestSig10", IPOnlyTestSig10);
+/* \todo fix it. We have disabled this unittest because 599 exposes 608,
+ * which is why these unittests fail. When we fix 608, we need to renable
+ * these sigs */
+#if 0
+ UtRegisterTest("IPOnlyTestSig11", IPOnlyTestSig11, 1);
+#endif
+ UtRegisterTest("IPOnlyTestSig12", IPOnlyTestSig12);
+ UtRegisterTest("IPOnlyTestSig13", IPOnlyTestSig13);
+ UtRegisterTest("IPOnlyTestSig14", IPOnlyTestSig14);
+ UtRegisterTest("IPOnlyTestSig15", IPOnlyTestSig15);
+ UtRegisterTest("IPOnlyTestSig16", IPOnlyTestSig16);
+
+ UtRegisterTest("IPOnlyTestSig17", IPOnlyTestSig17);
+ UtRegisterTest("IPOnlyTestSig18", IPOnlyTestSig18);
+
+ UtRegisterTest("IPOnlyTestBug5066v1", IPOnlyTestBug5066v1);
+ UtRegisterTest("IPOnlyTestBug5066v2", IPOnlyTestBug5066v2);
+ UtRegisterTest("IPOnlyTestBug5066v3", IPOnlyTestBug5066v3);
+ UtRegisterTest("IPOnlyTestBug5066v4", IPOnlyTestBug5066v4);
+ UtRegisterTest("IPOnlyTestBug5066v5", IPOnlyTestBug5066v5);
+
+ UtRegisterTest("IPOnlyTestBug5168v1", IPOnlyTestBug5168v1);
+ UtRegisterTest("IPOnlyTestBug5168v2", IPOnlyTestBug5168v2);
+#endif
+
+ return;
+}
+