Skip to content

Commit

Permalink
Feature: sync missing resolver logic from premium, but still net.IP o…
Browse files Browse the repository at this point in the history
…n opensource
  • Loading branch information
Dreamacro committed Aug 13, 2022
1 parent 5940f62 commit 3946d77
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 43 deletions.
83 changes: 61 additions & 22 deletions component/resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package resolver
import (
"context"
"errors"
"fmt"
"math/rand"
"net"
"strings"
Expand Down Expand Up @@ -33,29 +34,32 @@ var (
)

type Resolver interface {
LookupIP(ctx context.Context, host string) ([]net.IP, error)
LookupIPv4(ctx context.Context, host string) ([]net.IP, error)
LookupIPv6(ctx context.Context, host string) ([]net.IP, error)
ResolveIP(host string) (ip net.IP, err error)
ResolveIPv4(host string) (ip net.IP, err error)
ResolveIPv6(host string) (ip net.IP, err error)
}

// ResolveIPv4 with a host, return ipv4
func ResolveIPv4(host string) (net.IP, error) {
// LookupIPv4 with a host, return ipv4 list
func LookupIPv4(ctx context.Context, host string) ([]net.IP, error) {
if node := DefaultHosts.Search(host); node != nil {
if ip := node.Data.(net.IP).To4(); ip != nil {
return ip, nil
return []net.IP{ip}, nil
}
}

ip := net.ParseIP(host)
if ip != nil {
if !strings.Contains(host, ":") {
return ip, nil
return []net.IP{ip}, nil
}
return nil, ErrIPVersion
}

if DefaultResolver != nil {
return DefaultResolver.ResolveIPv4(host)
return DefaultResolver.LookupIPv4(ctx, host)
}

ctx, cancel := context.WithTimeout(context.Background(), DefaultDNSTimeout)
Expand All @@ -67,31 +71,42 @@ func ResolveIPv4(host string) (net.IP, error) {
return nil, ErrIPNotFound
}

return ipAddrs[rand.Intn(len(ipAddrs))], nil
return ipAddrs, nil
}

// ResolveIPv6 with a host, return ipv6
func ResolveIPv6(host string) (net.IP, error) {
// ResolveIPv4 with a host, return ipv4
func ResolveIPv4(host string) (net.IP, error) {
ips, err := LookupIPv4(context.Background(), host)
if err != nil {
return nil, err
} else if len(ips) == 0 {
return nil, fmt.Errorf("%w: %s", ErrIPNotFound, host)
}
return ips[rand.Intn(len(ips))], nil
}

// LookupIPv6 with a host, return ipv6 list
func LookupIPv6(ctx context.Context, host string) ([]net.IP, error) {
if DisableIPv6 {
return nil, ErrIPv6Disabled
}

if node := DefaultHosts.Search(host); node != nil {
if ip := node.Data.(net.IP).To16(); ip != nil {
return ip, nil
return []net.IP{ip}, nil
}
}

ip := net.ParseIP(host)
if ip != nil {
if strings.Contains(host, ":") {
return ip, nil
return []net.IP{ip}, nil
}
return nil, ErrIPVersion
}

if DefaultResolver != nil {
return DefaultResolver.ResolveIPv6(host)
return DefaultResolver.LookupIPv6(ctx, host)
}

ctx, cancel := context.WithTimeout(context.Background(), DefaultDNSTimeout)
Expand All @@ -103,38 +118,62 @@ func ResolveIPv6(host string) (net.IP, error) {
return nil, ErrIPNotFound
}

return ipAddrs[rand.Intn(len(ipAddrs))], nil
return ipAddrs, nil
}

// ResolveIPWithResolver same as ResolveIP, but with a resolver
func ResolveIPWithResolver(host string, r Resolver) (net.IP, error) {
// ResolveIPv6 with a host, return ipv6
func ResolveIPv6(host string) (net.IP, error) {
ips, err := LookupIPv6(context.Background(), host)
if err != nil {
return nil, err
} else if len(ips) == 0 {
return nil, fmt.Errorf("%w: %s", ErrIPNotFound, host)
}
return ips[rand.Intn(len(ips))], nil
}

// LookupIPWithResolver same as ResolveIP, but with a resolver
func LookupIPWithResolver(ctx context.Context, host string, r Resolver) ([]net.IP, error) {
if node := DefaultHosts.Search(host); node != nil {
return node.Data.(net.IP), nil
return []net.IP{node.Data.(net.IP)}, nil
}

if r != nil {
if DisableIPv6 {
return r.ResolveIPv4(host)
return r.LookupIPv4(ctx, host)
}
return r.ResolveIP(host)
return r.LookupIP(ctx, host)
} else if DisableIPv6 {
return ResolveIPv4(host)
return LookupIPv4(ctx, host)
}

ip := net.ParseIP(host)
if ip != nil {
return ip, nil
return []net.IP{ip}, nil
}

ipAddr, err := net.ResolveIPAddr("ip", host)
ips, err := net.DefaultResolver.LookupIP(ctx, "ip", host)
if err != nil {
return nil, err
} else if len(ips) == 0 {
return nil, ErrIPNotFound
}

return ipAddr.IP, nil
return ips, nil
}

// ResolveIP with a host, return ip
func LookupIP(ctx context.Context, host string) ([]net.IP, error) {
return LookupIPWithResolver(ctx, host, DefaultResolver)
}

// ResolveIP with a host, return ip
func ResolveIP(host string) (net.IP, error) {
return ResolveIPWithResolver(host, DefaultResolver)
ips, err := LookupIP(context.Background(), host)
if err != nil {
return nil, err
} else if len(ips) == 0 {
return nil, fmt.Errorf("%w: %s", ErrIPNotFound, host)
}
return ips[rand.Intn(len(ips))], nil
}
7 changes: 6 additions & 1 deletion dns/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"crypto/tls"
"fmt"
"math/rand"
"net"
"strings"

Expand Down Expand Up @@ -36,9 +37,13 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error)
return nil, fmt.Errorf("dns %s not a valid ip", c.host)
}
} else {
if ip, err = resolver.ResolveIPWithResolver(c.host, c.r); err != nil {
ips, err := resolver.LookupIPWithResolver(ctx, c.host, c.r)
if err != nil {
return nil, fmt.Errorf("use default dns resolve failed: %w", err)
} else if len(ips) == 0 {
return nil, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, c.host)
}
ip = ips[rand.Intn(len(ips))]
}

network := "udp"
Expand Down
7 changes: 6 additions & 1 deletion dns/doh.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"bytes"
"context"
"crypto/tls"
"fmt"
"io"
"math/rand"
"net"
"net/http"

Expand Down Expand Up @@ -91,10 +93,13 @@ func newDoHClient(url, iface string, r *Resolver) *dohClient {
return nil, err
}

ip, err := resolver.ResolveIPWithResolver(host, r)
ips, err := resolver.LookupIPWithResolver(ctx, host, r)
if err != nil {
return nil, err
} else if len(ips) == 0 {
return nil, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, host)
}
ip := ips[rand.Intn(len(ips))]

options := []dialer.Option{}
if iface != "" {
Expand Down
69 changes: 52 additions & 17 deletions dns/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,23 @@ type Resolver struct {
policy *trie.DomainTrie
}

// ResolveIP request with TypeA and TypeAAAA, priority return TypeA
func (r *Resolver) ResolveIP(host string) (ip net.IP, err error) {
ch := make(chan net.IP, 1)
// LookupIP request with TypeA and TypeAAAA, priority return TypeA
func (r *Resolver) LookupIP(ctx context.Context, host string) (ip []net.IP, err error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()

ch := make(chan []net.IP, 1)

go func() {
defer close(ch)
ip, err := r.resolveIP(host, D.TypeAAAA)
ip, err := r.lookupIP(ctx, host, D.TypeAAAA)
if err != nil {
return
}
ch <- ip
}()

ip, err = r.resolveIP(host, D.TypeA)
ip, err = r.lookupIP(ctx, host, D.TypeA)
if err == nil {
return
}
Expand All @@ -67,14 +71,47 @@ func (r *Resolver) ResolveIP(host string) (ip net.IP, err error) {
return ip, nil
}

// ResolveIP request with TypeA and TypeAAAA, priority return TypeA
func (r *Resolver) ResolveIP(host string) (ip net.IP, err error) {
ips, err := r.LookupIP(context.Background(), host)
if err != nil {
return nil, err
} else if len(ips) == 0 {
return nil, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, host)
}
return ips[rand.Intn(len(ips))], nil
}

// LookupIPv4 request with TypeA
func (r *Resolver) LookupIPv4(ctx context.Context, host string) ([]net.IP, error) {
return r.lookupIP(ctx, host, D.TypeA)
}

// ResolveIPv4 request with TypeA
func (r *Resolver) ResolveIPv4(host string) (ip net.IP, err error) {
return r.resolveIP(host, D.TypeA)
ips, err := r.lookupIP(context.Background(), host, D.TypeA)
if err != nil {
return nil, err
} else if len(ips) == 0 {
return nil, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, host)
}
return ips[rand.Intn(len(ips))], nil
}

// LookupIPv6 request with TypeAAAA
func (r *Resolver) LookupIPv6(ctx context.Context, host string) ([]net.IP, error) {
return r.lookupIP(ctx, host, D.TypeAAAA)
}

// ResolveIPv6 request with TypeAAAA
func (r *Resolver) ResolveIPv6(host string) (ip net.IP, err error) {
return r.resolveIP(host, D.TypeAAAA)
ips, err := r.lookupIP(context.Background(), host, D.TypeAAAA)
if err != nil {
return nil, err
} else if len(ips) == 0 {
return nil, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, host)
}
return ips[rand.Intn(len(ips))], nil
}

func (r *Resolver) shouldIPFallback(ip net.IP) bool {
Expand Down Expand Up @@ -253,14 +290,15 @@ func (r *Resolver) ipExchange(ctx context.Context, m *D.Msg) (msg *D.Msg, err er
return
}

func (r *Resolver) resolveIP(host string, dnsType uint16) (ip net.IP, err error) {
ip = net.ParseIP(host)
func (r *Resolver) lookupIP(ctx context.Context, host string, dnsType uint16) ([]net.IP, error) {
ip := net.ParseIP(host)
if ip != nil {
isIPv4 := ip.To4() != nil
ip4 := ip.To4()
isIPv4 := ip4 != nil
if dnsType == D.TypeAAAA && !isIPv4 {
return ip, nil
return []net.IP{ip}, nil
} else if dnsType == D.TypeA && isIPv4 {
return ip, nil
return []net.IP{ip4}, nil
} else {
return nil, resolver.ErrIPVersion
}
Expand All @@ -275,13 +313,10 @@ func (r *Resolver) resolveIP(host string, dnsType uint16) (ip net.IP, err error)
}

ips := msgToIP(msg)
ipLength := len(ips)
if ipLength == 0 {
if len(ips) == 0 {
return nil, resolver.ErrIPNotFound
}

ip = ips[rand.Intn(ipLength)]
return
return ips, nil
}

func (r *Resolver) msgToDomain(msg *D.Msg) string {
Expand Down
6 changes: 4 additions & 2 deletions tunnel/tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,13 @@ func handleUDPConn(packet *inbound.PacketAdapter) {

// local resolve UDP dns
if !metadata.Resolved() {
ip, err := resolver.ResolveIP(metadata.Host)
ips, err := resolver.LookupIP(context.Background(), metadata.Host)
if err != nil {
return
} else if len(ips) == 0 {
return
}
metadata.DstIP = ip
metadata.DstIP = ips[0]
}

key := packet.LocalAddr().String()
Expand Down

0 comments on commit 3946d77

Please sign in to comment.