我正在努力想出一个函数IPv4Range (startIPAddr, endIPAddr)
,它将返回一个CIDR范围列表。
例如:
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但它们不相等所以它不是我所期望的而不是整个范围。
答案 0 :(得分:3)
首先,这不是一个获取工作代码而不试图自己编写代码的网站。但是,我将解释如何解决这个问题,并为您提供一个可以轻松满足您需求的代码。
如果您的范围定义了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
。您将继续以这种方式拆分范围,直到:
这是我为此编写的代码。所有计算都是在IP地址的十进制表示(非点分十进制)上完成的,因此前两个函数将带有IP的string
以点分十进制表示法转换为long
,反之亦然: / p>
#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();
}
main函数需要两个(long
)参数 - Start IP和End 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