Find free ip

From Lolly's Wiki
Jump to navigationJump to search
#!/bin/bash

#
# $Id: find_free_ip.sh,v 1.2 2019/09/06 14:33:32 lollypop Exp $
# $Source: /var/cvs/lollypop/scripts/linux/find_free_ip.sh,v $
#
# Written in 2019 by Lars Timmann <L@rs.Timmann.de>
#

function usage () {
  printf "Usage: ${0} <ip address>[/(<CIDR suffix>|<netmask>)]\n\n"
  printf "  This script searches a range of IP addresses for ones that have no reverse DNS.\n"
  printf "  Default range if no CIDR suffix or netmask is given is a class C (/24) range of 256 addresses.\n" 
  printf "  address     : This has to be a IPv4 address. Zero octets can be omittet.\n"
  printf "                For example 192.168 is sufficient for 192.168.0.0 .\n"
  printf "  CIDR suffix : This describes the nomber of bits set to 1 from left in the netmask.\n"
  printf "  netmask     : Four octets representing the netmask.\n"
  printf "\n"
}

case ${1} in
""|--help|-h)
  usage
  exit 1
  ;;
*)
  input=${1}
  ;;
esac

case $(uname -s) in
Linux)
  PING='ping -4 -c 1 -n -q -W 1 ${ip}'
  ;;
SunOS)
  PING='ping -s -A inet -n -t 1 ${ip} 56 1'
  ;;
esac

IFS='/' read -ra parts <<< "${input}"
address=${parts[0]}
suffix=${parts[1]:-24}

# build binary notation from CIDR suffix
function ones2bin () {
  ones=${1}
  printf "%0.s1" $(seq 1 ${ones})
  [ ${ones} -lt 32 ] && printf "%0.s0" $(seq 1 $[ 32 - ${ones} ])
}

function bin2ones () {
  bin=${1}
  ones=0
  for((i=0;i<${#bin};i++))
  do
    bit=${bin:$i:1}
    [ ${bit} -eq 0 ] && break
    ones=$[ ones + 1 ]
  done
  echo ${ones}
}

# dezimal number to octets
# for example: 2130706689 -> 127.0.1.1
function dec2ipv4 () {
  ipdec=${1}
  octets=()
  for((i=24;i>=0;i-=8))
  do
    octet=$((${ipdec} >> ${i}))
    octets+=(${octet})
    ipdec=$(( ${ipdec} - ( ${octet} << ${i} ) ))
  done
  echo $(IFS=.;echo "${octets[*]}")
}

# ipv4 to decimal
function ipv42dec () {
  ipv4=$1
  dec=0
  IFS='.' read -ra octets <<< "${ipv4}"
  for ((i=0;i<4;i++))
  do
          dec=$(( dec + ${octets[i]} * ( 256 ** ( 3 - i ) ) ))
  done
  echo ${dec}
}

# decimal to binary
function dec2bin () {
  dec=$1
  bin=""
  for((i=${dec};i>0;i>>=1))
  do
    bin=$(( ${i} % 2 ))${bin}
  done
  echo ${bin}
}

# binary to decimal : dec = $(( 2#010001010001 )) 

# binary complement
function binaryComplement () {
  unset complement
  binary=$1
  for((i=0;i<${#binary};i++))
  do
    complement+=$(( ${binary:${i}:1} ^ 1 ))
  done
  echo $complement
}

# Add missing octets
function fillOctets () {
  IFS='.' read -ra octets <<< "${1}"
  for ((i=${#octets[@]};i<4;++i))
  do
    octets+=(0)
  done
  echo "$(IFS=. ; echo "${octets[*]}")"
}

if [[ ${suffix} =~ ^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$ ]]
then
  suffixbin=$(dec2bin $(ipv42dec $(fillOctets ${suffix})))
else
  suffixbin=$(ones2bin ${suffix})
fi

address=$(fillOctets ${address})

firstipdec=$(( ( $(ipv42dec ${address}) & 2#${suffixbin} ) )) 
network=$(dec2ipv4 ${firstipdec})
lastipdec=$(( ( $(ipv42dec ${address}) & 2#${suffixbin} ) | 2#$(binaryComplement ${suffixbin}) ))
broadcast=$(dec2ipv4 ${lastipdec})
netmask=$(dec2ipv4 $(( 2#${suffixbin} )) )

printf "Your request:\t${address}/$(bin2ones ${suffixbin})\nNetwork:\t${network}\nBroadcast:\t${broadcast}\nNetmask:\t${netmask}\nSearching in:\t${network}-${broadcast}\n"
printf "%0.s-" $(seq 1 80) ; echo

count=1
bool=( yes no )
for((i=${firstipdec};i<=${lastipdec};i++))
do
  ip=$(dec2ipv4 ${i})
  info=$(getent hosts ${ip})
  if [ "_${info}_" == "__" ]
  then
    eval ${PING} ${ip} >/dev/null 2>&1 ; pingable=$?
    case ${ip} in
      ${network})
        remark="This is the network IP."
        ;;
      ${broadcast})
        remark="This is the network IP."
        ;;
      *)
        remark=""
        ;;
      esac
    printf "%s\tfrei\t%d\t( got a pong: %s )\t%s\n" "${ip}" "${count}" "${bool[${pingable}]}" "${remark}"
    count=$[ ${count} + 1 ]
  else
    printf "%s\n" "${info}"
    count=1
  fi
done