mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-05-04 11:18:40 +00:00
feat: add queryStrategy option for DNS
This commit is contained in:
parent
41d3f31447
commit
8382b29922
16 changed files with 419 additions and 267 deletions
|
@ -21,7 +21,35 @@ type Client interface {
|
|||
features.Feature
|
||||
|
||||
// LookupIP returns IP address for the given domain. IPs may contain IPv4 and/or IPv6 addresses.
|
||||
LookupIP(domain string, option IPOption) ([]net.IP, error)
|
||||
LookupIP(domain string) ([]net.IP, error)
|
||||
}
|
||||
|
||||
// IPv4Lookup is an optional feature for querying IPv4 addresses only.
|
||||
//
|
||||
// xray:api:beta
|
||||
type IPv4Lookup interface {
|
||||
LookupIPv4(domain string) ([]net.IP, error)
|
||||
}
|
||||
|
||||
// IPv6Lookup is an optional feature for querying IPv6 addresses only.
|
||||
//
|
||||
// xray:api:beta
|
||||
type IPv6Lookup interface {
|
||||
LookupIPv6(domain string) ([]net.IP, error)
|
||||
}
|
||||
|
||||
// ClientWithIPOption is an optional feature for querying DNS information.
|
||||
//
|
||||
// xray:api:beta
|
||||
type ClientWithIPOption interface {
|
||||
// GetIPOption returns IPOption for the DNS client.
|
||||
GetIPOption() *IPOption
|
||||
|
||||
// SetQueryOption sets IPv4Enable and IPv6Enable for the DNS client.
|
||||
SetQueryOption(isIPv4Enable, isIPv6Enable bool)
|
||||
|
||||
// SetFakeDNSOption sets FakeEnable option for DNS client.
|
||||
SetFakeDNSOption(isFakeEnable bool)
|
||||
}
|
||||
|
||||
// ClientType returns the type of Client interface. Can be used for implementing common.HasType.
|
||||
|
|
|
@ -20,41 +20,59 @@ func (*Client) Start() error { return nil }
|
|||
func (*Client) Close() error { return nil }
|
||||
|
||||
// LookupIP implements Client.
|
||||
func (*Client) LookupIP(host string, option dns.IPOption) ([]net.IP, error) {
|
||||
func (*Client) LookupIP(host string) ([]net.IP, error) {
|
||||
ips, err := net.LookupIP(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parsedIPs := make([]net.IP, 0, len(ips))
|
||||
ipv4 := make([]net.IP, 0, len(ips))
|
||||
ipv6 := make([]net.IP, 0, len(ips))
|
||||
for _, ip := range ips {
|
||||
parsed := net.IPAddress(ip)
|
||||
if parsed != nil {
|
||||
parsedIPs = append(parsedIPs, parsed.IP())
|
||||
}
|
||||
}
|
||||
if len(parsedIPs) == 0 {
|
||||
return nil, dns.ErrEmptyResponse
|
||||
}
|
||||
return parsedIPs, nil
|
||||
}
|
||||
|
||||
// LookupIPv4 implements IPv4Lookup.
|
||||
func (c *Client) LookupIPv4(host string) ([]net.IP, error) {
|
||||
ips, err := c.LookupIP(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipv4 := make([]net.IP, 0, len(ips))
|
||||
for _, ip := range ips {
|
||||
if len(ip) == net.IPv4len {
|
||||
ipv4 = append(ipv4, ip)
|
||||
}
|
||||
}
|
||||
if len(ipv4) == 0 {
|
||||
return nil, dns.ErrEmptyResponse
|
||||
}
|
||||
return ipv4, nil
|
||||
}
|
||||
|
||||
// LookupIPv6 implements IPv6Lookup.
|
||||
func (c *Client) LookupIPv6(host string) ([]net.IP, error) {
|
||||
ips, err := c.LookupIP(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipv6 := make([]net.IP, 0, len(ips))
|
||||
for _, ip := range ips {
|
||||
if len(ip) == net.IPv6len {
|
||||
ipv6 = append(ipv6, ip)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case option.IPv4Enable && option.IPv6Enable:
|
||||
if len(parsedIPs) > 0 {
|
||||
return parsedIPs, nil
|
||||
}
|
||||
case option.IPv4Enable:
|
||||
if len(ipv4) > 0 {
|
||||
return ipv4, nil
|
||||
}
|
||||
case option.IPv6Enable:
|
||||
if len(ipv6) > 0 {
|
||||
return ipv6, nil
|
||||
}
|
||||
if len(ipv6) == 0 {
|
||||
return nil, dns.ErrEmptyResponse
|
||||
}
|
||||
return nil, dns.ErrEmptyResponse
|
||||
|
||||
return ipv6, nil
|
||||
}
|
||||
|
||||
// New create a new dns.Client that queries localhost for DNS.
|
||||
|
|
|
@ -26,11 +26,35 @@ func (ctx *ResolvableContext) GetTargetIPs() []net.IP {
|
|||
}
|
||||
|
||||
if domain := ctx.GetTargetDomain(); len(domain) != 0 {
|
||||
ips, err := ctx.dnsClient.LookupIP(domain, dns.IPOption{
|
||||
var lookupFunc func(string) ([]net.IP, error) = ctx.dnsClient.LookupIP
|
||||
ipOption := &dns.IPOption{
|
||||
IPv4Enable: true,
|
||||
IPv6Enable: true,
|
||||
FakeEnable: false,
|
||||
})
|
||||
}
|
||||
|
||||
if c, ok := ctx.dnsClient.(dns.ClientWithIPOption); ok {
|
||||
ipOption = c.GetIPOption()
|
||||
c.SetFakeDNSOption(false) // Skip FakeDNS.
|
||||
} else {
|
||||
newError("ctx.dnsClient doesn't implement ClientWithIPOption").AtDebug().WriteToLog()
|
||||
}
|
||||
|
||||
switch {
|
||||
case ipOption.IPv4Enable && !ipOption.IPv6Enable:
|
||||
if lookupIPv4, ok := ctx.dnsClient.(dns.IPv4Lookup); ok {
|
||||
lookupFunc = lookupIPv4.LookupIPv4
|
||||
} else {
|
||||
newError("ctx.dnsClient doesn't implement IPv4Lookup. Use LookupIP instead.").AtDebug().WriteToLog()
|
||||
}
|
||||
case !ipOption.IPv4Enable && ipOption.IPv6Enable:
|
||||
if lookupIPv6, ok := ctx.dnsClient.(dns.IPv6Lookup); ok {
|
||||
lookupFunc = lookupIPv6.LookupIPv6
|
||||
} else {
|
||||
newError("ctx.dnsClient doesn't implement IPv6Lookup. Use LookupIP instead.").AtDebug().WriteToLog()
|
||||
}
|
||||
}
|
||||
|
||||
ips, err := lookupFunc(domain)
|
||||
if err == nil {
|
||||
ctx.resolvedIPs = ips
|
||||
return ips
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue