mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-07-14 08:58:47 +00:00
Xray-core: Refactor geodata (#5814)
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
This commit is contained in:
@@ -0,0 +1,325 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user