pool_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. package fakeip
  2. import (
  3. "fmt"
  4. "net/netip"
  5. "os"
  6. "testing"
  7. "time"
  8. "github.com/metacubex/mihomo/component/profile/cachefile"
  9. "github.com/metacubex/mihomo/component/trie"
  10. "github.com/sagernet/bbolt"
  11. "github.com/stretchr/testify/assert"
  12. )
  13. func createPools(options Options) ([]*Pool, string, error) {
  14. pool, err := New(options)
  15. if err != nil {
  16. return nil, "", err
  17. }
  18. filePool, tempfile, err := createCachefileStore(options)
  19. if err != nil {
  20. return nil, "", err
  21. }
  22. return []*Pool{pool, filePool}, tempfile, nil
  23. }
  24. func createCachefileStore(options Options) (*Pool, string, error) {
  25. pool, err := New(options)
  26. if err != nil {
  27. return nil, "", err
  28. }
  29. f, err := os.CreateTemp("", "mihomo")
  30. if err != nil {
  31. return nil, "", err
  32. }
  33. db, err := bbolt.Open(f.Name(), 0o666, &bbolt.Options{Timeout: time.Second})
  34. if err != nil {
  35. return nil, "", err
  36. }
  37. pool.store = &cachefileStore{
  38. cache: &cachefile.CacheFile{DB: db},
  39. }
  40. return pool, f.Name(), nil
  41. }
  42. func TestPool_Basic(t *testing.T) {
  43. ipnet := netip.MustParsePrefix("192.168.0.0/28")
  44. pools, tempfile, err := createPools(Options{
  45. IPNet: ipnet,
  46. Size: 10,
  47. })
  48. assert.Nil(t, err)
  49. defer os.Remove(tempfile)
  50. for _, pool := range pools {
  51. first := pool.Lookup("foo.com")
  52. last := pool.Lookup("bar.com")
  53. bar, exist := pool.LookBack(last)
  54. assert.True(t, first == netip.AddrFrom4([4]byte{192, 168, 0, 4}))
  55. assert.True(t, pool.Lookup("foo.com") == netip.AddrFrom4([4]byte{192, 168, 0, 4}))
  56. assert.True(t, last == netip.AddrFrom4([4]byte{192, 168, 0, 5}))
  57. assert.True(t, exist)
  58. assert.Equal(t, bar, "bar.com")
  59. assert.True(t, pool.Gateway() == netip.AddrFrom4([4]byte{192, 168, 0, 1}))
  60. assert.True(t, pool.Broadcast() == netip.AddrFrom4([4]byte{192, 168, 0, 15}))
  61. assert.Equal(t, pool.IPNet().String(), ipnet.String())
  62. assert.True(t, pool.Exist(netip.AddrFrom4([4]byte{192, 168, 0, 5})))
  63. assert.False(t, pool.Exist(netip.AddrFrom4([4]byte{192, 168, 0, 6})))
  64. assert.False(t, pool.Exist(netip.MustParseAddr("::1")))
  65. }
  66. }
  67. func TestPool_BasicV6(t *testing.T) {
  68. ipnet := netip.MustParsePrefix("2001:4860:4860::8888/118")
  69. pools, tempfile, err := createPools(Options{
  70. IPNet: ipnet,
  71. Size: 10,
  72. })
  73. assert.Nil(t, err)
  74. defer os.Remove(tempfile)
  75. for _, pool := range pools {
  76. first := pool.Lookup("foo.com")
  77. last := pool.Lookup("bar.com")
  78. bar, exist := pool.LookBack(last)
  79. assert.True(t, first == netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8804"))
  80. assert.True(t, pool.Lookup("foo.com") == netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8804"))
  81. assert.True(t, last == netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8805"))
  82. assert.True(t, exist)
  83. assert.Equal(t, bar, "bar.com")
  84. assert.True(t, pool.Gateway() == netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8801"))
  85. assert.True(t, pool.Broadcast() == netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8bff"))
  86. assert.Equal(t, pool.IPNet().String(), ipnet.String())
  87. assert.True(t, pool.Exist(netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8805")))
  88. assert.False(t, pool.Exist(netip.MustParseAddr("2001:4860:4860:0000:0000:0000:0000:8806")))
  89. assert.False(t, pool.Exist(netip.MustParseAddr("127.0.0.1")))
  90. }
  91. }
  92. func TestPool_Case_Insensitive(t *testing.T) {
  93. ipnet := netip.MustParsePrefix("192.168.0.1/29")
  94. pools, tempfile, err := createPools(Options{
  95. IPNet: ipnet,
  96. Size: 10,
  97. })
  98. assert.Nil(t, err)
  99. defer os.Remove(tempfile)
  100. for _, pool := range pools {
  101. first := pool.Lookup("foo.com")
  102. last := pool.Lookup("Foo.Com")
  103. foo, exist := pool.LookBack(last)
  104. assert.Equal(t, first, pool.Lookup("Foo.Com"))
  105. assert.Equal(t, pool.Lookup("fOo.cOM"), first)
  106. assert.True(t, exist)
  107. assert.Equal(t, foo, "foo.com")
  108. }
  109. }
  110. func TestPool_CycleUsed(t *testing.T) {
  111. ipnet := netip.MustParsePrefix("192.168.0.16/28")
  112. pools, tempfile, err := createPools(Options{
  113. IPNet: ipnet,
  114. Size: 10,
  115. })
  116. assert.Nil(t, err)
  117. defer os.Remove(tempfile)
  118. for _, pool := range pools {
  119. foo := pool.Lookup("foo.com")
  120. bar := pool.Lookup("bar.com")
  121. for i := 0; i < 9; i++ {
  122. pool.Lookup(fmt.Sprintf("%d.com", i))
  123. }
  124. baz := pool.Lookup("baz.com")
  125. next := pool.Lookup("foo.com")
  126. assert.True(t, foo == baz)
  127. assert.True(t, next == bar)
  128. }
  129. }
  130. func TestPool_Skip(t *testing.T) {
  131. ipnet := netip.MustParsePrefix("192.168.0.1/29")
  132. tree := trie.New[struct{}]()
  133. tree.Insert("example.com", struct{}{})
  134. pools, tempfile, err := createPools(Options{
  135. IPNet: ipnet,
  136. Size: 10,
  137. Host: tree,
  138. })
  139. assert.Nil(t, err)
  140. defer os.Remove(tempfile)
  141. for _, pool := range pools {
  142. assert.True(t, pool.ShouldSkipped("example.com"))
  143. assert.False(t, pool.ShouldSkipped("foo.com"))
  144. }
  145. }
  146. func TestPool_MaxCacheSize(t *testing.T) {
  147. ipnet := netip.MustParsePrefix("192.168.0.1/24")
  148. pool, _ := New(Options{
  149. IPNet: ipnet,
  150. Size: 2,
  151. })
  152. first := pool.Lookup("foo.com")
  153. pool.Lookup("bar.com")
  154. pool.Lookup("baz.com")
  155. next := pool.Lookup("foo.com")
  156. assert.False(t, first == next)
  157. }
  158. func TestPool_DoubleMapping(t *testing.T) {
  159. ipnet := netip.MustParsePrefix("192.168.0.1/24")
  160. pool, _ := New(Options{
  161. IPNet: ipnet,
  162. Size: 2,
  163. })
  164. // fill cache
  165. fooIP := pool.Lookup("foo.com")
  166. bazIP := pool.Lookup("baz.com")
  167. // make foo.com hot
  168. pool.Lookup("foo.com")
  169. // should drop baz.com
  170. barIP := pool.Lookup("bar.com")
  171. _, fooExist := pool.LookBack(fooIP)
  172. _, bazExist := pool.LookBack(bazIP)
  173. _, barExist := pool.LookBack(barIP)
  174. newBazIP := pool.Lookup("baz.com")
  175. assert.True(t, fooExist)
  176. assert.False(t, bazExist)
  177. assert.True(t, barExist)
  178. assert.False(t, bazIP == newBazIP)
  179. }
  180. func TestPool_Clone(t *testing.T) {
  181. ipnet := netip.MustParsePrefix("192.168.0.1/24")
  182. pool, _ := New(Options{
  183. IPNet: ipnet,
  184. Size: 2,
  185. })
  186. first := pool.Lookup("foo.com")
  187. last := pool.Lookup("bar.com")
  188. assert.True(t, first == netip.AddrFrom4([4]byte{192, 168, 0, 4}))
  189. assert.True(t, last == netip.AddrFrom4([4]byte{192, 168, 0, 5}))
  190. newPool, _ := New(Options{
  191. IPNet: ipnet,
  192. Size: 2,
  193. })
  194. newPool.CloneFrom(pool)
  195. _, firstExist := newPool.LookBack(first)
  196. _, lastExist := newPool.LookBack(last)
  197. assert.True(t, firstExist)
  198. assert.True(t, lastExist)
  199. }
  200. func TestPool_Error(t *testing.T) {
  201. ipnet := netip.MustParsePrefix("192.168.0.1/31")
  202. _, err := New(Options{
  203. IPNet: ipnet,
  204. Size: 10,
  205. })
  206. assert.Error(t, err)
  207. }
  208. func TestPool_FlushFileCache(t *testing.T) {
  209. ipnet := netip.MustParsePrefix("192.168.0.1/28")
  210. pools, tempfile, err := createPools(Options{
  211. IPNet: ipnet,
  212. Size: 10,
  213. })
  214. assert.Nil(t, err)
  215. defer os.Remove(tempfile)
  216. for _, pool := range pools {
  217. foo := pool.Lookup("foo.com")
  218. bar := pool.Lookup("baz.com")
  219. bax := pool.Lookup("baz.com")
  220. fox := pool.Lookup("foo.com")
  221. err = pool.FlushFakeIP()
  222. assert.Nil(t, err)
  223. next := pool.Lookup("baz.com")
  224. baz := pool.Lookup("foo.com")
  225. nero := pool.Lookup("foo.com")
  226. assert.True(t, foo == fox)
  227. assert.True(t, foo == next)
  228. assert.False(t, foo == baz)
  229. assert.True(t, bar == bax)
  230. assert.True(t, bar == baz)
  231. assert.False(t, bar == next)
  232. assert.True(t, baz == nero)
  233. }
  234. }
  235. func TestPool_FlushMemoryCache(t *testing.T) {
  236. ipnet := netip.MustParsePrefix("192.168.0.1/28")
  237. pool, _ := New(Options{
  238. IPNet: ipnet,
  239. Size: 10,
  240. })
  241. foo := pool.Lookup("foo.com")
  242. bar := pool.Lookup("baz.com")
  243. bax := pool.Lookup("baz.com")
  244. fox := pool.Lookup("foo.com")
  245. err := pool.FlushFakeIP()
  246. assert.Nil(t, err)
  247. next := pool.Lookup("baz.com")
  248. baz := pool.Lookup("foo.com")
  249. nero := pool.Lookup("foo.com")
  250. assert.True(t, foo == fox)
  251. assert.True(t, foo == next)
  252. assert.False(t, foo == baz)
  253. assert.True(t, bar == bax)
  254. assert.True(t, bar == baz)
  255. assert.False(t, bar == next)
  256. assert.True(t, baz == nero)
  257. }