github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/features/dns/client.go (about) 1 package dns 2 3 import ( 4 "github.com/v2fly/v2ray-core/v5/common/errors" 5 "github.com/v2fly/v2ray-core/v5/common/net" 6 "github.com/v2fly/v2ray-core/v5/common/serial" 7 "github.com/v2fly/v2ray-core/v5/features" 8 ) 9 10 // IPOption is an object for IP query options. 11 type IPOption struct { 12 IPv4Enable bool 13 IPv6Enable bool 14 FakeEnable bool 15 } 16 17 func (opt IPOption) With(other IPOption) IPOption { 18 return IPOption{ 19 IPv4Enable: opt.IPv4Enable && other.IPv4Enable, 20 IPv6Enable: opt.IPv6Enable && other.IPv6Enable, 21 FakeEnable: opt.FakeEnable && other.FakeEnable, 22 } 23 } 24 25 func (opt IPOption) IsValid() bool { 26 return opt.IPv4Enable || opt.IPv6Enable 27 } 28 29 // Client is a V2Ray feature for querying DNS information. 30 // 31 // v2ray:api:stable 32 type Client interface { 33 features.Feature 34 35 // LookupIP returns IP address for the given domain. IPs may contain IPv4 and/or IPv6 addresses. 36 LookupIP(domain string) ([]net.IP, error) 37 } 38 39 // IPv4Lookup is an optional feature for querying IPv4 addresses only. 40 // 41 // v2ray:api:beta 42 type IPv4Lookup interface { 43 LookupIPv4(domain string) ([]net.IP, error) 44 } 45 46 // IPv6Lookup is an optional feature for querying IPv6 addresses only. 47 // 48 // v2ray:api:beta 49 type IPv6Lookup interface { 50 LookupIPv6(domain string) ([]net.IP, error) 51 } 52 53 // LookupIPWithOption is a helper function for querying DNS information from a dns.Client with dns.IPOption. 54 // 55 // v2ray:api:beta 56 func LookupIPWithOption(client Client, domain string, option IPOption) ([]net.IP, error) { 57 if option.FakeEnable { 58 if clientWithFakeDNS, ok := client.(ClientWithFakeDNS); ok { 59 client = clientWithFakeDNS.AsFakeDNSClient() 60 } 61 } 62 if option.IPv4Enable && !option.IPv6Enable { 63 if ipv4Lookup, ok := client.(IPv4Lookup); ok { 64 return ipv4Lookup.LookupIPv4(domain) 65 } else { 66 return nil, errors.New("dns.Client doesn't implement IPv4Lookup") 67 } 68 } 69 if option.IPv6Enable && !option.IPv4Enable { 70 if ipv6Lookup, ok := client.(IPv6Lookup); ok { 71 return ipv6Lookup.LookupIPv6(domain) 72 } else { 73 return nil, errors.New("dns.Client doesn't implement IPv6Lookup") 74 } 75 } 76 return client.LookupIP(domain) 77 } 78 79 // ClientType returns the type of Client interface. Can be used for implementing common.HasType. 80 // 81 // v2ray:api:beta 82 func ClientType() interface{} { 83 return (*Client)(nil) 84 } 85 86 // ErrEmptyResponse indicates that DNS query succeeded but no answer was returned. 87 var ErrEmptyResponse = errors.New("empty response") 88 89 type RCodeError uint16 90 91 func (e RCodeError) Error() string { 92 return serial.Concat("rcode: ", uint16(e)) 93 } 94 95 func RCodeFromError(err error) uint16 { 96 if err == nil { 97 return 0 98 } 99 cause := errors.Cause(err) 100 if r, ok := cause.(RCodeError); ok { 101 return uint16(r) 102 } 103 return 0 104 }