mirror of
https://github.com/apernet/hysteria.git
synced 2025-04-03 04:27:39 +03:00
84 lines
1.9 KiB
Go
84 lines
1.9 KiB
Go
package outbounds
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/babolivier/go-doh-client"
|
|
)
|
|
|
|
// dohResolver is a PluggableOutbound DNS resolver that resolves hostnames
|
|
// using the user-provided DNS-over-HTTPS server.
|
|
type dohResolver struct {
|
|
Resolver *doh.Resolver
|
|
Next PluggableOutbound
|
|
}
|
|
|
|
func NewDoHResolver(host string, timeout time.Duration, sni string, insecure bool, next PluggableOutbound) PluggableOutbound {
|
|
tr := http.DefaultTransport.(*http.Transport).Clone()
|
|
tr.TLSClientConfig = &tls.Config{
|
|
ServerName: sni,
|
|
InsecureSkipVerify: insecure,
|
|
}
|
|
return &dohResolver{
|
|
Resolver: &doh.Resolver{
|
|
Host: host,
|
|
Class: doh.IN,
|
|
HTTPClient: &http.Client{
|
|
Transport: tr,
|
|
Timeout: timeoutOrDefault(timeout),
|
|
},
|
|
},
|
|
Next: next,
|
|
}
|
|
}
|
|
|
|
func (r *dohResolver) resolve(reqAddr *AddrEx) {
|
|
if tryParseIP(reqAddr) {
|
|
// The host is already an IP address, we don't need to resolve it.
|
|
return
|
|
}
|
|
type lookupResult struct {
|
|
ip net.IP
|
|
err error
|
|
}
|
|
ch4, ch6 := make(chan lookupResult, 1), make(chan lookupResult, 1)
|
|
go func() {
|
|
recs, _, err := r.Resolver.LookupA(reqAddr.Host)
|
|
var ip net.IP
|
|
if err == nil && len(recs) > 0 {
|
|
ip = net.ParseIP(recs[0].IP4).To4()
|
|
}
|
|
ch4 <- lookupResult{ip, err}
|
|
}()
|
|
go func() {
|
|
recs, _, err := r.Resolver.LookupAAAA(reqAddr.Host)
|
|
var ip net.IP
|
|
if err == nil && len(recs) > 0 {
|
|
ip = net.ParseIP(recs[0].IP6).To16()
|
|
}
|
|
ch6 <- lookupResult{ip, err}
|
|
}()
|
|
result4, result6 := <-ch4, <-ch6
|
|
reqAddr.ResolveInfo = &ResolveInfo{
|
|
IPv4: result4.ip,
|
|
IPv6: result6.ip,
|
|
}
|
|
if result4.err != nil {
|
|
reqAddr.ResolveInfo.Err = result4.err
|
|
} else if result6.err != nil {
|
|
reqAddr.ResolveInfo.Err = result6.err
|
|
}
|
|
}
|
|
|
|
func (r *dohResolver) TCP(reqAddr *AddrEx) (net.Conn, error) {
|
|
r.resolve(reqAddr)
|
|
return r.Next.TCP(reqAddr)
|
|
}
|
|
|
|
func (r *dohResolver) UDP(reqAddr *AddrEx) (UDPConn, error) {
|
|
r.resolve(reqAddr)
|
|
return r.Next.UDP(reqAddr)
|
|
}
|