0

Using bash or perl on a minimal installed Linux, I am trying to validate two IP addresses if there are in a range.

I came across a bash script that works well, but the fact that it prints all the IP addresses in a range, it takes longer to complete a bigger range. I am not interested in printing all the individual IP addresses but simply to check if two given IP addresses are in a range. How can achieve my goal?

Example would be

"1.1.1.1 - 1.1.1.10"  is correct (This a valid range)
"1.1.2.1 - 1.1.1.10"  is incorrect (This is NOT a valid range)

Bash function below

#!/bin/bash
# convert IP to decimal
ip2dec() {
        set -- ${1//./ }     # split $1 with "." to $1 $2 $3 $4
        declare -i dec       # set integer attribute
        dec=$1*256*256*256+$2*256*256+$3*256+$4
        echo $dec
    }

# convert decimal to IP
dec2ip() {
        declare -i ip1 ip2 ip3 ip4
        ip1=$1/256/256/256
        ip2=($1-$ip1*256*256*256)/256/256
        ip3=($1-$ip1*256*256*256-$ip2*256*256)/256
        ip4=$1-$ip1*256*256*256-$ip2*256*256-$ip3*256
        echo $ip1.$ip2.$ip3.$ip4
        }

    start_ip=$(ip2dec $1)
    eend_ip=$(ip2dec $2)

    for ((i=$start_ip;i<=$end_ip;i++)); 
    do
    dec2ip $i
    done

Script usage: ./script_name 1.1.1.1 1.1.1.10

6
  • Any two addresses are in the "0.0.0.0/0" range (that's the entire address space), not really interesting, so you need to define what is a valid range in your case. The script you show is really poorly formatted, but the case you show would be caught by ip2dec($1) > ip2dec($2), leading me to think that you not only lack proper understanding of IP addressing (then you would have known to define "valid range") but also that you have a poor understanding of bash, leading to the obvious question: Why are you doing this? Commented Aug 25, 2023 at 8:32
  • 1
    Since you mentioned Perl, there are actual pre-existing modules in Perl for handling of IP addresses. It might be smarter to look at those rather than implement it yourself with any tool, in particular the shell.
    – ilkkachu
    Commented Aug 25, 2023 at 8:35
  • @Henriksupportsthecommunity, looking at the script, I think the two addresses given are the endpoints of the range. So there's a third address they want to check. With that script, I suppose it'd be something like ./script_name 1.1.1.1 1.1.1.10 | grep 1.1.1.7... Though it does say "to check if two given IP addresses are in a range", hmmh.
    – ilkkachu
    Commented Aug 25, 2023 at 8:39
  • @ilkkachu: But that's not a standard range - the only range that starts at 1.1.1.1 is a /32 and that does not include 1.1.1.10 (the smallest range to include both are 1.1.1.0/28). I haven't looked at the perl modules you mention, but I would be wary of using them with a non-standard definition of range. Commented Aug 25, 2023 at 8:55
  • @Henriksupportsthecommunity, it's not a power-of-two block or prefix, and you can't use it for routing as such, but I don't know why that should matter. It's trivial to define a range of contiguous addresses, even for non-powers of two. Here, that would just be the addresses 1.1.1.x, with 1 <= x <= 10, but you could do the same for ranges like 1.1.1.90 - 1.1.2.100. With some typos fixed, the script above works just fine for such a range.
    – ilkkachu
    Commented Aug 25, 2023 at 12:46

1 Answer 1

2

As of the writing of this answer, your question mentions there are "valid" ranges of IP addresses and "NOT valid" ranges, but you haven't defined how to test for the validity of a given address range. I guess that's not in the scope of the question.

That leaves us with how to compare an address with the lower/upper addresses in the range. Finally, all three of these addresses are converted to decimal values. I.e., integers.

My own bash routine to convert an IPv4 dotted-quad address string to an integer looks like this:

#!/usr/bin/env bash

declare ip_int=0

ip2int () {
  local addr="$1"
  local ip IFS=.

  # use IFS to split dotted quad into array of octets
  # i.e., "10.200.251.22" => ( "10" "200" "251" "22" )
  ip=( ${addr} )

  # bit shift the octets and combine into integer via bitwise-or
  ip_int=$(( ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3] ))
}

# get ip address as integer in $ip_int
ip2int 10.12.13.14

# show decimal and hex values, just for confirmation purposes
printf 'decimal: %d\n'   $ip_int
printf '    hex: %08x\n' $ip_int

If you put your integer values for the range in $start_ip/$end_ip and the integer value for the current address in $cur_ip, then testing the address is within the range is fairly simple pair of comparisons:

[[ ${cur_ip} -ge ${start_ip} && ${cur_ip} -le ${end_ip} ]] && echo "In the address range"

I.e., if the current address is equal to or greater than the starting ip, and it's equal to or less than the ending ip, then it's within the range.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .