Wednesday, January 29, 2014

Determining IP address range from Subnet/CIDR

Script to find the IP address range from the given Subnet.

There are few functions which can be reused like
  1. Convert IP to Decimal ip_to_int()
  2. Convert Decimal to IP int_to_ip()
  3. Netmask to CIDR to_cidr()

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/bin/bash
# http://linuxcalling.blogspot.in/
# Script to find the IP address range
# Script : ip_range
# Usage  : ip_range <IP> <Subnet> [0|1 print range]
# Ahamed (ahamed.en@gmail.com)

usage()
{
  EXE=${0#*/}
  echo "Usage: $EXE <IP> <Subnet> [0|1]<print range>"
  echo "   eg: To display the IP address range"
  echo "       $EXE 192.168.1.1 255.255.140.0"
  echo "   eg: To display the IP address range with entire range"
  echo "       $EXE 192.168.1.1 255.255.140.0 1"
  exit
}

[ $# -lt 2 ] && usage

echo $1 $2 $3 | awk '

  BEGIN{
    BITS=8
    mask_add[0]=valid_subnet[0]=0
    for(i=BITS-1;i>=0;i--){
      k=or(k,lshift(1,i))
      mask_add[k]=BITS-i
      valid_subnet[BITS-i]=k
    }
  }
  function validate_subnet(input)
  {
    split(input, oc, ".")

    if(oc[4] > oc[3] || oc[3] > oc[2] || oc[2] > oc[1]){
        print "Invalid Subnet: ",input
        exit
    }
    for(j=1; j<=BITS/2; j++){
      for(i=0;i<=BITS;i++){
        if(!xor(oc[j],valid_subnet[i])){
          break;
        }
        err++
      }
      if(err == (BITS+1)){
        print "Invalid Subnet: ",input
        exit
      }
      err=0
    }
  }

  function to_cidr(input)
  {
    split(input, oc, ".")
    ret=mask_add[oc[1]]+mask_add[oc[2]]+mask_add[oc[3]]+mask_add[oc[4]]
    return ret
  }

  function ip_to_int(input)
  {

    split(input, oc, ".")
    ip_int=(oc[1]*(256^3))+(oc[2]*(256^2))+(oc[3]*(256))+(oc[4])
    return ip_int

  }

  function int_to_ip(input)
  {
    str=""
    num=input
    for(i=3;i>=0;i--){
      octet = int (num / (256 ^ i))
      str= i==0?str octet:str octet "."
      num -= (octet * 256 ^ i)
    }
    return str
  }
  {
    ip=$1
    mask=$2
    range=$3

    validate_subnet(mask)

    cidr=to_cidr(mask)
    diff=32-cidr
    no_of_ip=2^diff

    ip_int=ip_to_int(ip)
    ip_mask=and(ip_int, (2^32 - 2^diff))

    ip_start=ip_mask
    ip_end=ip_mask+no_of_ip-1

    print "No of IPs\t"(no_of_ip-2)
    print "First IP\t" int_to_ip(ip_start+1)
    print "Last IP\t\t" int_to_ip(ip_end-1)
    print "Subnet\t\t" int_to_ip(ip_mask)
    print "Broadcast\t" int_to_ip(ip_end)

    if(range){
      print "\nIP address range -- START --\n"
      curr=ip_start
      i=0
      while(curr<=ip_end){
        printf int_to_ip(curr)"\t"
        if(j++%4 == 0) printf "\n"
        curr+=1
      }
      print "\nIP address range -- END --"
    }
  } '

Script Usage

[root@maximus] → ./ip_range 192.168.1.1 255.255.255.224
No of IPs       30
First IP        192.168.1.1
Last IP         192.168.1.30
Subnet          192.168.1.0
Broadcast       192.168.1.31


[root@maximus] → ./ip_range 192.168.1.1 255.255.255.224 1
No of IPs       30
First IP        192.168.1.1
Last IP         192.168.1.30
Subnet          192.168.1.0
Broadcast       192.168.1.31

IP address range -- START --

192.168.1.0     192.168.1.1     192.168.1.2     192.168.1.3
192.168.1.4     192.168.1.5     192.168.1.6     192.168.1.7
192.168.1.8     192.168.1.9     192.168.1.10    192.168.1.11
192.168.1.12    192.168.1.13    192.168.1.14    192.168.1.15
192.168.1.16    192.168.1.17    192.168.1.18    192.168.1.19
192.168.1.20    192.168.1.21    192.168.1.22    192.168.1.23
192.168.1.24    192.168.1.25    192.168.1.26    192.168.1.27
192.168.1.28    192.168.1.29    192.168.1.30    192.168.1.31

IP address range -- END --

[root@maximus] → ./ip_range 192.168.1.1 255.255.0.0
No of IPs       65534
First IP        192.168.0.1
Last IP         192.168.255.254
Subnet          192.168.0.0
Broadcast       192.168.255.255