4

I want to know if there's a way to check if some subnets are (or not) overlapped with a List of IPs For example, we have this List:

197.26.9.128/25
193.36.81.128/25
194.33.24.0/22
188.115.195.80/28
188.115.195.64/28
185.59.69.96/28
185.59.69.32/27
41.202.219.32/27
41.202.219.128/29
154.70.120.16/28
154.70.120.32/28
154.70.120.0/28
41.202.219.208/28
41.202.219.136/29
197.157.209.0/24

and I want to check if the following IPs are overlapped with the previous list.

197.26.9.0/26
194.33.26.0/26      (IP overlapped with 194.33.24.0/22)
188.115.195.88/29   (IP overlapped with 188.115.195.80/28)
41.202.219.0/24
197.157.209.128/28  (IP overlapped with 197.157.209.0/24)

The output would be the next:

197.26.9.0/26
41.202.219.0/24
  • Could you use python? which has a separate IP Address library? – Inian Mar 16 '18 at 9:51
  • 1
    Please detail what you have done until now and where you think you need help improving your script. – Rui F Ribeiro Mar 16 '18 at 10:04
  • Concur with @Inian -- don't try doing this in shell, use a scripting language - all the big ones these days grok IP addresses and network calculation. – Shadur Mar 16 '18 at 12:17
0

Here are a few bits for you. First, a script in Bash, so not very efficient. It doesn't do exactly what you want, because it only checks one pair of subnets and reports the overlap. Below the script a few rough shell commands follow, thought the result is not presented in the form you want. So you need to integrate and adjust the whole bunch to your needs, or treat them as a sketch illustrating the logic.

#!/usr/bin/env bash

subnet1="$1"
subnet2="$2"

# calculate min and max of subnet1
# calculate min and max of subnet2
# find the common range (check_overlap)
# print it if there is one

read_range () {
    IFS=/ read ip mask <<<"$1"
    IFS=. read -a octets <<< "$ip";
    set -- "${octets[@]}";
    min_ip=$(($1*256*256*256 + $2*256*256 + $3*256 + $4));
    host=$((32-mask))
    max_ip=$(($min_ip+(2**host)-1))
    printf "%d-%d\n" "$min_ip" "$max_ip"
}

check_overlap () {
    IFS=- read min1 max1 <<<"$1";
    IFS=- read min2 max2 <<<"$2";
    if [ "$max1" -lt "$min2" ] || [ "$max2" -lt "$min1" ]; then return; fi
    [ "$max1" -ge "$max2" ] && max="$max2" ||   max="$max1"
    [ "$min1" -le "$min2" ] && min="$min2" || min="$min1"
    printf "%s-%s\n" "$(to_octets $min)" "$(to_octets $max)"
}

to_octets () {
    first=$(($1>>24))
    second=$((($1&(256*256*255))>>16))
    third=$((($1&(256*255))>>8))
    fourth=$(($1&255))
    printf "%d.%d.%d.%d\n" "$first" "$second" "$third" "$fourth" 
}

range1="$(read_range $subnet1)"
range2="$(read_range $subnet2)"
overlap="$(check_overlap $range1 $range2)"
[ -n "$overlap" ] && echo "Overlap $overlap of $subnet1 and $subnet2"

The usage and result are these:

$ ./overlap.bash 194.33.26.0/26 194.33.24.0/22
Overlap 194.33.26.0-194.33.26.63 of 194.33.26.0/26 and 194.33.24.0/22

Now given your first list of subnets is in file list and the subnets to check are in the file to_check, you can use the script to find all overlaps.

$ while read l; do list+=("$l"); done < list
$ while read t; do to_check+=("$t"); done < to_check
$ for i in "${list[@]}"; do for j in "${to_check[@]}"; do \
./overlap.bash "$i" "$j"; done; done

This is the result:

Overlap 194.33.26.0-194.33.26.63 of 194.33.24.0/22 and 194.33.26.0/26
Overlap 188.115.195.88-188.115.195.95 of 188.115.195.80/28 and 188.115.195.88/29
Overlap 41.202.219.32-41.202.219.63 of 41.202.219.32/27 and 41.202.219.0/24
Overlap 41.202.219.128-41.202.219.135 of 41.202.219.128/29 and 41.202.219.0/24
Overlap 41.202.219.208-41.202.219.223 of 41.202.219.208/28 and 41.202.219.0/24
Overlap 41.202.219.136-41.202.219.143 of 41.202.219.136/29 and 41.202.219.0/24
Overlap 197.157.209.128-197.157.209.143 of 197.157.209.0/24 and 197.157.209.128/28

As you can see, 41.202.219.0/24 has four overlaps, contrary to your expectations in your question.

To get only the subnets with no overlaps with the first list, the script would be much shorter. You don't need the to_octets function and the check_overlap function can already give result on this line:

if [ "$max1" -lt "$min2" ] || [ "$max2" -lt "$min1" ]; then return; fi

Also the last two lines can can be changed (with the last one removed completely).

As for the integration logic, there's place for short-circuiting the checking against the first list, as not all combinations have to be checked. One negative is enough.

  • What do you mean exactly with "To get only the subnets with no overlaps"? I dind't understand very well and it seems a good idea. By the way @tomasz, thank you very much for you support! A great script. – lendoiro Mar 23 '18 at 7:52
  • @lendoiro The list of subnets from one list with no overlaps with another list of subnets. That's what you request in your question. Your expected output. – Tomasz Mar 23 '18 at 9:38
2

Try with ipconflict, pip install ipconflict.

Putting your subnets in /tmp/subnets.txt

ipconflict -f /tmp/subnets.txt

Output:

conflict found: 194.33.24.0/22 <-> 194.33.26.0/26
conflict found: 188.115.195.80/28 <-> 188.115.195.88/29
conflict found: 41.202.219.32/27 <-> 41.202.219.0/24
conflict found: 41.202.219.128/29 <-> 41.202.219.0/24
conflict found: 41.202.219.208/28 <-> 41.202.219.0/24
conflict found: 41.202.219.136/29 <-> 41.202.219.0/24
conflict found: 197.157.209.0/24 <-> 197.157.209.128/28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.