|
|
|
@ -173,7 +173,7 @@ type Resolver interface { |
|
|
|
Resolve(host string) ([]net.IP, error) |
|
|
|
// Exchange performs a synchronous query,
|
|
|
|
// It sends the message query and waits for a reply.
|
|
|
|
Exchange(ctx context.Context, query []byte) (reply []byte, err error) |
|
|
|
Exchange(ip net.IP, ctx context.Context, query []byte) (reply []byte, err error) |
|
|
|
} |
|
|
|
|
|
|
|
// ReloadResolver is resolover that support live reloading.
|
|
|
|
@ -282,7 +282,7 @@ func (r *resolver) Resolve(host string) (ips []net.IP, err error) { |
|
|
|
|
|
|
|
ctx := context.Background() |
|
|
|
for _, ns := range r.copyServers() { |
|
|
|
ips, err = r.resolve(ctx, ns.exchanger, host) |
|
|
|
ips, err = r.resolve(ip, ctx, ns.exchanger, host) |
|
|
|
if err != nil { |
|
|
|
log.Logf("[resolver] %s via %s : %s", host, ns.String(), err) |
|
|
|
continue |
|
|
|
@ -299,7 +299,7 @@ func (r *resolver) Resolve(host string) (ips []net.IP, err error) { |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
func (r *resolver) resolve(ctx context.Context, ex Exchanger, host string) (ips []net.IP, err error) { |
|
|
|
func (r *resolver) resolve(ip net.IP, ctx context.Context, ex Exchanger, host string) (ips []net.IP, err error) { |
|
|
|
if ex == nil { |
|
|
|
return |
|
|
|
} |
|
|
|
@ -309,36 +309,36 @@ func (r *resolver) resolve(ctx context.Context, ex Exchanger, host string) (ips |
|
|
|
r.mux.RUnlock() |
|
|
|
|
|
|
|
if prefer == "ipv6" { // prefer ipv6
|
|
|
|
if ips, err = r.resolve6(ctx, ex, host); len(ips) > 0 { |
|
|
|
if ips, err = r.resolve6(ip, ctx, ex, host); len(ips) > 0 { |
|
|
|
return |
|
|
|
} |
|
|
|
return r.resolve4(ctx, ex, host) |
|
|
|
return r.resolve4(ip, ctx, ex, host) |
|
|
|
} |
|
|
|
|
|
|
|
if ips, err = r.resolve4(ctx, ex, host); len(ips) > 0 { |
|
|
|
if ips, err = r.resolve4(ip, ctx, ex, host); len(ips) > 0 { |
|
|
|
return |
|
|
|
} |
|
|
|
return r.resolve6(ctx, ex, host) |
|
|
|
return r.resolve6(ip, ctx, ex, host) |
|
|
|
} |
|
|
|
|
|
|
|
func (r *resolver) resolve4(ctx context.Context, ex Exchanger, host string) (ips []net.IP, err error) { |
|
|
|
func (r *resolver) resolve4(ip net.IP, ctx context.Context, ex Exchanger, host string) (ips []net.IP, err error) { |
|
|
|
mq := dns.Msg{} |
|
|
|
mq.SetQuestion(dns.Fqdn(host), dns.TypeA) |
|
|
|
return r.resolveIPs(ctx, ex, &mq) |
|
|
|
return r.resolveIPs(ip, ctx, ex, &mq) |
|
|
|
} |
|
|
|
|
|
|
|
func (r *resolver) resolve6(ctx context.Context, ex Exchanger, host string) (ips []net.IP, err error) { |
|
|
|
func (r *resolver) resolve6(ip net.IP, ctx context.Context, ex Exchanger, host string) (ips []net.IP, err error) { |
|
|
|
mq := dns.Msg{} |
|
|
|
mq.SetQuestion(dns.Fqdn(host), dns.TypeAAAA) |
|
|
|
return r.resolveIPs(ctx, ex, &mq) |
|
|
|
return r.resolveIPs(ip, ctx, ex, &mq) |
|
|
|
} |
|
|
|
|
|
|
|
func (r *resolver) resolveIPs(ctx context.Context, ex Exchanger, mq *dns.Msg) (ips []net.IP, err error) { |
|
|
|
func (r *resolver) resolveIPs(ip net.IP, ctx context.Context, ex Exchanger, mq *dns.Msg) (ips []net.IP, err error) { |
|
|
|
key := newResolverCacheKey(&mq.Question[0]) |
|
|
|
mr := r.cache.loadCache(key) |
|
|
|
if mr == nil { |
|
|
|
r.addSubnetOpt(mq) |
|
|
|
mr, err = r.exchangeMsg(ctx, ex, mq) |
|
|
|
mr, err = r.exchangeMsg(ip, ctx, ex, mq) |
|
|
|
if err != nil { |
|
|
|
return |
|
|
|
} |
|
|
|
@ -379,7 +379,7 @@ func (r *resolver) addSubnetOpt(m *dns.Msg) { |
|
|
|
m.Extra = append(m.Extra, opt) |
|
|
|
} |
|
|
|
|
|
|
|
func (r *resolver) Exchange(ctx context.Context, query []byte) (reply []byte, err error) { |
|
|
|
func (r *resolver) Exchange(ip net.IP, ctx context.Context, query []byte) (reply []byte, err error) { |
|
|
|
mq := &dns.Msg{} |
|
|
|
if err = mq.Unpack(query); err != nil { |
|
|
|
return |
|
|
|
@ -411,7 +411,7 @@ func (r *resolver) Exchange(ctx context.Context, query []byte) (reply []byte, er |
|
|
|
|
|
|
|
for _, ns := range r.copyServers() { |
|
|
|
log.Logf("[dns] exchange message %d via %s: %s", mq.Id, ns.String(), mq.Question[0].String()) |
|
|
|
mr, err = r.exchangeMsg(ctx, ns.exchanger, mq) |
|
|
|
mr, err = r.exchangeMsg(ip, ctx, ns.exchanger, mq) |
|
|
|
if err == nil { |
|
|
|
break |
|
|
|
} |
|
|
|
@ -423,12 +423,12 @@ func (r *resolver) Exchange(ctx context.Context, query []byte) (reply []byte, er |
|
|
|
return mr.Pack() |
|
|
|
} |
|
|
|
|
|
|
|
func (r *resolver) exchangeMsg(ctx context.Context, ex Exchanger, mq *dns.Msg) (mr *dns.Msg, err error) { |
|
|
|
func (r *resolver) exchangeMsg(ip net.IP, ctx context.Context, ex Exchanger, mq *dns.Msg) (mr *dns.Msg, err error) { |
|
|
|
query, err := mq.Pack() |
|
|
|
if err != nil { |
|
|
|
return |
|
|
|
} |
|
|
|
reply, err := ex.Exchange(ctx, query) |
|
|
|
reply, err := ex.Exchange(ip, ctx, query) |
|
|
|
if err != nil { |
|
|
|
return |
|
|
|
} |
|
|
|
@ -657,7 +657,7 @@ func (rc *resolverCache) storeCache(key resolverCacheKey, mr *dns.Msg, ttl time. |
|
|
|
|
|
|
|
// Exchanger is an interface for DNS synchronous query.
|
|
|
|
type Exchanger interface { |
|
|
|
Exchange(ctx context.Context, query []byte) ([]byte, error) |
|
|
|
Exchange(ip net.IP, ctx context.Context, query []byte) ([]byte, error) |
|
|
|
} |
|
|
|
|
|
|
|
type exchangerOptions struct { |
|
|
|
@ -704,9 +704,9 @@ func NewDNSExchanger(addr string, opts ...ExchangerOption) Exchanger { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func (ex *dnsExchanger) Exchange(ctx context.Context, query []byte) ([]byte, error) { |
|
|
|
func (ex *dnsExchanger) Exchange(ip net.IP, ctx context.Context, query []byte) ([]byte, error) { |
|
|
|
t := time.Now() |
|
|
|
c, err := ex.options.chain.DialContext(ctx, |
|
|
|
c, err := ex.options.chain.DialContext(ip, ctx, |
|
|
|
"udp", ex.addr, |
|
|
|
TimeoutChainOption(ex.options.timeout), |
|
|
|
) |
|
|
|
@ -754,9 +754,9 @@ func NewDNSTCPExchanger(addr string, opts ...ExchangerOption) Exchanger { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func (ex *dnsTCPExchanger) Exchange(ctx context.Context, query []byte) ([]byte, error) { |
|
|
|
func (ex *dnsTCPExchanger) Exchange(ip net.IP, ctx context.Context, query []byte) ([]byte, error) { |
|
|
|
t := time.Now() |
|
|
|
c, err := ex.options.chain.DialContext(ctx, |
|
|
|
c, err := ex.options.chain.DialContext(ip, ctx, |
|
|
|
"tcp", ex.addr, |
|
|
|
TimeoutChainOption(ex.options.timeout), |
|
|
|
) |
|
|
|
@ -782,6 +782,7 @@ func (ex *dnsTCPExchanger) Exchange(ctx context.Context, query []byte) ([]byte, |
|
|
|
} |
|
|
|
|
|
|
|
type dotExchanger struct { |
|
|
|
ip net.IP |
|
|
|
addr string |
|
|
|
tlsConfig *tls.Config |
|
|
|
options exchangerOptions |
|
|
|
@ -810,8 +811,8 @@ func NewDoTExchanger(addr string, tlsConfig *tls.Config, opts ...ExchangerOption |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func (ex *dotExchanger) dial(ctx context.Context, network, address string) (conn net.Conn, err error) { |
|
|
|
conn, err = ex.options.chain.DialContext(ctx, |
|
|
|
func (ex *dotExchanger) dial(ip net.IP, ctx context.Context, network, address string) (conn net.Conn, err error) { |
|
|
|
conn, err = ex.options.chain.DialContext(ip, ctx, |
|
|
|
network, address, |
|
|
|
TimeoutChainOption(ex.options.timeout), |
|
|
|
) |
|
|
|
@ -823,9 +824,9 @@ func (ex *dotExchanger) dial(ctx context.Context, network, address string) (conn |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
func (ex *dotExchanger) Exchange(ctx context.Context, query []byte) ([]byte, error) { |
|
|
|
func (ex *dotExchanger) Exchange(ip net.IP, ctx context.Context, query []byte) ([]byte, error) { |
|
|
|
t := time.Now() |
|
|
|
c, err := ex.dial(ctx, "tcp", ex.addr) |
|
|
|
c, err := ex.dial(ip, ctx, "tcp", ex.addr) |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
@ -881,8 +882,9 @@ func NewDoHExchanger(urlStr *url.URL, tlsConfig *tls.Config, opts ...ExchangerOp |
|
|
|
return ex |
|
|
|
} |
|
|
|
|
|
|
|
func (ex *dohExchanger) dialContext(ctx context.Context, network, address string) (net.Conn, error) { |
|
|
|
return ex.options.chain.DialContext(ctx, |
|
|
|
func (ex *dohExchanger) dialContext(ip net.IP, ctx context.Context, network, address string) (net.Conn, error) { |
|
|
|
// todo::
|
|
|
|
return ex.options.chain.DialContext(ip, ctx, |
|
|
|
network, address, |
|
|
|
TimeoutChainOption(ex.options.timeout), |
|
|
|
) |
|
|
|
|