summaryrefslogtreecommitdiffstats
path: root/src/util-cidr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util-cidr.c')
-rw-r--r--src/util-cidr.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/src/util-cidr.c b/src/util-cidr.c
new file mode 100644
index 0000000..4e6e18d
--- /dev/null
+++ b/src/util-cidr.c
@@ -0,0 +1,157 @@
+/* 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>
+ *
+ * CIDR utility functions
+ */
+
+#include "suricata-common.h"
+#include "util-cidr.h"
+#include "util-debug.h"
+#include "util-unittest.h"
+
+/** \brief Turn 32 bit mask into CIDR
+ *
+ * \retval cidr The cidr value or -1 if the netmask can't be expressed as cidr
+ */
+int CIDRFromMask(uint32_t netmask)
+{
+ netmask = ntohl(netmask);
+ if (netmask == 0) {
+ return 0;
+ }
+ int p = 0;
+ bool seen_1 = false;
+ while (netmask > 0) {
+ if (netmask & 1) {
+ seen_1 = true;
+ p++;
+ } else {
+ if (seen_1) {
+ return -1;
+ }
+ }
+ netmask >>= 1;
+ }
+ return p;
+}
+
+uint32_t CIDRGet(int cidr)
+{
+ if (cidr <= 0 || cidr > 32)
+ return 0;
+ uint32_t netmask = htonl(0xFFFFFFFF << (32UL - (uint32_t)cidr));
+ SCLogDebug("CIDR %d -> netmask %08X", cidr, netmask);
+ return netmask;
+}
+
+/**
+ * \brief Creates a cidr ipv6 netblock, based on the cidr netblock value.
+ *
+ * For example if we send a cidr of 7 as argument, an ipv6 address
+ * mask of the value FE:00:00:00:00:00:00:00 is created and updated
+ * in the argument struct in6_addr *in6.
+ *
+ * \todo I think for the final section: while (cidr > 0), we can simply
+ * replace it with a
+ * if (cidr > 0) {
+ * in6->s6_addr[i] = -1 << (8 - cidr);
+ *
+ * \param cidr The value of the cidr.
+ * \param in6 Pointer to an ipv6 address structure(struct in6_addr) which will
+ * hold the cidr netblock result.
+ */
+void CIDRGetIPv6(int cidr, struct in6_addr *in6)
+{
+ int i = 0;
+
+ memset(in6, 0, sizeof(struct in6_addr));
+
+ while (cidr > 8) {
+ in6->s6_addr[i] = 0xff;
+ cidr -= 8;
+ i++;
+ }
+
+ while (cidr > 0) {
+ in6->s6_addr[i] |= 0x80;
+ if (--cidr > 0)
+ in6->s6_addr[i] = in6->s6_addr[i] >> 1;
+ }
+}
+
+#ifdef UNITTESTS
+
+static int CIDRFromMaskTest01(void)
+{
+ struct in_addr in;
+ int v = inet_pton(AF_INET, "255.255.255.0", &in);
+
+ FAIL_IF(v <= 0);
+ FAIL_IF_NOT(24 == CIDRFromMask(in.s_addr));
+
+ PASS;
+}
+
+static int CIDRFromMaskTest02(void)
+{
+ struct in_addr in;
+ int v = inet_pton(AF_INET, "255.255.0.42", &in);
+
+ FAIL_IF(v <= 0);
+ FAIL_IF_NOT(-1 == CIDRFromMask(in.s_addr));
+
+ PASS;
+}
+
+static int CIDRFromMaskTest03(void)
+{
+ struct in_addr in;
+ int v = inet_pton(AF_INET, "0.0.0.0", &in);
+
+ FAIL_IF(v <= 0);
+ FAIL_IF_NOT(0 == CIDRFromMask(in.s_addr));
+
+ PASS;
+}
+
+static int CIDRFromMaskTest04(void)
+{
+ struct in_addr in;
+ int v = inet_pton(AF_INET, "255.255.255.255", &in);
+
+ FAIL_IF(v <= 0);
+ FAIL_IF_NOT(32 == CIDRFromMask(in.s_addr));
+
+ PASS;
+}
+
+#endif /* UNITTESTS */
+
+void UtilCIDRTests(void)
+{
+#ifdef UNITTESTS
+ UtRegisterTest("CIDRFromMaskTest01", CIDRFromMaskTest01);
+ UtRegisterTest("CIDRFromMaskTest02", CIDRFromMaskTest02);
+ UtRegisterTest("CIDRFromMaskTest03", CIDRFromMaskTest03);
+ UtRegisterTest("CIDRFromMaskTest04", CIDRFromMaskTest04);
+#endif /* UNITTESTS */
+}