0

If I enter IP "127": I want to generate everything from 127.0.0.1 to 127.255.255.255


If I enter IP "127.0" I want to generate everything from 127.0.0.1 to 127.0.255.255


If I enter IP "127.0.0" I want to generate everything from 127.0.0.1 to 127.0.0.255


Using netaddr

  • 2
    Maybe start with: `IFS=. eval set -- $ip` (after checking for only digits-and-dots), then `$#` tells you how many octets, etc. For what it's worth, I once tried to write some of this kind of stuff in `sh`, but then found the Python `netaddr` package, and switched to that. :-) – torek Oct 03 '13 at 10:58
  • 1
    +1 for using Python or some other language instead. Doing this in Bash will be slightly tricky for no good reason. – John Zwinck Oct 03 '13 at 11:21

3 Answers3

6

The original question was based on bash.. if you just want the pure python implementation, scroll down:

I think your specific problem can probably be solved in bash with some pain, but here's a stab at the general problem:

So, first of all it's probably worth noting that not all the IP addresses in a particular range are valid host addresses. Specifically, the first and last addresses are reserved in IPv4 (network/broadcast).

Secondly, an IPv4 address, say 192.168.0.1, is really just a 32-bit/4-byte number that's split into 4 chunks of 8-bit/1-byte each. You don't have place the network/host portion split of the address on an 8-bit boundary though. 127.0.0.0/24 for example places the split at the third dot (24 bits in) and contains host addresses 127.0.0.1-254, but you can equally well split it 28 bits in, e.g. 127.0.0.0/28, which would contain hosts 127.0.0.1-14.

Thirdly, the "correct" way (I believe) to generate the data you are asking for, is by converting the IP address into binary, e.g. 127.0.0.1 = 01111111000000000000000000000001, determine where your host/network split is (say it's a /28), fix the first 28 bits, and then count up the binary number and then convert back to the dotted decimal representation if required:

01111111000000000000000000000001 = .1
---------fixed--------------**** ** variable

so you get:
01111111000000000000000000000010 = .2
01111111000000000000000000000011 = .3

etc.

Doing this in bash is of course a pain.

Now, if you have Python3 available, you can use the ipaddress module to generate all the valid host addresses on a given network (see below).

>>> import ipaddress
>>> print("\n".join([str(x) for x in ipaddress.ip_network("192.0.2.0/28").hosts()]))
192.0.2.1
192.0.2.2
192.0.2.3
192.0.2.4
192.0.2.5
192.0.2.6
192.0.2.7
192.0.2.8
192.0.2.9
192.0.2.10
192.0.2.11
192.0.2.12
192.0.2.13
192.0.2.14

This module also supports IPv6 incidentally, so you can generate the hosts of 2001:0db8::/120 using ipaddress.ip_network("2001:0db8::/120").hosts().

You can (though you don't have to) wrap this in a shell-script-compatible one-liner..

python3 -c 'import ipaddress; print("\n".join([str(x) for x in ipaddress.ip_network("192.0.2.0/28").hosts()]))'

Now, all you need to is

#!/bin/bash
# split it up
IFS='.' read -a array <<< "127.0.0"
#echo ${array[*]}
#127 0 0

mask=$(( ${#array[@]} * 8))
# 28

# add missing 0s.
for $i in {1..4}; do
   if [ i -gt ${#array[@]} ]; then
      array[i]="0"
   fi
done
#echo ${array[*]}
#127 0 0 0


# join, see http://stackoverflow.com/questions/1527049/bash-join-elements-of-an-array
SAVE_IFS=$IFS
IFS="."
full_ip="${array[*]}"
IFS=$SAVE_IFS
# 127.0.0.0

# now add /mask
network="$full_ip/$mask"
# 127.0.0.0/24

python3 -c "import ipaddress; print(\"\\n\".join([str(x) for x in ipaddress.ip_network(\"$network\").hosts()]))"
#127.0.0.1
#127.0.0.2
# ...
#127.0.0.254

Pure Python3:

import ipaddress
input="127.0.0"
input_arr=input.split(".") # ['127', '0', '0']
netmask=len(input_arr)*8  # 24
for i in range(len(input_arr), 4):
     input_arr.append('0')
# input_arr = ['127', '0', '0', '0']
ip='.'.join(input_arr)  # '127.0.0.0'
network=ip + '/' + str(netmask)  # '127.0.0.0/24'
print("\n".join([str(x) for x in ipaddress.ip_network(network).hosts()]))

If you want to add the network/broadcast, just print the .network_address and .broadcast_address in addition.

m01
  • 9,033
  • 6
  • 32
  • 58
1
def iprange(ip1,ip2):
 print(f'list of ip adresses between {ip1} and {ip2}') # list IPs between 127.0.0.1 and 127.0.0.100
 ip1_1 = ip1.split(".")
 ip2_2 = ip2.split(".")

for i in range(0, len(ip1_1)):
    ip1_1[i] = int(ip1_1[i])
for i in range(0, len(ip2_2)):
    ip2_2[i] = int(ip2_2[i])

for i in range(ip1_1[0], ip2_2[0]+1):
    for j in range(ip1_1[1], ip2_2[1]+1):
        for k in range(ip1_1[2], ip2_2[2]+1):
            for z in range(ip1_1[3], ip2_2[3]+1):
                print(f'{i}.{j}.{k}.{z}')

iprange("127.0.0.1","127.0.0.15")
thearnoldk
  • 11
  • 2
0

Here's a brute force approach:

#! /bin/bash
IFS=.
set -- $1
a=$1; b=$2; c=$3; d=$4
if [[ -z $d ]]; then
    for d in {0..255}; do
        if [[ -z $c ]]; then
            for c in {0..255}; do
                if [[ -z $b ]]; then
                    for b in {0..255}; do
                        echo $a.$b.$c.$d
                    done
                    unset b
                else
                    echo $a.$b.$c.$d
                fi
            done
            unset c
        else
            echo $a.$b.$c.$d
        fi
    done
    unset d
else
    echo $a.$b.$c.$d
fi

Some tests:

$ bash iprange.sh 127.0.0.1
127.0.0.1
$ bash iprange.sh 127.0.0 | sed -n '1,5p;$p'
127.0.0.0
127.0.0.1
127.0.0.2
127.0.0.3
127.0.0.4
127.0.0.255
$ bash iprange.sh 127.0.0 | wc
    256     256    2962
$ bash iprange.sh 127.0 | sed -n '1,5p;$p'
127.0.0.0
127.0.1.0
127.0.2.0
127.0.3.0
127.0.4.0
127.0.255.255
$ bash iprange.sh 127.0 | wc
  65536   65536  861184
glenn jackman
  • 238,783
  • 38
  • 220
  • 352