mirror of
https://github.com/mfontanini/libtins
synced 2026-01-28 12:44:25 +01:00
Added is_private and is_loopback methods to IPv4 and IPv6 addresses.
This commit is contained in:
@@ -124,6 +124,27 @@ public:
|
||||
return ip_addr < rhs.ip_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns true if this is a private IPv4 address.
|
||||
*
|
||||
* This takes into account the private network ranges defined in
|
||||
* RFC 1918. Therefore, this method returns true if this address
|
||||
* is in any of the following network ranges, false otherwise:
|
||||
*
|
||||
* - 192.168.0.0/16
|
||||
* - 10.0.0.0/8
|
||||
* - 172.16.0.0/12
|
||||
*/
|
||||
bool is_private() const;
|
||||
|
||||
/**
|
||||
* \brief Returns true if this is a loopback IPv4 address.
|
||||
*
|
||||
* This method returns true if this address is in the address range
|
||||
* 127.0.0.0/8, false otherwise.
|
||||
*/
|
||||
bool is_loopback() const;
|
||||
|
||||
/**
|
||||
* \brief Writes this address to a std::ostream.
|
||||
*
|
||||
|
||||
@@ -184,6 +184,14 @@ public:
|
||||
return std::copy(begin(), end(), iter);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns true if this is a loopback IPv6 address.
|
||||
*
|
||||
* This method returns true if this address is the ::1/128 address,
|
||||
* false otherwise.
|
||||
*/
|
||||
bool is_loopback() const;
|
||||
|
||||
/**
|
||||
* \brief Writes this address in hex-notation to a std::ostream.
|
||||
*
|
||||
|
||||
@@ -36,6 +36,14 @@
|
||||
using std::string;
|
||||
|
||||
namespace Tins{
|
||||
const AddressRange<IPv4Address> private_ranges[] = {
|
||||
IPv4Address("192.168.0.0") / 16,
|
||||
IPv4Address("10.0.0.0") / 8,
|
||||
IPv4Address("172.16.0.0") / 12
|
||||
};
|
||||
|
||||
const AddressRange<IPv4Address> loopback_range = IPv4Address("127.0.0.0") / 8;
|
||||
|
||||
IPv4Address::IPv4Address(uint32_t ip)
|
||||
: ip_addr(Endian::be_to_host(ip)) {
|
||||
|
||||
@@ -96,6 +104,20 @@ std::ostream &operator<<(std::ostream &output, const IPv4Address &addr) {
|
||||
return output;;
|
||||
}
|
||||
|
||||
bool IPv4Address::is_private() const {
|
||||
const AddressRange<IPv4Address> *iter = private_ranges;
|
||||
while(iter != private_ranges + 3) {
|
||||
if(iter->contains(*this))
|
||||
return true;
|
||||
++iter;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IPv4Address::is_loopback() const {
|
||||
return loopback_range.contains(*this);
|
||||
}
|
||||
|
||||
AddressRange<IPv4Address> operator/(const IPv4Address &addr, int mask) {
|
||||
if(mask > 32)
|
||||
throw std::logic_error("Prefix length cannot exceed 32");
|
||||
|
||||
@@ -44,72 +44,78 @@
|
||||
#include "address_range.h"
|
||||
|
||||
namespace Tins {
|
||||
IPv6Address::IPv6Address() {
|
||||
std::fill(address, address + address_size, 0);
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const char *addr) {
|
||||
init(addr);
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const_iterator ptr) {
|
||||
std::copy(ptr, ptr + address_size, address);
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const std::string &addr) {
|
||||
init(addr.c_str());
|
||||
}
|
||||
|
||||
void IPv6Address::init(const char *addr) {
|
||||
#ifdef WIN32
|
||||
// mingw on linux somehow doesn't have InetPton
|
||||
#ifdef _MSC_VER
|
||||
if(InetPtonA(AF_INET6, addr, address) != 1)
|
||||
throw malformed_address();
|
||||
#else
|
||||
ULONG dummy1;
|
||||
USHORT dummy2;
|
||||
// Maybe change this, mingw doesn't have any other conversion function
|
||||
if(RtlIpv6StringToAddressExA(addr, (IN6_ADDR*)address, &dummy1, &dummy2) != NO_ERROR)
|
||||
throw malformed_address();
|
||||
#endif
|
||||
#else
|
||||
if(inet_pton(AF_INET6, addr, address) == 0)
|
||||
throw malformed_address();
|
||||
#endif
|
||||
}
|
||||
const IPv6Address loopback_address = "::1";
|
||||
|
||||
std::string IPv6Address::to_string() const {
|
||||
char buffer[INET6_ADDRSTRLEN];
|
||||
#ifdef WIN32
|
||||
// mingw on linux somehow doesn't have InetNtop
|
||||
#ifdef _MSC_VER
|
||||
if(InetNtopA(AF_INET6, (PVOID)address, buffer, sizeof(buffer)) != 0)
|
||||
throw malformed_address();
|
||||
#else
|
||||
ULONG sz = sizeof(buffer);
|
||||
if(RtlIpv6AddressToStringExA((const IN6_ADDR*)address, 0, 0, buffer, &sz) != NO_ERROR)
|
||||
throw malformed_address();
|
||||
#endif
|
||||
#else
|
||||
if(inet_ntop(AF_INET6, address, buffer, sizeof(buffer)) == 0)
|
||||
throw malformed_address();
|
||||
#endif
|
||||
return buffer;
|
||||
}
|
||||
|
||||
AddressRange<IPv6Address> operator/(const IPv6Address &addr, int mask) {
|
||||
if(mask > 128)
|
||||
throw std::logic_error("Prefix length cannot exceed 128");
|
||||
IPv6Address last_addr;
|
||||
IPv6Address::iterator it = last_addr.begin();
|
||||
while(mask > 8) {
|
||||
*it = 0xff;
|
||||
++it;
|
||||
mask -= 8;
|
||||
}
|
||||
*it = 0xff << (8 - mask);
|
||||
return AddressRange<IPv6Address>::from_mask(addr, last_addr);
|
||||
}
|
||||
IPv6Address::IPv6Address() {
|
||||
std::fill(address, address + address_size, 0);
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const char *addr) {
|
||||
init(addr);
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const_iterator ptr) {
|
||||
std::copy(ptr, ptr + address_size, address);
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const std::string &addr) {
|
||||
init(addr.c_str());
|
||||
}
|
||||
|
||||
void IPv6Address::init(const char *addr) {
|
||||
#ifdef WIN32
|
||||
// mingw on linux somehow doesn't have InetPton
|
||||
#ifdef _MSC_VER
|
||||
if(InetPtonA(AF_INET6, addr, address) != 1)
|
||||
throw malformed_address();
|
||||
#else
|
||||
ULONG dummy1;
|
||||
USHORT dummy2;
|
||||
// Maybe change this, mingw doesn't have any other conversion function
|
||||
if(RtlIpv6StringToAddressExA(addr, (IN6_ADDR*)address, &dummy1, &dummy2) != NO_ERROR)
|
||||
throw malformed_address();
|
||||
#endif
|
||||
#else
|
||||
if(inet_pton(AF_INET6, addr, address) == 0)
|
||||
throw malformed_address();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string IPv6Address::to_string() const {
|
||||
char buffer[INET6_ADDRSTRLEN];
|
||||
#ifdef WIN32
|
||||
// mingw on linux somehow doesn't have InetNtop
|
||||
#ifdef _MSC_VER
|
||||
if(InetNtopA(AF_INET6, (PVOID)address, buffer, sizeof(buffer)) != 0)
|
||||
throw malformed_address();
|
||||
#else
|
||||
ULONG sz = sizeof(buffer);
|
||||
if(RtlIpv6AddressToStringExA((const IN6_ADDR*)address, 0, 0, buffer, &sz) != NO_ERROR)
|
||||
throw malformed_address();
|
||||
#endif
|
||||
#else
|
||||
if(inet_ntop(AF_INET6, address, buffer, sizeof(buffer)) == 0)
|
||||
throw malformed_address();
|
||||
#endif
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool IPv6Address::is_loopback() const {
|
||||
return loopback_address == *this;
|
||||
}
|
||||
|
||||
AddressRange<IPv6Address> operator/(const IPv6Address &addr, int mask) {
|
||||
if(mask > 128)
|
||||
throw std::logic_error("Prefix length cannot exceed 128");
|
||||
IPv6Address last_addr;
|
||||
IPv6Address::iterator it = last_addr.begin();
|
||||
while(mask > 8) {
|
||||
*it = 0xff;
|
||||
++it;
|
||||
mask -= 8;
|
||||
}
|
||||
*it = 0xff << (8 - mask);
|
||||
return AddressRange<IPv6Address>::from_mask(addr, last_addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,3 +49,34 @@ TEST(IPAddressTest, LessThanOperator) {
|
||||
EXPECT_LT(addr1, "192.168.0.226");
|
||||
EXPECT_LT(addr1, "193.0.0.0");
|
||||
}
|
||||
|
||||
TEST(IPAddressTest, IsPrivate) {
|
||||
EXPECT_TRUE(IPv4Address("192.168.0.1").is_private());
|
||||
EXPECT_TRUE(IPv4Address("192.168.133.7").is_private());
|
||||
EXPECT_TRUE(IPv4Address("192.168.255.254").is_private());
|
||||
EXPECT_FALSE(IPv4Address("192.169.0.1").is_private());
|
||||
EXPECT_FALSE(IPv4Address("192.167.255.254").is_private());
|
||||
|
||||
EXPECT_TRUE(IPv4Address("10.0.0.1").is_private());
|
||||
EXPECT_TRUE(IPv4Address("10.5.1.2").is_private());
|
||||
EXPECT_TRUE(IPv4Address("10.255.255.254").is_private());
|
||||
EXPECT_FALSE(IPv4Address("11.0.0.1").is_private());
|
||||
EXPECT_FALSE(IPv4Address("9.255.255.254").is_private());
|
||||
|
||||
EXPECT_TRUE(IPv4Address("172.16.0.1").is_private());
|
||||
EXPECT_TRUE(IPv4Address("172.31.255.254").is_private());
|
||||
EXPECT_TRUE(IPv4Address("172.20.13.75").is_private());
|
||||
EXPECT_FALSE(IPv4Address("172.15.0.1").is_private());
|
||||
EXPECT_FALSE(IPv4Address("172.32.0.1").is_private());
|
||||
|
||||
EXPECT_FALSE(IPv4Address("100.100.100.100").is_private());
|
||||
EXPECT_FALSE(IPv4Address("199.199.29.10").is_private());
|
||||
}
|
||||
|
||||
TEST(IPAddressTest, IsLoopback) {
|
||||
EXPECT_TRUE(IPv4Address("127.0.0.1").is_loopback());
|
||||
EXPECT_TRUE(IPv4Address("127.0.0.0").is_loopback());
|
||||
EXPECT_TRUE(IPv4Address("127.255.255.254").is_loopback());
|
||||
EXPECT_FALSE(IPv4Address("126.255.255.254").is_loopback());
|
||||
EXPECT_FALSE(IPv4Address("128.0.0.0").is_loopback());
|
||||
}
|
||||
|
||||
@@ -85,3 +85,9 @@ TEST(IPv6AddressTest, Copy) {
|
||||
addr1.copy(addr2.begin());
|
||||
EXPECT_EQ(addr1, addr2);
|
||||
}
|
||||
|
||||
TEST(IPv6AddressTest, IsLoopback) {
|
||||
EXPECT_TRUE(IPv6Address("::1").is_loopback());
|
||||
EXPECT_FALSE(IPv6Address("::2").is_loopback());
|
||||
EXPECT_FALSE(IPv6Address("ffff::2").is_loopback());
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ TEST_F(UtilsTest, ResolveDomain) {
|
||||
}
|
||||
|
||||
TEST_F(UtilsTest, ResolveDomain6) {
|
||||
IPv6Address localhost_ip("2001:500:88:200::10");
|
||||
IPv6Address localhost_ip("2606:2800:220:6d:26bf:1447:1097:aa7");
|
||||
|
||||
EXPECT_EQ(Utils::resolve_domain6("example.com"), localhost_ip);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user