mirror of
https://github.com/cmz0228/hysteria-dev.git
synced 2025-08-20 08:11:46 +00:00
feat: DNS over HTTPS resolver
This commit is contained in:
84
extras/outbounds/dns_https.go
Normal file
84
extras/outbounds/dns_https.go
Normal file
@@ -0,0 +1,84 @@
|
||||
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)
|
||||
}
|
Reference in New Issue
Block a user