9 static const char rcsid[] __attribute__((used)) =
"$Id: IPPrefix.cpp 1901 2017-06-24 20:03:54Z sella $";
12 #include "../util/String.h"
13 #include "../util/CommonMacro.h"
17 #define HASH_ALGO_INT1
19 using namespace sella::net;
20 using namespace sella::util;
23 struct sockaddr_storage *ss;
25 struct sockaddr_in *sa_in;
26 struct sockaddr_in6 *sa_in6;
29 IPPrefix::IPPrefix(
const IPAddress &address, uint8_t cidr)
throw (AddressException) :
32 mask{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
35 int family = this->address.getFamily();
38 this->cidr = (family == AF_INET) ? 32 : 128;
39 }
else if (family == AF_INET && cidr > 32) {
41 }
else if (cidr > 128) {
44 this->address.applyCIDR(this->cidr);
50 IPPrefix::IPPrefix(
const std::string &address, uint8_t cidr)
throw (AddressException) :
53 mask{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
56 int family = this->address.getFamily();
59 this->cidr = (family == AF_INET) ? 32 : 128;
60 }
else if (family == AF_INET && cidr > 32) {
62 }
else if (cidr > 128) {
65 this->address.applyCIDR(this->cidr);
71 IPPrefix::IPPrefix(
const std::string &prefix)
throw (AddressException) :
72 mask{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
76 const auto &parts = String::split(prefix,
"/");
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) {
82 cidr = (address.getFamily() == AF_INET) ? 32 : 128;
85 cidr = std::stoi(parts.at(1));
88 this->address.applyCIDR(cidr);
92 size_t i = prefix.rfind(
'/');
93 const char *p = prefix.c_str();
95 if (i == std::string::npos) {
96 if (inet_pton(AF_INET, p, &(this->address.addr.v4)) == 1) {
97 this->address.family = AF_INET;
100 if (inet_pton(AF_INET6, p, &(this->address.addr.v6)) == 1) {
101 this->address.family = AF_INET6;
104 THROW(AddressException,
"unable to parse prefix: '%s' does not represent a valid IPv4 or IPv6 prefix", p);
109 const char *p = prefix.c_str();
114 if (inet_pton(AF_INET, buf, &(this->address.addr.v4)) == 1) {
115 this->address.family = AF_INET;
117 if (inet_pton(AF_INET6, buf, &(this->address.addr.v6)) == 1) {
118 this->address.family = AF_INET6;
120 THROW(AddressException,
"unable to parse prefix: '%s' does not represent a valid IPv4 or IPv6 prefix", p);
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);
130 this->address.applyCIDR(this->cidr);
137 IPPrefix::IPPrefix(
const IPPrefix &other)
throw () :
138 address(other.address),
140 scache(other.scache),
143 memcpy(mask, other.mask,
sizeof(mask));
146 IPPrefix::IPPrefix(
const IPPrefix &&other) throw () :
147 address(std::move(other.address)),
149 scache(std::move(other.scache)),
152 memcpy(mask, other.mask,
sizeof(mask));
155 IPPrefix::~IPPrefix() 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;
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;
181 bool IPPrefix::operator==(
const IPPrefix &other)
const throw () {
182 return (this->cidr == other.cidr) ? ((this->address == other.address) ?
true :
false) :
false;
185 bool IPPrefix::operator!=(
const IPPrefix &other)
const throw () {
186 return !(*
this == other);
189 bool IPPrefix::operator>=(
const IPPrefix &other)
const throw () {
190 return !(*
this < other);
193 bool IPPrefix::operator<=(
const IPPrefix &other)
const throw () {
194 if (*
this <<= other) {
196 }
else if (other << *
this) {
200 return (this->address <= other.address);
203 bool IPPrefix::operator>(
const IPPrefix &other)
const throw () {
204 return !(*
this <= other);
207 bool IPPrefix::operator<(
const IPPrefix &other)
const throw () {
208 if (*
this << other) {
210 }
else if (other <<= *
this) {
214 return (this->address < other.address);
217 bool IPPrefix::operator<<(
const IPPrefix &other)
const throw () {
218 return other.contains(*
this,
false);
221 bool IPPrefix::operator<<=(
const IPPrefix &other)
const throw () {
222 return other.contains(*
this,
true);
225 bool IPPrefix::operator>>(
const IPPrefix &other)
const throw () {
226 return this->contains(other,
false);
229 bool IPPrefix::operator>>=(
const IPPrefix &other)
const throw () {
230 return this->contains(other,
true);
233 bool IPPrefix::operator<<(
const IPAddress &other)
const throw () {
234 return !(this->contains(other,
true));
237 bool IPPrefix::operator<<=(
const IPAddress &other)
const throw () {
238 return !(this->contains(other,
false));
241 bool IPPrefix::operator>>(
const IPAddress &other)
const throw () {
242 return this->contains(other,
false);
245 bool IPPrefix::operator>>=(
const IPAddress &other)
const throw () {
246 return this->contains(other,
true);
249 bool IPPrefix::contains(
const IPPrefix &other,
bool orEquals)
const throw () {
252 if (this->getFamily() != other.getFamily()) {
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];
261 cmp = ((ntohl(a) & m) == (ntohl(b) & m));
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;
267 cmp = ((ntohll(a[0]) & m[0]) == (ntohll(b[0]) & m[0]) && (ntohll(a[1]) & m[1]) == (ntohll(b[1]) & m[1]));
270 return (orEquals) ? cmp : (cmp && this->cidr != other.cidr);
273 bool IPPrefix::contains(
const IPAddress &other,
bool orEquals)
const throw () {
277 if (this->getFamily() != other.getFamily()) {
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];
287 cmp = ((ntohl(a) & m) == (ntohl(b) & m));
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;
294 cmp = ((ntohll(a[0]) & m[0]) == (ntohll(b[0]) & m[0]) && (ntohll(a[1]) & m[1]) == (ntohll(b[1]) & m[1]));
297 return (orEquals) ? cmp : (cmp && this->cidr != ocidr);
300 int IPPrefix::getFamily(
void)
const throw () {
301 return address.getFamily();
304 const IPAddress& IPPrefix::getIPAddress(
void)
const throw () {
305 return this->address;
308 IPAddress& IPPrefix::getIPAddress(
void) throw () {
309 return this->address;
312 uint8_t IPPrefix::getCIDR(
void)
const throw () {
316 IPAddress IPPrefix::getNetmask(
void)
const throw () {
317 if (getFamily() == AF_INET) {
318 return IPAddress(
"255.255.255.255", IPAddress::IPv4Required, cidr);
320 return IPAddress(
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", IPAddress::IPv6Required, cidr);
324 IPAddress IPPrefix::getInverseMask(
void)
const throw () {
325 return ~(getNetmask());
328 IPAddress IPPrefix::getNetwork(
void)
const throw () {
329 return getIPAddress();
332 IPAddress IPPrefix::getBroadcast(
void)
const throw () {
333 return this->address | getInverseMask();
336 IPAddress::vector IPPrefix::getIPAddresses(
bool usable)
const throw () {
337 IPAddress::vector addresses;
341 if (getFamily() == AF_INET && cidr < 31) {
343 }
else if (getFamily() == AF_INET6 && cidr < 127) {
348 while (contains(address,
true)) {
349 addresses.push_back(address++);
353 if (getFamily() == AF_INET && cidr < 31) {
354 addresses.pop_back();
355 }
else if (getFamily() == AF_INET6 && cidr < 127) {
356 addresses.pop_back();
363 const std::string& IPPrefix::str(
void)
const throw (AddressException) {
364 if (scache.empty()) {
365 scache = this->address.str();
367 scache.push_back(
'/');
368 scache.append(String::itoa(cidr));
374 const char* IPPrefix::c_str(
void)
const throw (AddressException) {
375 return str().c_str();
378 uint32_t IPPrefix::getU32(
void)
const throw () {
381 return (address.getU32() ^ (c | c << 4 | c << 8 | c << 12 | c << 16 | c << 20 | c << 24 | c << 28));
384 uint32_t IPPrefix::getHash(
void)
const throw () {
389 #if defined HASH_ALGO_INT1
390 uint32_t k = getU32();
392 hcache = ((k & 0xF0F0F0F0) >> 4) | ((k & 0x0F0F0F0F) << 4);
393 #elif defined HASH_ALGO_INT2
394 uint32_t k = getU32();
396 hcache = (k<<16)^(k>>16)^k;
397 #elif defined HASH_ALGO_INT3
400 #error No hash algo selected.
406 bool IPPrefix::empty(
void)
const throw () {
407 return (address.empty());
410 void IPPrefix::clear(
void) throw () {
413 mask[0] = 0xFFFFFFFF;
414 mask[1] = 0xFFFFFFFF;
415 mask[2] = 0xFFFFFFFF;
416 mask[3] = 0xFFFFFFFF;
421 const IPPrefix::shared IPPrefix::shared_ptr(
const IPAddress &address, uint8_t cidr)
throw (AddressException) {
422 return std::make_shared<IPPrefix>(address, cidr);
425 const IPPrefix::shared IPPrefix::shared_ptr(
const std::string &address, uint8_t cidr)
throw (AddressException) {
426 return std::make_shared<IPPrefix>(address, cidr);
429 const IPPrefix::shared IPPrefix::shared_ptr(
const std::string &prefix)
throw (AddressException) {
430 return std::make_shared<IPPrefix>(prefix);
433 void IPPrefix::generateMask(
void) throw () {
434 if (address.getFamily() == AF_INET) {
438 uint8_t adj = 32 - cidr;
440 mask[0] = 0xFFFFFFFF >> adj << adj;
445 uint8_t mod = cidr % 32;
446 uint8_t adj = 32 - mod;
448 for (
int i = 4; i > cidr / 32 - 1; i--) {
449 if (i == cidr / 32 && mod != 0) {
450 mask[i] = 0xFFFFFFFF >> adj << adj;