github.com/EagleQL/Xray-core@v1.4.3/app/dns/fakedns/fake.go (about) 1 package fakedns 2 3 import ( 4 "context" 5 "math" 6 "math/big" 7 gonet "net" 8 "time" 9 10 "github.com/xtls/xray-core/common" 11 "github.com/xtls/xray-core/common/cache" 12 "github.com/xtls/xray-core/common/net" 13 "github.com/xtls/xray-core/features/dns" 14 ) 15 16 type Holder struct { 17 domainToIP cache.Lru 18 ipRange *gonet.IPNet 19 20 config *FakeDnsPool 21 } 22 23 func (*Holder) Type() interface{} { 24 return (*dns.FakeDNSEngine)(nil) 25 } 26 27 func (fkdns *Holder) Start() error { 28 return fkdns.initializeFromConfig() 29 } 30 31 func (fkdns *Holder) Close() error { 32 fkdns.domainToIP = nil 33 fkdns.ipRange = nil 34 return nil 35 } 36 37 func NewFakeDNSHolder() (*Holder, error) { 38 var fkdns *Holder 39 var err error 40 41 if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil { 42 return nil, newError("Unable to create Fake Dns Engine").Base(err).AtError() 43 } 44 err = fkdns.initialize(dns.FakeIPPool, 65535) 45 if err != nil { 46 return nil, err 47 } 48 return fkdns, nil 49 } 50 51 func NewFakeDNSHolderConfigOnly(conf *FakeDnsPool) (*Holder, error) { 52 return &Holder{nil, nil, conf}, nil 53 } 54 55 func (fkdns *Holder) initializeFromConfig() error { 56 return fkdns.initialize(fkdns.config.IpPool, int(fkdns.config.LruSize)) 57 } 58 59 func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error { 60 var ipRange *gonet.IPNet 61 var err error 62 63 if _, ipRange, err = gonet.ParseCIDR(ipPoolCidr); err != nil { 64 return newError("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError() 65 } 66 67 ones, bits := ipRange.Mask.Size() 68 rooms := bits - ones 69 if math.Log2(float64(lruSize)) >= float64(rooms) { 70 return newError("LRU size is bigger than subnet size").AtError() 71 } 72 fkdns.domainToIP = cache.NewLru(lruSize) 73 fkdns.ipRange = ipRange 74 return nil 75 } 76 77 // GetFakeIPForDomain check and generate a fake IP for a domain name 78 func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address { 79 if v, ok := fkdns.domainToIP.Get(domain); ok { 80 return []net.Address{v.(net.Address)} 81 } 82 var currentTimeMillis = uint64(time.Now().UnixNano() / 1e6) 83 ones, bits := fkdns.ipRange.Mask.Size() 84 rooms := bits - ones 85 if rooms < 64 { 86 currentTimeMillis %= (uint64(1) << rooms) 87 } 88 var bigIntIP = big.NewInt(0).SetBytes(fkdns.ipRange.IP) 89 bigIntIP = bigIntIP.Add(bigIntIP, new(big.Int).SetUint64(currentTimeMillis)) 90 var ip net.Address 91 for { 92 ip = net.IPAddress(bigIntIP.Bytes()) 93 94 // if we run for a long time, we may go back to beginning and start seeing the IP in use 95 if _, ok := fkdns.domainToIP.PeekKeyFromValue(ip); !ok { 96 break 97 } 98 99 bigIntIP = bigIntIP.Add(bigIntIP, big.NewInt(1)) 100 if !fkdns.ipRange.Contains(bigIntIP.Bytes()) { 101 bigIntIP = big.NewInt(0).SetBytes(fkdns.ipRange.IP) 102 } 103 } 104 fkdns.domainToIP.Put(domain, ip) 105 return []net.Address{ip} 106 } 107 108 // GetDomainFromFakeDNS check if an IP is a fake IP and have corresponding domain name 109 func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string { 110 if !ip.Family().IsIP() || !fkdns.ipRange.Contains(ip.IP()) { 111 return "" 112 } 113 if k, ok := fkdns.domainToIP.GetKeyFromValue(ip); ok { 114 return k.(string) 115 } 116 newError("A fake ip request to ", ip, ", however there is no matching domain name in fake DNS").AtInfo().WriteToLog() 117 return "" 118 } 119 120 // GetFakeIPRange return fake IP range from configuration 121 func (fkdns *Holder) GetFakeIPRange() *gonet.IPNet { 122 return fkdns.ipRange 123 } 124 125 func init() { 126 common.Must(common.RegisterConfig((*FakeDnsPool)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 127 var f *Holder 128 var err error 129 if f, err = NewFakeDNSHolderConfigOnly(config.(*FakeDnsPool)); err != nil { 130 return nil, err 131 } 132 return f, nil 133 })) 134 }