С ++ найти диапазон IP-адресов по значащим битам - PullRequest
1 голос
/ 26 мая 2020

У меня есть следующий код для поиска диапазона IP-адресов v4. Работает отлично:

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;
}

Еще я написал код для расчета диапазона IP-адресов для IPv6 с сопоставлением IPv4-адресов:

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;
}

Но диапазон вычисляется неправильно ... Проблема только с этим кодом :

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

Как мне исправить этот код для расчета диапазонов IPv6?

1 Ответ

2 голосов
/ 26 мая 2020
const uint8_t insignificantBits = 128u - significantBits;
from = ip & (0xFFFFFFFF << insignificantBits);
to = (ip | ((1u << insignificantBits) - 1)) + 1;

Вы используете int для представления маски адреса, но для этого требуется до 128 бит. Используйте вместо него uint128_t, и все должно быть хорошо.

Кроме того, весь «диапазон IP-адресов» известен как su bnet. Я думаю, что обозначение /bits не имеет отношения к IPV6:

Помимо предложения большего количества адресов, IPv6 также реализует функции, отсутствующие в IPv4. Это упрощает аспекты конфигурации адреса, перенумерации сети и объявления маршрутизатора при смене поставщика сетевых подключений. Это упрощает обработку пакетов в маршрутизаторах, возлагая ответственность за фрагментацию пакетов на конечные точки. Размер IPv6 su bnet стандартизирован путем фиксации размера части идентификатора хоста адреса равной 64 битам.

И

IPv6-адреса имеют 128 бит. Дизайн адресного пространства IPv6 реализует другую философию дизайна, чем в IPv4, в котором подсети использовались для повышения эффективности использования небольшого адресного пространства. В IPv6 адресное пространство считается достаточно большим в обозримом будущем, и локальная область su bnet всегда использует 64 бита для части адреса хоста, обозначенной как идентификатор интерфейса, в то время как наиболее значимые 64 бита используются как префикс маршрутизации

enter image description here Источник https://en.wikipedia.org/wiki/IPv6

...