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 { type FakeIPStore interface {
Service Service
Contains(address netip.Addr) bool 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) Lookup(address netip.Addr) (string, bool)
Reset() error Reset() error
} }
@ -21,6 +21,7 @@ type FakeIPStorage interface {
FakeIPStore(address netip.Addr, domain string) error FakeIPStore(address netip.Addr, domain string) error
FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger) FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger)
FakeIPLoad(address netip.Addr) (string, bool) FakeIPLoad(address netip.Addr) (string, bool)
FakeIPLoadDomain(domain string, isIPv6 bool) (netip.Addr, bool)
FakeIPReset() error FakeIPReset() error
} }

View file

@ -6,13 +6,16 @@ import (
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
"go.etcd.io/bbolt" "go.etcd.io/bbolt"
) )
var ( var (
bucketFakeIP = []byte("fakeip") bucketFakeIP = []byte("fakeip")
keyMetadata = []byte("metadata") bucketFakeIPDomain4 = []byte("fakeip_domain4")
bucketFakeIPDomain6 = []byte("fakeip_domain6")
keyMetadata = []byte("metadata")
) )
func (c *CacheFile) FakeIPMetadata() *adapter.FakeIPMetadata { func (c *CacheFile) FakeIPMetadata() *adapter.FakeIPMetadata {
@ -54,7 +57,19 @@ func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
if err != nil { if err != nil {
return err 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 != "" 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 { func (c *CacheFile) FakeIPReset() error {
return c.DB.Batch(func(tx *bbolt.Tx) 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 ( import (
"net/netip" "net/netip"
"sync"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing/common/cache"
"github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/logger"
) )
var _ adapter.FakeIPStorage = (*MemoryStorage)(nil) var _ adapter.FakeIPStorage = (*MemoryStorage)(nil)
type MemoryStorage struct { type MemoryStorage struct {
metadata *adapter.FakeIPMetadata addressAccess sync.RWMutex
domainCache *cache.LruCache[netip.Addr, string] domainAccess sync.RWMutex
addressCache map[netip.Addr]string
domainCache4 map[string]netip.Addr
domainCache6 map[string]netip.Addr
} }
func NewMemoryStorage() *MemoryStorage { func NewMemoryStorage() *MemoryStorage {
return &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 { func (s *MemoryStorage) FakeIPMetadata() *adapter.FakeIPMetadata {
return s.metadata return nil
} }
func (s *MemoryStorage) FakeIPSaveMetadata(metadata *adapter.FakeIPMetadata) error { func (s *MemoryStorage) FakeIPSaveMetadata(metadata *adapter.FakeIPMetadata) error {
s.metadata = metadata
return nil return nil
} }
func (s *MemoryStorage) FakeIPStore(address netip.Addr, domain string) error { 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 return nil
} }
func (s *MemoryStorage) FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger) { 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) { 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 { 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 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) { func (s *Transport) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) {
var addresses []netip.Addr var addresses []netip.Addr
if strategy != dns.DomainStrategyUseIPv6 { if strategy != dns.DomainStrategyUseIPv6 {
inet4Address, err := s.store.Create(domain, dns.DomainStrategyUseIPv4) inet4Address, err := s.store.Create(domain, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
addresses = append(addresses, inet4Address) addresses = append(addresses, inet4Address)
} }
if strategy != dns.DomainStrategyUseIPv4 { if strategy != dns.DomainStrategyUseIPv4 {
inet6Address, err := s.store.Create(domain, dns.DomainStrategyUseIPv6) inet6Address, err := s.store.Create(domain, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -4,7 +4,6 @@ import (
"net/netip" "net/netip"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-dns"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger" "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 var address netip.Addr
if strategy == dns.DomainStrategyUseIPv4 { if !isIPv6 {
if !s.inet4Current.IsValid() { if !s.inet4Current.IsValid() {
return netip.Addr{}, E.New("missing IPv4 fakeip address range") return netip.Addr{}, E.New("missing IPv4 fakeip address range")
} }