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_ip.h author Michael Altizer <mialtize@cisco.com>
20 // based on work by Adam Keeton
21 
22 #ifndef SF_IP_H
23 #define SF_IP_H
24 
25 #include <arpa/inet.h>
26 #include <sys/socket.h>
27 
28 #include <cassert>
29 #include <cstring>
30 #include <sstream>
31 
32 #include "main/snort_types.h"
33 #include "sfip/sf_returns.h"
34 
35 namespace snort
36 {
37 using SfIpString = char[INET6_ADDRSTRLEN];
38 
39 // INET6_ADDRSTRLEN without IPv4-mapped IPv6
40 #define MAX_INET6_STRLEN_NO_IPV4_MAP 40
41 
42 struct SfCidr;
43 
44 struct SO_PUBLIC SfIp
45 {
46     /*
47      * Constructors
48      */
49     SfIp() = default;
SfIpSfIp50     SfIp(const void* src, int fam) { set(src, fam); }
51 
52     /*
53      * Modifiers
54      */
55     void clear();
56     SfIpRet set(const char* src, uint16_t* srcBits = nullptr);
57     /* Sets to a raw source IP (4 or 16 bytes, according to family) */
58     SfIpRet set(const void* src, int fam);
59     /* Sets to a raw source IP, source must be a 128 bit IPv6 (detects IPv4 mapped IPv6)
60      * This is specifically for conversion of DAQ_FlowStats_t ipv4 mapped ipv6 addresses */
61     SfIpRet set(const void* src);
62     /* Converts string IP format to an array of values. Also checks IP address format. */
63     SfIpRet pton(const int fam, const char* ip);
64 
65     /*
66      * Accessors
67      */
68     uint16_t get_family() const;
69     uint32_t get_ip4_value() const;
70     const uint32_t* get_ip4_ptr() const;
71     const uint32_t* get_ip6_ptr() const;
72     const uint32_t* get_ptr() const;
73     bool is_set() const;
74     bool is_ip6() const;
75     bool is_ip4() const;
76 
77     /*
78      *  Comparison functions
79      */
80     bool equals(const SfIp& rhs, bool match_unset = true) const;
81     bool less_than(const SfIp& rhs) const;
82     bool greater_than(const SfIp& rhs) const;
83     SfIpRet compare(const SfIp& ip2, bool match_unset = true) const;
84     bool fast_eq4(const SfIp& ip2) const;
85     bool fast_lt6(const SfIp& ip2) const;
86     bool fast_gt6(const SfIp& ip2) const;
87     bool fast_eq6(const SfIp& ip2) const;
88     bool fast_equals_raw(const SfIp& ip2) const;
89     bool operator==(const SfIp& ip2) const;
90 
91     /*
92      * Miscellaneous
93      */
94     /* Returns true if the IPv6 address appears mapped. */
95     bool is_mapped() const;
96     bool is_loopback() const;
97     bool is_private() const;
98 
99     const char* ntop(char* buf, int bufsize) const;
100     const char* ntop(SfIpString) const;
101 
102     void obfuscate(const SfCidr* ob);
103 
104     static bool test_features;
105 
106 private:
107     int cidr_mask(int val);
108     bool _is_equals(const SfIp& rhs) const;
109     bool _is_lesser(const SfIp& rhs) const;
110     SfIpRet _ip6_cmp(const SfIp& ip2) const;
111 
112     union
113     {
114         uint8_t ip8[16];
115         uint16_t ip16[8];
116         uint32_t ip32[4];
117     };
118     int16_t family;
119 } __attribute__((__packed__));
120 
121 
122 /*
123  * Member function definitions
124  */
125 
clear()126 inline void SfIp::clear()
127 {
128     family = 0;
129     ip32[0] = ip32[1] = ip32[2] = ip32[3] = 0;
130 }
131 
get_family()132 inline uint16_t SfIp::get_family() const
133 {
134     return family;
135 }
136 
get_ip4_value()137 inline uint32_t SfIp::get_ip4_value() const
138 {
139     return ip32[3];
140 }
141 
get_ip4_ptr()142 inline const uint32_t* SfIp::get_ip4_ptr() const
143 {
144     return &ip32[3];
145 }
146 
get_ip6_ptr()147 inline const uint32_t* SfIp::get_ip6_ptr() const
148 {
149     return ip32;
150 }
151 
get_ptr()152 inline const uint32_t* SfIp::get_ptr() const
153 {
154     if (is_ip4())
155         return &ip32[3];
156     return ip32;
157 }
158 
is_set()159 inline bool SfIp::is_set() const
160 {
161     return ((family == AF_INET && ip32[3]) ||
162             (family == AF_INET6 &&
163              (ip32[0] || ip32[1] || ip32[3] || ip16[4] ||
164               (ip16[5] && ip16[5] != 0xffff))));
165 }
166 
is_ip6()167 inline bool SfIp::is_ip6() const
168 {
169     return family == AF_INET6;
170 }
171 
is_ip4()172 inline bool SfIp::is_ip4() const
173 {
174     return family == AF_INET;
175 }
176 
is_loopback()177 inline bool SfIp::is_loopback() const
178 {
179     /* Check the first 80 bits in an IPv6 address, and
180         verify they're zero.  If not, it's not a loopback */
181     if (ip32[0] || ip32[1] || ip16[4])
182         return false;
183 
184     if (ip16[5] == 0xffff)
185     {
186         /* ::ffff:127.0.0.0/104 is IPv4 loopback mapped over IPv6 */
187         return (ip8[12] == 0x7f);
188     }
189 
190     if (!ip16[5])
191     {
192         /* ::7f00:0/104 is ipv4 compatible ipv6
193            ::1 is the IPv6 loopback */
194         return (ip32[3] == htonl(0x1) || ip8[12] == 0x7f);
195     }
196 
197     return false;
198 }
199 
is_private()200 inline bool SfIp::is_private() const
201 {
202     /* Check the first 80 bits in an IPv6 address, and
203         verify they're zero.  If not, it's not a loopback. */
204     if (ip32[0] || ip32[1] || ip16[4])
205         return false;
206 
207     /* (Mapped) v4 private addresses */
208     if (ip16[5] == 0xffff)
209     {
210         /*
211          * 10.0.0.0        -   10.255.255.255  (10/8 prefix)
212          * 172.16.0.0      -   172.31.255.255  (172.16/12 prefix)
213          * 192.168.0.0     -   192.168.255.255 (192.168/16 prefix)
214          */
215         return ( (ip8[12] == 10)
216                || ((ip8[12] == 172) && ((ip8[13] & 0xf0) == 16))
217                || ((ip8[12] == 192) && (ip8[13] == 168)) );
218     }
219 
220     /* Check if the 3rd 32-bit int is zero */
221     if (!ip16[5])
222     {
223         /* ::ipv4 compatible ipv6
224            ::1 is the IPv6 loopback */
225         return ( (ip8[12] == 10)
226                || ((ip8[12] == 172) && ((ip8[13] & 0xf0) == 16))
227                || ((ip8[12] == 192) && (ip8[13] == 168))
228                || (ip32[3] == htonl(0x1)) );
229     }
230 
231     return false;
232 }
233 
_is_equals(const SfIp & rhs)234 inline bool SfIp::_is_equals(const SfIp& rhs) const
235 {
236     if (is_ip4())
237     {
238         return (rhs.is_ip4()) &&
239                (ip32[3] == rhs.ip32[3]);
240     }
241     else if (is_ip6())
242     {
243         return (rhs.is_ip6()) &&
244                (ip32[0] == rhs.ip32[0]) &&
245                (ip32[1] == rhs.ip32[1]) &&
246                (ip32[2] == rhs.ip32[2]) &&
247                (ip32[3] == rhs.ip32[3]);
248     }
249     return false;
250 }
251 
_is_lesser(const SfIp & rhs)252 inline bool SfIp::_is_lesser(const SfIp& rhs) const
253 {
254     if (is_ip4() && rhs.is_ip4())
255         return ntohl(ip32[3]) < ntohl(rhs.ip32[3]);
256     uint32_t a = ntohl(ip32[0]);
257     uint32_t b = ntohl(rhs.ip32[0]);
258     if (a != b)
259         return a < b;
260     a = ntohl(ip32[1]);
261     b = ntohl(rhs.ip32[1]);
262     if (a != b)
263         return a < b;
264     a = ntohl(ip32[2]);
265     b = ntohl(rhs.ip32[2]);
266     if (a != b)
267         return a < b;
268     a = ntohl(ip32[3]);
269     b = ntohl(rhs.ip32[3]);
270     return a < b;
271 }
272 
equals(const SfIp & rhs,bool match_unset)273 inline bool SfIp::equals(const SfIp& rhs, bool match_unset) const
274 {
275     if (!is_set() || !rhs.is_set())
276         return match_unset;
277 
278     return _is_equals(rhs);
279 }
280 
less_than(const SfIp & rhs)281 inline bool SfIp::less_than(const SfIp& rhs) const
282 {
283     // I'm copying and pasting.  Don't ask me why this is different then sfip_equals
284     if (!is_set() || !rhs.is_set())
285         return false;
286 
287     return _is_lesser(rhs);
288 }
289 
greater_than(const SfIp & rhs)290 inline bool SfIp::greater_than(const SfIp& rhs) const
291 {
292     // I'm copying and pasting.  Don't ask me why this is different then sfip_equals
293     if (!is_set() || !rhs.is_set())
294         return false;
295 
296     return rhs._is_lesser(*this);
297 }
298 
299 /* Support function for SfIp::compare() */
_ip4_cmp(uint32_t ip1,uint32_t ip2)300 inline SfIpRet _ip4_cmp(uint32_t ip1, uint32_t ip2)
301 {
302     uint32_t hip1 = htonl(ip1);
303     uint32_t hip2 = htonl(ip2);
304     if (hip1 < hip2)
305         return SFIP_LESSER;
306     if (hip1 > hip2)
307         return SFIP_GREATER;
308     return SFIP_EQUAL;
309 }
310 
311 /* Support function for SfIp::compare() */
_ip6_cmp(const SfIp & ip2)312 inline SfIpRet SfIp::_ip6_cmp(const SfIp& ip2) const
313 {
314     SfIpRet ret;
315     const uint32_t* p1, * p2;
316 
317     p1 = ip32;
318     p2 = ip2.ip32;
319 
320     if ( (ret = _ip4_cmp(p1[0], p2[0])) != SFIP_EQUAL)
321         return ret;
322     if ( (ret = _ip4_cmp(p1[1], p2[1])) != SFIP_EQUAL)
323         return ret;
324     if ( (ret = _ip4_cmp(p1[2], p2[2])) != SFIP_EQUAL)
325         return ret;
326     if ( (ret = _ip4_cmp(p1[3], p2[3])) != SFIP_EQUAL)
327         return ret;
328 
329     return ret;
330 }
331 
332 /*
333  * Returns SFIP_LESSER, SFIP_EQUAL, SFIP_GREATER, if this is less than, equal to,
334  * or greater than ip2.  In the case of mismatched families, the IPv4 address
335  * is converted to an IPv6 representation.
336  * To support existing Snort code, an unset IP is considered to match anything
337  * unless 'match_unset' is set to false.
338  */
compare(const SfIp & ip2,bool match_unset)339 inline SfIpRet SfIp::compare(const SfIp& ip2, bool match_unset) const
340 {
341     if (!is_set() || !ip2.is_set())
342     {
343         if (match_unset)
344             return SFIP_EQUAL;
345         return SFIP_FAILURE;
346     }
347 
348     if (is_ip4() && ip2.is_ip4())
349         return _ip4_cmp(get_ip4_value(), ip2.get_ip4_value());
350 
351     return _ip6_cmp(ip2);
352 }
353 
fast_eq4(const SfIp & ip2)354 inline bool SfIp::fast_eq4(const SfIp& ip2) const
355 {
356     return get_ip4_value() == ip2.get_ip4_value();
357 }
358 
fast_lt6(const SfIp & ip2)359 inline bool SfIp::fast_lt6(const SfIp& ip2) const
360 {
361     const uint32_t* p1, * p2;
362 
363     p1 = ip32;
364     p2 = ip2.ip32;
365 
366     if (*p1 < *p2)
367         return true;
368     else if (*p1 > *p2)
369         return false;
370 
371     if (p1[1] < p2[1])
372         return true;
373     else if (p1[1] > p2[1])
374         return false;
375 
376     if (p1[2] < p2[2])
377         return true;
378     else if (p1[2] > p2[2])
379         return false;
380 
381     if (p1[3] < p2[3])
382         return true;
383     else if (p1[3] > p2[3])
384         return false;
385 
386     return false;
387 }
388 
fast_gt6(const SfIp & ip2)389 inline bool SfIp::fast_gt6(const SfIp& ip2) const
390 {
391     const uint32_t* p1, * p2;
392 
393     p1 = ip32;
394     p2 = ip2.ip32;
395 
396     if (*p1 > *p2)
397         return true;
398     else if (*p1 < *p2)
399         return false;
400 
401     if (p1[1] > p2[1])
402         return true;
403     else if (p1[1] < p2[1])
404         return false;
405 
406     if (p1[2] > p2[2])
407         return true;
408     else if (p1[2] < p2[2])
409         return false;
410 
411     if (p1[3] > p2[3])
412         return true;
413     else if (p1[3] < p2[3])
414         return false;
415 
416     return false;
417 }
418 
fast_eq6(const SfIp & ip2)419 inline bool SfIp::fast_eq6(const SfIp& ip2) const
420 {
421     const uint32_t* p1, * p2;
422 
423     p1 = ip32;
424     p2 = ip2.ip32;
425 
426     if (*p1 != *p2)
427         return false;
428     if (p1[1] != p2[1])
429         return false;
430     if (p1[2] != p2[2])
431         return false;
432     if (p1[3] != p2[3])
433         return false;
434 
435     return true;
436 }
437 
fast_equals_raw(const SfIp & ip2)438 inline bool SfIp::fast_equals_raw(const SfIp& ip2) const
439 {
440     int f1,f2;
441 
442     f1 = family;
443     f2 = ip2.family;
444 
445     if (f1 == AF_INET)
446     {
447         if (f2 != AF_INET)
448             return false;
449         if (fast_eq4(ip2))
450             return true;
451     }
452     else if (f1 == AF_INET6)
453     {
454         if (f2 != AF_INET6)
455             return false;
456         if (fast_eq6(ip2))
457             return true;
458     }
459     return false;
460 }
461 
462 inline bool SfIp::operator==(const SfIp& ip2) const
463 {
464     return fast_equals_raw(ip2);
465 }
466 
467 /* End of member function definitions */
468 
469 /* Support functions */
470 // note that an ip6 address may have a trailing dotted quad form
471 // but that it always has at least 2 ':'s; furthermore there is
472 // no valid ip4 format (including mask) with 2 ':'s
473 // we don't have to figure out if the format is entirely legal
474 // we just have to be able to tell correct formats apart
sfip_str_to_fam(const char * str)475 static inline int sfip_str_to_fam(const char* str)
476 {
477     const char* s;
478     assert(str);
479     s = strchr(str, (int)':');
480     if ( s && strchr(s+1, (int)':') )
481         return AF_INET6;
482     if ( strchr(str, (int)'.') )
483         return AF_INET;
484     return AF_UNSPEC;
485 }
486 
parse_ip_from_uri(const std::string & ip_str,SfIp & ip)487 static inline bool parse_ip_from_uri(const std::string& ip_str, SfIp& ip)
488 {
489     auto host_start = ip_str.find("://");
490     if ( host_start != std::string::npos )
491     {
492         host_start += 3;
493         if ( host_start >= ip_str.size() )
494             return false;
495     }
496     else
497         host_start = 0;
498 
499     auto host_end = host_start;
500     int family = sfip_str_to_fam(ip_str.c_str() + host_start);
501 
502     if ( family == AF_INET )
503     {
504         while ( host_end < ip_str.size() and ip_str[host_end] != ':' and ip_str[host_end] != '/' )
505             ++host_end;
506     }
507     else if ( family == AF_INET6 )
508     {
509         if ( ip_str[host_start] == '[' )
510         {
511             ++host_start;
512             ++host_end;
513         }
514         while ( host_end < ip_str.size() and ip_str[host_end] != ']' and ip_str[host_end] != '/')
515             ++host_end;
516     }
517     else
518         return false;
519 
520     if ( host_end <= host_start or (host_end - host_start) > MAX_INET6_STRLEN_NO_IPV4_MAP )
521         return false;
522 
523     if ( host_start != 0 or host_end != ip_str.size() )
524     {
525         const std::string host_str = ip_str.substr(host_start, host_end - host_start);
526         if ( ip.set(host_str.c_str()) != SFIP_SUCCESS )
527             return false;
528     }
529     else if ( ip.set(ip_str.c_str()) != SFIP_SUCCESS )
530         return false;
531 
532     return true;
533 }
534 
535 SO_PUBLIC const char* sfip_ntop(const SfIp* ip, char* buf, int bufsize);
536 
537 inline std::ostream& operator<<(std::ostream& os, const SfIp* addr)
538 {
539     SfIpString str;
540     return os << addr->ntop(str);
541 }
542 
543 // FIXIT-L X This should be in utils_net if anywhere, but that makes it way
544 // harder to link into unit tests
545 SO_PUBLIC const char* snort_inet_ntop(int family, const void* ip_raw, char* buf, int bufsize);
546 } // namespace snort
547 #endif
548