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  }