libutil++  1.9.3
 All Classes Functions Variables
IPPrefix.cpp
1 /*
2 ** libutil++
3 ** $Id: IPPrefix.cpp 1901 2017-06-24 20:03:54Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: IPPrefix.cpp 1901 2017-06-24 20:03:54Z sella $";
10 
11 #include "IPPrefix.h"
12 #include "../util/String.h"
13 #include "../util/CommonMacro.h"
14 
15 #include <string.h>
16 
17 #define HASH_ALGO_INT1
18 
19 using namespace sella::net;
20 using namespace sella::util;
21 
22 union __sockaddr_union {
23  struct sockaddr_storage *ss;
24  struct sockaddr *sa;
25  struct sockaddr_in *sa_in;
26  struct sockaddr_in6 *sa_in6;
27 };
28 
29 IPPrefix::IPPrefix(const IPAddress &address, uint8_t cidr) throw (AddressException) :
30  address(address),
31  cidr(cidr),
32  mask{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
33  hcache(0)
34 {
35  int family = this->address.getFamily();
36 
37  if (cidr == 255) {
38  this->cidr = (family == AF_INET) ? 32 : 128;
39  } else if (family == AF_INET && cidr > 32) {
40  this->cidr = 32;
41  } else if (cidr > 128) {
42  this->cidr = 128;
43  } else {
44  this->address.applyCIDR(this->cidr);
45  }
46 
47  generateMask();
48 }
49 
50 IPPrefix::IPPrefix(const std::string &address, uint8_t cidr) throw (AddressException) :
51  address(address),
52  cidr(cidr),
53  mask{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
54  hcache(0)
55 {
56  int family = this->address.getFamily();
57 
58  if (cidr == 255) {
59  this->cidr = (family == AF_INET) ? 32 : 128;
60  } else if (family == AF_INET && cidr > 32) {
61  this->cidr = 32;
62  } else if (cidr > 128) {
63  this->cidr = 128;
64  } else {
65  this->address.applyCIDR(this->cidr);
66  }
67 
68  generateMask();
69 }
70 
71 IPPrefix::IPPrefix(const std::string &prefix) throw (AddressException) :
72  mask{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
73  hcache(0)
74 {
75 #if 0
76  const auto &parts = String::split(prefix, "/");
77 
78  if (parts.empty()) {
79  THROW(AddressException, "unable to parse prefix: '%s' does not represent a valid IPv4 or IPv6 prefix", prefix.c_str());
80  } else if (parts.size() == 1) {
81  address = IPAddress(parts.at(0));
82  cidr = (address.getFamily() == AF_INET) ? 32 : 128;
83  } else {
84  address = IPAddress(parts.at(0));
85  cidr = std::stoi(parts.at(1));
86  }
87 
88  this->address.applyCIDR(cidr);
89 
90  generateMask();
91 #else
92  size_t i = prefix.rfind('/');
93  const char *p = prefix.c_str();
94 
95  if (i == std::string::npos) {
96  if (inet_pton(AF_INET, p, &(this->address.addr.v4)) == 1) {
97  this->address.family = AF_INET;
98  this->cidr = 32;
99  } else {
100  if (inet_pton(AF_INET6, p, &(this->address.addr.v6)) == 1) {
101  this->address.family = AF_INET6;
102  this->cidr = 128;
103  } else {
104  THROW(AddressException, "unable to parse prefix: '%s' does not represent a valid IPv4 or IPv6 prefix", p);
105  }
106  }
107  } else {
108  char buf[i + 1];
109  const char *p = prefix.c_str();
110 
111  strncpy(buf, p, i);
112  buf[i] = 0;
113 
114  if (inet_pton(AF_INET, buf, &(this->address.addr.v4)) == 1) {
115  this->address.family = AF_INET;
116  } else {
117  if (inet_pton(AF_INET6, buf, &(this->address.addr.v6)) == 1) {
118  this->address.family = AF_INET6;
119  } else {
120  THROW(AddressException, "unable to parse prefix: '%s' does not represent a valid IPv4 or IPv6 prefix", p);
121  }
122  }
123 
124  try {
125  this->cidr = std::stoi(p + i + 1);
126  } catch (std::exception &e) {
127  THROW(AddressException, "unable to parse prefix: '%s' does not represent a valid IPv4 or IPv6 prefix", p);
128  }
129 
130  this->address.applyCIDR(this->cidr);
131  }
132 
133  generateMask();
134 #endif
135 }
136 
137 IPPrefix::IPPrefix(const IPPrefix &other) throw () :
138  address(other.address),
139  cidr(other.cidr),
140  scache(other.scache),
141  hcache(other.hcache)
142 {
143  memcpy(mask, other.mask, sizeof(mask));
144 }
145 
146 IPPrefix::IPPrefix(const IPPrefix &&other) throw () :
147  address(std::move(other.address)),
148  cidr(other.cidr),
149  scache(std::move(other.scache)),
150  hcache(other.hcache)
151 {
152  memcpy(mask, other.mask, sizeof(mask));
153 }
154 
155 IPPrefix::~IPPrefix() throw () { }
156 
157 IPPrefix& IPPrefix::operator=(const IPPrefix &other) throw () {
158  if (this != &other) {
159  this->address = other.address;
160  this->cidr = other.cidr;
161  memcpy(this->mask, other.mask, sizeof(mask));
162  this->scache = other.scache;
163  this->hcache = other.hcache;
164  }
165 
166  return *this;
167 }
168 
169 IPPrefix& IPPrefix::operator=(const IPPrefix &&other) throw () {
170  if (this != &other) {
171  this->address = std::move(other.address);
172  this->cidr = other.cidr;
173  memcpy(this->mask, other.mask, sizeof(mask));
174  this->scache = std::move(other.scache);
175  this->hcache = other.hcache;
176  }
177 
178  return *this;
179 }
180 
181 bool IPPrefix::operator==(const IPPrefix &other) const throw () {
182  return (this->cidr == other.cidr) ? ((this->address == other.address) ? true : false) : false;
183 }
184 
185 bool IPPrefix::operator!=(const IPPrefix &other) const throw () {
186  return !(*this == other);
187 }
188 
189 bool IPPrefix::operator>=(const IPPrefix &other) const throw () {
190  return !(*this < other);
191 }
192 
193 bool IPPrefix::operator<=(const IPPrefix &other) const throw () {
194  if (*this <<= other) {
195  return true;
196  } else if (other << *this) {
197  return false;
198  }
199 
200  return (this->address <= other.address);
201 }
202 
203 bool IPPrefix::operator>(const IPPrefix &other) const throw () {
204  return !(*this <= other);
205 }
206 
207 bool IPPrefix::operator<(const IPPrefix &other) const throw () {
208  if (*this << other) {
209  return true;
210  } else if (other <<= *this) {
211  return false;
212  }
213 
214  return (this->address < other.address);
215 }
216 
217 bool IPPrefix::operator<<(const IPPrefix &other) const throw () {
218  return other.contains(*this, false);
219 }
220 
221 bool IPPrefix::operator<<=(const IPPrefix &other) const throw () {
222  return other.contains(*this, true);
223 }
224 
225 bool IPPrefix::operator>>(const IPPrefix &other) const throw () {
226  return this->contains(other, false);
227 }
228 
229 bool IPPrefix::operator>>=(const IPPrefix &other) const throw () {
230  return this->contains(other, true);
231 }
232 
233 bool IPPrefix::operator<<(const IPAddress &other) const throw () {
234  return !(this->contains(other, true));
235 }
236 
237 bool IPPrefix::operator<<=(const IPAddress &other) const throw () {
238  return !(this->contains(other, false));
239 }
240 
241 bool IPPrefix::operator>>(const IPAddress &other) const throw () {
242  return this->contains(other, false);
243 }
244 
245 bool IPPrefix::operator>>=(const IPAddress &other) const throw () {
246  return this->contains(other, true);
247 }
248 
249 bool IPPrefix::contains(const IPPrefix &other, bool orEquals) const throw () {
250  bool cmp;
251 
252  if (this->getFamily() != other.getFamily()) {
253  return false;
254  }
255 
256  if (this->getFamily() == AF_INET) {
257  const uint32_t &a = this->address.getIPv4AddressStructure().s_addr;
258  const uint32_t &b = other.address.getIPv4AddressStructure().s_addr;
259  const uint32_t &m = this->mask[0];
260 
261  cmp = ((ntohl(a) & m) == (ntohl(b) & m));
262  } else {
263  const uint64_t *a = (const uint64_t*) this->address.getIPv6AddressStructure().s6_addr;
264  const uint64_t *b = (const uint64_t*) other.address.getIPv6AddressStructure().s6_addr;
265  const uint64_t *m = (const uint64_t*) this->mask;
266 
267  cmp = ((ntohll(a[0]) & m[0]) == (ntohll(b[0]) & m[0]) && (ntohll(a[1]) & m[1]) == (ntohll(b[1]) & m[1]));
268  }
269 
270  return (orEquals) ? cmp : (cmp && this->cidr != other.cidr);
271 }
272 
273 bool IPPrefix::contains(const IPAddress &other, bool orEquals) const throw () {
274  bool cmp;
275  uint8_t ocidr;
276 
277  if (this->getFamily() != other.getFamily()) {
278  return false;
279  }
280 
281  if (this->getFamily() == AF_INET) {
282  const uint32_t &a = this->address.getIPv4AddressStructure().s_addr;
283  const uint32_t &b = other.getIPv4AddressStructure().s_addr;
284  const uint32_t &m = this->mask[0];
285 
286  ocidr = 32;
287  cmp = ((ntohl(a) & m) == (ntohl(b) & m));
288  } else {
289  const uint64_t *a = (const uint64_t*) this->address.getIPv6AddressStructure().s6_addr;
290  const uint64_t *b = (const uint64_t*) other.getIPv6AddressStructure().s6_addr;
291  const uint64_t *m = (const uint64_t*) this->mask;
292 
293  ocidr = 128;
294  cmp = ((ntohll(a[0]) & m[0]) == (ntohll(b[0]) & m[0]) && (ntohll(a[1]) & m[1]) == (ntohll(b[1]) & m[1]));
295  }
296 
297  return (orEquals) ? cmp : (cmp && this->cidr != ocidr);
298 }
299 
300 int IPPrefix::getFamily(void) const throw () {
301  return address.getFamily();
302 }
303 
304 const IPAddress& IPPrefix::getIPAddress(void) const throw () {
305  return this->address;
306 }
307 
308 IPAddress& IPPrefix::getIPAddress(void) throw () {
309  return this->address;
310 }
311 
312 uint8_t IPPrefix::getCIDR(void) const throw () {
313  return this->cidr;
314 }
315 
316 IPAddress IPPrefix::getNetmask(void) const throw () {
317  if (getFamily() == AF_INET) {
318  return IPAddress("255.255.255.255", IPAddress::IPv4Required, cidr);
319  } else {
320  return IPAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", IPAddress::IPv6Required, cidr);
321  }
322 }
323 
324 IPAddress IPPrefix::getInverseMask(void) const throw () {
325  return ~(getNetmask());
326 }
327 
328 IPAddress IPPrefix::getNetwork(void) const throw () {
329  return getIPAddress();
330 }
331 
332 IPAddress IPPrefix::getBroadcast(void) const throw () {
333  return this->address | getInverseMask();
334 }
335 
336 IPAddress::vector IPPrefix::getIPAddresses(bool usable) const throw () {
337  IPAddress::vector addresses;
338  IPAddress address = getIPAddress();
339 
340  if (usable) {
341  if (getFamily() == AF_INET && cidr < 31) {
342  ++address;
343  } else if (getFamily() == AF_INET6 && cidr < 127) {
344  ++address;
345  }
346  }
347 
348  while (contains(address, true)) {
349  addresses.push_back(address++);
350  }
351 
352  if (usable) {
353  if (getFamily() == AF_INET && cidr < 31) {
354  addresses.pop_back();
355  } else if (getFamily() == AF_INET6 && cidr < 127) {
356  addresses.pop_back();
357  }
358  }
359 
360  return addresses;
361 }
362 
363 const std::string& IPPrefix::str(void) const throw (AddressException) {
364  if (scache.empty()) {
365  scache = this->address.str();
366 
367  scache.push_back('/');
368  scache.append(String::itoa(cidr));
369  }
370 
371  return scache;
372 }
373 
374 const char* IPPrefix::c_str(void) const throw (AddressException) {
375  return str().c_str();
376 }
377 
378 uint32_t IPPrefix::getU32(void) const throw () {
379  uint32_t c = cidr;
380 
381  return (address.getU32() ^ (c | c << 4 | c << 8 | c << 12 | c << 16 | c << 20 | c << 24 | c << 28));
382 }
383 
384 uint32_t IPPrefix::getHash(void) const throw () {
385  if (hcache != 0) {
386  return hcache;
387  }
388 
389 #if defined HASH_ALGO_INT1 /* Fast. Nibble swap. */
390  uint32_t k = getU32();
391 
392  hcache = ((k & 0xF0F0F0F0) >> 4) | ((k & 0x0F0F0F0F) << 4);
393 #elif defined HASH_ALGO_INT2
394  uint32_t k = getU32();
395 
396  hcache = (k<<16)^(k>>16)^k; /* Fast. Mix by XOR shifting.. */
397 #elif defined HASH_ALGO_INT3 /* Very fast, but not good. */
398  hcache = getU32();
399 #else
400  #error No hash algo selected.
401 #endif
402 
403  return hcache;
404 }
405 
406 bool IPPrefix::empty(void) const throw () {
407  return (address.empty());
408 }
409 
410 void IPPrefix::clear(void) throw () {
411  address.clear();
412  cidr = 0;
413  mask[0] = 0xFFFFFFFF;
414  mask[1] = 0xFFFFFFFF;
415  mask[2] = 0xFFFFFFFF;
416  mask[3] = 0xFFFFFFFF;
417  scache.clear();
418  hcache = 0;
419 }
420 
421 const IPPrefix::shared IPPrefix::shared_ptr(const IPAddress &address, uint8_t cidr) throw (AddressException) {
422  return std::make_shared<IPPrefix>(address, cidr);
423 }
424 
425 const IPPrefix::shared IPPrefix::shared_ptr(const std::string &address, uint8_t cidr) throw (AddressException) {
426  return std::make_shared<IPPrefix>(address, cidr);
427 }
428 
429 const IPPrefix::shared IPPrefix::shared_ptr(const std::string &prefix) throw (AddressException) {
430  return std::make_shared<IPPrefix>(prefix);
431 }
432 
433 void IPPrefix::generateMask(void) throw () {
434  if (address.getFamily() == AF_INET) {
435  if (cidr == 0) {
436  mask[0] = 0;
437  } else {
438  uint8_t adj = 32 - cidr;
439 
440  mask[0] = 0xFFFFFFFF >> adj << adj;
441  }
442 
443  //printf("mask: %08X\n", mask[0]);
444  } else {
445  uint8_t mod = cidr % 32;
446  uint8_t adj = 32 - mod;
447 
448  for (int i = 4; i > cidr / 32 - 1; i--) {
449  if (i == cidr / 32 && mod != 0) {
450  mask[i] = 0xFFFFFFFF >> adj << adj;
451  } else {
452  mask[i] = 0;
453  }
454  }
455 
456  //printf("mask: %08X:%08X:%08X:%08X\n", mask[0], mask[1], mask[2], mask[3]);
457  }
458 }
459 
460 /*
461 ** vim: noet ts=3 sw=3
462 */