Reputation: 153
I have a text file containing a long list of IP addresses that are sorted. A sample of the file looks like this:
103.21.244.0/22 1; #Cloudflare
103.22.200.0/22 1; #Cloudflare
103.31.4.0/22 1; #Cloudflare
104.16.0.0/12 1; #Cloudflare
108.162.192.0/18 1; #Cloudflare
141.101.64.0/18 1; #Cloudflare
162.158.0.0/15 1; #Cloudflare
173.245.48.0/20 1; #Cloudflare
188.114.96.0/20 1; #Cloudflare
190.93.240.0/20 1; #Cloudflare
197.234.240.0/22 1; #Cloudflare
198.41.128.0/17 1; #Cloudflare
199.27.128.0/21 1; #Cloudflare
I'm trying to write a shell script that does the following:
For a given IP address (e.g. 1.2.3.4
) or an IP range (e.g. 1.2.3.0/24
), find out whether it is already in the file.
If it is, do nothing. If it is not, then insert it into the file in the right place.
Problems:
A. I'm stuck at checking whether an IP address or IP range is already in the file because a simple grep won't do. For example, grep will return negative for the IP 188.114.98.200
, which in fact is already represented by 188.114.96.0/20
. Likewise for 188.114.98.0/24
.
B. I am also clueless about how to insert an IP address/range entry in the right place without messing the sorted order.
Can someone help? Thank you very much.
Edit:
Okay, after looking at the suggestions, I guess I don't have to needlessly limit myself to Bash, especially if there are already existing libraries in other languages that can get the job done easily.
Upvotes: 1
Views: 925
Reputation: 14945
Not bash
, but this task is quite simple using Python
:
>>> print ips
103.21.244.0/22 1; #Cloudflare
103.22.200.0/22 1; #Cloudflare
103.31.4.0/22 1; #Cloudflare
104.16.0.0/12 1; #Cloudflare
108.162.192.0/18 1; #Cloudflare
141.101.64.0/18 1; #Cloudflare
162.158.0.0/15 1; #Cloudflare
173.245.48.0/20 1; #Cloudflare
188.114.96.0/20 1; #Cloudflare
190.93.240.0/20 1; #Cloudflare
197.234.240.0/22 1; #Cloudflare
198.41.128.0/17 1; #Cloudflare
199.27.128.0/21 1; #Cloudflare
>>> import iptools
>>> [raw_range for raw_range in ips.splitlines()
... if '188.114.98.200' in iptools.IpRangeList(raw_range.split()[0])]
['188.114.96.0/20 1; #Cloudflare']
>>>
>>> [raw_range for raw_range in ips.splitlines()
... if '188.112.98.200' in iptools.IpRangeList(raw_range.split()[0])]
[]
Upvotes: 0
Reputation: 989
Seems to me that comparing/matching IP-format strings will be quite annoying.
This page (Listing 4) has a good and simple trick to convert an IP string into an array of integers, only using bash parameter substitution (documented here, look for ${var#Pattern}, ${var##Pattern}
).
If you want to catch the mask, add something like IP[5]=${tmp##*/}
(with the notations of the linux mag pdf).
For simple IP comparison, you can simply compare/match arrays of integers with bash's arithmetic evaluation ((...))
(documented here for instance).
For more complex CIDR matching, either you are willing to implement quite a bit of logic yourself, or try tools like ipcalc
(check this) which is available on most Linux distros.
Upvotes: 1