github.com/xmplusdev/xmcore@v1.8.11-0.20240412132628-5518b55526af/app/router/condition_geoip_test.go (about)

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