算法找到CIDR标记的IPv4网络的两个IPv4地址之间 [英] algorithm to find IPv4 networks in CIDR notation between two IPv4 addresses
问题描述
我想找出所有在这两个网络之间CIDR标记的IPv4网络:
I would like to find out all the IPv4 networks in CIDR notation between those two networks:
10.11.3.64-10.11.3.127
10.11.52.0-10.11.52.255
IPv4网络应该有短子网掩码越好。
IPv4 networks should have as short subnet-mask as possible.
这是相当容易 10.11.3.127
转换成二进制,添加 1
和转换回十进制,以获得该网络的第一个地址。然后转换 10.11.52.0
成二进制,减 1
和转换回十进制,以获得的最后一个地址网络。然而,任何建议的算法是聪明才能使用,找出里面的CIDR块 10.11.3.128-10.11.51.255
范围是多少?就在哪个方向,我应该想到的建议将有望足够:)
It's fairly easy to convert 10.11.3.127
into binary, add 1
and convert back to decimal in order to get the first address of the network. Then convert 10.11.52.0
into binary, subtract 1
and convert back to decimal in order to get the last address of the network. However, any suggestions which algorithm is clever to use in order to find out the CIDR blocks inside the 10.11.3.128-10.11.51.255
range? Just a suggestion in which direction should I think would hopefully be enough :)
推荐答案
我真的很喜欢这个问题,我接过来一看,昨晚,决定给它一个镜头。在这一点上我有概念的shell脚本工作的证明。
I really like this problem, I took a look last night and decided to give it a shot. At this point I have a proof of concept shell script working.
声明:
- 这是一个概念证明只有
- 我种在这里重新发明了轮子,因为我没有使用任何TCP / IP库
- 我并没有实现输入验证
- 如果用一种程序语言,而不是bash中,虽然这种特异性网络范围也不是那么慢这code可能会更快
值得一提的另一件事是,我的理解:
Another thing worth mentioning is that my understanding of:
IPv4网络应该有短子网掩码越好。
是,我们应该从尝试 8 保留网络达提供最大的CIDR,在这种情况下位的 25 。
is that we should try from 8 bits reserved to network up to the greatest cidr provided, in this case 25.
OK,让我们看到了工作中的脚本:
OK, let us see the script in action:
[root@TIAGO-TEST2 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
下面以code:
Below the code:
#! /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
修改这可能是一个好主意,解释这些变量是:
Edit It's probably a good idea to explain what those variables are:
- snet_cidr:在CIDR标记启动网
- enet_cidr:年底净CIDR
- snet_dec:十进制开始净
- enet_dec:年底净十进制
- sbc_ip:开始广播IP
- ebc_ip:结束广播IP
- sbc_dec:开始广播IP
- ebc_dec:结束广播IP
和当你看到TNET或TBC是临时网,广播温度,温度,因为它是内循环。
And wherever you see tnet or tbc is temp net, temp broadcast, temp because it's inside the loop.
这篇关于算法找到CIDR标记的IPv4网络的两个IPv4地址之间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!