C++ find range ip addresses by significant bits

1

I have the following code for find range of the ip addresses v4. It works perfectly:

uint32_t byte1 = 0, byte2 = 0, byte3 = 0, byte4 = 0, significantBits = 0;
int read = sscanf(ipRangeStr.c_str(), "%3d.%3d.%3d.%3d/%2u", &byte1, &byte2, &byte3, &byte4, &significant);
if (read < 4) {
    throw std::runtime_error("Cannot parse ip range: " + ipRangeStr);
}
uint32_t ip = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
uint32_t from = 0, to = 0;
if (4 == read || 32 == significantBits) {
    from = ip;
    to = ip + 1;
} else {
    if (significantBits > 32) {
        throw std::runtime_error("Cannot parse ip range: " + ipRangeStr);
    }
    const uint8_t insignificantBits = 32 - significantBits;
    from = ip & (0xFFFFFFFF << insignificantBits);
    to = (ip | ((1 << insignificantBits) - 1)) + 1;
}

I also wrote code for calculating range IP addresses for IPv6 with mapping IPv4 addresses:

std::string significantBitsStr;
std::string ipRangeStrWithoutSignificantBits;
const size_t position = ipRangeStr.find("/");
if (position != std::string::npos) {
    significantBitsStr = ipRangeStr.substr(position + 1u);
    ipRangeStrWithoutSignificantBits = ipRangeStr.substr(0u, position);
}

std::string ipV6Address;
boost::system::error_code status;
bool mappedV4Address = false;
boost::asio::ip::address_v6::bytes_type bytes;
boost::asio::ip::address address = boost::asio::ip::address::from_string(ipRangeStrWithoutSignificantBits, status);
if (status != boost::system::errc::success) {
    throw std::runtime_error("Cannot parse ip range: " + ipRangeStr);
} else if (address.is_v6()) {
    ipV6Address = address.to_string();
    bytes = address.to_v6().to_bytes();
} else if (address.is_v4()) {
    boost::asio::ip::address_v6 addressV6 = boost::asio::ip::address_v6::v4_mapped(address.to_v4());
    ipV6Address = addressV6.to_string();
    bytes = addressV6.to_bytes();
    mappedV4Address = true;
}

boost::multiprecision::uint128_t ip = 0u;
for (const auto byte : bytes) {
    (ip <<= 8u) |= byte;
}

boost::multiprecision::uint128_t from = 0u, to = 0u;
const auto significantBits = boost::lexical_cast<uint32_t>(significantBitsStr);
if ((mappedV4Address && significantBits > 32u) || (significantBits > 128u)) {
    throw std::runtime_error("Cannot parse ip range: " + ipRangeStr + " - incorrect significant bits.");
} else if ((mappedV4Address && significantBits == 32u) || (significantBits == 128u)) {
    from = ip;
    to = ip + 1;
} else {
    // Theses interval calculates incorrectly
    const uint8_t insignificantBits = 128u - significantBits;
    from = ip & (0xFFFFFFFF << insignificantBits);
    to = (ip | ((1u << insignificantBits) - 1)) + 1;
}

But range calculates incorrectly... Problem only with this code:

const uint8_t insignificantBits = 128u - significantBits;
from = ip & (0xFFFFFFFF << insignificantBits);
to = (ip | ((1u << insignificantBits) - 1)) + 1;

How can I correct this code for calculating IPv6 ranges?

c++
boost
asked on Stack Overflow May 26, 2020 by QuickDzen

1 Answer

2
const uint8_t insignificantBits = 128u - significantBits;
from = ip & (0xFFFFFFFF << insignificantBits);
to = (ip | ((1u << insignificantBits) - 1)) + 1;

You're using int to represent the address mask, but it needs up to 128 bits. Use uint128_t instead and it should be fine.

Besides, the whole "IP range" thing is known as a subnet. I think the /bits notattion is not relevant to IPV6:

In addition to offering more addresses, IPv6 also implements features not present in IPv4. It simplifies aspects of address configuration, network renumbering, and router announcements when changing network connectivity providers. It simplifies processing of packets in routers by placing the responsibility for packet fragmentation into the end points. The IPv6 subnet size is standardized by fixing the size of the host identifier portion of an address to 64 bits.

And

IPv6 addresses have 128 bits. The design of the IPv6 address space implements a different design philosophy than in IPv4, in which subnetting was used to improve the efficiency of utilization of the small address space. In IPv6, the address space is deemed large enough for the foreseeable future, and a local area subnet always uses 64 bits for the host portion of the address, designated as the interface identifier, while the most-significant 64 bits are used as the routing prefix

enter image description here Source https://en.wikipedia.org/wiki/IPv6

answered on Stack Overflow May 26, 2020 by sehe • edited May 26, 2020 by sehe

User contributions licensed under CC BY-SA 3.0