Grepping for CIDR ranges
From time to time I want to grep CIDR ranges out of my Apache log files. This is easy for ranges that fall on the natural boundaries (/8, /16 and /24) but not so easy for other ranges such as /17 and /25.
Examples:
# 192.168.0.0/16: (easy)
grep " 192\.168\." access_log
# 192.168.128.0/17: (more thought required)
grep -E " 192\.168\.(12[89]|1[3-9][0-9]|2[0-5][0-9])\." access_log
# 192.168.0.0/17: (more thought required)
grep -E " 192\.168\.([0-9]|[0-9][0-9]|1[01][0-9]|12[0-7])\." access_log
# 192.168.128.0/18: (straining my brain)
grep -E " 192\.168\.(1[2-8][0-9]|19[01])\." access_log
These regexes ignore IP addresses that include leading zeros, such as 192.168.001.001
, which isn't a problem in Apache log files but could be in other log files. Printers in particular seem to like the leading zeroes. It's easy enough to add the optional zeroes to the regex but it just makes the whole thing a little bit more difficult. There has to be an easier way.
Is there an easy way to select lines from a file that match any CIDR range?
Fancy regex extensions will be considered as will different tools (such as awk
or perl
if necessary but I want it to be a one-liner) if they make the job easier. Ideally, what I'd like is something like
grep "[:CIDR 192.168.128.0/18:]" access_log
A tool that converts a CIDR range into the appropriate regex would also be OK.
$ cidr2regex 192.168.0.0/18
192\.168\.(1[2-8][0-9]|19[01])\.[0-9]{1,3}
or
$ grep -E "$(cidr2regex 192.168.0.0/18)" access_log
Bonus points if your answer also covers IPv6.
There is, unsurprisingly, a tool for this: grepcidr
.
It is not included by default with any system I'm aware of, but you can download it from here, and it is in both the Ubuntu package repository and the FreeBSD ports collection as well.
(Version 2.0 works with IPv6 networks too)
The recently released rgxg
command line tool generates regular expressions that match all addresses in a CIDR block:
$ rgxg cidr 192.168.128.0/18
192\.168\.(19[01]|1[3-8][0-9]|12[89])\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])
or
$ rgxg cidr 2001:db8:a:b:c:d::/112
2001:0?[Dd][Bb]8:0?0?0?[Aa]:0?0?0?[Bb]:0?0?0?[Cc]:0?0?0?[Dd]((::[0-9A-Fa-f]{1,4}|::|:0?0?0?0(::|:[0-9A-Fa-f]{1,4}))|:0\.0(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){2})
For more information, see http://rgxg.sf.net.