2015-02-05 5 views
2

Я пытаюсь найти и понять функцию IPv4Range (startIPAddr, endIPAddr), которая вернет список диапазонов CIDR.Расчет списка подсетей, которые делают данный диапазон IP

Например:

10.0.0.0 - 10.0.0.3 -> 10.0.0.0/30 
    10.0.0.0 - 10.0.0.6 -> 10.0.0.0/30, 10.0.0.4/31, 10.0.0.6/32 

и даже более сложные случаи.

Я уже нашел много онлайн-примеров этого кода, но некоторые из них не работают вообще, а остальные из них возвращают наименьшую общую подсеть (например, 10.0.0.0/29 содержит 10.0.0.0 - 10.0.0.4, но они не равны, так что это не то, что я ожидаю), а не весь диапазон.

ответ

2

Прежде всего, это не сайт для получения рабочего кода, не пытаясь что-то написать. Однако я объясню, как я подхожу к этой проблеме и даю вам код, который можно легко адаптировать к вашим потребностям.

Эта проблема проста, если у вас есть диапазоны, которые определяют единую область, такую ​​как 10.0.0.0 - 10.0.0.255, поэтому позволяет получить что-то более сложное, например 10.0.0.1 - 10.0.0.126. Этот диапазон действительно близок к 10.0.0.0/25, но на обоих концах отсутствует/32, гарантируя, что вам понадобится 12 областей для заполнения этого диапазона.

Эта проблема может быть представлена ​​следующим образом:

   Start IP       End IP 
        v        v 
-------|----------+----------------+---------------+-----------|------ 
    ^  .        .   ^
    Subnet address .        . Broadcast address 
     .   .        .   . 
     .   \________________________________/   . 
     .      Provided Range     . 
     .              . 
     \_______________________________________________________/ 
           Scope Range 

Вы можете решить эти виды проблем, наиболее легко, используя разделяй и властвуй подход. В этом случае (и имея в виду, что маска подсети всегда равна 2), мы можем разделить эту проблему (диапазон 10.0.0.1 - 10.0.0.126 с маской 25) в двух меньших.

   Start IP       End IP 
        v        v 
-------|----------+---------------++---------------+-----------|------ 
    ^      ||       ^
    Subnet address     ||     Broadcast address 
     .       ||       . 
     \__________________________/\___________________________/ 
     .   /X+1      /X+1    . 
     .              . 
     \_______________________________________________________/ 
         Scope prefix length: /X 

При увеличении длины префикса вы в основном разделяете область на две части. Поэтому вместо того, чтобы иметь 10.0.0.0/25, теперь у вас есть 10.0.0.0/26 и 10.0.0.64/26, а ваши два новых диапазона: 10.0.0.1 - 10.0.0.63 и 10.0.0.64 - 10.0.0.126. Вы бы продолжать разделить ваши диапазоны этот путь до:

  1. Ваш Start IP не равно адрес подсети и End IP равно широковещательный адрес
  2. Ваш диапазон настолько мал, вы не можете разделить его дальше (/ 32).

Это код, который я собрал для этого. Все расчеты производятся на десятичном представлении IP-адрес (не десятичный), поэтому первые две функций преобразования string с IP в точечно-десятичной нотации для long и наоборот:

#include <sstream> 
long str_to_long(string ip){ 
    stringstream s(ip); 
    int o1, o2, o3, o4; 
    char ch; 
    s >> o1 >> ch >> o2 >> ch >> o3 >> ch >> o4; 
    long ip_long = 0; 
    ip_long = 0 | (o1 << 24) | (o2 << 16) | (o3 << 8) | o4; 
    return ip_long; 
} 

string long_to_str(long ip){ 
    stringstream tmp; 
    tmp << to_string((long long) ip >> 24 & 0xFF).c_str() << '.'; 
    tmp << to_string((long long) ip >> 16 & 0xFF).c_str() << '.'; 
    tmp << to_string((long long) ip >> 8 & 0xFF).c_str() << '.'; 
    tmp << to_string((long long) ip & 0xFF).c_str(); 
    return tmp.str(); 
} 

Главных функция принимает два аргумента (long) - запуск IP и конечный IP - и печатает необходимые подсети.

void subnets(long start_ip, long end_ip){ 
    int host_bits = 0, host_mask = 0; 
    long tmp = start_ip^end_ip; 
    while(tmp != 0){ 
     tmp = tmp >> 1; 
     host_bits++; 
    } 
    host_mask = (unsigned long)-1 >> (32 - host_bits); 
    long network_addr = start_ip & (-1^host_mask); 
    long broadcast_addr = start_ip | host_mask; 
    if(host_bits > 1){ 
     long split_low = (network_addr | host_mask >> 1); 
     long split_high =(broadcast_addr & (-1^host_mask >> 1)); 
     if(start_ip != network_addr || end_ip != broadcast_addr){ 
      subnets(start_ip, split_low); 
      subnets(split_high, end_ip); 
     }else{ 
      cout << long_to_str(start_ip) << "/" << 32-host_bits << endl; 
     } 
    }else{ 
     cout << long_to_str(start_ip) << "/" << 32-host_bits << endl; 
    } 
} 

Вы можете принять это, чтобы положить подсети внутри вектора (или что вы хотите) вместо того, чтобы печатать его COUT. Поэтому, когда мы запускаем это с диапазоном, указанным в начале subnets(str_to_long("10.0.0.1"), str_to_long("10.0.0.126")), вы получаете точный список из 12 подсетей, составляющих этот диапазон.

10.0.0.1/32 
10.0.0.2/31 
10.0.0.4/30 
10.0.0.8/29 
10.0.0.16/28 
10.0.0.32/27 
10.0.0.64/27 
10.0.0.96/28 
10.0.0.112/29 
10.0.0.120/30 
10.0.0.124/31 
10.0.0.126/32