算法来寻找两个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块?就在哪个方向,我应该想到的建议将有望足够:)
如果你想在最短的面具(最大的网络)提供,开始与最低的地址(10.11.3.128),并戴上口罩最小的可能,开始在接下来的地址,并把上最小的面膜可能等只要不超出范围的最大地址:
- 10.11.3.128/25(10.11.3.128到10.11.3.255)更小的东西是无效的
- 10.11.4.0/22(10.11.4.0至10.11.7.255)任何更小的值无效
- 10.11.8.0/21(10.11.8.0至10.11.15.255)anyt hing越小越无效
- 10.11.16.0/20(10.11.16.0至10.11.31.255)任何更小的无效
- 10.11.32.0/20(10.11.32.0至10.11.47.255)/ 19是有效的,但会去太远
- 10.11.48.0/22(10.11.48.0到10.11.51.255)/ 20/21是有效的,但会适可而止
二进制这个来看,这是显而易见的。掩码与子网进行AND运算(子网或掩码中零的任何位置变为零;子网和掩码中的位置都必须有一个)。如果你和一个子网和一个掩码,它不等于子网,它是无效的。
所有的IP地址计算都需要用二进制完成。点分十进制表示对于人的可读性来说是很好的,但不应该用来做IP地址计算。
我真的很喜欢这个问题,我昨晚看了一眼,决定试一试。在这一点上,我有一个概念shell脚本工作的证明。
免责声明:
- 这是概念只
- 我有种又彻底改造了车轮这里我没有使用任何TCP/IP库
- 我没有实现的证明输入验证
- 如果使用编程语言而不是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
编辑这可能是一个好主意,解释这些变量是:
- snet_cidr:以cidr符号开始网络 个
- enet_cidr:年底净CIDR
- snet_dec:十进制
- enet_dec开始网:年底净十进制
- sbc_ip:开始广播IP
- ebc_ip:高端广播IP
- sbc_dec:开始广播IP
- ebc_dec:高端广播IP
何地,你看到TNET或TBC是临时网,广播温度,温度,因为它是insid循环。
解释'IPv4网络应尽可能使用短子网掩码。' – hek2mgl 2014-09-19 14:03:01
@ 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
或从10.11.3.128/0到10.11.51.255/0使用32位的前缀,这实际上是IPV4最大可能的前缀..这就是为什么我问.. – hek2mgl 2014-09-19 14:50:15