Fix fakeip lookup

This commit is contained in:
世界 2023-07-11 14:05:14 +08:00
parent bb651db2d2
commit 120dae4eed
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
5 changed files with 94 additions and 20 deletions

View file

@ -10,7 +10,7 @@ import (
type FakeIPStore interface {
Service
Contains(address netip.Addr) bool
Create(domain string, strategy dns.DomainStrategy) (netip.Addr, error)
Create(domain string, isIPv6 bool) (netip.Addr, error)
Lookup(address netip.Addr) (string, bool)
Reset() error
}
@ -21,6 +21,7 @@ type FakeIPStorage interface {
FakeIPStore(address netip.Addr, domain string) error
FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger)
FakeIPLoad(address netip.Addr) (string, bool)
FakeIPLoadDomain(domain string, isIPv6 bool) (netip.Addr, bool)
FakeIPReset() error
}

View file

@ -6,13 +6,16 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
"go.etcd.io/bbolt"
)
var (
bucketFakeIP = []byte("fakeip")
keyMetadata = []byte("metadata")
bucketFakeIP = []byte("fakeip")
bucketFakeIPDomain4 = []byte("fakeip_domain4")
bucketFakeIPDomain6 = []byte("fakeip_domain6")
keyMetadata = []byte("metadata")
)
func (c *CacheFile) FakeIPMetadata() *adapter.FakeIPMetadata {
@ -54,7 +57,19 @@ func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
if err != nil {
return err
}
return bucket.Put(address.AsSlice(), []byte(domain))
err = bucket.Put(address.AsSlice(), []byte(domain))
if err != nil {
return err
}
if address.Is4() {
bucket, err = tx.CreateBucketIfNotExists(bucketFakeIPDomain4)
} else {
bucket, err = tx.CreateBucketIfNotExists(bucketFakeIPDomain6)
}
if err != nil {
return err
}
return bucket.Put([]byte(domain), address.AsSlice())
})
}
@ -92,8 +107,34 @@ func (c *CacheFile) FakeIPLoad(address netip.Addr) (string, bool) {
return domain, domain != ""
}
func (c *CacheFile) FakeIPLoadDomain(domain string, isIPv6 bool) (netip.Addr, bool) {
var address netip.Addr
_ = c.DB.View(func(tx *bbolt.Tx) error {
var bucket *bbolt.Bucket
if isIPv6 {
bucket = tx.Bucket(bucketFakeIPDomain6)
} else {
bucket = tx.Bucket(bucketFakeIPDomain4)
}
if bucket == nil {
return nil
}
address = M.AddrFromIP(bucket.Get([]byte(domain)))
return nil
})
return address, address.IsValid()
}
func (c *CacheFile) FakeIPReset() error {
return c.DB.Batch(func(tx *bbolt.Tx) error {
return tx.DeleteBucket(bucketFakeIP)
err := tx.DeleteBucket(bucketFakeIP)
if err != nil {
return err
}
err = tx.DeleteBucket(bucketFakeIPDomain4)
if err != nil {
return err
}
return tx.DeleteBucket(bucketFakeIPDomain6)
})
}

View file

@ -2,48 +2,78 @@ package fakeip
import (
"net/netip"
"sync"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing/common/cache"
"github.com/sagernet/sing/common/logger"
)
var _ adapter.FakeIPStorage = (*MemoryStorage)(nil)
type MemoryStorage struct {
metadata *adapter.FakeIPMetadata
domainCache *cache.LruCache[netip.Addr, string]
addressAccess sync.RWMutex
domainAccess sync.RWMutex
addressCache map[netip.Addr]string
domainCache4 map[string]netip.Addr
domainCache6 map[string]netip.Addr
}
func NewMemoryStorage() *MemoryStorage {
return &MemoryStorage{
domainCache: cache.New[netip.Addr, string](),
addressCache: make(map[netip.Addr]string),
domainCache4: make(map[string]netip.Addr),
domainCache6: make(map[string]netip.Addr),
}
}
func (s *MemoryStorage) FakeIPMetadata() *adapter.FakeIPMetadata {
return s.metadata
return nil
}
func (s *MemoryStorage) FakeIPSaveMetadata(metadata *adapter.FakeIPMetadata) error {
s.metadata = metadata
return nil
}
func (s *MemoryStorage) FakeIPStore(address netip.Addr, domain string) error {
s.domainCache.Store(address, domain)
s.addressAccess.Lock()
s.domainAccess.Lock()
s.addressCache[address] = domain
if address.Is4() {
s.domainCache4[domain] = address
} else {
s.domainCache6[domain] = address
}
s.domainAccess.Unlock()
s.addressAccess.Unlock()
return nil
}
func (s *MemoryStorage) FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger) {
s.domainCache.Store(address, domain)
_ = s.FakeIPStore(address, domain)
}
func (s *MemoryStorage) FakeIPLoad(address netip.Addr) (string, bool) {
return s.domainCache.Load(address)
s.addressAccess.RLock()
defer s.addressAccess.RUnlock()
domain, loaded := s.addressCache[address]
return domain, loaded
}
func (s *MemoryStorage) FakeIPLoadDomain(domain string, isIPv6 bool) (netip.Addr, bool) {
s.domainAccess.RLock()
defer s.domainAccess.RUnlock()
if !isIPv6 {
address, loaded := s.domainCache4[domain]
return address, loaded
} else {
address, loaded := s.domainCache6[domain]
return address, loaded
}
}
func (s *MemoryStorage) FakeIPReset() error {
s.domainCache = cache.New[netip.Addr, string]()
s.addressCache = make(map[netip.Addr]string)
s.domainCache4 = make(map[string]netip.Addr)
s.domainCache6 = make(map[string]netip.Addr)
return nil
}

View file

@ -69,14 +69,14 @@ func (s *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg,
func (s *Transport) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) {
var addresses []netip.Addr
if strategy != dns.DomainStrategyUseIPv6 {
inet4Address, err := s.store.Create(domain, dns.DomainStrategyUseIPv4)
inet4Address, err := s.store.Create(domain, false)
if err != nil {
return nil, err
}
addresses = append(addresses, inet4Address)
}
if strategy != dns.DomainStrategyUseIPv4 {
inet6Address, err := s.store.Create(domain, dns.DomainStrategyUseIPv6)
inet6Address, err := s.store.Create(domain, true)
if err != nil {
return nil, err
}

View file

@ -4,7 +4,6 @@ import (
"net/netip"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-dns"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
)
@ -72,9 +71,12 @@ func (s *Store) Close() error {
})
}
func (s *Store) Create(domain string, strategy dns.DomainStrategy) (netip.Addr, error) {
func (s *Store) Create(domain string, isIPv6 bool) (netip.Addr, error) {
if address, loaded := s.storage.FakeIPLoadDomain(domain, isIPv6); loaded {
return address, nil
}
var address netip.Addr
if strategy == dns.DomainStrategyUseIPv4 {
if !isIPv6 {
if !s.inet4Current.IsValid() {
return netip.Addr{}, E.New("missing IPv4 fakeip address range")
}