mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 09:40:12 +00:00
fix(security): block IPv6 transition ranges for webhooks
This commit is contained in:
@@ -40,9 +40,11 @@ var blockedHTTPClientCIDRs = mustParseHTTPClientCIDRs([]string{
|
|||||||
"::1/128",
|
"::1/128",
|
||||||
"::ffff:0:0/96",
|
"::ffff:0:0/96",
|
||||||
"64:ff9b::/96",
|
"64:ff9b::/96",
|
||||||
|
"64:ff9b:1::/48",
|
||||||
"100::/64",
|
"100::/64",
|
||||||
"2001::/23",
|
"2001::/23",
|
||||||
"2001:db8::/32",
|
"2001:db8::/32",
|
||||||
|
"2002::/16",
|
||||||
"fc00::/7",
|
"fc00::/7",
|
||||||
"fe80::/10",
|
"fe80::/10",
|
||||||
"ff00::/8",
|
"ff00::/8",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -8,6 +9,47 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestHTTPURLTargetIPAllowed(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
address string
|
||||||
|
allowed bool
|
||||||
|
}{
|
||||||
|
{name: "public IPv4", address: "1.1.1.1", allowed: true},
|
||||||
|
{name: "public IPv6", address: "2606:4700:4700::1111", allowed: true},
|
||||||
|
{name: "well-known NAT64", address: "64:ff9b::a9fe:a9fe", allowed: false},
|
||||||
|
{name: "local-use NAT64", address: "64:ff9b:1::a9fe:a9fe", allowed: false},
|
||||||
|
{name: "6to4 public IPv4 embedding", address: "2002:0101:0101::1", allowed: false},
|
||||||
|
{name: "6to4 link-local IPv4 embedding", address: "2002:a9fe:a9fe::1", allowed: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
ip := net.ParseIP(test.address)
|
||||||
|
if ip == nil {
|
||||||
|
t.Fatalf("ParseIP(%q) returned nil", test.address)
|
||||||
|
}
|
||||||
|
if got := HTTPURLTargetIPAllowed(ip); got != test.allowed {
|
||||||
|
t.Fatalf("HTTPURLTargetIPAllowed(%q) = %t, want %t", test.address, got, test.allowed)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveAllowedHTTPURLRejectsSpecialIPv6Literals(t *testing.T) {
|
||||||
|
for _, rawURL := range []string{
|
||||||
|
"http://[64:ff9b:1::a9fe:a9fe]/metadata",
|
||||||
|
"http://[2002:a9fe:a9fe::1]/metadata",
|
||||||
|
} {
|
||||||
|
t.Run(rawURL, func(t *testing.T) {
|
||||||
|
_, _, err := ResolveAllowedHTTPURL(rawURL)
|
||||||
|
if !errors.Is(err, ErrHTTPURLTargetNotAllowed) {
|
||||||
|
t.Fatalf("ResolveAllowedHTTPURL(%q) error = %v, want %v", rawURL, err, ErrHTTPURLTargetNotAllowed)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBuildRestrictedHTTPClientPreservesHostnameAsTLSServerName(t *testing.T) {
|
func TestBuildRestrictedHTTPClientPreservesHostnameAsTLSServerName(t *testing.T) {
|
||||||
// Construct a hostname URL paired with an arbitrary public IP so we exercise
|
// Construct a hostname URL paired with an arbitrary public IP so we exercise
|
||||||
// the SNI preservation path without depending on live DNS in unit tests.
|
// the SNI preservation path without depending on live DNS in unit tests.
|
||||||
|
|||||||
Reference in New Issue
Block a user