I really like this problem, I took a look last night and decided to do it. At this point, I have proof of work of the shell script shell.
Denial of responsibility:
- This is just a proof of concept.
- I kind of reinvented the wheel here, since I did not use any TCP / IP library
- I did not implement input validation
- This code can be much faster if it is written in a programming language rather than bash, although for this particular range of network the network is not so slow
Another thing worth mentioning is that my understanding:
IPv4 networks should have as short subnet-mask as possible.
is that we should try with 8 bits reserved for the network, up to the maximum cidr provided, in this case 25 .
OK, let's see the script in action:
[ root@TIAGO-TEST2 tmp]
Below 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
Change Perhaps it is a good idea to explain what these variables are:
- snet_cidr: start network in cidr notation
- enet_cidr: end net in cidr
- snet_dec: start network in decimal
- enet_dec: end net in decimal
- sbc_ip: start ip broadcast
- ebc_ip: end broadcast ip
- sbc_dec: start ip broadcast
- ebc_dec: end broadcast ip
And wherever you see tnet or tbc, it is temp net, temp broadcast, temp, because it is inside the loop.
Tiago source share