iprange is a fast command-line tool for managing IPv4 and IPv6 address sets. It reads IP addresses, CIDRs, ranges, and hostnames in any combination, normalizes them into optimal non-overlapping sets, and performs set operations (union, intersection, difference, complement). It can also compare sets as CSV, reduce prefix diversity for firewall performance, and produce binary output for fast round-trips.
For 1 million input lines, a merge completes in under a second.
iprange accepts one entry per line. All formats can be mixed in the same file.
| Format | Example | Notes |
|---|---|---|
| Single IP | 1.2.3.4 |
|
| CIDR | 1.2.3.0/24 |
Network address applied by default |
| Netmask | 1.2.3.0/255.255.255.0 |
Equivalent to /24 |
| Range | 1.2.3.0 - 1.2.3.255 |
Dash with optional spaces |
| CIDR range | 1.2.3.0/24 - 1.2.4.0/24 |
Network of first to broadcast of second |
| Abbreviated | 10.1 |
Expands via inet_aton() |
| Numeric | 16909060 |
Integer, parsed by inet_aton() |
| Octal | 012.0.0.1 |
Components starting with 0 are octal |
| Hex | 0x0A000001 |
Components starting with 0x are hex |
| Hostname | example.com |
Resolved via parallel DNS |
Parsing uses inet_aton(), so all numeric forms it accepts (decimal integers, octal, hex, mixed) are supported. This is intentional and documented behavior.
| Format | Example | Notes |
|---|---|---|
| Full notation | 2001:0db8:0000:0000:0000:0000:0000:0001 |
|
| Compressed | 2001:db8::1 |
Standard :: compression |
| Loopback | ::1 |
|
| CIDR | 2001:db8::/32 |
Prefix 0-128 |
| Range | 2001:db8::1 - 2001:db8::ff |
|
| IPv4-mapped | ::ffff:10.0.0.1 |
|
| Plain IPv4 | 10.0.0.1 |
Normalized to ::ffff:10.0.0.1 |
| Hostname | example.com |
Both AAAA and A records resolved |
Parsing uses inet_pton(AF_INET6).
- Lines starting with
#or;are comments. - Inline comments after
#or;are stripped from data lines. - Empty lines and leading/trailing whitespace are ignored.
| Syntax | Meaning |
|---|---|
file.txt |
Load a single file as one ipset |
- |
Read from stdin |
@filelist.txt |
Load a file list (one filename per line, comments allowed) |
@directory/ |
Load all regular files in directory (sorted, no recursion) |
file.txt as name |
Override the name shown in CSV output |
When no files are given, stdin is assumed.
Feature detection for scripts:
iprange --has-filelist-loading && echo "supports @filename"
iprange --has-directory-loading && echo "supports @directory"Binary files (produced by --print-binary) are auto-detected by their header. IPv4 binary uses format v1.0; IPv6 uses v2.0. Loading a binary file of the wrong family is an error.
| Flag | Meaning |
|---|---|
| (none) | IPv4 mode (default for text input) |
--ipv4 / -4 |
Explicit IPv4 mode |
--ipv6 / -6 |
IPv6 mode |
Rules:
- Without
-4or-6, text input defaults to IPv4 mode. - In IPv6 mode, plain IPv4 input is accepted and normalized to
::ffff:x.x.x.x. - In IPv4 mode,
::ffff:x.x.x.xis converted back to IPv4. All other IPv6 input is dropped with one summary warning. - Operations between IPv4 and IPv6 datasets are not supported.
- Mixed-family range endpoints (e.g.,
10.0.0.1 - 2001:db8::1) are invalid. - Binary files declare their family in the header.
- Feature detection:
iprange --has-ipv6exits 0 if IPv6 is supported.
Merge all inputs into one sorted, deduplicated set.
iprange blocklist-a.txt blocklist-b.txtAliases: --optimize, --combine, --merge, --union, --union-all, -J
Print only the IPs common to all inputs.
iprange --common blocklist-a.txt blocklist-b.txtAliases: --common, --intersect, --intersect-all
Merge all files before --except, then remove all IPs matched by the files after it.
iprange allow.txt --except deny.txtAliases: --except, --exclude-next, --complement, --complement-next
Print IPs that exist in either A or B, but not both. Exits 1 if there are differences, 0 if the sets are equal.
iprange before.txt --diff after.txt
echo $? # 0 = identical, 1 = differentUse --quiet to suppress the output and only check the exit code.
Aliases: --diff, --diff-next
Merge all inputs, then reduce the number of distinct CIDR prefixes while allowing a controlled increase in entry count. This optimizes netfilter/iptables hash:net ipsets, where each distinct prefix adds a lookup but entry count does not affect performance.
iprange --ipset-reduce 20 blocklist.txtParameters:
| Option | Default | Meaning |
|---|---|---|
--ipset-reduce PERCENT |
20 | Allow this % increase in entries |
--ipset-reduce-entries ENTRIES |
16384 | Minimum acceptable entry count |
The tool computes the maximum acceptable entries as max(current * (1 + PERCENT/100), ENTRIES), then iteratively eliminates the prefix with the smallest cost until the limit is reached. The result matches exactly the same set of IPs.
Use -v to see the elimination steps and prefix breakdown.
Aliases: --reduce-factor, --reduce-entries
Compare all files pairwise and print CSV with entry counts, unique IPs, combined IPs, and common IPs.
iprange --compare --header blocklist-a.txt blocklist-b.txt blocklist-c.txtCompare first: compare the first file against every other:
iprange --compare-first --header reference.txt other1.txt other2.txtCompare next: compare files before the option against files after:
iprange --compare-next --header before1.txt before2.txt --compare-next after1.txt after2.txtMerge all inputs and print a single CSV line with entry and unique IP counts:
iprange --count-unique --header blocklist.txtPrint one CSV line per input file:
iprange --count-unique-all --header blocklist-a.txt blocklist-b.txtOutputs optimal non-overlapping CIDR blocks:
10.0.0.0/24
10.0.1.0/25
10.0.1.128/26
10.0.0.0-10.0.0.255
10.0.1.0-10.0.1.191
Enumerates every individual IP. Ranges larger than 16,777,216 IPs (256^3) are skipped with a warning to prevent unbounded output.
Fast machine-readable format for the same architecture (no endianness conversion). Use for caching and fast round-trips:
iprange --print-binary blocklist.txt > cache.bin
iprange cache.bin # reads binary, outputs CIDRCustomize output for ipset restore, iptables rules, or other tools:
# Generate ipset restore commands
iprange --print-prefix "add myset " blocklist.txt
# Different prefixes for single IPs vs networks
iprange --print-prefix-ips "add ips " --print-prefix-nets "add nets " blocklist.txt
# Add suffixes
iprange --print-suffix " timeout 3600" blocklist.txtLimit which CIDR prefixes appear in output:
# Only generate /24 to /32 (no large blocks)
iprange --min-prefix 24 blocklist.txt
# Only use specific prefixes
iprange --prefixes 24,32 blocklist.txtWarning: restricting prefixes can dramatically increase the number of output entries.
Hostnames in input files are resolved in parallel using a thread pool.
| Option | Default | Meaning |
|---|---|---|
--dns-threads N |
5 | Number of parallel DNS queries |
--dns-silent |
off | Suppress DNS error messages |
--dns-progress |
off | Show resolution progress bar |
In IPv4 mode, only A records are resolved. In IPv6 mode, both AAAA and A records are resolved (A records normalized to ::ffff:x.x.x.x).
Temporary failures (EAI_AGAIN) are retried up to 20 times. Permanent failures are reported to stderr (unless --dns-silent).
| Option | Default | Meaning |
|---|---|---|
--dont-fix-network |
off | Disable network address normalization (1.1.1.17/24 read as 1.1.1.17-1.1.1.255 instead of 1.1.1.0/24) |
--default-prefix N / -p N |
32 | Default prefix for bare IPs without a mask |
For scripts that need to check which features are available:
iprange --has-compare && echo "compare modes available"
iprange --has-reduce && echo "reduce mode available"
iprange --has-filelist-loading && echo "@filename supported"
iprange --has-directory-loading && echo "@directory supported"
iprange --has-ipv6 && echo "IPv6 supported"Each flag exits 0 if the feature is present, 1 otherwise.
Reduce a country blocklist for optimal ipset performance:
# Before: 406 entries using 18 prefixes (18 lookups per packet)
iprange -v country_gr.netset >/dev/null
# After: 4326 entries using 3 prefixes (3 lookups per packet)
# Same 6.3 million unique IPs matched
iprange -v --ipset-reduce 20 country_gr.netset >/dev/nullThe reduction is lossless: piping the reduced output back through iprange reproduces the original set exactly.
# Merge multiple blocklists into one optimized set
iprange list1.txt list2.txt list3.txt > merged.txt
# Find IPs that appear in all blocklists
iprange --common list1.txt list2.txt list3.txt > common.txt
# Create a blocklist but exclude your own networks
iprange merged.txt --except my-networks.txt > final.txt
# Check if two versions of a blocklist differ
iprange old.txt --diff new.txt --quiet
echo $? # 0 = no changes, 1 = changed
# Compare overlap between blocklists
iprange --compare --header list1.txt list2.txt list3.txt# Merge IPv6 blocklists
iprange -6 v6-list1.txt v6-list2.txt
# Mix IPv4 and IPv6 in one file (IPv6 mode normalizes IPv4)
iprange -6 mixed-input.txt
# Count unique IPv6 addresses
iprange -6 -C v6-list.txt
# Binary cache for IPv6
iprange -6 --print-binary large-v6.txt > cache-v6.bin
iprange -6 cache-v6.binFrom a release tarball:
./configure
make
make installFrom git:
./autogen.sh
./configure
make
make installTo skip the man page: ./configure --disable-man
| Command | What it tests |
|---|---|
make check |
Full test suite (CLI + build) |
./run-tests.sh |
CLI regression tests |
./run-build-tests.sh |
Build and layout regressions |
./run-sanitizer-tests.sh |
ASAN/UBSAN/TSAN coverage |
make check-sanitizers |
Sanitizer-integrated path |
| Directory | Contents |
|---|---|
src/ |
C sources and headers |
wiki/ |
Documentation (synced to GitHub wiki) |
packaging/ |
Spec template, ebuild, release tooling |
tests.d/ |
CLI regression tests |
tests.build.d/ |
Build and layout regressions |
tests.sanitizers.d/ |
Sanitizer CLI regressions |
tests.tsan.d/ |
TSAN regressions |
tests.unit/ |
Unit-style internal harnesses |
Detailed guides in the wiki/ directory (also published to the GitHub wiki):
Operations — one page per operation with verified examples: Merge | Intersection | Exclude | Diff | Reduce | Compare | Count
Reference: Input formats | Output formats | IPv6 | DNS resolution | Ipset optimization
iprange --help # full option reference
iprange --version # version and copyright