github.com/sagernet/sing-box@v1.9.0-rc.20/experimental/cachefile/fakeip.go (about) 1 package cachefile 2 3 import ( 4 "net/netip" 5 "os" 6 "time" 7 8 "github.com/sagernet/bbolt" 9 "github.com/sagernet/sing-box/adapter" 10 C "github.com/sagernet/sing-box/constant" 11 "github.com/sagernet/sing/common/logger" 12 M "github.com/sagernet/sing/common/metadata" 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 os.ErrNotExist 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 c.saveMetadataTimer == nil { 63 c.saveMetadataTimer = time.AfterFunc(C.FakeIPMetadataSaveInterval, func() { 64 _ = c.FakeIPSaveMetadata(metadata) 65 }) 66 } else { 67 c.saveMetadataTimer.Reset(C.FakeIPMetadataSaveInterval) 68 } 69 } 70 71 func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error { 72 return c.DB.Batch(func(tx *bbolt.Tx) error { 73 bucket, err := tx.CreateBucketIfNotExists(bucketFakeIP) 74 if err != nil { 75 return err 76 } 77 oldDomain := bucket.Get(address.AsSlice()) 78 err = bucket.Put(address.AsSlice(), []byte(domain)) 79 if err != nil { 80 return err 81 } 82 if address.Is4() { 83 bucket, err = tx.CreateBucketIfNotExists(bucketFakeIPDomain4) 84 } else { 85 bucket, err = tx.CreateBucketIfNotExists(bucketFakeIPDomain6) 86 } 87 if err != nil { 88 return err 89 } 90 if oldDomain != nil { 91 if err := bucket.Delete(oldDomain); err != nil { 92 return err 93 } 94 } 95 return bucket.Put([]byte(domain), address.AsSlice()) 96 }) 97 } 98 99 func (c *CacheFile) FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger) { 100 c.saveFakeIPAccess.Lock() 101 if oldDomain, loaded := c.saveDomain[address]; loaded { 102 if address.Is4() { 103 delete(c.saveAddress4, oldDomain) 104 } else { 105 delete(c.saveAddress6, oldDomain) 106 } 107 } 108 c.saveDomain[address] = domain 109 if address.Is4() { 110 c.saveAddress4[domain] = address 111 } else { 112 c.saveAddress6[domain] = address 113 } 114 c.saveFakeIPAccess.Unlock() 115 go func() { 116 err := c.FakeIPStore(address, domain) 117 if err != nil { 118 logger.Warn("save FakeIP cache: ", err) 119 } 120 c.saveFakeIPAccess.Lock() 121 delete(c.saveDomain, address) 122 if address.Is4() { 123 delete(c.saveAddress4, domain) 124 } else { 125 delete(c.saveAddress6, domain) 126 } 127 c.saveFakeIPAccess.Unlock() 128 }() 129 } 130 131 func (c *CacheFile) FakeIPLoad(address netip.Addr) (string, bool) { 132 c.saveFakeIPAccess.RLock() 133 cachedDomain, cached := c.saveDomain[address] 134 c.saveFakeIPAccess.RUnlock() 135 if cached { 136 return cachedDomain, true 137 } 138 var domain string 139 _ = c.DB.View(func(tx *bbolt.Tx) error { 140 bucket := tx.Bucket(bucketFakeIP) 141 if bucket == nil { 142 return nil 143 } 144 domain = string(bucket.Get(address.AsSlice())) 145 return nil 146 }) 147 return domain, domain != "" 148 } 149 150 func (c *CacheFile) FakeIPLoadDomain(domain string, isIPv6 bool) (netip.Addr, bool) { 151 var ( 152 cachedAddress netip.Addr 153 cached bool 154 ) 155 c.saveFakeIPAccess.RLock() 156 if !isIPv6 { 157 cachedAddress, cached = c.saveAddress4[domain] 158 } else { 159 cachedAddress, cached = c.saveAddress6[domain] 160 } 161 c.saveFakeIPAccess.RUnlock() 162 if cached { 163 return cachedAddress, true 164 } 165 var address netip.Addr 166 _ = c.DB.View(func(tx *bbolt.Tx) error { 167 var bucket *bbolt.Bucket 168 if isIPv6 { 169 bucket = tx.Bucket(bucketFakeIPDomain6) 170 } else { 171 bucket = tx.Bucket(bucketFakeIPDomain4) 172 } 173 if bucket == nil { 174 return nil 175 } 176 address = M.AddrFromIP(bucket.Get([]byte(domain))) 177 return nil 178 }) 179 return address, address.IsValid() 180 } 181 182 func (c *CacheFile) FakeIPReset() error { 183 return c.DB.Batch(func(tx *bbolt.Tx) error { 184 err := tx.DeleteBucket(bucketFakeIP) 185 if err != nil { 186 return err 187 } 188 err = tx.DeleteBucket(bucketFakeIPDomain4) 189 if err != nil { 190 return err 191 } 192 return tx.DeleteBucket(bucketFakeIPDomain6) 193 }) 194 }