sing-box/experimental/cachefile/fakeip.go

180 lines
4.1 KiB
Go
Raw Normal View History

2023-03-25 04:03:23 +00:00
package cachefile
import (
"net/netip"
"os"
2023-08-07 13:53:19 +00:00
"time"
2023-03-25 04:03:23 +00:00
2023-10-08 14:29:31 +00:00
"github.com/sagernet/bbolt"
2023-03-25 04:03:23 +00:00
"github.com/sagernet/sing-box/adapter"
2023-07-08 08:08:46 +00:00
"github.com/sagernet/sing/common/logger"
2023-07-11 06:05:14 +00:00
M "github.com/sagernet/sing/common/metadata"
2023-03-25 04:03:23 +00:00
)
2023-07-19 12:40:34 +00:00
const fakeipBucketPrefix = "fakeip_"
2023-03-25 04:03:23 +00:00
var (
2023-07-19 12:40:34 +00:00
bucketFakeIP = []byte(fakeipBucketPrefix + "address")
bucketFakeIPDomain4 = []byte(fakeipBucketPrefix + "domain4")
bucketFakeIPDomain6 = []byte(fakeipBucketPrefix + "domain6")
keyMetadata = []byte(fakeipBucketPrefix + "metadata")
2023-03-25 04:03:23 +00:00
)
func (c *CacheFile) FakeIPMetadata() *adapter.FakeIPMetadata {
var metadata adapter.FakeIPMetadata
2023-07-20 11:51:04 +00:00
err := c.DB.Batch(func(tx *bbolt.Tx) error {
2023-03-25 04:03:23 +00:00
bucket := tx.Bucket(bucketFakeIP)
if bucket == nil {
return nil
}
metadataBinary := bucket.Get(keyMetadata)
if len(metadataBinary) == 0 {
return os.ErrInvalid
}
2023-07-20 11:51:04 +00:00
err := bucket.Delete(keyMetadata)
if err != nil {
return err
}
2023-03-25 04:03:23 +00:00
return metadata.UnmarshalBinary(metadataBinary)
})
if err != nil {
return nil
}
return &metadata
}
func (c *CacheFile) FakeIPSaveMetadata(metadata *adapter.FakeIPMetadata) error {
return c.DB.Batch(func(tx *bbolt.Tx) error {
bucket, err := tx.CreateBucketIfNotExists(bucketFakeIP)
if err != nil {
return err
}
metadataBinary, err := metadata.MarshalBinary()
if err != nil {
return err
}
return bucket.Put(keyMetadata, metadataBinary)
})
}
2023-08-07 13:53:19 +00:00
func (c *CacheFile) FakeIPSaveMetadataAsync(metadata *adapter.FakeIPMetadata) {
if timer := c.saveMetadataTimer; timer != nil {
timer.Stop()
}
c.saveMetadataTimer = time.AfterFunc(10*time.Second, func() {
_ = c.FakeIPSaveMetadata(metadata)
})
}
2023-03-25 04:03:23 +00:00
func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
return c.DB.Batch(func(tx *bbolt.Tx) error {
bucket, err := tx.CreateBucketIfNotExists(bucketFakeIP)
if err != nil {
return err
}
2023-07-11 06:05:14 +00:00
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())
2023-03-25 04:03:23 +00:00
})
}
2023-07-08 08:08:46 +00:00
func (c *CacheFile) FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger) {
c.saveAccess.Lock()
2023-07-20 11:51:04 +00:00
c.saveDomain[address] = domain
if address.Is4() {
c.saveAddress4[domain] = address
} else {
c.saveAddress6[domain] = address
}
2023-07-08 08:08:46 +00:00
c.saveAccess.Unlock()
go func() {
err := c.FakeIPStore(address, domain)
if err != nil {
logger.Warn("save FakeIP address pair: ", err)
}
c.saveAccess.Lock()
2023-07-20 11:51:04 +00:00
delete(c.saveDomain, address)
if address.Is4() {
delete(c.saveAddress4, domain)
} else {
delete(c.saveAddress6, domain)
}
2023-07-08 08:08:46 +00:00
c.saveAccess.Unlock()
}()
}
2023-03-25 04:03:23 +00:00
func (c *CacheFile) FakeIPLoad(address netip.Addr) (string, bool) {
2023-07-08 08:08:46 +00:00
c.saveAccess.RLock()
2023-07-20 11:51:04 +00:00
cachedDomain, cached := c.saveDomain[address]
2023-07-08 08:08:46 +00:00
c.saveAccess.RUnlock()
if cached {
return cachedDomain, true
}
2023-03-25 04:03:23 +00:00
var domain string
_ = c.DB.View(func(tx *bbolt.Tx) error {
bucket := tx.Bucket(bucketFakeIP)
if bucket == nil {
return nil
}
domain = string(bucket.Get(address.AsSlice()))
return nil
})
return domain, domain != ""
}
2023-07-11 06:05:14 +00:00
func (c *CacheFile) FakeIPLoadDomain(domain string, isIPv6 bool) (netip.Addr, bool) {
2023-07-20 11:51:04 +00:00
var (
cachedAddress netip.Addr
cached bool
)
c.saveAccess.RLock()
if !isIPv6 {
cachedAddress, cached = c.saveAddress4[domain]
} else {
cachedAddress, cached = c.saveAddress6[domain]
}
c.saveAccess.RUnlock()
if cached {
return cachedAddress, true
}
2023-07-11 06:05:14 +00:00
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()
}
2023-03-25 04:03:23 +00:00
func (c *CacheFile) FakeIPReset() error {
return c.DB.Batch(func(tx *bbolt.Tx) error {
2023-07-11 06:05:14 +00:00
err := tx.DeleteBucket(bucketFakeIP)
if err != nil {
return err
}
err = tx.DeleteBucket(bucketFakeIPDomain4)
if err != nil {
return err
}
return tx.DeleteBucket(bucketFakeIPDomain6)
2023-03-25 04:03:23 +00:00
})
}