iprange

April 4, 2026 ยท View on GitHub

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.

Input formats

iprange accepts one entry per line. All formats can be mixed in the same file.

IPv4 (default mode)

FormatExampleNotes
Single IP1.2.3.4
CIDR1.2.3.0/24Network address applied by default
Netmask1.2.3.0/255.255.255.0Equivalent to /24
Range1.2.3.0 - 1.2.3.255Dash with optional spaces
CIDR range1.2.3.0/24 - 1.2.4.0/24Network of first to broadcast of second
Abbreviated10.1Expands via inet_aton()
Numeric16909060Integer, parsed by inet_aton()
Octal012.0.0.1Components starting with 0 are octal
Hex0x0A000001Components starting with 0x are hex
Hostnameexample.comResolved 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.

IPv6 (-6 mode)

FormatExampleNotes
Full notation2001:0db8:0000:0000:0000:0000:0000:0001
Compressed2001:db8::1Standard :: compression
Loopback::1
CIDR2001:db8::/32Prefix 0-128
Range2001:db8::1 - 2001:db8::ff
IPv4-mapped::ffff:10.0.0.1
Plain IPv410.0.0.1Normalized to ::ffff:10.0.0.1
Hostnameexample.comBoth AAAA and A records resolved

Parsing uses inet_pton(AF_INET6).

Comments and whitespace

  • Lines starting with # or ; are comments.
  • Inline comments after # or ; are stripped from data lines.
  • Empty lines and leading/trailing whitespace are ignored.

File inputs

SyntaxMeaning
file.txtLoad a single file as one ipset
-Read from stdin
@filelist.txtLoad a file list (one filename per line, comments allowed)
@directory/Load all regular files in directory (sorted, no recursion)
file.txt as nameOverride 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 input

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.

Address family

FlagMeaning
(none)IPv4 mode (default for text input)
--ipv4 / -4Explicit IPv4 mode
--ipv6 / -6IPv6 mode

Rules:

  • Without -4 or -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.x is 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-ipv6 exits 0 if IPv6 is supported.

Operations

Merge / Union (default)

Merge all inputs into one sorted, deduplicated set.

iprange blocklist-a.txt blocklist-b.txt

Aliases: --optimize, --combine, --merge, --union, --union-all, -J

Intersection

Print only the IPs common to all inputs.

iprange --common blocklist-a.txt blocklist-b.txt

Aliases: --common, --intersect, --intersect-all

Complement (exclude)

Merge all files before --except, then remove all IPs matched by the files after it.

iprange allow.txt --except deny.txt

Aliases: --except, --exclude-next, --complement, --complement-next

Symmetric difference

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 = different

Use --quiet to suppress the output and only check the exit code.

Aliases: --diff, --diff-next

Reduce prefixes

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.txt

Parameters:

OptionDefaultMeaning
--ipset-reduce PERCENT20Allow this % increase in entries
--ipset-reduce-entries ENTRIES16384Minimum 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 (CSV)

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.txt

Compare first: compare the first file against every other:

iprange --compare-first --header reference.txt other1.txt other2.txt

Compare next: compare files before the option against files after:

iprange --compare-next --header before1.txt before2.txt --compare-next after1.txt after2.txt

Count unique (CSV)

Merge all inputs and print a single CSV line with entry and unique IP counts:

iprange --count-unique --header blocklist.txt

Print one CSV line per input file:

iprange --count-unique-all --header blocklist-a.txt blocklist-b.txt

Output formats

CIDR (default)

Outputs optimal non-overlapping CIDR blocks:

10.0.0.0/24
10.0.1.0/25
10.0.1.128/26

Ranges (--print-ranges / -j)

10.0.0.0-10.0.0.255
10.0.1.0-10.0.1.191

Single IPs (--print-single-ips / -1)

Enumerates every individual IP. Ranges larger than 16,777,216 IPs (2563256^{3}) are skipped with a warning to prevent unbounded output.

Binary (--print-binary)

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 CIDR

Prefix and suffix strings

Customize 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.txt

Prefix control

Limit 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.txt

Warning: restricting prefixes can dramatically increase the number of output entries.

DNS resolution

Hostnames in input files are resolved in parallel using a thread pool.

OptionDefaultMeaning
--dns-threads N5Number of parallel DNS queries
--dns-silentoffSuppress DNS error messages
--dns-progressoffShow 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).

Input behavior

OptionDefaultMeaning
--dont-fix-networkoffDisable 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 N32Default prefix for bare IPs without a mask

Feature detection

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.

Examples

Firewall optimization

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/null

The reduction is lossless: piping the reduced output back through iprange reproduces the original set exactly.

Blocklist management

# 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

IPv6 workflows

# 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.bin

Build and install

From a release tarball:

./configure
make
make install

From git:

./autogen.sh
./configure
make
make install

To skip the man page: ./configure --disable-man

Testing

CommandWhat it tests
make checkFull test suite (CLI + build)
./run-tests.shCLI regression tests
./run-build-tests.shBuild and layout regressions
./run-sanitizer-tests.shASAN/UBSAN/TSAN coverage
make check-sanitizersSanitizer-integrated path

Repository layout

DirectoryContents
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

Documentation

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

Getting help

iprange --help     # full option reference
iprange --version  # version and copyright