算法来寻找两个IPv4之间的CIDR表示IPv4网络地址

算法来寻找两个IPv4之间的CIDR表示IPv4网络地址

问题描述:

我想找出所有在这两个网络之间CIDR标记的IPv4网络:算法来寻找两个IPv4之间的CIDR表示IPv4网络地址

10.11.3.64-10.11.3.127 
10.11.52.0-10.11.52.255 

IPv4网络应该有尽可能短子网掩码为可能。

10.11.3.127转换为二进制,添加1并将其转换回十进制以便获取网络的第一个地址是相当容易的。然后将10.11.52.0转换为二进制,减去1并转换回十进制以获得网络的最后地址。但是,有哪些算法可以巧妙地用于找出10.11.3.128-10.11.51.255范围内的CIDR块?就在哪个方向,我应该想到的建议将有望足够:)

+0

解释'IPv4网络应尽可能使用短子网掩码。' – hek2mgl 2014-09-19 14:03:01

+0

@ hek2mgl这意味着IPv4前缀应该尽可能大。例如,网络范围'10.11.3.128-10.11.51.255'可以用'10.11.3.128/25'的CIDR表示法,然后用'24前缀的'10.11.4.0/24'表示为'10.11.51.0/24'。实际上这些'/ 24'可以被聚合。 – Martin 2014-09-19 14:26:07

+0

或从10.11.3.128/0到10.11.51.255/0使用32位的前缀,这实际上是IPV4最大可能的前缀..这就是为什么我问.. – hek2mgl 2014-09-19 14:50:15

如果你想在最短的面具(最大的网络)提供,开始与最低的地址(10.11.3.128),并戴上口罩最小的可能,开始在接下来的地址,并把上最小的面膜可能等只要不超出范围的最大地址:

  1. 10.11.3.128/25(10.11.3.128到10.11.3.255)更小的东西是无效的
  2. 10.11.4.0/22(10.11.4.0至10.11.7.255)任何更小的值无效
  3. 10.11.8.0/21(10.11.8.0至10.11.15.255)anyt hing越小越无效
  4. 10.11.16.0/20(10.11.16.0至10.11.31.255)任何更小的无效
  5. 10.11.32.0/20(10.11.32.0至10.11.47.255)/ 19是有效的,但会去太远
  6. 10.11.48.0/22(10.11.48.0到10.11.51.255)/ 20/21是有效的,但会适可而止

二进制这个来看,这是显而易见的。掩码与子网进行AND运算(子网或掩码中零的任何位置变为零;子网和掩码中的位置都必须有一个)。如果你和一个子网和一个掩码,它不等于子网,它是无效的。

所有的IP地址计算都需要用二进制完成。点分十进制表示对于人的可读性来说是很好的,但不应该用来做IP地址计算。

我真的很喜欢这个问题,我昨晚看了一眼,决定试一试。在这一点上,我有一个概念shell脚本工作的证明。

免责声明:

  1. 这是概念只
  2. 我有种又彻底改造了车轮这里我没有使用任何TCP/IP库
  3. 我没有实现的证明输入验证
  4. 如果使用编程语言而不是bash编写代码,该代码可能会快得多,但对于此特定网络范围并不那么慢

另一件事值得一提的是,我的理解:

IPv4 networks should have as short subnet-mask as possible.

是,我们应该试着从保留到网点达提供最大的CIDR 位,在这种情况下。

OK,让我们看到了正在运行的脚本:

[[email protected] tmp]# time bash ip.sh 10.11.3.64/25 10.11.52.0/24 
10.11.3.128/25 
10.11.4.0/22 
10.11.8.0/21 
10.11.16.0/20 
10.11.32.0/20 
10.11.48.0/22 

real 0m48.376s 
user 0m6.174s 
sys  0m34.644s 

代码如下:

#! /bin/bash 

function split_octet { 
    sed -re "s/\./ /g" <<< "$1" 
} 

function dec2bin { 
    perl -e 'printf "%0'"$1"'b\n",'"$2"';' 
} 

function bin2dec { 
    perl -le 'print 0b'"$1"';' 
} 

function ip2bin { 
    str="" 
    for octet in $(split_octet $1); do 
     str="${str}$(dec2bin 8 $octet)" 
    done 
    echo "$str" 
} 

function bin2ip { 
    str="" 
    for octet in $(grep -Eo '.{8}' <<< $1); do 
     dec=$(bin2dec $octet) 
     str="${str}.${dec}" 
    done 
    echo "$str" | sed -re 's/^\.|\.$//g' 
} 

function ip2dec { 
    ip=$1 
    bin2dec $(ip2bin $ip) 
} 

function dec2ip { 
    dec=$1 
    bin2ip $(dec2bin 32 $dec) 
} 

function AND { 
    perl -e ' $a=0b'"$1"' & 0b'"$2"'; 
         printf "%032b\n",$a 
        ' 
} 

function OR { 
    perl -e ' $a=0b'"$1"' | 0b'"$2"'; 
         printf "%032b\n",$a 
        ' 
} 

function NOT { 
    perl -le ' $a= (~ 0b'"$1"') & 0xFFFFFFFF; 
          printf "%032b\n",$a 
        ' 
} 

function get_network { 
    ip=$1; mask=$2; 

    if [ -n "$ip" -a -n "$mask" ];then 
    echo $(bin2ip $(AND $(ip2bin $ip) $(ip2bin $mask))) 
     return 
    fi 

    grep -qP "\d+\.\d+\.\d+.\d+/\d+" <<< "$ip" 
    if [ "$?" == 0 ];then 
     ip=$(get_ip_from_cidr $1) 
     mask=$(get_mask_from_cidr $1) 
     echo $(bin2ip $(AND $(ip2bin $ip) $(ip2bin $mask))) 
    fi 
} 

function get_broadcast { 
    ip=$1; mask=$2; 

    if [ -n "$ip" -a -n "$mask" ];then 
     echo $(bin2ip $(OR $(ip2bin $ip) $(NOT $(ip2bin $mask)))) 
     return 
    fi 

    grep -qP "\d+\.\d+\.\d+.\d+/\d+" <<< "$ip" 
    if [ "$?" == 0 ];then 
     ip=$(get_ip_from_cidr $1) 
     mask=$(get_mask_from_cidr $1) 
     echo $(bin2ip $(OR $(ip2bin $ip) $(NOT $(ip2bin $mask)))) 
    fi 

} 

function get_ip_from_cidr { 
    awk -F/ '{print $1}' <<< "$1" 
} 

function get_mask_from_cidr { 
    mask=$(awk -F/ '{print $2}' <<< "$1") 
    mask=$(cidr $mask) 
    mask=$(bin2ip $mask) 
    echo $mask 
} 

function cidr { 
    perl -e ' 
         $n='"$1"'; 
         $diff=32-$n; 
         print "1"x$n . "0"x$diff; 
        ' 
} 


snet_cidr=$1 
enet_cidr=$2 

largest_cidr=$(echo -e "$snet_cidr\n$enet_cidr"| awk -F/ '{print $2}' | sort -rn | head -1) 

snet_dec=$(ip2dec $(get_ip_from_cidr $snet_cidr)) 
enet_dec=$(ip2dec $(get_ip_from_cidr $enet_cidr)) 

sbc_ip=$(get_broadcast $snet_cidr) 
ebc_ip=$(get_broadcast $enet_cidr) 

sbc_dec=$(ip2dec $sbc_ip) 
ebc_dec=$(ip2dec $ebc_ip) 

counter=$sbc_dec 

while [ $counter -lt $enet_dec ];do 
    tip=$(dec2ip $counter) 
    for cidr in $(seq 8 $largest_cidr) ; do 
     tnet_ip=$(get_network $tip/$cidr) 
     tnet_cidr=$tnet_ip/$cidr 
     tbc_ip=$(get_broadcast $tnet_cidr) 
     tnet_dec=$(ip2dec $(get_ip_from_cidr $tnet_cidr)) 
     tbc_dec=$(ip2dec $tbc_ip) 
     if [ $sbc_dec -lt $tnet_dec -a $enet_dec -gt $tbc_dec ];then 
      echo $tnet_cidr 
      counter=$tbc_dec 
      break 
     fi 
    done 
    let counter++ 
done 

编辑这可能是一个好主意,解释这些变量是:

  1. snet_cidr:以cidr符号开始网络
  2. enet_cidr:年底净CIDR
  3. snet_dec:十进制
  4. enet_dec开始网:年底净十进制
  5. sbc_ip:开始广播IP
  6. ebc_ip:高端广播IP
  7. sbc_dec:开始广播IP
  8. ebc_dec:高端广播IP

何地,你看到TNET或TBC是临时网,广播温度,温度,因为它是insid循环。