github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/experimental/clashapi/cachefile/fakeip.go (about)

     1  package cachefile
     2  
     3  import (
     4  	"net/netip"
     5  	"os"
     6  	"time"
     7  
     8  	"github.com/inazumav/sing-box/adapter"
     9  	"github.com/sagernet/sing/common/logger"
    10  	M "github.com/sagernet/sing/common/metadata"
    11  
    12  	"go.etcd.io/bbolt"
    13  )
    14  
    15  const fakeipBucketPrefix = "fakeip_"
    16  
    17  var (
    18  	bucketFakeIP        = []byte(fakeipBucketPrefix + "address")
    19  	bucketFakeIPDomain4 = []byte(fakeipBucketPrefix + "domain4")
    20  	bucketFakeIPDomain6 = []byte(fakeipBucketPrefix + "domain6")
    21  	keyMetadata         = []byte(fakeipBucketPrefix + "metadata")
    22  )
    23  
    24  func (c *CacheFile) FakeIPMetadata() *adapter.FakeIPMetadata {
    25  	var metadata adapter.FakeIPMetadata
    26  	err := c.DB.Batch(func(tx *bbolt.Tx) error {
    27  		bucket := tx.Bucket(bucketFakeIP)
    28  		if bucket == nil {
    29  			return nil
    30  		}
    31  		metadataBinary := bucket.Get(keyMetadata)
    32  		if len(metadataBinary) == 0 {
    33  			return os.ErrInvalid
    34  		}
    35  		err := bucket.Delete(keyMetadata)
    36  		if err != nil {
    37  			return err
    38  		}
    39  		return metadata.UnmarshalBinary(metadataBinary)
    40  	})
    41  	if err != nil {
    42  		return nil
    43  	}
    44  	return &metadata
    45  }
    46  
    47  func (c *CacheFile) FakeIPSaveMetadata(metadata *adapter.FakeIPMetadata) error {
    48  	return c.DB.Batch(func(tx *bbolt.Tx) error {
    49  		bucket, err := tx.CreateBucketIfNotExists(bucketFakeIP)
    50  		if err != nil {
    51  			return err
    52  		}
    53  		metadataBinary, err := metadata.MarshalBinary()
    54  		if err != nil {
    55  			return err
    56  		}
    57  		return bucket.Put(keyMetadata, metadataBinary)
    58  	})
    59  }
    60  
    61  func (c *CacheFile) FakeIPSaveMetadataAsync(metadata *adapter.FakeIPMetadata) {
    62  	if timer := c.saveMetadataTimer; timer != nil {
    63  		timer.Stop()
    64  	}
    65  	c.saveMetadataTimer = time.AfterFunc(10*time.Second, func() {
    66  		_ = c.FakeIPSaveMetadata(metadata)
    67  	})
    68  }
    69  
    70  func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
    71  	return c.DB.Batch(func(tx *bbolt.Tx) error {
    72  		bucket, err := tx.CreateBucketIfNotExists(bucketFakeIP)
    73  		if err != nil {
    74  			return err
    75  		}
    76  		err = bucket.Put(address.AsSlice(), []byte(domain))
    77  		if err != nil {
    78  			return err
    79  		}
    80  		if address.Is4() {
    81  			bucket, err = tx.CreateBucketIfNotExists(bucketFakeIPDomain4)
    82  		} else {
    83  			bucket, err = tx.CreateBucketIfNotExists(bucketFakeIPDomain6)
    84  		}
    85  		if err != nil {
    86  			return err
    87  		}
    88  		return bucket.Put([]byte(domain), address.AsSlice())
    89  	})
    90  }
    91  
    92  func (c *CacheFile) FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger) {
    93  	c.saveAccess.Lock()
    94  	c.saveDomain[address] = domain
    95  	if address.Is4() {
    96  		c.saveAddress4[domain] = address
    97  	} else {
    98  		c.saveAddress6[domain] = address
    99  	}
   100  	c.saveAccess.Unlock()
   101  	go func() {
   102  		err := c.FakeIPStore(address, domain)
   103  		if err != nil {
   104  			logger.Warn("save FakeIP address pair: ", err)
   105  		}
   106  		c.saveAccess.Lock()
   107  		delete(c.saveDomain, address)
   108  		if address.Is4() {
   109  			delete(c.saveAddress4, domain)
   110  		} else {
   111  			delete(c.saveAddress6, domain)
   112  		}
   113  		c.saveAccess.Unlock()
   114  	}()
   115  }
   116  
   117  func (c *CacheFile) FakeIPLoad(address netip.Addr) (string, bool) {
   118  	c.saveAccess.RLock()
   119  	cachedDomain, cached := c.saveDomain[address]
   120  	c.saveAccess.RUnlock()
   121  	if cached {
   122  		return cachedDomain, true
   123  	}
   124  	var domain string
   125  	_ = c.DB.View(func(tx *bbolt.Tx) error {
   126  		bucket := tx.Bucket(bucketFakeIP)
   127  		if bucket == nil {
   128  			return nil
   129  		}
   130  		domain = string(bucket.Get(address.AsSlice()))
   131  		return nil
   132  	})
   133  	return domain, domain != ""
   134  }
   135  
   136  func (c *CacheFile) FakeIPLoadDomain(domain string, isIPv6 bool) (netip.Addr, bool) {
   137  	var (
   138  		cachedAddress netip.Addr
   139  		cached        bool
   140  	)
   141  	c.saveAccess.RLock()
   142  	if !isIPv6 {
   143  		cachedAddress, cached = c.saveAddress4[domain]
   144  	} else {
   145  		cachedAddress, cached = c.saveAddress6[domain]
   146  	}
   147  	c.saveAccess.RUnlock()
   148  	if cached {
   149  		return cachedAddress, true
   150  	}
   151  	var address netip.Addr
   152  	_ = c.DB.View(func(tx *bbolt.Tx) error {
   153  		var bucket *bbolt.Bucket
   154  		if isIPv6 {
   155  			bucket = tx.Bucket(bucketFakeIPDomain6)
   156  		} else {
   157  			bucket = tx.Bucket(bucketFakeIPDomain4)
   158  		}
   159  		if bucket == nil {
   160  			return nil
   161  		}
   162  		address = M.AddrFromIP(bucket.Get([]byte(domain)))
   163  		return nil
   164  	})
   165  	return address, address.IsValid()
   166  }
   167  
   168  func (c *CacheFile) FakeIPReset() error {
   169  	return c.DB.Batch(func(tx *bbolt.Tx) error {
   170  		err := tx.DeleteBucket(bucketFakeIP)
   171  		if err != nil {
   172  			return err
   173  		}
   174  		err = tx.DeleteBucket(bucketFakeIPDomain4)
   175  		if err != nil {
   176  			return err
   177  		}
   178  		return tx.DeleteBucket(bucketFakeIPDomain6)
   179  	})
   180  }