Прежде всего, это не сайт для получения рабочего кода, не пытаясь что-то написать. Однако я объясню, как я подхожу к этой проблеме и даю вам код, который можно легко адаптировать к вашим потребностям.
Эта проблема проста, если у вас есть диапазоны, которые определяют единую область, такую как 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
. Вы бы продолжать разделить ваши диапазоны этот путь до:
- Ваш Start IP не равно адрес подсети и End IP равно широковещательный адрес
- Ваш диапазон настолько мал, вы не можете разделить его дальше (/ 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