feat: support fake-ip-range6 in dns module

This commit is contained in:
wwqgtxx
2025-10-28 11:40:00 +08:00
parent ff62386f6b
commit c8af92a01f
13 changed files with 234 additions and 153 deletions

View File

@@ -50,6 +50,10 @@ func (c *cachefileStore) FlushFakeIP() error {
return c.cache.FlushFakeIP()
}
func newCachefileStore(cache *cachefile.CacheFile) *cachefileStore {
return &cachefileStore{cache.FakeIpStore()}
func newCachefileStore(cache *cachefile.CacheFile, prefix netip.Prefix) *cachefileStore {
if prefix.Addr().Is6() {
return &cachefileStore{cache.FakeIpStore6()}
} else {
return &cachefileStore{cache.FakeIpStore()}
}
}

View File

@@ -7,7 +7,6 @@ import (
"sync"
"github.com/metacubex/mihomo/component/profile/cachefile"
C "github.com/metacubex/mihomo/constant"
"go4.org/netipx"
)
@@ -36,8 +35,6 @@ type Pool struct {
offset netip.Addr
cycle bool
mux sync.Mutex
host []C.DomainMatcher
mode C.FilterMode
ipnet netip.Prefix
store store
}
@@ -66,24 +63,6 @@ func (p *Pool) LookBack(ip netip.Addr) (string, bool) {
return p.store.GetByIP(ip)
}
// ShouldSkipped return if domain should be skipped
func (p *Pool) ShouldSkipped(domain string) bool {
should := p.shouldSkipped(domain)
if p.mode == C.FilterWhiteList {
return !should
}
return should
}
func (p *Pool) shouldSkipped(domain string) bool {
for _, matcher := range p.host {
if matcher.MatchDomain(domain) {
return true
}
}
return false
}
// Exist returns if given ip exists in fake-ip pool
func (p *Pool) Exist(ip netip.Addr) bool {
p.mux.Lock()
@@ -166,8 +145,6 @@ func (p *Pool) restoreState() {
type Options struct {
IPNet netip.Prefix
Host []C.DomainMatcher
Mode C.FilterMode
// Size sets the maximum number of entries in memory
// and does not work if Persistence is true
@@ -197,12 +174,10 @@ func New(options Options) (*Pool, error) {
last: last,
offset: first.Prev(),
cycle: false,
host: options.Host,
mode: options.Mode,
ipnet: options.IPNet,
}
if options.Persistence {
pool.store = newCachefileStore(cachefile.Cache())
pool.store = newCachefileStore(cachefile.Cache(), options.IPNet)
} else {
pool.store = newMemoryStore(options.Size)
}

View File

@@ -8,8 +8,6 @@ import (
"time"
"github.com/metacubex/mihomo/component/profile/cachefile"
"github.com/metacubex/mihomo/component/trie"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/bbolt"
"github.com/stretchr/testify/assert"
@@ -43,7 +41,7 @@ func createCachefileStore(options Options) (*Pool, string, error) {
return nil, "", err
}
pool.store = newCachefileStore(&cachefile.CacheFile{DB: db})
pool.store = newCachefileStore(&cachefile.CacheFile{DB: db}, options.IPNet)
return pool, f.Name(), nil
}
@@ -146,47 +144,6 @@ func TestPool_CycleUsed(t *testing.T) {
}
}
func TestPool_Skip(t *testing.T) {
ipnet := netip.MustParsePrefix("192.168.0.1/29")
tree := trie.New[struct{}]()
assert.NoError(t, tree.Insert("example.com", struct{}{}))
assert.False(t, tree.IsEmpty())
pools, tempfile, err := createPools(Options{
IPNet: ipnet,
Size: 10,
Host: []C.DomainMatcher{tree.NewDomainSet()},
})
assert.Nil(t, err)
defer os.Remove(tempfile)
for _, pool := range pools {
assert.True(t, pool.ShouldSkipped("example.com"))
assert.False(t, pool.ShouldSkipped("foo.com"))
assert.False(t, pool.shouldSkipped("baz.com"))
}
}
func TestPool_SkipWhiteList(t *testing.T) {
ipnet := netip.MustParsePrefix("192.168.0.1/29")
tree := trie.New[struct{}]()
assert.NoError(t, tree.Insert("example.com", struct{}{}))
assert.False(t, tree.IsEmpty())
pools, tempfile, err := createPools(Options{
IPNet: ipnet,
Size: 10,
Host: []C.DomainMatcher{tree.NewDomainSet()},
Mode: C.FilterWhiteList,
})
assert.Nil(t, err)
defer os.Remove(tempfile)
for _, pool := range pools {
assert.False(t, pool.ShouldSkipped("example.com"))
assert.True(t, pool.ShouldSkipped("foo.com"))
assert.True(t, pool.ShouldSkipped("baz.com"))
}
}
func TestPool_MaxCacheSize(t *testing.T) {
ipnet := netip.MustParsePrefix("192.168.0.1/24")
pool, _ := New(Options{

View File

@@ -0,0 +1,28 @@
package fakeip
import (
C "github.com/metacubex/mihomo/constant"
)
type Skipper struct {
Host []C.DomainMatcher
Mode C.FilterMode
}
// ShouldSkipped return if domain should be skipped
func (p *Skipper) ShouldSkipped(domain string) bool {
should := p.shouldSkipped(domain)
if p.Mode == C.FilterWhiteList {
return !should
}
return should
}
func (p *Skipper) shouldSkipped(domain string) bool {
for _, matcher := range p.Host {
if matcher.MatchDomain(domain) {
return true
}
}
return false
}

View File

@@ -0,0 +1,35 @@
package fakeip
import (
"testing"
"github.com/metacubex/mihomo/component/trie"
C "github.com/metacubex/mihomo/constant"
"github.com/stretchr/testify/assert"
)
func TestSkipper_BlackList(t *testing.T) {
tree := trie.New[struct{}]()
assert.NoError(t, tree.Insert("example.com", struct{}{}))
assert.False(t, tree.IsEmpty())
skipper := &Skipper{
Host: []C.DomainMatcher{tree.NewDomainSet()},
}
assert.True(t, skipper.ShouldSkipped("example.com"))
assert.False(t, skipper.ShouldSkipped("foo.com"))
assert.False(t, skipper.shouldSkipped("baz.com"))
}
func TestSkipper_WhiteList(t *testing.T) {
tree := trie.New[struct{}]()
assert.NoError(t, tree.Insert("example.com", struct{}{}))
assert.False(t, tree.IsEmpty())
skipper := &Skipper{
Host: []C.DomainMatcher{tree.NewDomainSet()},
Mode: C.FilterWhiteList,
}
assert.False(t, skipper.ShouldSkipped("example.com"))
assert.True(t, skipper.ShouldSkipped("foo.com"))
assert.True(t, skipper.ShouldSkipped("baz.com"))
}

View File

@@ -19,6 +19,7 @@ var (
bucketSelected = []byte("selected")
bucketFakeip = []byte("fakeip")
bucketFakeip6 = []byte("fakeip6")
bucketETag = []byte("etag")
bucketSubscriptionInfo = []byte("subscriptioninfo")
)

View File

@@ -10,10 +10,15 @@ import (
type FakeIpStore struct {
*CacheFile
bucketName []byte
}
func (c *CacheFile) FakeIpStore() *FakeIpStore {
return &FakeIpStore{c}
return &FakeIpStore{c, bucketFakeip}
}
func (c *CacheFile) FakeIpStore6() *FakeIpStore {
return &FakeIpStore{c, bucketFakeip6}
}
func (c *FakeIpStore) GetByHost(host string) (ip netip.Addr, exist bool) {
@@ -21,7 +26,7 @@ func (c *FakeIpStore) GetByHost(host string) (ip netip.Addr, exist bool) {
return
}
c.DB.View(func(t *bbolt.Tx) error {
if bucket := t.Bucket(bucketFakeip); bucket != nil {
if bucket := t.Bucket(c.bucketName); bucket != nil {
if v := bucket.Get([]byte(host)); v != nil {
ip, exist = netip.AddrFromSlice(v)
}
@@ -36,7 +41,7 @@ func (c *FakeIpStore) PutByHost(host string, ip netip.Addr) {
return
}
err := c.DB.Batch(func(t *bbolt.Tx) error {
bucket, err := t.CreateBucketIfNotExists(bucketFakeip)
bucket, err := t.CreateBucketIfNotExists(c.bucketName)
if err != nil {
return err
}
@@ -52,7 +57,7 @@ func (c *FakeIpStore) GetByIP(ip netip.Addr) (host string, exist bool) {
return
}
c.DB.View(func(t *bbolt.Tx) error {
if bucket := t.Bucket(bucketFakeip); bucket != nil {
if bucket := t.Bucket(c.bucketName); bucket != nil {
if v := bucket.Get(ip.AsSlice()); v != nil {
host, exist = string(v), true
}
@@ -67,7 +72,7 @@ func (c *FakeIpStore) PutByIP(ip netip.Addr, host string) {
return
}
err := c.DB.Batch(func(t *bbolt.Tx) error {
bucket, err := t.CreateBucketIfNotExists(bucketFakeip)
bucket, err := t.CreateBucketIfNotExists(c.bucketName)
if err != nil {
return err
}
@@ -85,7 +90,7 @@ func (c *FakeIpStore) DelByIP(ip netip.Addr) {
addr := ip.AsSlice()
err := c.DB.Batch(func(t *bbolt.Tx) error {
bucket, err := t.CreateBucketIfNotExists(bucketFakeip)
bucket, err := t.CreateBucketIfNotExists(c.bucketName)
if err != nil {
return err
}
@@ -105,11 +110,11 @@ func (c *FakeIpStore) DelByIP(ip netip.Addr) {
func (c *FakeIpStore) FlushFakeIP() error {
err := c.DB.Batch(func(t *bbolt.Tx) error {
bucket := t.Bucket(bucketFakeip)
bucket := t.Bucket(c.bucketName)
if bucket == nil {
return nil
}
return t.DeleteBucket(bucketFakeip)
return t.DeleteBucket(c.bucketName)
})
return err
}