LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   Scripting Help needed - IP Enumeration (http://www.linuxquestions.org/questions/programming-9/scripting-help-needed-ip-enumeration-493950/)

AnonyMooseUK 10-19-2006 05:05 PM

Scripting Help needed - IP Enumeration
 
Hi all,
Total site newbie, but been working on unix for 12 years, but is no longer my primary skillset, so getting rusty.

I am trying to create a bash script to enumerate a series of ip ranges, to individual IP addresses, so i can process them later.

For example; i want to be able to input a start IP and and end IP (using the usual $1 $2 script variables), i then want the script to list all the ip addresses one by one. So if i ran;

# myscript.sh 192.168.1.1 192.168.1.35

it would output;
192.168.10.1.1
192.168.10.1.2
192.168.10.1.3
192.168.10.1.5 ...... etc to .35

now i could work this out quite simply given some time, but the fact i then have to cater for more complex inputs, means i thought i had better ask for help here.

An complex example;
# myscript.sh 10.1.1.1 10.2.5.7

so would need all IP's between this range, so;
10.1.1.1
10.1.1.2
10.1.1.3 ..... etc until

10.1.1.254
10.1.2.1
10.1.2.2 ..... etc until

10.1.254.254
10.2.1.1
10.2.1.2 ...... etc until end


Hope you get the idea, i would appreciate any help on how to achieve this.

Thanks in Advance.
:)

tuxdev 10-19-2006 05:37 PM

So, essentially you want to convert the given IP addresses to their corresponding 32 bit integers, then loop through in between them and then convert the loop iterator back into IP addresses? I can't help you with the actual scripting because I don't bash that well, but I could probably code in C that program Real Quick (c).

ghostdog74 10-19-2006 06:36 PM

If you have Python

Code:

import socket, struct
start ='192.168.1.1'
end = '192.168.1.10'
startip = struct.unpack('>L',socket.inet_aton(start))[0]
endip = struct.unpack('>L',socket.inet_aton(end))[0]
while startip <= endip:
        print socket.inet_ntoa(struct.pack('>L',startip))
        startip += 1

output:
Code:

/home> python test.py
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


Dark_Helmet 10-19-2006 10:17 PM

It's not elegant, but it works.

myscript.bash
Code:

#!/bin/bash

start_ip=$1
end_ip=$2

s_quartet[0]=$( echo ${start_ip} | cut -f 1 -d . )
s_quartet[1]=$( echo ${start_ip} | cut -f 2 -d . )
s_quartet[2]=$( echo ${start_ip} | cut -f 3 -d . )
s_quartet[3]=$( echo ${start_ip} | cut -f 4 -d . )

e_quartet[0]=$( echo ${end_ip} | cut -f 1 -d . )
e_quartet[1]=$( echo ${end_ip} | cut -f 2 -d . )
e_quartet[2]=$( echo ${end_ip} | cut -f 3 -d . )
e_quartet[3]=$( echo ${end_ip} | cut -f 4 -d . )

echo "Start IP: ${s_quartet[0]}.${s_quartet[1]}.${s_quartet[2]}.${s_quartet[3]}"
echo "End  IP: ${e_quartet[0]}.${e_quartet[1]}.${e_quartet[2]}.${e_quartet[3]}"

counter[0]=${s_quartet[0]}
while [ ${e_quartet[0]} -ge ${counter[0]} ]; do
  counter[1]=${s_quartet[1]}
  while [ ${e_quartet[1]} -ge ${counter[1]} ] ; do
    counter[2]=${s_quartet[2]}
    while [ ${e_quartet[2]} -ge ${counter[2]} ] ; do
      counter[3]=${s_quartet[3]}
      while [ ${e_quartet[3]} -ge ${counter[3]} ] ; do
        echo "${counter[0]}.${counter[1]}.${counter[2]}.${counter[3]}"
        let counter[3]=${counter[3]}+1
      done
      let counter[2]=${counter[2]}+1
    done
    let counter[1]=${counter[1]}+1
  done
  let counter[0]=${counter[0]}+1
done

Sample output
Code:

$ ./myscript.bash  10.0.0.1 10.1.2.3
Start IP: 10.0.0.1
End  IP: 10.1.2.3
10.0.0.1
10.0.0.2
10.0.0.3
10.0.1.1
10.0.1.2
10.0.1.3
10.0.2.1
10.0.2.2
10.0.2.3
10.1.0.1
10.1.0.2
10.1.0.3
10.1.1.1
10.1.1.2
10.1.1.3
10.1.2.1
10.1.2.2
10.1.2.3


AnonyMooseUK 10-20-2006 05:28 PM

Dark Helmet - Doesnt quite work, as will only enumerate to the number stated in the end ip.

For example; if i do 10.1.1.1 to 10.1.2.50

it will then only do upto 50 for both 10.1.1.1[-50] and 10.1.2.[-50]

so it misses out the entire 10.1.1.51 to 10.1.1.254 range ....

nice try though. Anyone else?

AnonyMooseUK 10-20-2006 05:33 PM

ghostdog74 - that works, but i have no python knowledge, so how would i then change it to allow the script to be run with the startip and endip variables passed on the command line; eg;

python script.py 10.1.1.1 10.1.2.45




thanks people

homey 10-20-2006 06:14 PM

I took the liberty of editing a handy little scanmac script which a programming guru made for me many moons ago in another world. :)
Code:

#!/bin/bash
#Example: ./myscript 192.168.0.1 192.168.0.10

if [ -z "$1" -o "$1" == "-?" ] ; then
  echo "Usage: ./myscript starting-ip ending-ip"
  exit 0
fi

startw=$(echo "$1" | cut -d. -f1)
startx=$(echo "$1" | cut -d. -f2)
starty=$(echo "$1" | cut -d. -f3)
startz=$(echo "$1" | cut -d. -f4)

echo "Starting address: $startw.$startx.$starty.$startz"

end_ip="$2"

if [ -z "$end_ip" ] ; then
        if [ $startz -eq 255 ] ; then
                endz=0

                if [ $starty -eq 255 ] ; then
                        endy=0

                        if [ $startx -eq 255 ] ; then
                                endx=0

                                if [ $startw -eq 255 ] ; then
                                        echo "255.255.255.255 is not valid"
                                        exit 1
                                else
                                        endw=$(($startw+1))
                                fi
                        else
                                endx=$(($startx+1))
                        fi
                else
                        endy=$(($starty+1))
                fi
        else
                endz=$(($startz+1))
        fi

        end_ip="$endw.$endx.$endy.$endz"
fi

echo "Ending address: $end_ip"

currentw=$startw
currentx=$startx
currenty=$starty
currentz=$startz

currentip="$currentw.$currentx.$currenty.$currentz"

#if [ "$currentz" -ne "0" ] ; then
#  echo "$currentip"
#fi

trap "exit 15" 15
trap "exit 2" 2

while [ "$currentip" != "$end_ip" ] ; do
        currentip="$currentw.$currentx.$currenty.$currentz"

#        if [ "$currentz" -eq "0" ] ; then
#                echo "$currentip"
#        fi

        echo $currentip

        if [ $currentz -eq 255 ] ; then
                currentz=0
        else
                currentz=$(($currentz+1))
                continue
        fi

        if [ $currenty -eq 255 ] ; then
                currenty=0
        else
                currenty=$(($currenty+1))
                continue
        fi

        if [ $currentx -eq 255 ] ; then
                currentx=0
        else
                currentx=$(($currentx+1))
                continue
        fi

        if [ $currentw -eq 255 ] ; then
                break
        else
                currentz=$(($currentz+1))
                continue
        fi
done

Here is the original scanmac script.
Code:

#!/bin/bash

if [ -z "$1" -o "$1" == "-?" ] ; then
        echo "Usage: scanmac starting-ip [ending-ip]"
        echo
        echo "Will list IP and MAC adresses of all active computers"
        echo "within a physical network segment."
        echo
        echo "If ending-ip is omitted, ending-ip = starting-ip+1"
        echo " (so that only the host specified will be scanned)."
        echo
        echo "If you wish to scan from 192.168.2.1 to 192.168.2.31,"
        echo " inclusive, specify ending-ip to be 192.168.2.32."
        echo

        exit 0
fi

startw=$(echo "$1" | cut -d. -f1)
startx=$(echo "$1" | cut -d. -f2)
starty=$(echo "$1" | cut -d. -f3)
startz=$(echo "$1" | cut -d. -f4)

echo "Starting address: $startw.$startx.$starty.$startz"

endip="$2"

if [ -z "$endip" ] ; then
        if [ $startz -eq 255 ] ; then
                endz=0

                if [ $starty -eq 255 ] ; then
                        endy=0

                        if [ $startx -eq 255 ] ; then
                                endx=0

                                if [ $startw -eq 255 ] ; then
                                        echo "Sorry, you cannot just scan 255.255.255.255."
                                        echo "  Maybe later, or you can try to hack support in."

                                        exit 1
                                else
                                        endw=$(($startw+1))
                                fi
                        else
                                endx=$(($startx+1))
                        fi
                else
                        endy=$(($starty+1))
                fi
        else
                endz=$(($startz+1))
        fi

        endip=$endw.$endx.$endy.$endz
fi

echo "Ending address: $endip"

currentw=$startw
currentx=$startx
currenty=$starty
currentz=$startz

currentip=$currentw.$currentx.$currenty.$currentz

# If the bottom octet is zero, it'll get logged inside the while, so
# don't do it here

if [ "$currentz" -ne "0" ] ; then
        echo "$(date): $currentip"
fi

trap "exit 15" 15
trap "exit 2" 2

while [ "$currentip" != "$endip" ] ; do
        currentip=$currentw.$currentx.$currenty.$currentz

        # another log message whenever the bottom octet rolls over

        if [ "$currentz" -eq "0" ] ; then
                echo "$(date): $currentip"
        fi

        ping -c 1 -w 10 $currentip >/dev/null 2>&1

        mac=$(arp -a $currentip | cut -d' ' -f4)

        case "$mac" in
        ?incomplete?)
                :  # do nothing -- no MAC for this IP
                ;;
        entries)
                :  # again, do nothing -- this is a broadcast address
                ;;
        *)
                echo "IP: $currentip -- MAC: $mac"
                ;;
        esac

        mac=""  # reset for the next loop iteration

        # now increment the ip values (w,x,y,z)

        if [ $currentz -eq 255 ] ; then
                currentz=0
        else
                currentz=$(($currentz+1))
                continue
        fi

        if [ $currenty -eq 255 ] ; then
                currenty=0
        else
                currenty=$(($currenty+1))
                continue
        fi

        if [ $currentx -eq 255 ] ; then
                currentx=0
        else
                currentx=$(($currentx+1))
                continue
        fi

        if [ $currentw -eq 255 ] ; then
                break
        else
                currentz=$(($currentz+1))
                continue
        fi
done


ghostdog74 10-20-2006 08:59 PM

Quote:

Originally Posted by AnonyMooseUK
ghostdog74 - that works, but i have no python knowledge, so how would i then change it to allow the script to be run with the startip and endip variables passed on the command line; eg;

python script.py 10.1.1.1 10.1.2.45


thanks people

Code:

#!/usr/bin/python
import socket, struct,sys
start = sys.argv[1] #first arg
end = sys.argv[2] #second arg
startip = struct.unpack('>L',socket.inet_aton(start))[0]
endip = struct.unpack('>L',socket.inet_aton(end))[0]
while startip <= endip:
        print socket.inet_ntoa(struct.pack('>L',startip))
        startip += 1

Code:

python yourscript.py 10.0.0.1 10.0.0.10

Dark_Helmet 10-21-2006 01:06 AM

Quote:

Originally Posted by AnonyMooseUK
Dark Helmet - Doesnt quite work, as will only enumerate to the number stated in the end ip.

Yeah, you're right. I got too focused on setting up the looping that I forgot to add some needed logic. My mistake.

I'll try to remember to post a corrected version later. Right now, I need to sleep. :)

AnonyMooseUK 10-21-2006 11:34 AM

Homey - Thanks for that, works a treat, will make some mods to remove the .0 and .255 out of the ranges though.

As to the scanmac tool, i wrote a similar one a while ago, but mine was just a few lines :) as it simply pinged the subnet mask, which caused all the local ips in use to reply, then used the arp command to list all the new known ones out.

I also wrote a script to work with this and samba, for linux.
Which then took the list of alive ip addreses and polled them to see who was logged into them (winXP clients). Worked a treat.


Thanks again. Appreciated.

Dark_Helmet 10-21-2006 01:07 PM

It turns out my first attempt made things more difficult than they really needed to be. Anyway, here's a bash script that removes the 0 and 255 addresses.

Code:

#!/bin/bash

start_ip=$1
end_ip=$2

counter[0]=$( echo ${start_ip} | cut -f 1 -d . )
counter[1]=$( echo ${start_ip} | cut -f 2 -d . )
counter[2]=$( echo ${start_ip} | cut -f 3 -d . )
counter[3]=$( echo ${start_ip} | cut -f 4 -d . )


while [ "${end_ip}" != "${counter[0]}.${counter[1]}.${counter[2]}.${counter[3]}" ] ; do

  if [ \( ${counter[3]} -ne 0 \) -a          \
      \( ${counter[3]} -ne 255 \) ] ; then
    echo "${counter[0]}.${counter[1]}.${counter[2]}.${counter[3]}"
  fi

  let counter[3]=${counter[3]}+1

  if [ ${counter[3]} -eq 256 ] ; then
    counter[3]=0
    let counter[2]=${counter[2]}+1
  fi

  if [ ${counter[2]} -eq 256 ] ; then
    counter[2]=0
    let counter[1]=${counter[1]}+1
  fi

  if [ ${counter[1]} -eq 256 ] ; then
    counter[1]=0
    let counter[0]=${counter[0]}+1
  fi
done

echo "${end_ip}"


Tischbein 10-22-2006 10:17 AM

# Using awk:

Code:

echo $min $max |\
sed 's/[:.]/ /g' |\
awk '
{
 a=$1; b=$2; c=$3; d=$4
 for (; a < 256; ++a && b=0)
 for (; b < 256; ++b && c=0)
 for (; c < 256; ++c && d=0)
 for (; d < 256; ++d      )
 {if ( (a < $5) || (b < $6) || (c < $7) || (d <= $8))
    {print a ":" b ":" c ":" d}
  else {exit 0}
 }
}'

# Using bash:

Code:

function print_range_core
{
 a=$1;b=$2;c=$3;d=$4
  for ((; a < 256; ((a=a + 1)) && ((b=0)) ))
 do for ((; b < 256; ((b=b + 1)) && ((c=0)) ))
  do for ((; c < 256; ((c=c + 1)) && ((d=0)) ))
  do for ((; d < 256; ((d=d + 1)) ))
    do if [ $a -lt $5 ] ||
          [ $b -lt $6 ] ||
          [ $c -lt $7 ] ||
          [ $d -le $8 ]
      then echo ${a}:${b}:${c}:${d}
      else return 0
      fi
    done
  done
  done
 done
}


function print_range
{
  args=$(echo "$1" "$2" | sed 's/[.:]/ /g')
  echo $args
  print_range_core $args
}


print_range 1.255.255.60 2.0.1.1



All times are GMT -5. The time now is 05:33 PM.