-/* Copyright (C) 2007-2010 Open Information Security Foundation
+/* Copyright (C) 2007-2020 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
* \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 adresses
+ * We use radix trees for src dst ipv4 and ipv6 addresses
* This radix trees hold information for subnets and hosts in a
* hierarchical distribution
*/
return 0;
}
+//declaration for using it already
+static IPOnlyCIDRItem *IPOnlyCIDRItemInsert(IPOnlyCIDRItem *head,
+ IPOnlyCIDRItem *item);
+
/**
* \internal
* \brief Parses an ipv4/ipv6 address string and updates the result into the
* IPOnlyCIDRItem instance sent as the argument.
*
- * \param dd Pointer to the IPOnlyCIDRItem instance which should be updated with
- * the address (in cidr) details from the parsed ip string.
+ * \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 *dd, const char *str)
+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++;
/* 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");
+ 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");
+ IPOnlyCIDRItemParseSingle(&dd->next, "::/0");
BUG_ON(dd->family == 0);
SCLogDebug("address is \'any\'");
ip[ip2 - ip] = '\0';
ip2++;
- uint32_t tmp_ip[4];
- uint32_t tmp_ip2[4];
uint32_t first, last;
r = inet_pton(AF_INET, ip, &in);
if (r <= 0)
goto error;
- tmp_ip[0] = in.s_addr;
+ first = SCNtohl(in.s_addr);
r = inet_pton(AF_INET, ip2, &in);
if (r <= 0)
goto error;
- tmp_ip2[0] = in.s_addr;
+ last = SCNtohl(in.s_addr);
/* a > b is illegal, a = b is ok */
- if (SCNtohl(tmp_ip[0]) > SCNtohl(tmp_ip2[0]))
+ if (first > last)
goto error;
- first = SCNtohl(tmp_ip[0]);
- last = SCNtohl(tmp_ip2[0]);
-
dd->netmask = 32;
dd->ip[0] =htonl(first);
if (first < last) {
- for (first++; first <= last; first++) {
+ SCLogDebug("Creating CIDR range for [%s - %s]", ip, ip2);
+ while ( first <= last) {
IPOnlyCIDRItem *new = IPOnlyCIDRItemNew();
if (new == NULL)
goto error;
- dd->next = new;
new->negated = dd->negated;
new->family= dd->family;
- new->netmask = dd->netmask;
+ new->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 (new->netmask > 0 &&
+ (first & (1UL << (32-new->netmask))) == 0 &&
+ first + (1UL << (32-(new->netmask-1))) - 1 <= last) {
+ new->netmask--;
+ }
new->ip[0] = htonl(first);
- dd = dd->next;
+ dd = IPOnlyCIDRItemInsert(dd, new);
+ first += 1UL << (32-new->netmask);
+ if (first == 0) {
+ //case whatever-255.255.255.255 looping to 0.0.0.0/0
+ break;
+ }
}
+ //update head of list
+ *pdd = dd;
}
} else {
* \retval 0 On success.
* \retval -1 On failure.
*/
-static int IPOnlyCIDRItemSetup(IPOnlyCIDRItem *gh, char *s)
+static int IPOnlyCIDRItemSetup(IPOnlyCIDRItem **gh, char *s)
{
- SCLogDebug("gh %p, s %s", gh, s);
+ SCLogDebug("gh %p, s %s", *gh, s);
/* parse the address */
if (IPOnlyCIDRItemParseSingle(gh, s) == -1) {
else
subhead->negated = 1;
- if (IPOnlyCIDRItemSetup(subhead, address) < 0) {
+ if (IPOnlyCIDRItemSetup(&subhead, address) < 0) {
IPOnlyCIDRListFree(subhead);
subhead = NULL;
goto error;
else
subhead->negated = 1;
- if (IPOnlyCIDRItemSetup(subhead, address) < 0) {
+ if (IPOnlyCIDRItemSetup(&subhead, address) < 0) {
IPOnlyCIDRListFree(subhead);
subhead = NULL;
goto error;
SCFree(tmpaux);
}
- /* print all the trees: for debuggin it might print too much info
+ /* 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:");
}
/**
- * \brief Add a signature to the lists of Adrresses in CIDR format (sorted)
+ * \brief Add a signature to the lists of Addresses in CIDR format (sorted)
* this step is necesary to build the radix tree with a hierarchical
* relation between nodes
* \param de_ctx Pointer to the current detection engine context
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;
+}
+
#endif /* UNITTESTS */
void IPOnlyRegisterTests(void)
UtRegisterTest("IPOnlyTestSig16", IPOnlyTestSig16);
UtRegisterTest("IPOnlyTestSig17", IPOnlyTestSig17);
+ UtRegisterTest("IPOnlyTestSig18", IPOnlyTestSig18);
#endif
return;