mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-12-20 00:50:06 +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()
|
return c.cache.FlushFakeIP()
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCachefileStore(cache *cachefile.CacheFile) *cachefileStore {
|
func newCachefileStore(cache *cachefile.CacheFile, prefix netip.Prefix) *cachefileStore {
|
||||||
|
if prefix.Addr().Is6() {
|
||||||
|
return &cachefileStore{cache.FakeIpStore6()}
|
||||||
|
} else {
|
||||||
return &cachefileStore{cache.FakeIpStore()}
|
return &cachefileStore{cache.FakeIpStore()}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/component/profile/cachefile"
|
"github.com/metacubex/mihomo/component/profile/cachefile"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
|
||||||
|
|
||||||
"go4.org/netipx"
|
"go4.org/netipx"
|
||||||
)
|
)
|
||||||
@ -36,8 +35,6 @@ type Pool struct {
|
|||||||
offset netip.Addr
|
offset netip.Addr
|
||||||
cycle bool
|
cycle bool
|
||||||
mux sync.Mutex
|
mux sync.Mutex
|
||||||
host []C.DomainMatcher
|
|
||||||
mode C.FilterMode
|
|
||||||
ipnet netip.Prefix
|
ipnet netip.Prefix
|
||||||
store store
|
store store
|
||||||
}
|
}
|
||||||
@ -66,24 +63,6 @@ func (p *Pool) LookBack(ip netip.Addr) (string, bool) {
|
|||||||
return p.store.GetByIP(ip)
|
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
|
// Exist returns if given ip exists in fake-ip pool
|
||||||
func (p *Pool) Exist(ip netip.Addr) bool {
|
func (p *Pool) Exist(ip netip.Addr) bool {
|
||||||
p.mux.Lock()
|
p.mux.Lock()
|
||||||
@ -166,8 +145,6 @@ func (p *Pool) restoreState() {
|
|||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
IPNet netip.Prefix
|
IPNet netip.Prefix
|
||||||
Host []C.DomainMatcher
|
|
||||||
Mode C.FilterMode
|
|
||||||
|
|
||||||
// Size sets the maximum number of entries in memory
|
// Size sets the maximum number of entries in memory
|
||||||
// and does not work if Persistence is true
|
// and does not work if Persistence is true
|
||||||
@ -197,12 +174,10 @@ func New(options Options) (*Pool, error) {
|
|||||||
last: last,
|
last: last,
|
||||||
offset: first.Prev(),
|
offset: first.Prev(),
|
||||||
cycle: false,
|
cycle: false,
|
||||||
host: options.Host,
|
|
||||||
mode: options.Mode,
|
|
||||||
ipnet: options.IPNet,
|
ipnet: options.IPNet,
|
||||||
}
|
}
|
||||||
if options.Persistence {
|
if options.Persistence {
|
||||||
pool.store = newCachefileStore(cachefile.Cache())
|
pool.store = newCachefileStore(cachefile.Cache(), options.IPNet)
|
||||||
} else {
|
} else {
|
||||||
pool.store = newMemoryStore(options.Size)
|
pool.store = newMemoryStore(options.Size)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,8 +8,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/component/profile/cachefile"
|
"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/metacubex/bbolt"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -43,7 +41,7 @@ func createCachefileStore(options Options) (*Pool, string, error) {
|
|||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.store = newCachefileStore(&cachefile.CacheFile{DB: db})
|
pool.store = newCachefileStore(&cachefile.CacheFile{DB: db}, options.IPNet)
|
||||||
return pool, f.Name(), nil
|
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) {
|
func TestPool_MaxCacheSize(t *testing.T) {
|
||||||
ipnet := netip.MustParsePrefix("192.168.0.1/24")
|
ipnet := netip.MustParsePrefix("192.168.0.1/24")
|
||||||
pool, _ := New(Options{
|
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")
|
bucketSelected = []byte("selected")
|
||||||
bucketFakeip = []byte("fakeip")
|
bucketFakeip = []byte("fakeip")
|
||||||
|
bucketFakeip6 = []byte("fakeip6")
|
||||||
bucketETag = []byte("etag")
|
bucketETag = []byte("etag")
|
||||||
bucketSubscriptionInfo = []byte("subscriptioninfo")
|
bucketSubscriptionInfo = []byte("subscriptioninfo")
|
||||||
)
|
)
|
||||||
|
|||||||
@ -10,10 +10,15 @@ import (
|
|||||||
|
|
||||||
type FakeIpStore struct {
|
type FakeIpStore struct {
|
||||||
*CacheFile
|
*CacheFile
|
||||||
|
bucketName []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CacheFile) FakeIpStore() *FakeIpStore {
|
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) {
|
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
|
return
|
||||||
}
|
}
|
||||||
c.DB.View(func(t *bbolt.Tx) error {
|
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 {
|
if v := bucket.Get([]byte(host)); v != nil {
|
||||||
ip, exist = netip.AddrFromSlice(v)
|
ip, exist = netip.AddrFromSlice(v)
|
||||||
}
|
}
|
||||||
@ -36,7 +41,7 @@ func (c *FakeIpStore) PutByHost(host string, ip netip.Addr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := c.DB.Batch(func(t *bbolt.Tx) error {
|
err := c.DB.Batch(func(t *bbolt.Tx) error {
|
||||||
bucket, err := t.CreateBucketIfNotExists(bucketFakeip)
|
bucket, err := t.CreateBucketIfNotExists(c.bucketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -52,7 +57,7 @@ func (c *FakeIpStore) GetByIP(ip netip.Addr) (host string, exist bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.DB.View(func(t *bbolt.Tx) error {
|
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 {
|
if v := bucket.Get(ip.AsSlice()); v != nil {
|
||||||
host, exist = string(v), true
|
host, exist = string(v), true
|
||||||
}
|
}
|
||||||
@ -67,7 +72,7 @@ func (c *FakeIpStore) PutByIP(ip netip.Addr, host string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := c.DB.Batch(func(t *bbolt.Tx) error {
|
err := c.DB.Batch(func(t *bbolt.Tx) error {
|
||||||
bucket, err := t.CreateBucketIfNotExists(bucketFakeip)
|
bucket, err := t.CreateBucketIfNotExists(c.bucketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -85,7 +90,7 @@ func (c *FakeIpStore) DelByIP(ip netip.Addr) {
|
|||||||
|
|
||||||
addr := ip.AsSlice()
|
addr := ip.AsSlice()
|
||||||
err := c.DB.Batch(func(t *bbolt.Tx) error {
|
err := c.DB.Batch(func(t *bbolt.Tx) error {
|
||||||
bucket, err := t.CreateBucketIfNotExists(bucketFakeip)
|
bucket, err := t.CreateBucketIfNotExists(c.bucketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -105,11 +110,11 @@ func (c *FakeIpStore) DelByIP(ip netip.Addr) {
|
|||||||
|
|
||||||
func (c *FakeIpStore) FlushFakeIP() error {
|
func (c *FakeIpStore) FlushFakeIP() error {
|
||||||
err := c.DB.Batch(func(t *bbolt.Tx) error {
|
err := c.DB.Batch(func(t *bbolt.Tx) error {
|
||||||
bucket := t.Bucket(bucketFakeip)
|
bucket := t.Bucket(c.bucketName)
|
||||||
if bucket == nil {
|
if bucket == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return t.DeleteBucket(bucketFakeip)
|
return t.DeleteBucket(c.bucketName)
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -157,7 +157,11 @@ type DNS struct {
|
|||||||
DefaultNameserver []dns.NameServer
|
DefaultNameserver []dns.NameServer
|
||||||
CacheAlgorithm string
|
CacheAlgorithm string
|
||||||
CacheMaxSize int
|
CacheMaxSize int
|
||||||
FakeIPRange *fakeip.Pool
|
FakeIPRange netip.Prefix
|
||||||
|
FakeIPPool *fakeip.Pool
|
||||||
|
FakeIPRange6 netip.Prefix
|
||||||
|
FakeIPPool6 *fakeip.Pool
|
||||||
|
FakeIPSkipper *fakeip.Skipper
|
||||||
NameServerPolicy []dns.Policy
|
NameServerPolicy []dns.Policy
|
||||||
ProxyServerNameserver []dns.NameServer
|
ProxyServerNameserver []dns.NameServer
|
||||||
DirectNameServer []dns.NameServer
|
DirectNameServer []dns.NameServer
|
||||||
@ -221,6 +225,7 @@ type RawDNS struct {
|
|||||||
Listen string `yaml:"listen" json:"listen"`
|
Listen string `yaml:"listen" json:"listen"`
|
||||||
EnhancedMode C.DNSMode `yaml:"enhanced-mode" json:"enhanced-mode"`
|
EnhancedMode C.DNSMode `yaml:"enhanced-mode" json:"enhanced-mode"`
|
||||||
FakeIPRange string `yaml:"fake-ip-range" json:"fake-ip-range"`
|
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"`
|
FakeIPFilter []string `yaml:"fake-ip-filter" json:"fake-ip-filter"`
|
||||||
FakeIPFilterMode C.FilterMode `yaml:"fake-ip-filter-mode" json:"fake-ip-filter-mode"`
|
FakeIPFilterMode C.FilterMode `yaml:"fake-ip-filter-mode" json:"fake-ip-filter-mode"`
|
||||||
DefaultNameserver []string `yaml:"default-nameserver" json:"default-nameserver"`
|
DefaultNameserver []string `yaml:"default-nameserver" json:"default-nameserver"`
|
||||||
@ -686,7 +691,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
|||||||
}
|
}
|
||||||
config.DNS = dnsCfg
|
config.DNS = dnsCfg
|
||||||
|
|
||||||
err = parseTun(rawCfg.Tun, config.General)
|
err = parseTun(rawCfg.Tun, dnsCfg, config.General)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1407,13 +1412,21 @@ func parseDNS(rawCfg *RawConfig, ruleProviders map[string]providerTypes.RuleProv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fakeIPRange, err := netip.ParsePrefix(cfg.FakeIPRange)
|
if cfg.FakeIPRange != "" {
|
||||||
T.SetFakeIPRange(fakeIPRange)
|
dnsCfg.FakeIPRange, err = netip.ParsePrefix(cfg.FakeIPRange)
|
||||||
if cfg.EnhancedMode == C.DNSFakeIP {
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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{}]
|
var fakeIPTrie *trie.DomainTrie[struct{}]
|
||||||
if len(dnsCfg.Fallback) != 0 {
|
if len(dnsCfg.Fallback) != 0 {
|
||||||
fakeIPTrie = trie.New[struct{}]()
|
fakeIPTrie = trie.New[struct{}]()
|
||||||
@ -1431,18 +1444,39 @@ func parseDNS(rawCfg *RawConfig, ruleProviders map[string]providerTypes.RuleProv
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pool, err := fakeip.New(fakeip.Options{
|
skipper := &fakeip.Skipper{
|
||||||
IPNet: fakeIPRange,
|
|
||||||
Size: 1000,
|
|
||||||
Host: host,
|
Host: host,
|
||||||
Mode: cfg.FakeIPFilterMode,
|
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,
|
Persistence: rawCfg.Profile.StoreFakeIP,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
if len(cfg.Fallback) != 0 {
|
||||||
@ -1504,9 +1538,9 @@ func parseAuthentication(rawRecords []string) []auth.AuthUser {
|
|||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTun(rawTun RawTun, general *General) error {
|
func parseTun(rawTun RawTun, dns *DNS, general *General) error {
|
||||||
tunAddressPrefix := T.FakeIPRange()
|
tunAddressPrefix := dns.FakeIPRange
|
||||||
if !tunAddressPrefix.IsValid() {
|
if !tunAddressPrefix.IsValid() || !tunAddressPrefix.Addr().Is4() {
|
||||||
tunAddressPrefix = netip.MustParsePrefix("198.18.0.1/16")
|
tunAddressPrefix = netip.MustParsePrefix("198.18.0.1/16")
|
||||||
}
|
}
|
||||||
tunAddressPrefix = netip.PrefixFrom(tunAddressPrefix.Addr(), 30)
|
tunAddressPrefix = netip.PrefixFrom(tunAddressPrefix.Addr(), 30)
|
||||||
|
|||||||
@ -10,7 +10,9 @@ import (
|
|||||||
|
|
||||||
type ResolverEnhancer struct {
|
type ResolverEnhancer struct {
|
||||||
mode C.DNSMode
|
mode C.DNSMode
|
||||||
fakePool *fakeip.Pool
|
fakeIPPool *fakeip.Pool
|
||||||
|
fakeIPPool6 *fakeip.Pool
|
||||||
|
fakeIPSkipper *fakeip.Skipper
|
||||||
mapping *lru.LruCache[netip.Addr, string]
|
mapping *lru.LruCache[netip.Addr, string]
|
||||||
useHosts bool
|
useHosts bool
|
||||||
}
|
}
|
||||||
@ -28,10 +30,14 @@ func (h *ResolverEnhancer) IsExistFakeIP(ip netip.Addr) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if pool := h.fakePool; pool != nil {
|
if pool := h.fakeIPPool; pool != nil {
|
||||||
return pool.Exist(ip)
|
return pool.Exist(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pool6 := h.fakeIPPool6; pool6 != nil {
|
||||||
|
return pool6.Exist(ip)
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,10 +46,14 @@ func (h *ResolverEnhancer) IsFakeIP(ip netip.Addr) bool {
|
|||||||
return false
|
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()
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,20 +62,30 @@ func (h *ResolverEnhancer) IsFakeBroadcastIP(ip netip.Addr) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if pool := h.fakePool; pool != nil {
|
if pool := h.fakeIPPool; pool != nil {
|
||||||
return pool.Broadcast() == ip
|
return pool.Broadcast() == ip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pool6 := h.fakeIPPool6; pool6 != nil {
|
||||||
|
return pool6.Broadcast() == ip
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ResolverEnhancer) FindHostByIP(ip netip.Addr) (string, bool) {
|
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 {
|
if host, existed := pool.LookBack(ip); existed {
|
||||||
return host, true
|
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 mapping := h.mapping; mapping != nil {
|
||||||
if host, existed := h.mapping.Get(ip); existed {
|
if host, existed := h.mapping.Get(ip); existed {
|
||||||
return host, true
|
return host, true
|
||||||
@ -82,9 +102,12 @@ func (h *ResolverEnhancer) InsertHostByIP(ip netip.Addr, host string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *ResolverEnhancer) FlushFakeIP() error {
|
func (h *ResolverEnhancer) FlushFakeIP() error {
|
||||||
if pool := h.fakePool; pool != nil {
|
if pool := h.fakeIPPool; pool != nil {
|
||||||
return pool.FlushFakeIP()
|
return pool.FlushFakeIP()
|
||||||
}
|
}
|
||||||
|
if pool6 := h.fakeIPPool6; pool6 != nil {
|
||||||
|
return pool6.FlushFakeIP()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,36 +116,48 @@ func (h *ResolverEnhancer) PatchFrom(o *ResolverEnhancer) {
|
|||||||
o.mapping.CloneTo(h.mapping)
|
o.mapping.CloneTo(h.mapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.fakePool != nil && o.fakePool != nil {
|
if h.fakeIPPool != nil && o.fakeIPPool != nil {
|
||||||
h.fakePool.CloneFrom(o.fakePool)
|
h.fakeIPPool.CloneFrom(o.fakeIPPool)
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.fakeIPPool6 != nil && o.fakeIPPool6 != nil {
|
||||||
|
h.fakeIPPool6.CloneFrom(o.fakeIPPool6)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ResolverEnhancer) StoreFakePoolState() {
|
func (h *ResolverEnhancer) StoreFakePoolState() {
|
||||||
if h.fakePool != nil {
|
if h.fakeIPPool != nil {
|
||||||
h.fakePool.StoreState()
|
h.fakeIPPool.StoreState()
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.fakeIPPool6 != nil {
|
||||||
|
h.fakeIPPool6.StoreState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type EnhancerConfig struct {
|
type EnhancerConfig struct {
|
||||||
|
IPv6 bool
|
||||||
EnhancedMode C.DNSMode
|
EnhancedMode C.DNSMode
|
||||||
Pool *fakeip.Pool
|
FakeIPPool *fakeip.Pool
|
||||||
|
FakeIPPool6 *fakeip.Pool
|
||||||
|
FakeIPSkipper *fakeip.Skipper
|
||||||
UseHosts bool
|
UseHosts bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEnhancer(cfg EnhancerConfig) *ResolverEnhancer {
|
func NewEnhancer(cfg EnhancerConfig) *ResolverEnhancer {
|
||||||
var fakePool *fakeip.Pool
|
e := &ResolverEnhancer{
|
||||||
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{
|
|
||||||
mode: cfg.EnhancedMode,
|
mode: cfg.EnhancedMode,
|
||||||
fakePool: fakePool,
|
|
||||||
mapping: mapping,
|
|
||||||
useHosts: cfg.UseHosts,
|
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 {
|
} else if q.Qtype == D.TypeAAAA {
|
||||||
rr := &D.AAAA{}
|
rr := &D.AAAA{}
|
||||||
rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeAAAA, Class: D.ClassINET, Ttl: 10}
|
rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeAAAA, Class: D.ClassINET, Ttl: 10}
|
||||||
ip := ipAddr.As16()
|
rr.AAAA = ipAddr.AsSlice()
|
||||||
rr.AAAA = ip[:]
|
|
||||||
msg.Answer = append(msg.Answer, rr)
|
msg.Answer = append(msg.Answer, rr)
|
||||||
if mapping != nil {
|
if mapping != nil {
|
||||||
mapping.SetWithExpire(ipAddr, host, time.Now().Add(time.Second*10))
|
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(next handler) handler {
|
||||||
return func(ctx *icontext.DNSContext, r *D.Msg) (*D.Msg, error) {
|
return func(ctx *icontext.DNSContext, r *D.Msg) (*D.Msg, error) {
|
||||||
q := r.Question[0]
|
q := r.Question[0]
|
||||||
|
|
||||||
host := strings.TrimRight(q.Name, ".")
|
host := strings.TrimRight(q.Name, ".")
|
||||||
if fakePool.ShouldSkipped(host) {
|
if skipper.ShouldSkipped(host) {
|
||||||
return next(ctx, r)
|
return next(ctx, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rr D.RR
|
||||||
switch q.Qtype {
|
switch q.Qtype {
|
||||||
case D.TypeAAAA, D.TypeSVCB, D.TypeHTTPS:
|
case D.TypeA:
|
||||||
|
if fakePool == nil {
|
||||||
return handleMsgWithEmptyAnswer(r), nil
|
return handleMsgWithEmptyAnswer(r), nil
|
||||||
}
|
}
|
||||||
|
ip := fakePool.Lookup(host)
|
||||||
if q.Qtype != D.TypeA {
|
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
|
||||||
|
default:
|
||||||
return next(ctx, r)
|
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 := r.Copy()
|
||||||
msg.Answer = []D.RR{rr}
|
msg.Answer = []D.RR{rr}
|
||||||
|
|
||||||
@ -226,7 +238,7 @@ func newHandler(resolver *Resolver, mapper *ResolverEnhancer) handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if mapper.mode == C.DNSFakeIP {
|
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 {
|
if mapper.mode != C.DNSNormal {
|
||||||
|
|||||||
@ -261,6 +261,7 @@ dns:
|
|||||||
enhanced-mode: fake-ip # or redir-host
|
enhanced-mode: fake-ip # or redir-host
|
||||||
|
|
||||||
fake-ip-range: 198.18.0.1/16 # fake-ip 池设置
|
fake-ip-range: 198.18.0.1/16 # fake-ip 池设置
|
||||||
|
# fake-ip-range6: fdfe:dcba:9876::1/64 # fake-ip6 池设置
|
||||||
|
|
||||||
# 配置不使用 fake-ip 的域名
|
# 配置不使用 fake-ip 的域名
|
||||||
fake-ip-filter:
|
fake-ip-filter:
|
||||||
|
|||||||
@ -247,10 +247,11 @@ func updateDNS(c *config.DNS, generalIPv6 bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ipv6 := c.IPv6 && generalIPv6
|
||||||
r := dns.NewResolver(dns.Config{
|
r := dns.NewResolver(dns.Config{
|
||||||
Main: c.NameServer,
|
Main: c.NameServer,
|
||||||
Fallback: c.Fallback,
|
Fallback: c.Fallback,
|
||||||
IPv6: c.IPv6 && generalIPv6,
|
IPv6: ipv6,
|
||||||
IPv6Timeout: c.IPv6Timeout,
|
IPv6Timeout: c.IPv6Timeout,
|
||||||
FallbackIPFilter: c.FallbackIPFilter,
|
FallbackIPFilter: c.FallbackIPFilter,
|
||||||
FallbackDomainFilter: c.FallbackDomainFilter,
|
FallbackDomainFilter: c.FallbackDomainFilter,
|
||||||
@ -263,8 +264,11 @@ func updateDNS(c *config.DNS, generalIPv6 bool) {
|
|||||||
CacheMaxSize: c.CacheMaxSize,
|
CacheMaxSize: c.CacheMaxSize,
|
||||||
})
|
})
|
||||||
m := dns.NewEnhancer(dns.EnhancerConfig{
|
m := dns.NewEnhancer(dns.EnhancerConfig{
|
||||||
|
IPv6: ipv6,
|
||||||
EnhancedMode: c.EnhancedMode,
|
EnhancedMode: c.EnhancedMode,
|
||||||
Pool: c.FakeIPRange,
|
FakeIPPool: c.FakeIPPool,
|
||||||
|
FakeIPPool6: c.FakeIPPool6,
|
||||||
|
FakeIPSkipper: c.FakeIPSkipper,
|
||||||
UseHosts: c.UseHosts,
|
UseHosts: c.UseHosts,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -61,8 +61,6 @@ var (
|
|||||||
|
|
||||||
findProcessMode = atomic.NewInt32Enum(P.FindProcessStrict)
|
findProcessMode = atomic.NewInt32Enum(P.FindProcessStrict)
|
||||||
|
|
||||||
fakeIPRange netip.Prefix
|
|
||||||
|
|
||||||
snifferDispatcher *sniffer.Dispatcher
|
snifferDispatcher *sniffer.Dispatcher
|
||||||
sniffingEnable = false
|
sniffingEnable = false
|
||||||
|
|
||||||
@ -142,14 +140,6 @@ func Status() TunnelStatus {
|
|||||||
return status.Load()
|
return status.Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetFakeIPRange(p netip.Prefix) {
|
|
||||||
fakeIPRange = p
|
|
||||||
}
|
|
||||||
|
|
||||||
func FakeIPRange() netip.Prefix {
|
|
||||||
return fakeIPRange
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetSniffing(b bool) {
|
func SetSniffing(b bool) {
|
||||||
if snifferDispatcher.Enable() {
|
if snifferDispatcher.Enable() {
|
||||||
configMux.Lock()
|
configMux.Lock()
|
||||||
@ -563,7 +553,7 @@ func handleTCPConn(connCtx C.ConnContext) {
|
|||||||
dialMetadata := metadata
|
dialMetadata := metadata
|
||||||
if len(metadata.Host) > 0 {
|
if len(metadata.Host) > 0 {
|
||||||
if node, ok := resolver.DefaultHosts.Search(metadata.Host, false); ok {
|
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.DstIP = dstIp
|
||||||
dialMetadata.DNSMode = C.DNSHosts
|
dialMetadata.DNSMode = C.DNSHosts
|
||||||
dialMetadata = dialMetadata.Pure()
|
dialMetadata = dialMetadata.Pure()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user