Search IP addresses and networks in text files.
It's grep, except instead of regular expressions, the needle is an IP-CIDR. The match-mode decides whether your CIDR is contained-in or containing the haystack.
Find IPs or ranges in which your needle fits:
$ ipgrep 192.168.1.1,172.17.1.2 /etc/firejail/nolocal.net -A OUTPUT -d 192.168.0.0/16 -j DROP -A OUTPUT -d 172.16.0.0/12 -j DROP
Find IPs contained inside your supplied ranges:
$ ip -br a | ipgrep localhost
NOTE: The default -m mode changes from "contains" to "within" when any needle is a network larger than a single IP.
Find exact IP matches:
$ ip -br a | ipgrep 0:0:0:0:0:0:0:1 -m equals lo UNKNOWN 127.0.0.1/8 ::1/128
Find and show only the matches:
$ ip -br a | ipgrep localhost -o 127.0.0.1/8 ::1/128 $ ip -br a | ipgrep '!localhost4' -o 192.168.2.49/24 172.17.0.1/16 172.18.0.1/16
Truncate the matches:
$ ip -br a | ipgrep '!localhost4' -O12 192.160.0.0/12 172.16.0.0/12 172.16.0.0/12
Supports IPv6:
$ ipgrep fe00::/7 /etc/hosts fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters
Looking for IPv4-mapped IPv6 addresses?:
$ echo ::ffff:127.0.0.1 | ipgrep ::ffff:0:0/96 ::ffff:127.0.0.1
Look for a few IPs in all networks found in /etc:
ipgrep -C 5 -a net -a oldnet -r 192.168.2.5,10.0.2.1 /etc/*
Find all unique /24 networks in a pcap. Requires a bit of sed magic because tcpdump outputs the port as the fifth octet.:
tcpdump -nr my.pcap |
sed -Ee 's/([0-9]+([.][0-9]+){3})[.]([0-9]+)/\1:\3/g' |
ipgrep -O24 | sort | uniq -c | sort -k2V
After sed has turned all IPs into 4-tuples ipgrep can match them
and print them as x.x.x.0/24.
This is a slightly polished version of the inline --help:
ipgrep - Search IP addresses and networks in text files
Usage: ipgrep [OPTIONS] [NEEDLES] [HAYSTACKS]...
Arguments:
NEEDLES are one or more IP addresses, networks or IP classes (separated
by comma/whitespace). Needles may be negated by prefixing them with a '!'.
Matches are made if any of the positive needles match and none of the
negative ones do.
Examples of valid needles:
- ip4,ip6 (default)
- 192.168.0.0/16
- 10.0.0.0/8,!10.2.0.0/16,fc00::/7
- ip4,!rfc1918
Valid classes include: ip4, ip6, global, localhost4, multicast6, private.
HAYSTACKS are one or more files. If none (or '-') given,
stdin is read
Matching Control:
-a, --accept <ACCEPT>
Accept input forms (may repeat or use commas):
ip - bare host IP
net - valid network (CIDR)
oldnet - valid network (host/dotted-netmask)
iface - interface IP (host/mask)
Defaults to: ip,net,iface
-I, --interface-mode <INTERFACE_MODE>
Select interface IP matching mode:
ip - treat as single IP (default)
net - treat as if network bits were unset
complain - complain/reject when network bits are set
-m, --match <MATCH_MODE>
Match mode:
auto - 'contains' if the all needles are a single IP,
else 'within' (default)
contains - haystack net contains needle net
within - haystack net is within needle net (inverse of contains)
equals - exact IP or network equality
overlaps - haystack and needle nets overlap
General Output Control:
-c, --count Print only a count of matching records
-l, --files-with-matches List filenames with matches only
-o, --only-matching Print only the matching IPs/networks
-O, --output-prefix <OUTPUT_PREFIX>
Implies -o/--only-matching. Truncates found IPs/networks to the
specified prefix length. E.g. pass 24 to get 192.168.2.0/24 instead
of 192.168.2.4
-q, --quiet Quiet; exit status only
-v, --invert-match Select non-matching lines; can include non-IPs
Output Line Prefix Control:
-h, --no-filename Suppress filename prefix on output
-n, --line-number Prefix each output line/record with lineno
-Z, --null Output a zero byte instead of LF in output;
useful in tandem with -l
Context Line Control:
-B, --before-context <N> Print N lines of leading context
-A, --after-context <N> Print N lines of trailing context
-C, --context <N> Print N lines of output context
File and Directory Selection:
-r, --recursive Read files under each directory, recursively
-R, --dereference-recursive Dereference symlinks while doing so
Other Options:
--line-buffered Flush output on every line
Generic Program Information:
--help Show help
-V, --version Show program version
Exit status:
0 if match found
1 if no match found
2 if error
The options mimic standard (GNU) grep options.
Obviously ossobv/ipgrep isn't the first tool that searches for IPs.
And apparently, there are several applications called ipgrep
already, and then a few called cidrgrep, cidr-grep and
grepcidr. Here's an attempt at enumerating other versions and their
features. Ordered by feature-completeness.
| Features in application | ipgrep | grep | grepcidr | grepcidr | ipgrep | ipgrep | cidr-grep | cidrgrep | ipgrep | ipgrep | ipgrep | ipgrep |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Author/source | ossobv | POSIX | levine | berkes | robrwo | joonas | pangraz | doherty | dmages | jstarke | princeb | jesdict |
| Version | 0.1.3 | many | 3.02 | 2.0 | 0.7.0 | 0.3.2 | 1.0.3 | none | 0.2 | 0.2.0 | none | 1.0.1 |
| Last updated | 2025 | 2025 | 2025 | 2014 | 2023 | 2025 | 2015 | 2020 | 2019 | 2023 | 2016 | 2023 |
| Programming language | rust | C | C | C | perl | golang | nodejs | golang | perl | rust | golang | python |
| IP address aware [1] | ✅ | ❌ | ✅ [6] | ✅ | ✅ [6] | ✅ [6] | ✅ | ✅ [6] | ✅ | ✅ | ✅ [6] | ✅ |
| Search by needle(s) [2] | ✅ | ✅ | 🟡 [2] | 🟡 [2] | 🟡 [2] | 🟡 | ✅ | 🟡 | 🟡 | ❌ | ❌ | ❌ |
| Search by IP class (e.g. "public") | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| Network/CIDR "contains" match | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| Handles legacy 1.2.3.0m255.255.255.0 | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Handles IPv6 | ✅ | ✅ [1] | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ [7] | ❌ | ✅ | ❌ |
| Search multiple files | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 🟡 [7] | ✅ | ✅ | ✅ |
| Search directories recursively | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Highlight/colorize matches | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| Extract only IPs (-o) [3] | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🟡 | 🟡 |
| Support negative match (-v) | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| Support showing context lines (-C) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Support showing counts (-c) | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Deobfuscate / resolve hostnames [4] | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
| Run duration [5] | 1 | ∅ | 1.3 | 1.8 | 3.7 | 4.2 | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ |
| [1] | (1, 2) POSIX grep does not have any notion of IP addresses, but it can match both IPv4 and IPv6 if you provide the right regular expression. |
| [2] | (1, 2, 3, 4) Most tools only allow searching by a single needle IP or CIDR. Some tools do allow multiple needles specified through a file, but specifying those using bash process substitution fails because that file is reread for each opened haystack file. |
| [3] | Better tools support extracting only IPs using a -o flag, or
similar. Other implementations either return full lines or only IPs,
without an option to switch. |
| [4] | jesdict1/ipgrep detects obfuscated hostnames such as
hxxp:// and www[.]example[.]com and resolves them. This
feature is not planned for ossobv/ipgrep. |
| [5] | Run duration is a non-scientific test over the same dataset. The fastest one has a duration of 1. Only tools that could reasonably be compared were eligible. |
| [6] | (1, 2, 3, 4, 5) robrwo/ipgrep, jrlevine/grepcidr and tomdoherty/cidrgrep
consider ([0-9]+[.]){4}[0-9] to be valid, while those are
generally ASN.1 object identifiers.
princebot/ipgrep and the berkes/grepcidr tools don't consider
([0-9]+[.]){4}[.] valid while that would be a valid the end of a
sentence.
joneskoo/ipgrep won't list "commented out" IPs. |
| [7] | (1, 2) digitalmages/ipgrep doesn't know what ::/0 is. So we can't
trust this for IPv6. digitalmages/ipgrep also dies as soon as it
has trouble reading a file. |
Other tools not shown in the list:
- markust: markusthilo/ipgrep (v0.3, 2020, C) merges and filters PCAP files.
GPLv3+
- Maybe make colored output option. Right now you can always disable it
by piping to
cat. - There are a few TODOs in the source to tackle. Not a big priority.
