Skip to content

deps: remove iplib in favor of net/netip#2466

Open
kotakanbe wants to merge 5 commits intomasterfrom
diet-iplib
Open

deps: remove iplib in favor of net/netip#2466
kotakanbe wants to merge 5 commits intomasterfrom
diet-iplib

Conversation

@kotakanbe
Copy link
Copy Markdown
Member

Why (motivation for removing this dependency)

  • c-robinson/iplib is a library for IP address/CIDR manipulation
  • Only used in a single function enumerateHosts() in config/tomlloader.go to expand CIDR notation into individual IP addresses
  • Go's stdlib net/netip (added in Go 1.18) provides equivalent functionality with netip.ParsePrefix and Addr.Next()
  • iplib is a direct-only dependency — removing it eliminates it completely from go.mod and go.sum

What (replacement details)

  • Rewrote enumerateHosts() using net/netip.ParsePrefix + Addr.Next() iteration
  • Preserved IPv4 network/broadcast address stripping for prefix lengths < /31
  • Added TestEnumerateHosts unit test covering IPv4 (/30, /31, /32), IPv6 (/126, /127, /128), overflow (/32 IPv6), and non-CIDR inputs

Changed files

File Change
config/tomlloader.go Rewrote enumerateHosts() from iplib to net/netip (~30 lines), removed iplib import
config/tomlloader_test.go Added TestEnumerateHosts with 9 test cases
go.mod / go.sum Removed c-robinson/iplib

Safety (why this is safe)

  • Risk level: medium (IP math, but well-scoped to 1 function)
  • Behavioral parity verified by existing TestHosts (11 test cases covering IPv4/IPv6 CIDR ranges, ignore lists, edge cases)
  • New TestEnumerateHosts directly tests the rewritten function
  • IPv4 network/broadcast stripping matches iplib behavior: strip for prefix < /31, include all for /31-/32 (RFC 3021)

Test plan

  • TestHosts — existing 11 test cases pass (behavioral parity)
  • TestEnumerateHosts — new 9 test cases pass (direct function coverage)
  • go build ./cmd/... — pass
  • go test ./... — all pass
  • GOEXPERIMENT=jsonv2 golangci-lint run ./... — 0 issues

Review hint (how to review efficiently)

  1. config/tomlloader.go — the core change, ~30 lines. Key logic: netip.ParsePrefix → iterate with Addr.Next() → strip network/broadcast for IPv4 < /31
  2. config/tomlloader_test.go — new test function, straightforward table-driven tests
  3. go.mod — confirm iplib is removed entirely

🤖 Generated with Claude Code

kotakanbe and others added 4 commits March 17, 2026 10:32
Replace iplib CIDR enumeration with net/netip in enumerateHosts().
IPv4 network/broadcast stripping behavior preserved for prefix < /31.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the github.com/c-robinson/iplib dependency by rewriting config.enumerateHosts() to use Go’s standard library net/netip for CIDR expansion, and adds targeted unit tests to validate parity across IPv4/IPv6 cases.

Changes:

  • Replaced enumerateHosts() implementation from iplib to netip.ParsePrefix + Addr.Next() iteration.
  • Added TestEnumerateHosts table test covering IPv4, IPv6, and error cases.
  • Removed github.com/c-robinson/iplib from go.mod and go.sum.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
config/tomlloader.go Reimplements CIDR host expansion using net/netip and preserves IPv4 network/broadcast stripping behavior.
config/tomlloader_test.go Adds direct unit coverage for enumerateHosts() behavior across IPv4/IPv6 and invalid inputs.
go.mod Drops direct dependency on github.com/c-robinson/iplib.
go.sum Removes checksums for github.com/c-robinson/iplib.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +206 to +208
count := uint64(1) << hostBits
addrs := make([]string, 0, count)
addr := prefix.Masked().Addr()
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

count is a uint64, but make([]string, 0, count) requires an int capacity/length (per Go spec). As written this won’t compile (or will require an implicit conversion that Go doesn’t do). Convert count to int after checking it fits in math.MaxInt (and adjust the loop accordingly).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c35f046. Changed count from uint64 to int so make([]string, 0, count) receives the correct type directly. Additionally, the hard upper bound was tightened from 2^63 to 2^16 host bits, which guarantees count always fits comfortably in an int on any platform.

Comment on lines +201 to +212
hostBits := prefix.Addr().BitLen() - prefix.Bits()
if hostBits > 63 {
return nil, xerrors.Errorf("Failed to enumerate IP address. err: mask bitsize too big")
}

count := uint64(1) << hostBits
addrs := make([]string, 0, count)
addr := prefix.Masked().Addr()
for range count {
addrs = append(addrs, addr.String())
addr = addr.Next()
}
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This enumerates 1<<hostBits addresses and also preallocates the slice to that size. For inputs like IPv4 /0 (hostBits=32) or IPv6 /65 (hostBits=63), this will attempt to allocate/enumerate billions to quintillions of entries and will reliably OOM/hang. Consider adding a hard upper bound on the number of hosts that can be expanded (or at least reject prefixes where count exceeds a reasonable limit / math.MaxInt) to avoid config-triggered resource exhaustion.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c35f046. Tightened the upper bound from 2^63 to 2^16 host bits (maxHostBits = 16), so the maximum enumerable range is now a /16 for IPv4 (65,536 addresses) or /112 for IPv6. Wider prefixes like /0 or /8 now return an error immediately instead of attempting a huge allocation. Added test cases for 10.0.0.0/0 and 192.168.0.0/8 to verify.

- Change count from uint64 to int to avoid implicit conversion in make()
- Lower the hard upper bound from 2^63 to 2^16 host bits to prevent OOM
  on wide prefixes like IPv4 /0 or /8
- Add test cases for oversized IPv4 prefixes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 4 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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.

2 participants