suricata
util-cidr.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2022 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 Victor Julien <victor@inliniac.net>
22  *
23  * CIDR utility functions
24  */
25 
26 #include "suricata-common.h"
27 #include "util-cidr.h"
28 #include "util-debug.h"
29 #include "util-unittest.h"
30 
31 /** \brief turn 32 bit mask into CIDR
32  * \retval cidr cidr value or -1 if the netmask can't be expressed as cidr
33  */
34 int CIDRFromMask(uint32_t netmask)
35 {
36  netmask = ntohl(netmask);
37  if (netmask == 0) {
38  return 0;
39  }
40  int p = 0;
41  bool seen_1 = false;
42  while (netmask > 0) {
43  if (netmask & 1) {
44  seen_1 = true;
45  p++;
46  } else {
47  if (seen_1) {
48  return -1;
49  }
50  }
51  netmask >>= 1;
52  }
53  return p;
54 }
55 
56 uint32_t CIDRGet(int cidr)
57 {
58  if (cidr <= 0 || cidr > 32)
59  return 0;
60  uint32_t netmask = htonl(0xFFFFFFFF << (32UL - (uint32_t)cidr));
61  SCLogDebug("CIDR %d -> netmask %08X", cidr, netmask);
62  return netmask;
63 }
64 
65 /**
66  * \brief Creates a cidr ipv6 netblock, based on the cidr netblock value.
67  *
68  * For example if we send a cidr of 7 as argument, an ipv6 address
69  * mask of the value FE:00:00:00:00:00:00:00 is created and updated
70  * in the argument struct in6_addr *in6.
71  *
72  * \todo I think for the final section: while (cidr > 0), we can simply
73  * replace it with a
74  * if (cidr > 0) {
75  * in6->s6_addr[i] = -1 << (8 - cidr);
76  *
77  * \param cidr The value of the cidr.
78  * \param in6 Pointer to an ipv6 address structure(struct in6_addr) which will
79  * hold the cidr netblock result.
80  */
81 void CIDRGetIPv6(int cidr, struct in6_addr *in6)
82 {
83  int i = 0;
84 
85  memset(in6, 0, sizeof(struct in6_addr));
86 
87  while (cidr > 8) {
88  in6->s6_addr[i] = 0xff;
89  cidr -= 8;
90  i++;
91  }
92 
93  while (cidr > 0) {
94  in6->s6_addr[i] |= 0x80;
95  if (--cidr > 0)
96  in6->s6_addr[i] = in6->s6_addr[i] >> 1;
97  }
98 }
99 
100 #ifdef UNITTESTS
101 
102 static int CIDRFromMaskTest01(void)
103 {
104  struct in_addr in;
105  int v = inet_pton(AF_INET, "255.255.255.0", &in);
106 
107  FAIL_IF(v <= 0);
108  FAIL_IF_NOT(24 == CIDRFromMask(in.s_addr));
109 
110  PASS;
111 }
112 
113 static int CIDRFromMaskTest02(void)
114 {
115  struct in_addr in;
116  int v = inet_pton(AF_INET, "255.255.0.42", &in);
117 
118  FAIL_IF(v <= 0);
119  FAIL_IF_NOT(-1 == CIDRFromMask(in.s_addr));
120 
121  PASS;
122 }
123 
124 static int CIDRFromMaskTest03(void)
125 {
126  struct in_addr in;
127  int v = inet_pton(AF_INET, "0.0.0.0", &in);
128 
129  FAIL_IF(v <= 0);
130  FAIL_IF_NOT(0 == CIDRFromMask(in.s_addr));
131 
132  PASS;
133 }
134 
135 static int CIDRFromMaskTest04(void)
136 {
137  struct in_addr in;
138  int v = inet_pton(AF_INET, "255.255.255.255", &in);
139 
140  FAIL_IF(v <= 0);
141  FAIL_IF_NOT(32 == CIDRFromMask(in.s_addr));
142 
143  PASS;
144 }
145 
146 #endif /* UNITTESTS */
147 
148 void UtilCIDRTests(void)
149 {
150 #ifdef UNITTESTS
151  UtRegisterTest("CIDRFromMaskTest01", CIDRFromMaskTest01);
152  UtRegisterTest("CIDRFromMaskTest02", CIDRFromMaskTest02);
153  UtRegisterTest("CIDRFromMaskTest03", CIDRFromMaskTest03);
154  UtRegisterTest("CIDRFromMaskTest04", CIDRFromMaskTest04);
155 #endif /* UNITTESTS */
156 }
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
CIDRGet
uint32_t CIDRGet(int cidr)
Definition: util-cidr.c:56
util-unittest.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
util-cidr.h
util-debug.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
CIDRFromMask
int CIDRFromMask(uint32_t netmask)
turn 32 bit mask into CIDR
Definition: util-cidr.c:34
UtilCIDRTests
void UtilCIDRTests(void)
Definition: util-cidr.c:148
CIDRGetIPv6
void CIDRGetIPv6(int cidr, struct in6_addr *in6)
Creates a cidr ipv6 netblock, based on the cidr netblock value.
Definition: util-cidr.c:81
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
suricata-common.h