sing-box/experimental/cachefile/fakeip.go

195 lines
4.6 KiB
Go
Raw Permalink 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"
2024-04-02 15:07:26 +00:00
C "github.com/sagernet/sing-box/constant"
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 {
2023-12-01 05:24:12 +00:00
return os.ErrNotExist
2023-03-25 04:03:23 +00:00
}
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) {
2024-04-02 15:07:26 +00:00
if c.saveMetadataTimer == nil {
c.saveMetadataTimer = time.AfterFunc(C.FakeIPMetadataSaveInterval, func() {
_ = c.FakeIPSaveMetadata(metadata)
})
} else {
c.saveMetadataTimer.Reset(C.FakeIPMetadataSaveInterval)
2023-08-07 13:53:19 +00:00
}
}
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
}
2024-04-27 14:31:12 +00:00
oldDomain := bucket.Get(address.AsSlice())
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
}
2024-04-27 14:31:12 +00:00
if oldDomain != nil {
if err := bucket.Delete(oldDomain); err != nil {
return err
}
}
2023-07-11 06:05:14 +00:00
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.saveFakeIPAccess.Lock()
2024-04-27 14:31:12 +00:00
if oldDomain, loaded := c.saveDomain[address]; loaded {
if address.Is4() {
delete(c.saveAddress4, oldDomain)
} else {
delete(c.saveAddress6, oldDomain)
}
}
2023-07-20 11:51:04 +00:00
c.saveDomain[address] = domain
if address.Is4() {
c.saveAddress4[domain] = address
} else {
c.saveAddress6[domain] = address
}
c.saveFakeIPAccess.Unlock()
2023-07-08 08:08:46 +00:00
go func() {
err := c.FakeIPStore(address, domain)
if err != nil {
logger.Warn("save FakeIP cache: ", err)
2023-07-08 08:08:46 +00:00
}
c.saveFakeIPAccess.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)
}
c.saveFakeIPAccess.Unlock()
2023-07-08 08:08:46 +00:00
}()
}
2023-03-25 04:03:23 +00:00
func (c *CacheFile) FakeIPLoad(address netip.Addr) (string, bool) {
c.saveFakeIPAccess.RLock()
2023-07-20 11:51:04 +00:00
cachedDomain, cached := c.saveDomain[address]
c.saveFakeIPAccess.RUnlock()
2023-07-08 08:08:46 +00:00
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.saveFakeIPAccess.RLock()
2023-07-20 11:51:04 +00:00
if !isIPv6 {
cachedAddress, cached = c.saveAddress4[domain]
} else {
cachedAddress, cached = c.saveAddress6[domain]
}
c.saveFakeIPAccess.RUnlock()
2023-07-20 11:51:04 +00:00
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
})
}