mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-08 14:13:22 +00:00
https://github.com/XTLS/Xray-core/issues/4422#issuecomment-3533007890 Breaking changes https://github.com/XTLS/Xray-core/pull/5569 Reverts https://github.com/XTLS/Xray-core/pull/5505 Closes https://github.com/XTLS/Xray-core/pull/643
326 lines
6.1 KiB
Go
326 lines
6.1 KiB
Go
package geodata
|
|
|
|
import (
|
|
"net"
|
|
"path/filepath"
|
|
"reflect"
|
|
"slices"
|
|
"testing"
|
|
|
|
"github.com/xtls/xray-core/common"
|
|
xnet "github.com/xtls/xray-core/common/net"
|
|
)
|
|
|
|
func buildIPMatcher(rawRules ...string) IPMatcher {
|
|
rules, err := ParseIPRules(rawRules)
|
|
common.Must(err)
|
|
|
|
matcher, err := newIPRegistry().BuildIPMatcher(rules)
|
|
common.Must(err)
|
|
|
|
return matcher
|
|
}
|
|
|
|
func sortIPStrings(ips []net.IP) []string {
|
|
output := make([]string, 0, len(ips))
|
|
for _, ip := range ips {
|
|
output = append(output, ip.String())
|
|
}
|
|
slices.Sort(output)
|
|
return output
|
|
}
|
|
|
|
func TestIPMatcher(t *testing.T) {
|
|
matcher := buildIPMatcher(
|
|
"0.0.0.0/8",
|
|
"10.0.0.0/8",
|
|
"100.64.0.0/10",
|
|
"127.0.0.0/8",
|
|
"169.254.0.0/16",
|
|
"172.16.0.0/12",
|
|
"192.0.0.0/24",
|
|
"192.0.2.0/24",
|
|
"192.168.0.0/16",
|
|
"192.18.0.0/15",
|
|
"198.51.100.0/24",
|
|
"203.0.113.0/24",
|
|
"8.8.8.8/32",
|
|
"91.108.4.0/16",
|
|
)
|
|
|
|
testCases := []struct {
|
|
Input string
|
|
Output bool
|
|
}{
|
|
{
|
|
Input: "192.168.1.1",
|
|
Output: true,
|
|
},
|
|
{
|
|
Input: "192.0.0.0",
|
|
Output: true,
|
|
},
|
|
{
|
|
Input: "192.0.1.0",
|
|
Output: false,
|
|
},
|
|
{
|
|
Input: "0.1.0.0",
|
|
Output: true,
|
|
},
|
|
{
|
|
Input: "1.0.0.1",
|
|
Output: false,
|
|
},
|
|
{
|
|
Input: "8.8.8.7",
|
|
Output: false,
|
|
},
|
|
{
|
|
Input: "8.8.8.8",
|
|
Output: true,
|
|
},
|
|
{
|
|
Input: "2001:cdba::3257:9652",
|
|
Output: false,
|
|
},
|
|
{
|
|
Input: "91.108.255.254",
|
|
Output: true,
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
if v := matcher.Match(xnet.ParseAddress(test.Input).IP()); v != test.Output {
|
|
t.Error("unexpected output: ", v, " for test case ", test)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIPMatcherRegression(t *testing.T) {
|
|
matcher := buildIPMatcher(
|
|
"98.108.20.0/22",
|
|
"98.108.20.0/23",
|
|
)
|
|
|
|
testCases := []struct {
|
|
Input string
|
|
Output bool
|
|
}{
|
|
{
|
|
Input: "98.108.22.11",
|
|
Output: true,
|
|
},
|
|
{
|
|
Input: "98.108.25.0",
|
|
Output: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
if v := matcher.Match(xnet.ParseAddress(test.Input).IP()); v != test.Output {
|
|
t.Error("unexpected output: ", v, " for test case ", test)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIPReverseMatcher(t *testing.T) {
|
|
matcher := buildIPMatcher(
|
|
"8.8.8.8/32",
|
|
"91.108.4.0/16",
|
|
)
|
|
matcher.SetReverse(true)
|
|
|
|
testCases := []struct {
|
|
Input string
|
|
Output bool
|
|
}{
|
|
{
|
|
Input: "8.8.8.8",
|
|
Output: false,
|
|
},
|
|
{
|
|
Input: "2001:cdba::3257:9652",
|
|
Output: false,
|
|
},
|
|
{
|
|
Input: "91.108.255.254",
|
|
Output: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
if v := matcher.Match(xnet.ParseAddress(test.Input).IP()); v != test.Output {
|
|
t.Error("unexpected output: ", v, " for test case ", test)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIPReverseMatcher2(t *testing.T) {
|
|
matcher := buildIPMatcher(
|
|
"8.8.8.8/32",
|
|
"91.108.4.0/16",
|
|
"fe80::", // Keep IPv6 family non-empty so reverse matching can evaluate IPv6 input.
|
|
)
|
|
matcher.SetReverse(true)
|
|
|
|
testCases := []struct {
|
|
Input string
|
|
Output bool
|
|
}{
|
|
{
|
|
Input: "8.8.8.8",
|
|
Output: false,
|
|
},
|
|
{
|
|
Input: "2001:cdba::3257:9652",
|
|
Output: true,
|
|
},
|
|
{
|
|
Input: "91.108.255.254",
|
|
Output: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range testCases {
|
|
if v := matcher.Match(xnet.ParseAddress(test.Input).IP()); v != test.Output {
|
|
t.Error("unexpected output: ", v, " for test case ", test)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIPMatcherAnyMatchAndMatches(t *testing.T) {
|
|
matcher := buildIPMatcher(
|
|
"8.8.8.8/32",
|
|
"2001:4860:4860::8888/128",
|
|
)
|
|
ip := func(raw string) net.IP {
|
|
return xnet.ParseAddress(raw).IP()
|
|
}
|
|
|
|
if matcher.AnyMatch(nil) {
|
|
t.Fatal("expect AnyMatch(nil) to be false")
|
|
}
|
|
|
|
if !matcher.AnyMatch([]net.IP{
|
|
net.IP{},
|
|
ip("1.1.1.1"),
|
|
ip("8.8.8.8"),
|
|
}) {
|
|
t.Fatal("expect AnyMatch to ignore invalid IPs and return true when one valid IP matches")
|
|
}
|
|
|
|
if matcher.AnyMatch([]net.IP{
|
|
ip("1.1.1.1"),
|
|
ip("2001:db8::1"),
|
|
}) {
|
|
t.Fatal("expect AnyMatch to be false when no valid IP matches")
|
|
}
|
|
|
|
if !matcher.Matches([]net.IP{
|
|
ip("8.8.8.8"),
|
|
ip("2001:4860:4860::8888"),
|
|
}) {
|
|
t.Fatal("expect Matches to be true when all valid IPs match")
|
|
}
|
|
|
|
if matcher.Matches([]net.IP{
|
|
ip("8.8.8.8"),
|
|
ip("1.1.1.1"),
|
|
}) {
|
|
t.Fatal("expect Matches to be false when one valid IP does not match")
|
|
}
|
|
|
|
if matcher.Matches([]net.IP{
|
|
ip("8.8.8.8"),
|
|
net.IP{},
|
|
}) {
|
|
t.Fatal("expect Matches to be false when any IP is invalid")
|
|
}
|
|
}
|
|
|
|
func TestIPMatcherFilterIPs(t *testing.T) {
|
|
matcher := buildIPMatcher(
|
|
"8.8.8.8/32",
|
|
"91.108.4.0/16",
|
|
"2001:4860:4860::8888/128",
|
|
)
|
|
ip := func(raw string) net.IP {
|
|
return xnet.ParseAddress(raw).IP()
|
|
}
|
|
|
|
matched, unmatched := matcher.FilterIPs([]net.IP{
|
|
net.IP{},
|
|
ip("8.8.8.8"),
|
|
ip("91.108.255.254"),
|
|
ip("1.1.1.1"),
|
|
ip("2001:4860:4860::8888"),
|
|
ip("2001:db8::1"),
|
|
})
|
|
|
|
wantMatched := []string{
|
|
"2001:4860:4860::8888",
|
|
"8.8.8.8",
|
|
"91.108.255.254",
|
|
}
|
|
slices.Sort(wantMatched)
|
|
if v := sortIPStrings(matched); !reflect.DeepEqual(v, wantMatched) {
|
|
t.Error("unexpected output: ", v, " want ", wantMatched)
|
|
}
|
|
|
|
wantUnmatched := []string{
|
|
"1.1.1.1",
|
|
"2001:db8::1",
|
|
}
|
|
slices.Sort(wantUnmatched)
|
|
if v := sortIPStrings(unmatched); !reflect.DeepEqual(v, wantUnmatched) {
|
|
t.Error("unexpected output: ", v, " want ", wantUnmatched)
|
|
}
|
|
}
|
|
|
|
func TestIPMatcher4CN(t *testing.T) {
|
|
t.Setenv("xray.location.asset", filepath.Join("..", "..", "resources"))
|
|
|
|
matcher := buildIPMatcher("geoip:cn")
|
|
|
|
if matcher.Match([]byte{8, 8, 8, 8}) {
|
|
t.Error("expect CN geoip doesn't contain 8.8.8.8, but actually does")
|
|
}
|
|
}
|
|
|
|
func TestIPMatcher6US(t *testing.T) {
|
|
t.Setenv("xray.location.asset", filepath.Join("..", "..", "resources"))
|
|
|
|
matcher := buildIPMatcher("geoip:us")
|
|
|
|
if !matcher.Match(xnet.ParseAddress("2001:4860:4860::8888").IP()) {
|
|
t.Error("expect US geoip contain 2001:4860:4860::8888, but actually not")
|
|
}
|
|
}
|
|
|
|
func BenchmarkIPMatcher4CN(b *testing.B) {
|
|
b.Setenv("xray.location.asset", filepath.Join("..", "..", "resources"))
|
|
|
|
matcher := buildIPMatcher("geoip:cn")
|
|
ip := net.IP{8, 8, 8, 8}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
_ = matcher.Match(ip)
|
|
}
|
|
}
|
|
|
|
func BenchmarkIPMatcher6US(b *testing.B) {
|
|
b.Setenv("xray.location.asset", filepath.Join("..", "..", "resources"))
|
|
|
|
matcher := buildIPMatcher("geoip:us")
|
|
ip := xnet.ParseAddress("2001:4860:4860::8888").IP()
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
_ = matcher.Match(ip)
|
|
}
|
|
}
|