Skip to content

Add IPv6 support with --ipv4/-4 and --ipv6/-6 flags#40

Merged
ktsaou merged 9 commits intomasterfrom
ipv6-support
Apr 4, 2026
Merged

Add IPv6 support with --ipv4/-4 and --ipv6/-6 flags#40
ktsaou merged 9 commits intomasterfrom
ipv6-support

Conversation

@ktsaou
Copy link
Copy Markdown
Member

@ktsaou ktsaou commented Apr 4, 2026

Summary

Add IPv6 support to iprange without breaking the existing IPv4 contract.

IPv6 support

  • --ipv4 / -4 forces IPv4 mode (default for text input)
  • --ipv6 / -6 forces IPv6 mode
  • IPv6 mode accepts both IPv6 and IPv4 input, normalizing IPv4 to ::ffff:x.x.x.x
  • IPv4 mode converts ::ffff:x.x.x.x back to IPv4; drops other IPv6 with one warning
  • Binary format v2.0 with family-aware header; cross-family loading rejected
  • All set operations work for IPv6: merge, common, diff, exclude, compare, reduce
  • --has-ipv6 feature flag for script detection
  • IPv6 address type: __uint128_t with parallel ipset6 container and operation modules
  • IPv6 DNS resolves both AAAA and A records (A normalized to mapped IPv6)

Code organization

  • DNS thread pools extracted into ipset_dns.c/h (IPv4) and ipset6_dns.c/h (IPv6)
  • Load files (ipset_load.c, ipset6_load.c) are now pure text parsers

Bug fixes

  • Fix UINT32_MAX boundary wrap in ipset_added_entry() and ipset_optimize() where broadcast + 1 overflows to 0, incorrectly merging ranges at opposite ends of the address space

Build

  • Enable -O3 and LTO for GCC builds

Documentation

  • Comprehensive README rewrite with all input/output formats, operations, and examples
  • Wiki pages moved into wiki/ directory in the repo (synced to GitHub wiki via Action)
  • One wiki page per operation with verified examples (every output was run through iprange)
  • Reference pages: input formats, output formats, IPv6, DNS resolution, ipset optimization

Test plan

  • All 71 existing IPv4 CLI tests pass
  • 22 new IPv6 tests (merge, CIDR decomposition, set operations, mapped normalization, binary roundtrip, count/compare, single-IP cap, default mode, mixed-family rejection, boundary addresses, adjacency wrap, invalid prefix, min-prefix/prefixes)
  • 7 build tests pass
  • VPATH (out-of-tree) build works
  • Sanitizer tests (ASAN, UBSAN)
  • Performance comparison: IPv4 before/after

ktsaou added 9 commits April 3, 2026 17:33
Add 6 new test cases covering previously weak IPv4 areas:
- numeric forms (integer, octal, two-part, three-part via inet_aton)
- boundary addresses (0.0.0.0, 255.255.255.255)
- adjacency merge at IPv4 boundaries
- default-mode IPv4 contract (no family flag)
- numeric forms in ranges and CIDRs
- max-edge wrap safety (overflow-safe operations near 255.255.255.255)

Total test count: 71 → 77
IPv6 support using __uint128_t for 128-bit address representation.
One active family per invocation; normalization at input boundary.

Family contract:
- Default (no flag): IPv4 mode for backward compatibility
- --ipv4 / -4: explicit IPv4 mode
- --ipv6 / -6: IPv6 mode, accepts both IPv6 and IPv4 input
  (IPv4 normalized to ::ffff:x.x.x.x mapped addresses)

Implementation:
- iprange6.h: IPv6 types, helpers (netmask6, broadcast6, etc.)
- ipset6.*: IPv6 container with all set operations
  (optimize, merge, common, exclude, diff, combine, copy)
- ipset6_load.c: IPv6 parser with mixed-family detection,
  DNS resolution for both AAAA and A records
- ipset6_print.c: IPv6 CIDR decomposition (0..128 prefixes),
  range/single-IP output, 128-bit decimal formatting
- ipset6_binary.c: Binary format v2 with family header,
  keeps v1 reading for IPv4
- iprange6_main.c: Complete IPv6 mode execution path
- iprange.c: CLI flags, family routing, --has-ipv6 detection

All modes supported in IPv6: merge, common, exclude, diff,
compare, compare-first, compare-next, count-unique,
count-unique-all, print-binary, print-ranges, print-single-ips.

Tests: 88 total (77 IPv4 + 11 IPv6), all passing.
Critical fixes:
- ipset6_added_entry adjacency check now guards against IPV6_ADDR_MAX
  overflow (previously "ffff:...:ffff" + "::" merged to "::/0")
- str2netaddr6 prefix parsing uses strtol instead of atoi (previously
  "/abc" silently became /0, expanding input to entire IPv6 space)
- IPv4 mode now converts ::ffff:x.x.x.x mapped addresses back to IPv4
- IPv6 lines in IPv4 mode are dropped gracefully with one-warning
  summary instead of hard failure (ipv6_dropped_in_ipv4_mode)
- IPv4 loader detects v2 binary header and produces clear error
- CMakeLists.txt updated with all 16 new IPv6 source files

High fixes:
- configure.ac checks for __uint128_t availability (fails with
  clear message on platforms that lack it)

Medium fixes:
- unique_ips saturates at IPV6_ADDR_MAX instead of wrapping to 0
  for full address space ranges
- --min-prefix and --prefixes now work in IPv6 mode (1..128 range)
- --default-prefix skipped in IPv6 mode (always uses /128)
- --has-ipv6 added to --help output
- MODE_ defines moved to iprange.h (shared, no duplication)
- Overflow guards added to ipset6_exclude and ipset6_diff for
  hi+1 at IPV6_ADDR_MAX boundary
- unsigned long -> size_t in set operation index variables
- UTF-8 BOM stripped from first line in IPv6 loader
- unique_ips < entries check added to binary v2 loader

Low fixes:
- Dead ipset6_chain_append removed from iprange.c
- NULL check added to ipset6_free
- Debug logging added to ipset6_added_entry

Tests: 93 total (77 IPv4 + 16 IPv6), all passing.
5 new regression tests for the critical bugs found.
…3/LTO

- Extract IPv4 DNS thread pool from ipset_load.c into ipset_dns.c/h
- Extract IPv6 DNS thread pool from ipset6_load.c into ipset6_dns.c/h
- ipset_load.c and ipset6_load.c are now pure text parsers
- Fix UINT32_MAX boundary wrap in ipset_added_entry() and ipset_optimize()
  where broadcast + 1 overflows to 0, incorrectly merging ranges at
  opposite ends of the address space
- Enable -O3 and LTO for GCC builds in configure.ac
Complete rewrite covering all input formats, operations, output modes,
address family behavior, DNS resolution, prefix control, and feature
detection flags. Organized with tables for quick scanning. Includes
practical examples for firewall optimization, blocklist management,
and IPv6 workflows.
Move documentation from the wiki into the repository so it is versioned
with the code. The wiki now redirects here.

- docs/input-formats.md — every accepted format, file lists, directories, binary
- docs/output-formats.md — CIDR, ranges, single IPs, binary, CSV, prefix/suffix
- docs/operations.md — merge, intersect, exclude, diff, reduce, compare, count
- docs/ipv6.md — address family, normalization, cross-family rules
- docs/dns-resolution.md — threading, retry, configuration
- docs/ipset-reduce.md — prefix reduction tutorial with examples
- README.md updated with documentation section linking to docs/
- Rename docs/ to wiki/ — source of truth for wiki content
- Add wiki/Home.md as the wiki landing page with navigation
- Add .github/workflows/sync-wiki.yml to auto-publish wiki/
  to the GitHub wiki on push to master
- Update README.md links to wiki/ directory

The wiki at github.com/firehol/iprange/wiki is now a mirror of
the wiki/ directory in this repo. Edit wiki/ in the repo, and
the GitHub Action syncs it to the wiki on merge to master.
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.
- Add missing ipset_dns.c/h and ipset6_dns.c/h
- Link pthreads properly via Threads::Threads
- Generate config.h from cmake/config.h.in template
- Check for __uint128_t at configure time
- Enable COMPARE_WITH_COMMON and compiler warnings
- Fix target name to 'iprange' (was 'iprange_git')
@ktsaou ktsaou merged commit 53a838d into master Apr 4, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant