Skip to content

Commit 97bcd44

Browse files
committed
Split operations into individual wiki pages with verified examples
Replace the monolithic operations.md with one page per operation: merge, intersect, exclude, diff, reduce, compare, count-unique. Every example in every page was run against the built iprange binary and the output copied verbatim into the documentation.
1 parent 2885de4 commit 97bcd44

10 files changed

Lines changed: 478 additions & 147 deletions

File tree

README.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -378,12 +378,11 @@ To skip the man page: `./configure --disable-man`
378378

379379
Detailed guides in the [`wiki/`](wiki/) directory (also published to the [GitHub wiki](https://github.com/firehol/iprange/wiki)):
380380

381-
- [Input formats](wiki/input-formats.md) — every accepted format, file lists, directories, binary
382-
- [Output formats](wiki/output-formats.md) — CIDR, ranges, single IPs, binary, CSV, prefix/suffix
383-
- [Operations](wiki/operations.md) — merge, intersect, exclude, diff, reduce, compare, count
384-
- [IPv6 support](wiki/ipv6.md) — address family, normalization, cross-family rules
385-
- [DNS resolution](wiki/dns-resolution.md) — threading, retry, configuration
386-
- [Optimizing ipsets for iptables](wiki/ipset-reduce.md) — prefix reduction with examples
381+
**Operations** — one page per operation with verified examples:
382+
[Merge](wiki/merge.md) | [Intersection](wiki/intersect.md) | [Exclude](wiki/exclude.md) | [Diff](wiki/diff.md) | [Reduce](wiki/reduce.md) | [Compare](wiki/compare.md) | [Count](wiki/count-unique.md)
383+
384+
**Reference:**
385+
[Input formats](wiki/input-formats.md) | [Output formats](wiki/output-formats.md) | [IPv6](wiki/ipv6.md) | [DNS resolution](wiki/dns-resolution.md) | [Ipset optimization](wiki/ipset-reduce.md)
387386

388387
## Getting help
389388

wiki/Home.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,23 @@ For 1 million input lines, a merge completes in under a second.
66

77
## Documentation
88

9+
### Operations
10+
11+
- [Merge / Union](merge.md) — merge all inputs into one optimized set (default mode)
12+
- [Intersection](intersect.md) — find IPs common to all inputs
13+
- [Complement / Exclude](exclude.md) — remove one set from another
14+
- [Symmetric Difference](diff.md) — find IPs in either set but not both
15+
- [Reduce Prefixes](reduce.md) — reduce CIDR prefix diversity for firewall performance
16+
- [Compare](compare.md) — compare sets pairwise as CSV (all, first, next)
17+
- [Count Unique](count-unique.md) — count entries and unique IPs as CSV
18+
19+
### Reference
20+
921
- [Input formats](input-formats.md) — every accepted format, file lists, directories, binary input
1022
- [Output formats](output-formats.md) — CIDR, ranges, single IPs, binary, CSV, prefix/suffix strings
11-
- [Operations](operations.md) — merge, intersect, exclude, diff, reduce, compare, count
1223
- [IPv6 support](ipv6.md) — address family selection, normalization, cross-family rules
1324
- [DNS resolution](dns-resolution.md) — parallel threading, retry, configuration
14-
- [Optimizing ipsets for iptables](ipset-reduce.md)prefix reduction tutorial with examples
25+
- [Optimizing ipsets for iptables](ipset-reduce.md)extended tutorial with real-world examples
1526

1627
## Quick reference
1728

wiki/compare.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Compare
2+
3+
Compare IP sets pairwise and print CSV with overlap statistics.
4+
5+
Three comparison modes are available:
6+
7+
## Compare all (`--compare`)
8+
9+
Compare every file with every other file.
10+
11+
```
12+
# list-a.txt # list-b.txt # list-c.txt
13+
10.0.0.0/24 10.0.0.128/25 10.0.0.0/16
14+
10.0.1.0/24 10.0.2.0/24 172.16.0.0/12
15+
192.168.1.0/24 192.168.1.0/24
16+
```
17+
18+
```
19+
$ iprange --compare --header list-a.txt list-b.txt list-c.txt
20+
name1,name2,entries1,entries2,ips1,ips2,combined_ips,common_ips
21+
list-a.txt,list-b.txt,2,3,768,640,1024,384
22+
list-a.txt,list-c.txt,2,2,768,1114112,1114368,512
23+
list-b.txt,list-c.txt,3,2,640,1114112,1114368,384
24+
```
25+
26+
**Columns**: name1, name2, entries in each, unique IPs in each, combined (union) IPs, common (intersection) IPs.
27+
28+
## Compare first (`--compare-first`)
29+
30+
Compare the first file against each subsequent file.
31+
32+
```
33+
$ iprange --compare-first --header list-a.txt list-b.txt list-c.txt
34+
name,entries,unique_ips,common_ips
35+
list-b.txt,3,640,384
36+
list-c.txt,2,1114112,512
37+
```
38+
39+
This is useful for checking how much of a reference list overlaps with each of several other lists.
40+
41+
## Compare next (`--compare-next`)
42+
43+
**Positional**: compare files before the option against files after it.
44+
45+
```
46+
$ iprange list-a.txt --compare-next list-b.txt list-c.txt --header
47+
name1,name2,entries1,entries2,ips1,ips2,combined_ips,common_ips
48+
list-a.txt,list-b.txt,2,3,768,640,1024,384
49+
list-a.txt,list-c.txt,2,2,768,1114112,1114368,512
50+
```
51+
52+
Only `list-a.txt` (before `--compare-next`) is compared against `list-b.txt` and `list-c.txt` (after it).
53+
54+
## Naming files in CSV output
55+
56+
Use `as NAME` after a filename to set a custom name in the CSV:
57+
58+
```
59+
$ iprange --count-unique-all --header list-a.txt as "Blocklist A" list-b.txt as "Blocklist B"
60+
name,entries,unique_ips
61+
Blocklist A,2,768
62+
Blocklist B,3,640
63+
```
64+
65+
## CSV header
66+
67+
All CSV modes default to no header. Add `--header` to include column names as the first row.

wiki/count-unique.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Count Unique
2+
3+
Print entry counts and unique IP counts as CSV.
4+
5+
Two counting modes are available:
6+
7+
## Count merged (`--count-unique` / `-C`)
8+
9+
Merge all inputs and print a single CSV line with the totals:
10+
11+
```
12+
# list-a.txt # list-b.txt
13+
10.0.0.0/24 10.0.0.128/25
14+
10.0.1.0/24 10.0.2.0/24
15+
192.168.1.0/24 192.168.1.0/24
16+
```
17+
18+
```
19+
$ iprange -C --header list-a.txt list-b.txt
20+
entries,unique_ips
21+
2,1024
22+
```
23+
24+
The merged set has 2 entries (ranges) covering 1024 unique IPs.
25+
26+
## Count per file (`--count-unique-all`)
27+
28+
Print one CSV line per input file without merging:
29+
30+
```
31+
$ iprange --count-unique-all --header list-a.txt list-b.txt list-c.txt
32+
name,entries,unique_ips
33+
list-a.txt,2,768
34+
list-b.txt,3,640
35+
list-c.txt,2,1114112
36+
```
37+
38+
## Naming files in CSV output
39+
40+
Use `as NAME` to customize the name column:
41+
42+
```
43+
$ iprange --count-unique-all --header list-a.txt as "Blocklist A" list-b.txt as "Blocklist B"
44+
name,entries,unique_ips
45+
Blocklist A,2,768
46+
Blocklist B,3,640
47+
```
48+
49+
## IPv6
50+
51+
```
52+
$ printf '2001:db8::/32\n' | iprange -6 -C --header
53+
entries,unique_ips
54+
1,79228162514264337593543950336
55+
```
56+
57+
IPv6 unique IP counts are printed as full 128-bit decimal numbers.
58+
59+
## CSV header
60+
61+
Add `--header` to include column names. Without it, only data lines are printed.

wiki/diff.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Symmetric Difference
2+
3+
Print the IPs that exist in either A or B, but **not both**.
4+
5+
**Aliases**: `--diff`, `--diff-next`
6+
7+
## How it works
8+
9+
This is a **positional** operation:
10+
1. All files before `--diff` are merged into set **A**
11+
2. All files after `--diff` are merged into set **B**
12+
3. The output is (A - B) union (B - A) — the XOR of the two sets
13+
14+
**Exit code**: 0 if the sets are identical (no output), 1 if there are differences. This makes `--diff` useful in scripts to detect changes.
15+
16+
## Examples
17+
18+
Compare two versions of a blocklist:
19+
20+
```
21+
# before.txt # after.txt
22+
10.0.0.0/24 10.0.0.0/24
23+
10.0.1.0/24 10.0.1.0/25 # shrunk
24+
10.0.2.0/24 10.0.2.0/24
25+
10.0.3.0/24 # added
26+
```
27+
28+
```
29+
$ iprange before.txt --diff after.txt
30+
10.0.1.128/25
31+
10.0.3.0/24
32+
```
33+
34+
The output shows `10.0.1.128/25` (the upper half of the /24 that was shrunk to a /25) and `10.0.3.0/24` (newly added). The two entries that remained identical are excluded.
35+
36+
**Exit code check**:
37+
38+
```
39+
$ iprange before.txt --diff after.txt
40+
10.0.1.128/25
41+
10.0.3.0/24
42+
$ echo $?
43+
1
44+
```
45+
46+
```
47+
$ iprange before.txt --diff before.txt
48+
$ echo $?
49+
0
50+
```
51+
52+
**Quiet mode** — suppress output, only check exit code:
53+
54+
```
55+
$ iprange before.txt --diff after.txt --quiet
56+
$ echo $?
57+
1
58+
```

wiki/exclude.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Complement / Exclude
2+
3+
Merge all files before `--except`, then remove all IPs matched by the files after it.
4+
5+
**Aliases**: `--except`, `--exclude-next`, `--complement`, `--complement-next`
6+
7+
## How it works
8+
9+
This is a **positional** operation:
10+
1. All files before `--except` are merged into set **A**
11+
2. Each file after `--except` is subtracted from A, one by one
12+
3. The result is the IPs in A that are not in any of the subtracted sets
13+
14+
## Examples
15+
16+
Remove specific entries from a whitelist:
17+
18+
```
19+
# allow.txt # deny.txt
20+
10.0.0.0/8 10.0.0.0/24
21+
172.16.0.0/12 172.16.0.0/16
22+
192.168.0.0/16 192.168.1.100
23+
```
24+
25+
```
26+
$ iprange allow.txt --except deny.txt
27+
10.0.1.0/24
28+
10.0.2.0/23
29+
10.0.4.0/22
30+
10.0.8.0/21
31+
10.0.16.0/20
32+
10.0.32.0/19
33+
10.0.64.0/18
34+
10.0.128.0/17
35+
10.1.0.0/16
36+
10.2.0.0/15
37+
10.4.0.0/14
38+
10.8.0.0/13
39+
10.16.0.0/12
40+
10.32.0.0/11
41+
10.64.0.0/10
42+
10.128.0.0/9
43+
172.17.0.0/16
44+
172.18.0.0/15
45+
172.20.0.0/14
46+
172.24.0.0/13
47+
192.168.0.0/24
48+
192.168.1.0/26
49+
192.168.1.64/27
50+
192.168.1.96/30
51+
192.168.1.101
52+
192.168.1.102/31
53+
192.168.1.104/29
54+
192.168.1.112/28
55+
192.168.1.128/25
56+
192.168.2.0/23
57+
192.168.4.0/22
58+
192.168.8.0/21
59+
192.168.16.0/20
60+
192.168.32.0/19
61+
192.168.64.0/18
62+
192.168.128.0/17
63+
```
64+
65+
The `10.0.0.0/24` was carved out of `10.0.0.0/8`, leaving the remaining address space as multiple CIDRs. The single IP `192.168.1.100` was punched out of `192.168.0.0/16`, creating a gap around it.
66+
67+
## IPv6
68+
69+
```
70+
$ printf '2001:db8::/32\n' > all.txt
71+
$ printf '2001:db8:1::/48\n' > remove.txt
72+
$ iprange -6 all.txt --except remove.txt | head -5
73+
2001:db8::/48
74+
2001:db8:2::/47
75+
2001:db8:4::/46
76+
2001:db8:8::/45
77+
2001:db8:10::/44
78+
```
79+
80+
Carving a /48 out of a /32 leaves 16 CIDR blocks covering the remaining address space.

wiki/intersect.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Intersection
2+
3+
Print only the IPs that appear in **all** input files.
4+
5+
**Aliases**: `--common`, `--intersect`, `--intersect-all`
6+
7+
## How it works
8+
9+
Each input file is optimized, then the intersection is computed pairwise. An IP appears in the output only if it is covered by every input file. If the files have no overlap, the output is empty.
10+
11+
## Examples
12+
13+
Find IPs common to two blocklists:
14+
15+
```
16+
# list-a.txt # list-b.txt
17+
10.0.0.0/24 10.0.0.128/25
18+
10.0.1.0/24 10.0.2.0/24
19+
192.168.1.0/24 192.168.1.0/24
20+
```
21+
22+
```
23+
$ iprange --common list-a.txt list-b.txt
24+
10.0.0.128/25
25+
192.168.1.0/24
26+
```
27+
28+
Only the upper half of `10.0.0.0/24` (which is `10.0.0.128/25`) overlaps with `list-b.txt`'s `10.0.0.128/25`. `192.168.1.0/24` is in both files. `10.0.1.0/24` and `10.0.2.0/24` have no overlap and are excluded.
29+
30+
## IPv6
31+
32+
```
33+
$ printf '2001:db8::/32\n' > v6-a.txt
34+
$ printf '2001:db8:1::/48\n2001:db9::/32\n' > v6-b.txt
35+
$ iprange -6 --common v6-a.txt v6-b.txt
36+
2001:db8:1::/48
37+
```
38+
39+
The `/32` in v6-a.txt contains the `/48` from v6-b.txt. The `2001:db9::/32` in v6-b.txt does not overlap.

0 commit comments

Comments
 (0)