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 }