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