diff --git a/.golangci.yml b/.golangci.yml index 3ee3205..33598d6 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -75,7 +75,6 @@ linters: - mnd - exportloopref - contextcheck - - intrange # not supported by yaegi issues: exclude-use-default: false max-same-issues: 0 diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index 83f8743..b33b5cb 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -11,7 +11,7 @@ import ( ttl_map "github.com/leprosus/golang-ttl-map" simpleredis "github.com/maxlerebourg/simpleredis" - ip "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/ip" + "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/ip" ) const ( diff --git a/pkg/ip/cidr.go b/pkg/ip/cidr.go index 49a0129..c30e189 100644 --- a/pkg/ip/cidr.go +++ b/pkg/ip/cidr.go @@ -2,38 +2,18 @@ package ip import ( "net" - "strconv" "strings" ) // CIDRKeys returns all possible CIDR prefixes of an IP, from the most specific (/32 for IPv4, /128 for IPv6) to the least specific (/0). func CIDRKeys(ipStr string) []string { - ip := net.ParseIP(ipStr) - if ip == nil { + parsed, maxBits := parseForPrefix(ipStr) + if parsed == nil { return nil } - ip4 := ip.To4() - if ip4 != nil { - keys := make([]string, 0, 33) - for bits := 32; bits >= 0; bits-- { - mask := net.CIDRMask(bits, 32) - n := make(net.IP, 4) - for i := 0; i < 4; i++ { - n[i] = ip4[i] & mask[i] - } - keys = append(keys, n.String()+"/"+strconv.Itoa(bits)) - } - return keys - } - ip16 := ip.To16() - keys := make([]string, 0, 129) - for bits := 128; bits >= 0; bits-- { - mask := net.CIDRMask(bits, 128) - n := make(net.IP, 16) - for i := 0; i < 16; i++ { - n[i] = ip16[i] & mask[i] - } - keys = append(keys, n.String()+"/"+strconv.Itoa(bits)) + keys := make([]string, 0, maxBits+1) + for bits := maxBits; bits >= 0; bits-- { + keys = append(keys, cidrKey(parsed, bits, maxBits)) } return keys } @@ -46,3 +26,23 @@ func NormalizeCIDR(cidrStr string) string { } return ipNet.String() } + +// parseForPrefix returns the IP in the native form of its family, and that family's bit length. +func parseForPrefix(ipStr string) (net.IP, int) { + parsed := net.ParseIP(ipStr) + if parsed == nil { + return nil, 0 + } + if parsed4 := parsed.To4(); parsed4 != nil { + return parsed4, 32 + } + return parsed.To16(), 128 +} + +// cidrKey builds the key of the CIDR of bits length containing the IP. +// It formats through net.IPNet like NormalizeCIDR, so writes and lookups agree. +func cidrKey(parsed net.IP, bits, maxBits int) string { + mask := net.CIDRMask(bits, maxBits) + ipNet := net.IPNet{IP: parsed.Mask(mask), Mask: mask} + return ipNet.String() +}