【问题标题】:Calculating list of subnets that make a given IP range [closed]计算构成给定 IP 范围的子网列表 [关闭]
【发布时间】:2015-04-05 00:29:47
【问题描述】:

我正在尝试提出并理解一个函数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 但它们不相等,所以这不是我所期望的)而不是整个范围。

【问题讨论】:

    标签: c++ networking ip cidr


    【解决方案1】:

    首先,这不是一个无需尝试自己编写东西即可获得工作代码的网站。不过,我将解释我将如何解决这个问题,并为您提供可以轻松满足您需求的代码。

    如果您有定义单个范围的范围,如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/2610.0.0.64/26 而不是10.0.0.0/25,而您的两个新范围是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;
        }
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-28
      • 2012-10-06
      • 2012-12-28
      • 1970-01-01
      • 2013-06-09
      • 2010-12-01
      • 2013-09-15
      • 2017-10-08
      相关资源
      最近更新 更多