mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-10-20 19:12:30 +00:00
Fix FakeIP storage consistency with buffered cache file writes
This commit is contained in:
parent
ab5be37361
commit
b1dbabc49e
4 changed files with 54 additions and 46 deletions
|
|
@ -17,7 +17,6 @@ type FakeIPStore interface {
|
|||
type FakeIPStorage interface {
|
||||
FakeIPMetadata() *FakeIPMetadata
|
||||
FakeIPSaveMetadata(metadata *FakeIPMetadata) error
|
||||
FakeIPSaveMetadataAsync(metadata *FakeIPMetadata)
|
||||
FakeIPStore(address netip.Addr, domain string) error
|
||||
FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger)
|
||||
FakeIPLoad(address netip.Addr) (string, bool)
|
||||
|
|
|
|||
|
|
@ -34,9 +34,6 @@ func (s *MemoryStorage) FakeIPSaveMetadata(metadata *adapter.FakeIPMetadata) err
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *MemoryStorage) FakeIPSaveMetadataAsync(metadata *adapter.FakeIPMetadata) {
|
||||
}
|
||||
|
||||
func (s *MemoryStorage) FakeIPStore(address netip.Addr, domain string) error {
|
||||
s.addressAccess.Lock()
|
||||
s.domainAccess.Lock()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import (
|
|||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
||||
const reservedAddressCount = 1024
|
||||
|
||||
var _ adapter.FakeIPStore = (*Store)(nil)
|
||||
|
||||
type Store struct {
|
||||
|
|
@ -25,6 +27,7 @@ type Store struct {
|
|||
addressAccess sync.Mutex
|
||||
inet4Current netip.Addr
|
||||
inet6Current netip.Addr
|
||||
reservedCount int
|
||||
}
|
||||
|
||||
func NewStore(ctx context.Context, logger logger.Logger, inet4Range netip.Prefix, inet6Range netip.Prefix) *Store {
|
||||
|
|
@ -59,6 +62,14 @@ func broadcastAddress(prefix netip.Prefix) netip.Addr {
|
|||
return netip.AddrFrom16(raw)
|
||||
}
|
||||
|
||||
func nextAddress(addressRange netip.Prefix, last netip.Addr, current netip.Addr) netip.Addr {
|
||||
address := current.Next()
|
||||
if address == last || !addressRange.Contains(address) {
|
||||
address = addressRange.Addr().Next().Next()
|
||||
}
|
||||
return address
|
||||
}
|
||||
|
||||
func (s *Store) Start() error {
|
||||
var storage adapter.FakeIPStorage
|
||||
cacheFile := service.FromContext[adapter.CacheFile](s.ctx)
|
||||
|
|
@ -117,35 +128,42 @@ func (s *Store) Create(domain string, isIPv6 bool) (netip.Addr, error) {
|
|||
return address, nil
|
||||
}
|
||||
|
||||
if !isIPv6 && !s.inet4Current.IsValid() {
|
||||
return netip.Addr{}, E.New("missing IPv4 fakeip address range")
|
||||
} else if isIPv6 && !s.inet6Current.IsValid() {
|
||||
return netip.Addr{}, E.New("missing IPv6 fakeip address range")
|
||||
}
|
||||
if s.reservedCount == 0 {
|
||||
metadata := &adapter.FakeIPMetadata{
|
||||
Inet4Range: s.inet4Range,
|
||||
Inet6Range: s.inet6Range,
|
||||
Inet4Current: s.inet4Current,
|
||||
Inet6Current: s.inet6Current,
|
||||
}
|
||||
for range reservedAddressCount {
|
||||
if metadata.Inet4Current.IsValid() {
|
||||
metadata.Inet4Current = nextAddress(s.inet4Range, s.inet4Last, metadata.Inet4Current)
|
||||
}
|
||||
if metadata.Inet6Current.IsValid() {
|
||||
metadata.Inet6Current = nextAddress(s.inet6Range, s.inet6Last, metadata.Inet6Current)
|
||||
}
|
||||
}
|
||||
err := s.storage.FakeIPSaveMetadata(metadata)
|
||||
if err != nil {
|
||||
return netip.Addr{}, E.Cause(err, "save fakeip metadata")
|
||||
}
|
||||
s.reservedCount = reservedAddressCount
|
||||
}
|
||||
s.reservedCount--
|
||||
var address netip.Addr
|
||||
if !isIPv6 {
|
||||
if !s.inet4Current.IsValid() {
|
||||
return netip.Addr{}, E.New("missing IPv4 fakeip address range")
|
||||
}
|
||||
nextAddress := s.inet4Current.Next()
|
||||
if nextAddress == s.inet4Last || !s.inet4Range.Contains(nextAddress) {
|
||||
nextAddress = s.inet4Range.Addr().Next().Next()
|
||||
}
|
||||
s.inet4Current = nextAddress
|
||||
address = nextAddress
|
||||
s.inet4Current = nextAddress(s.inet4Range, s.inet4Last, s.inet4Current)
|
||||
address = s.inet4Current
|
||||
} else {
|
||||
if !s.inet6Current.IsValid() {
|
||||
return netip.Addr{}, E.New("missing IPv6 fakeip address range")
|
||||
}
|
||||
nextAddress := s.inet6Current.Next()
|
||||
if nextAddress == s.inet6Last || !s.inet6Range.Contains(nextAddress) {
|
||||
nextAddress = s.inet6Range.Addr().Next().Next()
|
||||
}
|
||||
s.inet6Current = nextAddress
|
||||
address = nextAddress
|
||||
s.inet6Current = nextAddress(s.inet6Range, s.inet6Last, s.inet6Current)
|
||||
address = s.inet6Current
|
||||
}
|
||||
s.storage.FakeIPStoreAsync(address, domain, s.logger)
|
||||
s.storage.FakeIPSaveMetadataAsync(&adapter.FakeIPMetadata{
|
||||
Inet4Range: s.inet4Range,
|
||||
Inet6Range: s.inet6Range,
|
||||
Inet4Current: s.inet4Current,
|
||||
Inet6Current: s.inet6Current,
|
||||
})
|
||||
return address, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package cachefile
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/netip"
|
||||
"os"
|
||||
|
||||
|
|
@ -21,7 +22,7 @@ var (
|
|||
|
||||
func (c *CacheFile) FakeIPMetadata() *adapter.FakeIPMetadata {
|
||||
var metadata adapter.FakeIPMetadata
|
||||
err := c.batch(func(tx *bbolt.Tx) error {
|
||||
err := c.view(func(tx *bbolt.Tx) error {
|
||||
bucket := tx.Bucket(bucketFakeIP)
|
||||
if bucket == nil {
|
||||
return os.ErrNotExist
|
||||
|
|
@ -30,10 +31,6 @@ func (c *CacheFile) FakeIPMetadata() *adapter.FakeIPMetadata {
|
|||
if len(metadataBinary) == 0 {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
err := bucket.Delete(keyMetadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return metadata.UnmarshalBinary(metadataBinary)
|
||||
})
|
||||
if err != nil {
|
||||
|
|
@ -43,17 +40,13 @@ func (c *CacheFile) FakeIPMetadata() *adapter.FakeIPMetadata {
|
|||
}
|
||||
|
||||
func (c *CacheFile) FakeIPSaveMetadata(metadata *adapter.FakeIPMetadata) error {
|
||||
c.FakeIPSaveMetadataAsync(metadata)
|
||||
c.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CacheFile) FakeIPSaveMetadataAsync(metadata *adapter.FakeIPMetadata) {
|
||||
c.pendingAccess.Lock()
|
||||
defer c.pendingAccess.Unlock()
|
||||
added := c.pending.fakeIPMetadata == nil
|
||||
c.pending.fakeIPMetadata = metadata
|
||||
c.enqueueLocked(added, 0)
|
||||
c.pendingAccess.Unlock()
|
||||
c.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func putFakeIPMetadata(tx *bbolt.Tx, metadata *adapter.FakeIPMetadata) error {
|
||||
|
|
@ -79,23 +72,24 @@ func (c *CacheFile) FakeIPStoreAsync(address netip.Addr, domain string, logger l
|
|||
}
|
||||
|
||||
func (c *CacheFile) queueFakeIP(address netip.Addr, domain string) {
|
||||
oldDomain, loaded := c.FakeIPLoad(address)
|
||||
c.pendingAccess.Lock()
|
||||
defer c.pendingAccess.Unlock()
|
||||
oldDomain, loaded := c.pending.fakeIPDomain[address]
|
||||
if loaded {
|
||||
if address.Is4() {
|
||||
delete(c.pending.fakeIPAddress4, oldDomain)
|
||||
c.pending.fakeIPAddress4[oldDomain] = netip.Addr{}
|
||||
} else {
|
||||
delete(c.pending.fakeIPAddress6, oldDomain)
|
||||
c.pending.fakeIPAddress6[oldDomain] = netip.Addr{}
|
||||
}
|
||||
}
|
||||
pendingDomain, pendingLoaded := c.pending.fakeIPDomain[address]
|
||||
c.pending.fakeIPDomain[address] = domain
|
||||
if address.Is4() {
|
||||
c.pending.fakeIPAddress4[domain] = address
|
||||
} else {
|
||||
c.pending.fakeIPAddress6[domain] = address
|
||||
}
|
||||
c.enqueueLocked(!loaded, len(domain)-len(oldDomain))
|
||||
c.enqueueLocked(!pendingLoaded, len(domain)-len(pendingDomain))
|
||||
}
|
||||
|
||||
func putFakeIP(tx *bbolt.Tx, address netip.Addr, domain string) error {
|
||||
|
|
@ -117,7 +111,7 @@ func putFakeIP(tx *bbolt.Tx, address netip.Addr, domain string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if oldDomain != nil {
|
||||
if oldDomain != nil && bytes.Equal(bucket.Get(oldDomain), addressBytes) {
|
||||
err = bucket.Delete(oldDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -164,7 +158,7 @@ func (c *CacheFile) FakeIPLoadDomain(domain string, isIPv6 bool) (netip.Addr, bo
|
|||
}
|
||||
c.pendingAccess.RUnlock()
|
||||
if cached {
|
||||
return address, true
|
||||
return address, address.IsValid()
|
||||
}
|
||||
_ = c.view(func(tx *bbolt.Tx) error {
|
||||
var bucket *bbolt.Bucket
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue