From ac27614bb2ef2aa0ff680f5447c9d3843848dfd9 Mon Sep 17 00:00:00 2001 From: kotakanbe Date: Tue, 17 Mar 2026 10:32:24 +0900 Subject: [PATCH 1/2] deps: remove iplib 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 --- config/tomlloader.go | 36 +++++++++++++++++++----------------- config/tomlloader_test.go | 30 ++++++++++++++++++++++++++++++ go.mod | 1 - go.sum | 2 -- 4 files changed, 49 insertions(+), 20 deletions(-) diff --git a/config/tomlloader.go b/config/tomlloader.go index a2503e9a5f..53113bf663 100644 --- a/config/tomlloader.go +++ b/config/tomlloader.go @@ -4,13 +4,13 @@ import ( "fmt" "maps" "net" + "net/netip" "regexp" "runtime" "slices" "strings" "github.com/BurntSushi/toml" - "github.com/c-robinson/iplib" "github.com/knqyf263/go-cpe/naming" "golang.org/x/xerrors" @@ -193,27 +193,29 @@ func enumerateHosts(host string) ([]string, error) { return []string{host}, nil } - ipAddr, ipNet, err := net.ParseCIDR(host) + prefix, err := netip.ParsePrefix(host) if err != nil { return nil, xerrors.Errorf("Failed to parse CIDR. err: %w", err) } - maskLen, _ := ipNet.Mask.Size() - addrs := []string{} - if net.ParseIP(ipAddr.String()).To4() != nil { - n := iplib.NewNet4(ipAddr, int(maskLen)) - for _, addr := range n.Enumerate(int(n.Count()), 0) { - addrs = append(addrs, addr.String()) - } - } else if net.ParseIP(ipAddr.String()).To16() != nil { - n := iplib.NewNet6(ipAddr, int(maskLen), 0) - if !n.Count().IsInt64() { - return nil, xerrors.Errorf("Failed to enumerate IP address. err: mask bitsize too big") - } - for _, addr := range n.Enumerate(int(n.Count().Int64()), 0) { - addrs = append(addrs, addr.String()) - } + 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() + } + + // IPv4 with prefix < 31: strip network (first) and broadcast (last) addresses + if prefix.Addr().Is4() && prefix.Bits() < 31 && len(addrs) > 2 { + addrs = addrs[1 : len(addrs)-1] } + return addrs, nil } diff --git a/config/tomlloader_test.go b/config/tomlloader_test.go index 85affb428f..3be6cba84d 100644 --- a/config/tomlloader_test.go +++ b/config/tomlloader_test.go @@ -97,6 +97,36 @@ func TestHosts(t *testing.T) { } } +func TestEnumerateHosts(t *testing.T) { + t.Parallel() + tests := []struct { + in string + expected []string + err bool + }{ + {in: "192.168.1.1", expected: []string{"192.168.1.1"}}, + {in: "ssh/host", expected: []string{"ssh/host"}}, + {in: "192.168.1.0/30", expected: []string{"192.168.1.1", "192.168.1.2"}}, + {in: "192.168.1.0/31", expected: []string{"192.168.1.0", "192.168.1.1"}}, + {in: "192.168.1.1/32", expected: []string{"192.168.1.1"}}, + {in: "2001:db8::1/126", expected: []string{"2001:db8::", "2001:db8::1", "2001:db8::2", "2001:db8::3"}}, + {in: "2001:db8::1/127", expected: []string{"2001:db8::", "2001:db8::1"}}, + {in: "2001:db8::1/128", expected: []string{"2001:db8::1"}}, + {in: "2001:db8::1/32", err: true}, + } + for i, tt := range tests { + actual, err := enumerateHosts(tt.in) + if err != nil && !tt.err { + t.Errorf("[%d] unexpected error: %v", i, err) + } else if err == nil && tt.err { + t.Errorf("[%d] expected error but got none", i) + } + if !reflect.DeepEqual(actual, tt.expected) { + t.Errorf("[%d] in: %s, got: %q, want: %q", i, tt.in, actual, tt.expected) + } + } +} + func TestToCpeURI(t *testing.T) { var tests = []struct { in string diff --git a/go.mod b/go.mod index c793fa3a72..dd08463c70 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,6 @@ require ( github.com/aws/aws-sdk-go-v2/credentials v1.19.10 github.com/aws/aws-sdk-go-v2/service/s3 v1.96.2 github.com/aws/aws-sdk-go-v2/service/sts v1.41.7 - github.com/c-robinson/iplib v1.0.8 github.com/cenkalti/backoff v2.2.1+incompatible github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 diff --git a/go.sum b/go.sum index 4543b8bbec..c3f5c40a06 100644 --- a/go.sum +++ b/go.sum @@ -202,8 +202,6 @@ github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuP github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bytecodealliance/wasmtime-go/v39 v39.0.1 h1:RibaT47yiyCRxMOj/l2cvL8cWiWBSqDXHyqsa9sGcCE= github.com/bytecodealliance/wasmtime-go/v39 v39.0.1/go.mod h1:miR4NYIEBXeDNamZIzpskhJ0z/p8al+lwMWylQ/ZJb4= -github.com/c-robinson/iplib v1.0.8 h1:exDRViDyL9UBLcfmlxxkY5odWX5092nPsQIykHXhIn4= -github.com/c-robinson/iplib v1.0.8/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= From c35f046b05cfa4973596ec2e7da9b1e452d7fd3c Mon Sep 17 00:00:00 2001 From: vuls-bot Date: Tue, 24 Mar 2026 02:08:58 +0000 Subject: [PATCH 2/2] fix: address Copilot review on iplib removal - 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) --- config/tomlloader.go | 9 ++++++--- config/tomlloader_test.go | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/config/tomlloader.go b/config/tomlloader.go index 53113bf663..2605157b96 100644 --- a/config/tomlloader.go +++ b/config/tomlloader.go @@ -199,11 +199,14 @@ func enumerateHosts(host string) ([]string, error) { } hostBits := prefix.Addr().BitLen() - prefix.Bits() - if hostBits > 63 { - return nil, xerrors.Errorf("Failed to enumerate IP address. err: mask bitsize too big") + + // Cap at 2^16 = 65536 addresses (a /16 for IPv4, /112 for IPv6) to prevent OOM. + const maxHostBits = 16 + if hostBits > maxHostBits { + return nil, xerrors.Errorf("Failed to enumerate IP address: prefix /%d too large (max host bits %d)", prefix.Bits(), maxHostBits) } - count := uint64(1) << hostBits + count := int(1) << hostBits addrs := make([]string, 0, count) addr := prefix.Masked().Addr() for range count { diff --git a/config/tomlloader_test.go b/config/tomlloader_test.go index 3be6cba84d..a7e1011b36 100644 --- a/config/tomlloader_test.go +++ b/config/tomlloader_test.go @@ -113,6 +113,8 @@ func TestEnumerateHosts(t *testing.T) { {in: "2001:db8::1/127", expected: []string{"2001:db8::", "2001:db8::1"}}, {in: "2001:db8::1/128", expected: []string{"2001:db8::1"}}, {in: "2001:db8::1/32", err: true}, + {in: "10.0.0.0/0", err: true}, + {in: "192.168.0.0/8", err: true}, } for i, tt := range tests { actual, err := enumerateHosts(tt.in)