2014-09-19 159 views
5

我想找出所有在這兩個網絡之間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

回答

2

如果你想在最短的面具(最大的網絡)提供,開始與最低的地址(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地址計算。

2

我真的很喜歡這個問題,我昨晚看了一眼,決定試一試。在這一點上,我有一個概念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循環。