github.com/v2fly/v2ray-core/v4@v4.45.2/app/router/condition_geoip_test.go (about)

     1  package router_test
     2  
     3  import (
     4  	"errors"
     5  	"io/fs"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  	"testing"
    10  
    11  	"google.golang.org/protobuf/proto"
    12  
    13  	"github.com/v2fly/v2ray-core/v4/app/router"
    14  	"github.com/v2fly/v2ray-core/v4/common"
    15  	"github.com/v2fly/v2ray-core/v4/common/net"
    16  	"github.com/v2fly/v2ray-core/v4/common/platform/filesystem"
    17  )
    18  
    19  func init() {
    20  	const geoipURL = "https://raw.githubusercontent.com/v2fly/geoip/release/geoip.dat"
    21  
    22  	wd, err := os.Getwd()
    23  	common.Must(err)
    24  
    25  	tempPath := filepath.Join(wd, "..", "..", "testing", "temp")
    26  	geoipPath := filepath.Join(tempPath, "geoip.dat")
    27  
    28  	os.Setenv("v2ray.location.asset", tempPath)
    29  
    30  	if _, err := os.Stat(geoipPath); err != nil && errors.Is(err, fs.ErrNotExist) {
    31  		common.Must(os.MkdirAll(tempPath, 0o755))
    32  		geoipBytes, err := common.FetchHTTPContent(geoipURL)
    33  		common.Must(err)
    34  		common.Must(filesystem.WriteFile(geoipPath, geoipBytes))
    35  	}
    36  }
    37  
    38  func TestGeoIPMatcherContainer(t *testing.T) {
    39  	container := &router.GeoIPMatcherContainer{}
    40  
    41  	m1, err := container.Add(&router.GeoIP{
    42  		CountryCode: "CN",
    43  	})
    44  	common.Must(err)
    45  
    46  	m2, err := container.Add(&router.GeoIP{
    47  		CountryCode: "US",
    48  	})
    49  	common.Must(err)
    50  
    51  	m3, err := container.Add(&router.GeoIP{
    52  		CountryCode: "CN",
    53  	})
    54  	common.Must(err)
    55  
    56  	if m1 != m3 {
    57  		t.Error("expect same matcher for same geoip, but not")
    58  	}
    59  
    60  	if m1 == m2 {
    61  		t.Error("expect different matcher for different geoip, but actually same")
    62  	}
    63  }
    64  
    65  func TestGeoIPMatcher(t *testing.T) {
    66  	cidrList := []*router.CIDR{
    67  		{Ip: []byte{0, 0, 0, 0}, Prefix: 8},
    68  		{Ip: []byte{10, 0, 0, 0}, Prefix: 8},
    69  		{Ip: []byte{100, 64, 0, 0}, Prefix: 10},
    70  		{Ip: []byte{127, 0, 0, 0}, Prefix: 8},
    71  		{Ip: []byte{169, 254, 0, 0}, Prefix: 16},
    72  		{Ip: []byte{172, 16, 0, 0}, Prefix: 12},
    73  		{Ip: []byte{192, 0, 0, 0}, Prefix: 24},
    74  		{Ip: []byte{192, 0, 2, 0}, Prefix: 24},
    75  		{Ip: []byte{192, 168, 0, 0}, Prefix: 16},
    76  		{Ip: []byte{192, 18, 0, 0}, Prefix: 15},
    77  		{Ip: []byte{198, 51, 100, 0}, Prefix: 24},
    78  		{Ip: []byte{203, 0, 113, 0}, Prefix: 24},
    79  		{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
    80  		{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
    81  	}
    82  
    83  	matcher := &router.GeoIPMatcher{}
    84  	common.Must(matcher.Init(cidrList))
    85  
    86  	testCases := []struct {
    87  		Input  string
    88  		Output bool
    89  	}{
    90  		{
    91  			Input:  "192.168.1.1",
    92  			Output: true,
    93  		},
    94  		{
    95  			Input:  "192.0.0.0",
    96  			Output: true,
    97  		},
    98  		{
    99  			Input:  "192.0.1.0",
   100  			Output: false,
   101  		},
   102  		{
   103  			Input:  "0.1.0.0",
   104  			Output: true,
   105  		},
   106  		{
   107  			Input:  "1.0.0.1",
   108  			Output: false,
   109  		},
   110  		{
   111  			Input:  "8.8.8.7",
   112  			Output: false,
   113  		},
   114  		{
   115  			Input:  "8.8.8.8",
   116  			Output: true,
   117  		},
   118  		{
   119  			Input:  "2001:cdba::3257:9652",
   120  			Output: false,
   121  		},
   122  		{
   123  			Input:  "91.108.255.254",
   124  			Output: true,
   125  		},
   126  	}
   127  
   128  	for _, testCase := range testCases {
   129  		ip := net.ParseAddress(testCase.Input).IP()
   130  		actual := matcher.Match(ip)
   131  		if actual != testCase.Output {
   132  			t.Error("expect input", testCase.Input, "to be", testCase.Output, ", but actually", actual)
   133  		}
   134  	}
   135  }
   136  
   137  func TestGeoIPReverseMatcher(t *testing.T) {
   138  	cidrList := []*router.CIDR{
   139  		{Ip: []byte{8, 8, 8, 8}, Prefix: 32},
   140  		{Ip: []byte{91, 108, 4, 0}, Prefix: 16},
   141  	}
   142  	matcher := &router.GeoIPMatcher{}
   143  	matcher.SetReverseMatch(true) // Reverse match
   144  	common.Must(matcher.Init(cidrList))
   145  
   146  	testCases := []struct {
   147  		Input  string
   148  		Output bool
   149  	}{
   150  		{
   151  			Input:  "8.8.8.8",
   152  			Output: false,
   153  		},
   154  		{
   155  			Input:  "2001:cdba::3257:9652",
   156  			Output: true,
   157  		},
   158  		{
   159  			Input:  "91.108.255.254",
   160  			Output: false,
   161  		},
   162  	}
   163  
   164  	for _, testCase := range testCases {
   165  		ip := net.ParseAddress(testCase.Input).IP()
   166  		actual := matcher.Match(ip)
   167  		if actual != testCase.Output {
   168  			t.Error("expect input", testCase.Input, "to be", testCase.Output, ", but actually", actual)
   169  		}
   170  	}
   171  }
   172  
   173  func TestGeoIPMatcher4CN(t *testing.T) {
   174  	ips, err := loadGeoIP("CN")
   175  	common.Must(err)
   176  
   177  	matcher := &router.GeoIPMatcher{}
   178  	common.Must(matcher.Init(ips))
   179  
   180  	if matcher.Match([]byte{8, 8, 8, 8}) {
   181  		t.Error("expect CN geoip doesn't contain 8.8.8.8, but actually does")
   182  	}
   183  }
   184  
   185  func TestGeoIPMatcher6US(t *testing.T) {
   186  	ips, err := loadGeoIP("US")
   187  	common.Must(err)
   188  
   189  	matcher := &router.GeoIPMatcher{}
   190  	common.Must(matcher.Init(ips))
   191  
   192  	if !matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP()) {
   193  		t.Error("expect US geoip contain 2001:4860:4860::8888, but actually not")
   194  	}
   195  }
   196  
   197  func loadGeoIP(country string) ([]*router.CIDR, error) {
   198  	geoipBytes, err := filesystem.ReadAsset("geoip.dat")
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  	var geoipList router.GeoIPList
   203  	if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {
   204  		return nil, err
   205  	}
   206  
   207  	for _, geoip := range geoipList.Entry {
   208  		if strings.EqualFold(geoip.CountryCode, country) {
   209  			return geoip.Cidr, nil
   210  		}
   211  	}
   212  
   213  	panic("country not found: " + country)
   214  }
   215  
   216  func BenchmarkGeoIPMatcher4CN(b *testing.B) {
   217  	ips, err := loadGeoIP("CN")
   218  	common.Must(err)
   219  
   220  	matcher := &router.GeoIPMatcher{}
   221  	common.Must(matcher.Init(ips))
   222  
   223  	b.ResetTimer()
   224  
   225  	for i := 0; i < b.N; i++ {
   226  		_ = matcher.Match([]byte{8, 8, 8, 8})
   227  	}
   228  }
   229  
   230  func BenchmarkGeoIPMatcher6US(b *testing.B) {
   231  	ips, err := loadGeoIP("US")
   232  	common.Must(err)
   233  
   234  	matcher := &router.GeoIPMatcher{}
   235  	common.Must(matcher.Init(ips))
   236  
   237  	b.ResetTimer()
   238  
   239  	for i := 0; i < b.N; i++ {
   240  		_ = matcher.Match(net.ParseAddress("2001:4860:4860::8888").IP())
   241  	}
   242  }