mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-12-19 16:30:07 +08:00
feat: support fake-ip-range6 in dns module
This commit is contained in:
parent
ff62386f6b
commit
c8af92a01f
@ -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()}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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{
|
||||
|
||||
28
component/fakeip/skipper.go
Normal file
28
component/fakeip/skipper.go
Normal 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
|
||||
}
|
||||
35
component/fakeip/skipper_test.go
Normal file
35
component/fakeip/skipper_test.go
Normal 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"))
|
||||
}
|
||||
@ -19,6 +19,7 @@ var (
|
||||
|
||||
bucketSelected = []byte("selected")
|
||||
bucketFakeip = []byte("fakeip")
|
||||
bucketFakeip6 = []byte("fakeip6")
|
||||
bucketETag = []byte("etag")
|
||||
bucketSubscriptionInfo = []byte("subscriptioninfo")
|
||||
)
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -157,7 +157,11 @@ type DNS struct {
|
||||
DefaultNameserver []dns.NameServer
|
||||
CacheAlgorithm string
|
||||
CacheMaxSize int
|
||||
FakeIPRange *fakeip.Pool
|
||||
FakeIPRange netip.Prefix
|
||||
FakeIPPool *fakeip.Pool
|
||||
FakeIPRange6 netip.Prefix
|
||||
FakeIPPool6 *fakeip.Pool
|
||||
FakeIPSkipper *fakeip.Skipper
|
||||
NameServerPolicy []dns.Policy
|
||||
ProxyServerNameserver []dns.NameServer
|
||||
DirectNameServer []dns.NameServer
|
||||
@ -221,6 +225,7 @@ type RawDNS struct {
|
||||
Listen string `yaml:"listen" json:"listen"`
|
||||
EnhancedMode C.DNSMode `yaml:"enhanced-mode" json:"enhanced-mode"`
|
||||
FakeIPRange string `yaml:"fake-ip-range" json:"fake-ip-range"`
|
||||
FakeIPRange6 string `yaml:"fake-ip-range6" json:"fake-ip-range6"`
|
||||
FakeIPFilter []string `yaml:"fake-ip-filter" json:"fake-ip-filter"`
|
||||
FakeIPFilterMode C.FilterMode `yaml:"fake-ip-filter-mode" json:"fake-ip-filter-mode"`
|
||||
DefaultNameserver []string `yaml:"default-nameserver" json:"default-nameserver"`
|
||||
@ -686,7 +691,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
||||
}
|
||||
config.DNS = dnsCfg
|
||||
|
||||
err = parseTun(rawCfg.Tun, config.General)
|
||||
err = parseTun(rawCfg.Tun, dnsCfg, config.General)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1407,13 +1412,21 @@ func parseDNS(rawCfg *RawConfig, ruleProviders map[string]providerTypes.RuleProv
|
||||
}
|
||||
}
|
||||
|
||||
fakeIPRange, err := netip.ParsePrefix(cfg.FakeIPRange)
|
||||
T.SetFakeIPRange(fakeIPRange)
|
||||
if cfg.EnhancedMode == C.DNSFakeIP {
|
||||
if cfg.FakeIPRange != "" {
|
||||
dnsCfg.FakeIPRange, err = netip.ParsePrefix(cfg.FakeIPRange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.FakeIPRange6 != "" {
|
||||
dnsCfg.FakeIPRange6, err = netip.ParsePrefix(cfg.FakeIPRange6)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.EnhancedMode == C.DNSFakeIP {
|
||||
var fakeIPTrie *trie.DomainTrie[struct{}]
|
||||
if len(dnsCfg.Fallback) != 0 {
|
||||
fakeIPTrie = trie.New[struct{}]()
|
||||
@ -1431,18 +1444,39 @@ func parseDNS(rawCfg *RawConfig, ruleProviders map[string]providerTypes.RuleProv
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pool, err := fakeip.New(fakeip.Options{
|
||||
IPNet: fakeIPRange,
|
||||
Size: 1000,
|
||||
Host: host,
|
||||
Mode: cfg.FakeIPFilterMode,
|
||||
Persistence: rawCfg.Profile.StoreFakeIP,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
skipper := &fakeip.Skipper{
|
||||
Host: host,
|
||||
Mode: cfg.FakeIPFilterMode,
|
||||
}
|
||||
dnsCfg.FakeIPSkipper = skipper
|
||||
|
||||
if dnsCfg.FakeIPRange.IsValid() {
|
||||
pool, err := fakeip.New(fakeip.Options{
|
||||
IPNet: dnsCfg.FakeIPRange,
|
||||
Size: 1000,
|
||||
Persistence: rawCfg.Profile.StoreFakeIP,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dnsCfg.FakeIPPool = pool
|
||||
}
|
||||
|
||||
dnsCfg.FakeIPRange = pool
|
||||
if dnsCfg.FakeIPRange6.IsValid() {
|
||||
pool6, err := fakeip.New(fakeip.Options{
|
||||
IPNet: dnsCfg.FakeIPRange6,
|
||||
Size: 1000,
|
||||
Persistence: rawCfg.Profile.StoreFakeIP,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dnsCfg.FakeIPPool6 = pool6
|
||||
}
|
||||
|
||||
if dnsCfg.FakeIPPool == nil && dnsCfg.FakeIPPool6 == nil {
|
||||
return nil, errors.New("disallow `fake-ip-range` and `fake-ip-range6` both empty with fake-ip mode")
|
||||
}
|
||||
}
|
||||
|
||||
if len(cfg.Fallback) != 0 {
|
||||
@ -1504,9 +1538,9 @@ func parseAuthentication(rawRecords []string) []auth.AuthUser {
|
||||
return users
|
||||
}
|
||||
|
||||
func parseTun(rawTun RawTun, general *General) error {
|
||||
tunAddressPrefix := T.FakeIPRange()
|
||||
if !tunAddressPrefix.IsValid() {
|
||||
func parseTun(rawTun RawTun, dns *DNS, general *General) error {
|
||||
tunAddressPrefix := dns.FakeIPRange
|
||||
if !tunAddressPrefix.IsValid() || !tunAddressPrefix.Addr().Is4() {
|
||||
tunAddressPrefix = netip.MustParsePrefix("198.18.0.1/16")
|
||||
}
|
||||
tunAddressPrefix = netip.PrefixFrom(tunAddressPrefix.Addr(), 30)
|
||||
|
||||
@ -9,10 +9,12 @@ import (
|
||||
)
|
||||
|
||||
type ResolverEnhancer struct {
|
||||
mode C.DNSMode
|
||||
fakePool *fakeip.Pool
|
||||
mapping *lru.LruCache[netip.Addr, string]
|
||||
useHosts bool
|
||||
mode C.DNSMode
|
||||
fakeIPPool *fakeip.Pool
|
||||
fakeIPPool6 *fakeip.Pool
|
||||
fakeIPSkipper *fakeip.Skipper
|
||||
mapping *lru.LruCache[netip.Addr, string]
|
||||
useHosts bool
|
||||
}
|
||||
|
||||
func (h *ResolverEnhancer) FakeIPEnabled() bool {
|
||||
@ -28,10 +30,14 @@ func (h *ResolverEnhancer) IsExistFakeIP(ip netip.Addr) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if pool := h.fakePool; pool != nil {
|
||||
if pool := h.fakeIPPool; pool != nil {
|
||||
return pool.Exist(ip)
|
||||
}
|
||||
|
||||
if pool6 := h.fakeIPPool6; pool6 != nil {
|
||||
return pool6.Exist(ip)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@ -40,10 +46,14 @@ func (h *ResolverEnhancer) IsFakeIP(ip netip.Addr) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if pool := h.fakePool; pool != nil {
|
||||
if pool := h.fakeIPPool; pool != nil {
|
||||
return pool.IPNet().Contains(ip) && ip != pool.Gateway() && ip != pool.Broadcast()
|
||||
}
|
||||
|
||||
if pool6 := h.fakeIPPool6; pool6 != nil {
|
||||
return pool6.IPNet().Contains(ip) && ip != pool6.Gateway() && ip != pool6.Broadcast()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@ -52,20 +62,30 @@ func (h *ResolverEnhancer) IsFakeBroadcastIP(ip netip.Addr) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if pool := h.fakePool; pool != nil {
|
||||
if pool := h.fakeIPPool; pool != nil {
|
||||
return pool.Broadcast() == ip
|
||||
}
|
||||
|
||||
if pool6 := h.fakeIPPool6; pool6 != nil {
|
||||
return pool6.Broadcast() == ip
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *ResolverEnhancer) FindHostByIP(ip netip.Addr) (string, bool) {
|
||||
if pool := h.fakePool; pool != nil {
|
||||
if pool := h.fakeIPPool; pool != nil {
|
||||
if host, existed := pool.LookBack(ip); existed {
|
||||
return host, true
|
||||
}
|
||||
}
|
||||
|
||||
if pool6 := h.fakeIPPool6; pool6 != nil {
|
||||
if host, existed := pool6.LookBack(ip); existed {
|
||||
return host, true
|
||||
}
|
||||
}
|
||||
|
||||
if mapping := h.mapping; mapping != nil {
|
||||
if host, existed := h.mapping.Get(ip); existed {
|
||||
return host, true
|
||||
@ -82,9 +102,12 @@ func (h *ResolverEnhancer) InsertHostByIP(ip netip.Addr, host string) {
|
||||
}
|
||||
|
||||
func (h *ResolverEnhancer) FlushFakeIP() error {
|
||||
if pool := h.fakePool; pool != nil {
|
||||
if pool := h.fakeIPPool; pool != nil {
|
||||
return pool.FlushFakeIP()
|
||||
}
|
||||
if pool6 := h.fakeIPPool6; pool6 != nil {
|
||||
return pool6.FlushFakeIP()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -93,36 +116,48 @@ func (h *ResolverEnhancer) PatchFrom(o *ResolverEnhancer) {
|
||||
o.mapping.CloneTo(h.mapping)
|
||||
}
|
||||
|
||||
if h.fakePool != nil && o.fakePool != nil {
|
||||
h.fakePool.CloneFrom(o.fakePool)
|
||||
if h.fakeIPPool != nil && o.fakeIPPool != nil {
|
||||
h.fakeIPPool.CloneFrom(o.fakeIPPool)
|
||||
}
|
||||
|
||||
if h.fakeIPPool6 != nil && o.fakeIPPool6 != nil {
|
||||
h.fakeIPPool6.CloneFrom(o.fakeIPPool6)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ResolverEnhancer) StoreFakePoolState() {
|
||||
if h.fakePool != nil {
|
||||
h.fakePool.StoreState()
|
||||
if h.fakeIPPool != nil {
|
||||
h.fakeIPPool.StoreState()
|
||||
}
|
||||
|
||||
if h.fakeIPPool6 != nil {
|
||||
h.fakeIPPool6.StoreState()
|
||||
}
|
||||
}
|
||||
|
||||
type EnhancerConfig struct {
|
||||
EnhancedMode C.DNSMode
|
||||
Pool *fakeip.Pool
|
||||
UseHosts bool
|
||||
IPv6 bool
|
||||
EnhancedMode C.DNSMode
|
||||
FakeIPPool *fakeip.Pool
|
||||
FakeIPPool6 *fakeip.Pool
|
||||
FakeIPSkipper *fakeip.Skipper
|
||||
UseHosts bool
|
||||
}
|
||||
|
||||
func NewEnhancer(cfg EnhancerConfig) *ResolverEnhancer {
|
||||
var fakePool *fakeip.Pool
|
||||
var mapping *lru.LruCache[netip.Addr, string]
|
||||
|
||||
if cfg.EnhancedMode != C.DNSNormal {
|
||||
fakePool = cfg.Pool
|
||||
mapping = lru.New(lru.WithSize[netip.Addr, string](4096))
|
||||
}
|
||||
|
||||
return &ResolverEnhancer{
|
||||
e := &ResolverEnhancer{
|
||||
mode: cfg.EnhancedMode,
|
||||
fakePool: fakePool,
|
||||
mapping: mapping,
|
||||
useHosts: cfg.UseHosts,
|
||||
}
|
||||
|
||||
if cfg.EnhancedMode != C.DNSNormal {
|
||||
e.fakeIPPool = cfg.FakeIPPool
|
||||
if cfg.IPv6 {
|
||||
e.fakeIPPool6 = cfg.FakeIPPool6
|
||||
}
|
||||
e.fakeIPSkipper = cfg.FakeIPSkipper
|
||||
e.mapping = lru.New(lru.WithSize[netip.Addr, string](4096))
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
@ -67,8 +67,7 @@ func withHosts(mapping *lru.LruCache[netip.Addr, string]) middleware {
|
||||
} else if q.Qtype == D.TypeAAAA {
|
||||
rr := &D.AAAA{}
|
||||
rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeAAAA, Class: D.ClassINET, Ttl: 10}
|
||||
ip := ipAddr.As16()
|
||||
rr.AAAA = ip[:]
|
||||
rr.AAAA = ipAddr.AsSlice()
|
||||
msg.Answer = append(msg.Answer, rr)
|
||||
if mapping != nil {
|
||||
mapping.SetWithExpire(ipAddr, host, time.Now().Add(time.Second*10))
|
||||
@ -147,29 +146,42 @@ func withMapping(mapping *lru.LruCache[netip.Addr, string]) middleware {
|
||||
}
|
||||
}
|
||||
|
||||
func withFakeIP(fakePool *fakeip.Pool) middleware {
|
||||
func withFakeIP(skipper *fakeip.Skipper, fakePool *fakeip.Pool, fakePool6 *fakeip.Pool) middleware {
|
||||
return func(next handler) handler {
|
||||
return func(ctx *icontext.DNSContext, r *D.Msg) (*D.Msg, error) {
|
||||
q := r.Question[0]
|
||||
|
||||
host := strings.TrimRight(q.Name, ".")
|
||||
if fakePool.ShouldSkipped(host) {
|
||||
if skipper.ShouldSkipped(host) {
|
||||
return next(ctx, r)
|
||||
}
|
||||
|
||||
var rr D.RR
|
||||
switch q.Qtype {
|
||||
case D.TypeAAAA, D.TypeSVCB, D.TypeHTTPS:
|
||||
case D.TypeA:
|
||||
if fakePool == nil {
|
||||
return handleMsgWithEmptyAnswer(r), nil
|
||||
}
|
||||
ip := fakePool.Lookup(host)
|
||||
rr = &D.A{
|
||||
Hdr: D.RR_Header{Name: q.Name, Rrtype: D.TypeA, Class: D.ClassINET, Ttl: dnsDefaultTTL},
|
||||
A: ip.AsSlice(),
|
||||
}
|
||||
case D.TypeAAAA:
|
||||
if fakePool6 == nil {
|
||||
return handleMsgWithEmptyAnswer(r), nil
|
||||
}
|
||||
ip := fakePool6.Lookup(host)
|
||||
rr = &D.AAAA{
|
||||
Hdr: D.RR_Header{Name: q.Name, Rrtype: D.TypeAAAA, Class: D.ClassINET, Ttl: dnsDefaultTTL},
|
||||
AAAA: ip.AsSlice(),
|
||||
}
|
||||
case D.TypeSVCB, D.TypeHTTPS:
|
||||
return handleMsgWithEmptyAnswer(r), nil
|
||||
}
|
||||
|
||||
if q.Qtype != D.TypeA {
|
||||
default:
|
||||
return next(ctx, r)
|
||||
}
|
||||
|
||||
rr := &D.A{}
|
||||
rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeA, Class: D.ClassINET, Ttl: dnsDefaultTTL}
|
||||
ip := fakePool.Lookup(host)
|
||||
rr.A = ip.AsSlice()
|
||||
msg := r.Copy()
|
||||
msg.Answer = []D.RR{rr}
|
||||
|
||||
@ -226,7 +238,7 @@ func newHandler(resolver *Resolver, mapper *ResolverEnhancer) handler {
|
||||
}
|
||||
|
||||
if mapper.mode == C.DNSFakeIP {
|
||||
middlewares = append(middlewares, withFakeIP(mapper.fakePool))
|
||||
middlewares = append(middlewares, withFakeIP(mapper.fakeIPSkipper, mapper.fakeIPPool, mapper.fakeIPPool6))
|
||||
}
|
||||
|
||||
if mapper.mode != C.DNSNormal {
|
||||
|
||||
@ -261,6 +261,7 @@ dns:
|
||||
enhanced-mode: fake-ip # or redir-host
|
||||
|
||||
fake-ip-range: 198.18.0.1/16 # fake-ip 池设置
|
||||
# fake-ip-range6: fdfe:dcba:9876::1/64 # fake-ip6 池设置
|
||||
|
||||
# 配置不使用 fake-ip 的域名
|
||||
fake-ip-filter:
|
||||
|
||||
@ -247,10 +247,11 @@ func updateDNS(c *config.DNS, generalIPv6 bool) {
|
||||
return
|
||||
}
|
||||
|
||||
ipv6 := c.IPv6 && generalIPv6
|
||||
r := dns.NewResolver(dns.Config{
|
||||
Main: c.NameServer,
|
||||
Fallback: c.Fallback,
|
||||
IPv6: c.IPv6 && generalIPv6,
|
||||
IPv6: ipv6,
|
||||
IPv6Timeout: c.IPv6Timeout,
|
||||
FallbackIPFilter: c.FallbackIPFilter,
|
||||
FallbackDomainFilter: c.FallbackDomainFilter,
|
||||
@ -263,9 +264,12 @@ func updateDNS(c *config.DNS, generalIPv6 bool) {
|
||||
CacheMaxSize: c.CacheMaxSize,
|
||||
})
|
||||
m := dns.NewEnhancer(dns.EnhancerConfig{
|
||||
EnhancedMode: c.EnhancedMode,
|
||||
Pool: c.FakeIPRange,
|
||||
UseHosts: c.UseHosts,
|
||||
IPv6: ipv6,
|
||||
EnhancedMode: c.EnhancedMode,
|
||||
FakeIPPool: c.FakeIPPool,
|
||||
FakeIPPool6: c.FakeIPPool6,
|
||||
FakeIPSkipper: c.FakeIPSkipper,
|
||||
UseHosts: c.UseHosts,
|
||||
})
|
||||
|
||||
// reuse cache of old host mapper
|
||||
|
||||
@ -61,8 +61,6 @@ var (
|
||||
|
||||
findProcessMode = atomic.NewInt32Enum(P.FindProcessStrict)
|
||||
|
||||
fakeIPRange netip.Prefix
|
||||
|
||||
snifferDispatcher *sniffer.Dispatcher
|
||||
sniffingEnable = false
|
||||
|
||||
@ -142,14 +140,6 @@ func Status() TunnelStatus {
|
||||
return status.Load()
|
||||
}
|
||||
|
||||
func SetFakeIPRange(p netip.Prefix) {
|
||||
fakeIPRange = p
|
||||
}
|
||||
|
||||
func FakeIPRange() netip.Prefix {
|
||||
return fakeIPRange
|
||||
}
|
||||
|
||||
func SetSniffing(b bool) {
|
||||
if snifferDispatcher.Enable() {
|
||||
configMux.Lock()
|
||||
@ -563,7 +553,7 @@ func handleTCPConn(connCtx C.ConnContext) {
|
||||
dialMetadata := metadata
|
||||
if len(metadata.Host) > 0 {
|
||||
if node, ok := resolver.DefaultHosts.Search(metadata.Host, false); ok {
|
||||
if dstIp, _ := node.RandIP(); !FakeIPRange().Contains(dstIp) {
|
||||
if dstIp, _ := node.RandIP(); !resolver.IsFakeIP(dstIp) {
|
||||
dialMetadata.DstIP = dstIp
|
||||
dialMetadata.DNSMode = C.DNSHosts
|
||||
dialMetadata = dialMetadata.Pure()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user