feat: accept single addresses and IPv4-mapped ranges as trusted proxies

This commit is contained in:
DiheChen committed 2026-11-08 22:45:54 +08:00
1 parent 27a98e990a
commit b8e64a88af
2 files changed
+34 -4

No files matched your search

+21 -3
View File
@@ -155,15 +155,33 @@ func parseTrustedProxies(value string) ([]netip.Prefix, error) {
if item == "" {
return nil, errors.New("ALISTEN_TRUSTED_PROXIES 中有空项")
}
prefix, err := netip.ParsePrefix(item)
prefix, err := parseTrustedProxy(item)
if err != nil {
return nil, fmt.Errorf("ALISTEN_TRUSTED_PROXIES 中的 %q 不是 CIDR:%w", item, err)
return nil, fmt.Errorf("ALISTEN_TRUSTED_PROXIES 中的 %q 不是 IP 地址或 CIDR:%w", item, err)
}
prefixes = append(prefixes, prefix.Masked())
prefixes = append(prefixes, prefix)
}
return prefixes, nil
}
// 单个地址视为只含它自己的网段。clientIP 先把 IPv4 映射的 IPv6 地址还原成 IPv4 再匹配,所以 ::ffff: 开头的网段换成等价的
// IPv4 网段,否则永远匹配不上。带 zone 的地址永远匹配不上网段,按不合法处理。
func parseTrustedProxy(item string) (netip.Prefix, error) {
prefix, err := netip.ParsePrefix(item)
if err != nil {
addr, addrErr := netip.ParseAddr(item)
if addrErr != nil || addr.Zone() != "" {
return netip.Prefix{}, err
}
prefix = netip.PrefixFrom(addr, addr.BitLen())
}
prefix = prefix.Masked()
if prefix.Addr().Is4In6() {
prefix = netip.PrefixFrom(prefix.Addr().Unmap(), prefix.Bits()-96)
}
return prefix, nil
}
func canonicalPort(port string) bool {
n, err := strconv.Atoi(port)
return err == nil && n >= 1 && n <= 65535 && strconv.Itoa(n) == port
+13 -1
View File
@@ -100,7 +100,19 @@ func TestParseTrustedProxies(t *testing.T) {
if got, err := parseTrustedProxies(""); err != nil || got != nil {
t.Errorf("空值 = %v, %v,期望没有受信任的代理", got, err)
}
for _, bad := range []string{"10.42.0.1", "10.42.0.0/16,", "not-a-cidr"} {
// 单个地址只含它自己;客户端地址先还原成 IPv4 再匹配,所以 IPv4 映射的网段换成等价的 IPv4 网段。
for value, want := range map[string]string{
"10.42.0.1": "10.42.0.1/32",
"fd00::1": "fd00::1/128",
"::ffff:10.42.0.0/112": "10.42.0.0/16",
"::ffff:10.42.0.1": "10.42.0.1/32",
"::ffff:0.0.0.0/96": "0.0.0.0/0",
} {
if got, err := parseTrustedProxies(value); err != nil || !slices.Equal(got, []netip.Prefix{netip.MustParsePrefix(want)}) {
t.Errorf("parseTrustedProxies(%q) = %v, %v,期望 %s", value, got, err, want)
}
}
for _, bad := range []string{"10.42.0.0/16,", "not-a-cidr", "10.42.0.1/33", "fe80::1%eth0", "10.42.0.256"} {
if _, err := parseTrustedProxies(bad); err == nil {
t.Errorf("parseTrustedProxies(%q) 应报错", bad)
}