CIDR calculator

Bill Gradwohl bill at ycc.com
Sat Nov 20 16:00:15 UTC 2004


Joshua Andrews wrote:

> I am looking for a network calculator that will take input in the form 
> of,
> 67.160.0.0  :  67.191.255.255,  and output the IP block in cidr 
> notation, 67.160.0.0/11.
>
I remembered I wrote a script to do something like that a few years ago 
and I called it cidrcalc.

To use it to get the example output you provided, call it as follows:
   ./cidrcalc 160 191 8 67.
The comments in the script say what that means, but in essence; varying 
from 160 thru 191 at an offset of 8 bits with a leading text string of 
those 8 bits of '67.' generate the cidr.

To pass the script 2 IP addresses  as you suggested and have it figure 
out the bit offsets, etc would take a bit of additional scripting. Fix 
it as you see fit.

#!/bin/bash

# This routine accepts 4 passed in parameters.
# The starting IP octet value
# The ending IP octet value.
# A displacement constant.
# A static prefix.
#
# The intent of this routine is to print out IP octets and CIDR values
# that will encompass the range from starting octet to ending octet.
# The need for this routine arose when we saw that a good portion of an
# area of the world was serviced by a given range of IP addresses, and
# we wanted to block that range in a firewall.
#
# As an example, suppose we want to block all the IP addresses from
# 61.158.0.0 thru 61.189.255.255, and we need to specify this range in
# CIDR notation. What we actually want to block are the networks 61.158
# 61.189. What varies is the range 158 through 189 with a displacement
# of 8 bits which represents the static constant area between them namely
# the 61 field. This routine would be called passing the parameters
# 158 189 8 "61." to produce :
# 61.158/15
# 61.160/12
# 61.176/13
# 61.184/14
# 61.188/15
# If the example were changed to block 123.61.158.00 thru 123.61.189.255,
# the routine would be called passing 158 189 16 "123.61." to represent
# that now 16 bits are static (123.61) and considered a displacement.
# The output would be:
# 123.61.158/23
# 123.61.160/20
# 123.61.176/21
# 123.61.184/22
# 123.61.188/23
# If the routine were called passing 158 189 16 "Hello there ", then the
# output would be:
# Hello There 158/23
# Hello There 160/20
# Hello There 176/21
# Hello There 184/22
# Hello There 188/23
# The prefix is applied with no processing. It is purely a convenience
# for the user.
# Note that the minimum execution would have DISPLACEMENT of 0, and a
# PREFIX of "". Therefore, passing 158 189 0 "" produces:
# 158/7
# 160/4
# 176/5
# 184/6
# 188/7
# That provides an answer as though the OCTETSTART and OCTETEND are for the
# first octet of an IP address.

# Lets define some specialized variables and functions here.
syntax() {
echo "Syntax: $(basename $0) { OCTETSTART OCTETEND DISPLACEMENT PREFIX }"
echo
echo "Where: OCTETSTART is the starting octet value."
echo "       OCTETEND   is the ending   octet value."
echo "       DISPLACEMENT is a bit displacement constant."
echo "       PREFIX is a character string prefix constant."
echo
echo "The intent of this script is to output the network addresses in CIDR"
echo "notation for the range of addresses specified between OCTETSTART and"
echo "OCTETEND."
echo
echo "Examples:"
echo "$(basename $0) 158 189 8 \"61.\" produces:"
echo "61.158/15"
echo "61.160/12"
echo "61.176/13"
echo "61.184/14"
echo "61.188/15"
echo
echo "$(basename $0) 158 189 16 \"123.61.\" produces:"
echo "123.61.158/23"
echo "123.61.160/20"
echo "123.61.176/21"
echo "123.61.184/22"
echo "123.61.188/23"
echo
echo "$(basename $0) 158 189 16 \"Hello.\" produces:"
echo "Hello.158/23"
echo "Hello.160/20"
echo "Hello.176/21"
echo "Hello.184/22"
echo "Hello.188/23"
echo
echo "The DISPLACEMENT applies a constant bit distance to the answer for"
echo "display purposes, and the PREFIX is also purely for display purposes."
}
getcidr() (
   # This function gets the cidr from an octet value passed in.
   local octet=${1}
   local bits=0
   local i
   local x

   # Convert the octet to cidr.
   x=0;
   for i in 128 64 32 16 8 4 2 1; do
      x=$((${x}+1))
      if [ ${octet} -ge ${i} ]; then
         bits=$x
         octet=$((${octet}-${i}))
      fi
   done

   return ${bits}
)

getcidrfromcommonbits() {
   # This routine gets 2 passed in parameters, the octet starting
   # and ending values.
   # The purpose of the routine is to find the common bits between
   # the start and end values and form a cidr that encompasses the
   # entire range.
   local start=${1}
   local end=${2}

   [ ${start} -eq ${end} ] && return 8

   local startbits[]
   local endbits[]
   local i
   local x
   local cidr=0

   # Convert the start and end values into bits.
   x=0
   for i in 128 64 32 16 8 4 2 1; do
      if [ ${start} -ge ${i} ]; then
         startbits[${x}]="1"
         start=$((${start}-${i}))
      else
         startbits[${x}]="0"
      fi
      let "x+=1"
   done
   x=0
   for i in 128 64 32 16 8 4 2 1; do
      if [ ${end} -ge ${i} ]; then
         endbits[${x}]="1"
         end=$((${end}-${i}))
      else
         endbits[${x}]="0"
      fi
      let "x+=1"
   done

   # Now compare the start and end bit patterns to find
   # out how many left most bits they have in common.
   # There are always 8 bits in each string to compare.
   for ((x=0;x<=7;++x)); do
      [ "${startbits[${x}]}" != "${endbits[${x}]}" ] && break
   done
   let "cidr+=x"

   # If the startbits to the right of the proposed cidr are all 0 and
   # the endbits to the right of the proposed cidr are all 1, then
   # the cidr is OK. Else, we have to increase the cidr by 1 bit.
   let "x+=1"
   while [ ${x} -le 7 ]; do
      [ "${startbits[${x}]}" != "0" ] && break
      [ "${endbits[${x}]}" != "1" ] && break
      let "x+=1"
   done
   if [ ${x} -le 7 ]; then
      let "cidr+=1"
   fi

   return ${cidr}
}

getdisp() {
   # Get the displacement from the passed in cidr value.
   return $(((2**(8-${1}))-1))
}

[ $# -ne 4 ] && syntax && exit 1

# For each possible IP octet in the range do the following:
i=${1}
while [ $i -le ${2} ]; do
   #echo "IP=$i"
   getcidr ${i}
   cidr=$?
   #echo "cidr=${cidr}"
   getdisp ${cidr}
   displacement=$?
   #echo "displacement==${displacement}"
   endpoint=$((${i}+${displacement}))
   #echo "endpoint=${endpoint}"

   if [ ${endpoint} -gt ${2} ]; then
      # We have to shorten up the endpoint to miss it and
      # recalculate cidr and displacement values for that endpoint
      endpoint=$((${endpoint}-1))
      #echo "   endpoint=${endpoint}"
      getcidrfromcommonbits ${i} ${endpoint}
      cidr=$?
      #echo "   cidr=${cidr}"
      getdisp ${cidr}
      displacement=$?
      #echo "   displacement==${displacement}"
      endpoint=$((${i}+${displacement}))
      #echo "   endpoint=${endpoint}"
   fi
   cidr=$((${cidr}+${3}))
   echo "${4}${i}/${cidr}"
   i=$((${endpoint}+1))
done


-- 
Bill Gradwohl
bill at ycc.com
http://www.ycc.com
spamSTOMPER Protected email




More information about the users mailing list