1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 1998-2013 Sourcefire, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License Version 2 as published
7 // by the Free Software Foundation.  You may not use, modify or distribute
8 // this program under any other version of the GNU General Public License.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 //--------------------------------------------------------------------------
19 // sf_cidr.h author Michael Altizer <mialtize@cisco.com>
20 
21 #ifndef SF_CIDR_H
22 #define SF_CIDR_H
23 
24 #include "sfip/sf_ip.h"
25 
26 namespace snort
27 {
28 /*
29  * NOTE: As much as I'd love to make this a subclass of SfIp, member layout
30  * is undefined for POD inheritance.
31  */
32 
33 struct SO_PUBLIC SfCidr
34 {
35     /*
36      * Constructors
37      */
38     SfCidr() = default;
39 
40     /*
41      * Modifiers (incl. convenience ones that delegate to addr)
42      */
43     void clear();
44     void set(const SfCidr& src);
45     void set(const SfIp& src);
46     SfIpRet set(const void* src, int fam);
47     SfIpRet set(const char* src);
48     void set_bits(uint16_t new_bits);
49 
50     /*
51      * Accessors (incl. convenience ones that delegate to addr)
52      */
53     const SfIp* get_addr() const;
54     uint16_t get_family() const;
55     uint16_t get_bits() const;
56     bool is_set() const;
57 
58     /*
59      * Containment checks
60      */
61     bool fast_cont4(const SfIp& ip) const;
62     bool fast_cont6(const SfIp& ip) const;
63     SfIpRet contains(const SfIp* ip) const;
64 
65     const char* ntop(SfIpString) const;
66     SfIpRet compare(const SfCidr&) const;
67 
68 private:
69     SfIp addr;
70     uint16_t bits;
71 } __attribute__((__packed__));
72 
73 
clear()74 inline void SfCidr::clear()
75 {
76     addr.clear();
77     bits = 0;
78 }
79 
set(const SfCidr & src)80 inline void SfCidr::set(const SfCidr& src)
81 {
82     addr = src.addr;
83     bits = src.bits;
84 }
85 
set(const SfIp & src)86 inline void SfCidr::set(const SfIp& src)
87 {
88     addr = src;
89     bits = 128;
90 }
91 
set(const void * src,int fam)92 inline SfIpRet SfCidr::set(const void* src, int fam)
93 {
94     SfIpRet ret = addr.set(src, fam);
95     if (ret != SFIP_SUCCESS)
96         return ret;
97     bits = 128;
98     return SFIP_SUCCESS;
99 }
100 
set_bits(uint16_t new_bits)101 inline void SfCidr::set_bits(uint16_t new_bits)
102 {
103     if (new_bits > 128)
104         return;
105     bits = new_bits;
106 }
107 
get_addr()108 inline const SfIp* SfCidr::get_addr() const
109 {
110     return &addr;
111 }
112 
get_family()113 inline uint16_t SfCidr::get_family() const
114 {
115     return addr.get_family();
116 }
117 
get_bits()118 inline uint16_t SfCidr::get_bits() const
119 {
120     return bits;
121 }
122 
is_set()123 inline bool SfCidr::is_set() const
124 {
125     return (addr.is_set() ||
126             ((addr.get_family() == AF_INET || addr.get_family() == AF_INET6) &&
127              bits != 128));
128 }
129 
fast_cont4(const SfIp & ip)130 inline bool SfCidr::fast_cont4(const SfIp& ip) const
131 {
132     uint32_t shift = 128 - bits;
133     uint32_t needle = ntohl(ip.get_ip4_value());
134     uint32_t haystack = ntohl(addr.get_ip4_value());
135 
136     if (haystack == 0)
137         return true;
138 
139     needle >>= shift;
140     needle <<= shift;
141 
142     return haystack == needle;
143 }
144 
fast_cont6(const SfIp & ip)145 inline bool SfCidr::fast_cont6(const SfIp& ip) const
146 {
147     uint32_t needle;
148     int words = bits / 32;
149     int shift, i;
150 
151     for (i = 0; i < words; i++)
152     {
153         if (addr.get_ip6_ptr()[i] != ip.get_ip6_ptr()[i])
154             return false;
155     }
156 
157     shift = 32 - (bits % 32);
158     if (shift == 32)
159         return true;
160 
161     needle = ntohl(ip.get_ip6_ptr()[i]);
162 
163     needle >>= shift;
164     needle <<= shift;
165 
166     return ntohl(addr.get_ip6_ptr()[i]) == needle;
167 }
168 
ntop(SfIpString ip_str)169 inline const char* SfCidr::ntop(SfIpString ip_str) const
170 {
171     return addr.ntop(ip_str);
172 }
173 
compare(const SfCidr & cidr2)174 inline SfIpRet SfCidr::compare(const SfCidr& cidr2) const
175 {
176     SfIpRet ret = addr.compare(*cidr2.get_addr());
177     if(SFIP_EQUAL == ret)
178     {
179         if(bits < cidr2.get_bits()) return SFIP_LESSER;
180         if(bits > cidr2.get_bits()) return SFIP_GREATER;
181     }
182     return ret;
183 }
184 }
185 #endif
186