c++ - 计算构成给定 IP 范围的子网列表

标签 c++ networking ip cidr

我正在尝试想出并理解一个函数 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

甚至更复杂的情况。

我之前找到过许多此代码的在线示例可供查看,但其中一些根本不起作用,其余的则返回最小的公共(public)子网(例如 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/2510.0.0.0/26 ,而不是 10.0.0.64/26 ,并且两个新范围是 10.0.0.1 - 10.0.0.6310.0.0.64 - 10.0.0.126 。您将继续以这种方式分割范围,直到:

  1. 您的起始 IP 等于子网地址并且结束 IP 等于广播地址
  2. 您的范围太小,无法进一步分割 (/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;
    }
}

您可以采用此方法将子网放入 vector (或您想要的任何内容)中,而不是将其打印到 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

关于c++ - 计算构成给定 IP 范围的子网列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28339094/

相关文章:

python - 如何为 std::vector 数据的形状 View 编写 LLDB 合成提供程序

c++ - 不知道如何正确使用 IShellWindows::Item

c++ - 服务器端库 (c/c++) xmlrpc

c# - 如何使程序能够在运行时写入自己的可执行文件?

c++ - 如何在 linux 上的 c\c++ 中获取 net encap?

java - 确定给定 IP 是否为 Web 主机

python - 高效的ip查找

testing - Hyperledger Fabric 测试网络中 channel 创建失败

c# - 两个 C# 应用程序如何通过 WiFi 网络发送消息?

javascript - 将 cookie 域设置为 IP 地址(使用 CORS)