正在计算组成给定IP范围的子网列表
Calculating list of subnets that make a given IP range
我正试图想出并理解一个函数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,但它们不相等,所以这不是我所期望的),而不是整个范围。
首先,这不是一个在不尝试自己编写代码的情况下获得工作代码的网站。然而,我将解释我将如何处理这个问题,并为您提供一个可以根据您的需求轻松采用的代码。
如果您有定义单个作用域(如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/26
和10.0.0.64/26
,而不是10.0.0.0/25
,并且您的两个新范围是10.0.0.1 - 10.0.0.63
和10.0.0.64 - 10.0.0.126
。您将继续以这种方式划分您的范围,直到:
- 您的起始IP等于子网地址,结束IP等于广播地址
- 你的射程太小了,不能再分开了(/32)
这是我为此编写的代码。所有计算都是在IP地址的十进制表示上完成的(不是点式十进制),因此前两个函数将带点式十进制表示的IP的string
转换为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
- 为什么在全局范围内使用"extern int a"似乎不行?
- 尝试通过多个向量访问变量时,向量下标超出范围
- 错误:未在此范围内声明'reverse'
- 正在将指针转换为范围
- 使用std::transform将一个范围的元素添加到另一个范围中
- 在基于范围的for循环中使用结构化绑定声明
- 如何计算数据类型的范围,例如int
- 为什么 const std::p air<K,V>& 在 std::map 上基于范围的 for 循环不起作用?
- 在C++中查找范围的长度
- 如何设置一个范围来提取我想要获得的信息
- 并行用于C++17中数组索引范围内的循环
- 为左值和右值的包装器实现C++范围
- 求出有多少个数字是完美平方,而sqrt()是L,R范围内的素数
- 检查IP是否在其他IP网络范围内,并查找下一个可用IP
- 数学:计算范围内的总IP
- IP 地址重叠/在 CIDR 范围内
- 在 ipv6 链接范围单播 udp 客户端-服务器中应用 boost::asio::ip::udp,有时有效,但有时无效
- 正在计算组成给定IP范围的子网列表
- 使用inet_pton()检查给定的IP是否属于IP范围
- IP在CIDR范围内