mirror of
https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin.git
synced 2026-09-02 20:28:50 +02:00
♻️ cidr: build keys through net.IPNet instead of hand-masking bytes
CIDRKeys masked the address byte by byte and formatted the result with string concatenation, while SetCIDR/DeleteCIDR format their keys with net.IPNet.String() via NormalizeCIDR. The two agreed only by coincidence: any divergence in formatting silently stops every range decision from matching, with no test covering the invariant. Mask with net.IP.Mask and format through net.IPNet.String() so both sides go through the same formatter. Output is byte for byte identical to the previous implementation (checked against a golden dump of both IPv4 and IPv6 keys, including ::ffff: forms). Dropping the inner byte loops also removes the only intrange violation in the tree, so the linter exclusion added for them is no longer needed, and the redundant import alias on pkg/ip goes away with it.
This commit is contained in:
@@ -75,7 +75,6 @@ linters:
|
||||
- mnd
|
||||
- exportloopref
|
||||
- contextcheck
|
||||
- intrange # not supported by yaegi
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
max-same-issues: 0
|
||||
|
||||
Vendored
+1
-1
@@ -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 (
|
||||
|
||||
+25
-25
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user