From 4f634edaa9b967273c7cdef2814e85ac4a00decd Mon Sep 17 00:00:00 2001 From: Skyxim Date: Thu, 28 Apr 2022 22:21:48 +0800 Subject: [PATCH] refactor: doq dialer --- dns/{quic.go => doq.go} | 53 ++++++++++++++++++++++++++++++++++++++++- dns/util.go | 2 +- 2 files changed, 53 insertions(+), 2 deletions(-) rename dns/{quic.go => doq.go} (74%) diff --git a/dns/quic.go b/dns/doq.go similarity index 74% rename from dns/quic.go rename to dns/doq.go index 0a080a4e..a0682745 100644 --- a/dns/quic.go +++ b/dns/doq.go @@ -5,6 +5,10 @@ import ( "context" "crypto/tls" "fmt" + "github.com/Dreamacro/clash/component/dialer" + "github.com/Dreamacro/clash/component/resolver" + "net" + "strconv" "sync" "time" @@ -19,10 +23,20 @@ var bytesPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }} type quicClient struct { addr string + r *Resolver session quic.Connection + proxyAdapter string sync.RWMutex // protects session and bytesPool } +func newDOQ(r *Resolver, addr, proxyAdapter string) *quicClient { + return &quicClient{ + addr: addr, + r: r, + proxyAdapter: proxyAdapter, + } +} + func (dc *quicClient) Exchange(m *D.Msg) (msg *D.Msg, err error) { return dc.ExchangeContext(context.Background(), m) } @@ -127,7 +141,44 @@ func (dc *quicClient) openSession() (quic.Connection, error) { } log.Debugln("opening session to %s", dc.addr) - session, err := quic.DialAddrContext(context.Background(), dc.addr, tlsConfig, quicConfig) + var ( + udp net.PacketConn + err error + ) + + host, port, err := net.SplitHostPort(dc.addr) + if err != nil { + return nil, err + } + + ip, err := resolver.ResolveIPv4WithResolver(host, dc.r) + if err != nil { + return nil, err + } + + p, err := strconv.Atoi(port) + udpAddr := net.UDPAddr{IP: ip.AsSlice(), Port: p} + + if dc.proxyAdapter == "" { + udp, err = dialer.ListenPacket(context.Background(), "udp", "") + if err != nil { + return nil, err + } + } else { + conn, err := dialContextWithProxyAdapter(context.Background(), dc.proxyAdapter, "udp", ip, port) + if err != nil { + return nil, err + } + + wrapConn, ok := conn.(*wrapPacketConn) + if !ok { + return nil, fmt.Errorf("quio create packet failed") + } + + udp = wrapConn.PacketConn + } + + session, err := quic.Dial(udp, &udpAddr, host, tlsConfig, quicConfig) if err != nil { return nil, fmt.Errorf("failed to open QUIC session: %w", err) } diff --git a/dns/util.go b/dns/util.go index 2cc13074..bc86d4fa 100644 --- a/dns/util.go +++ b/dns/util.go @@ -64,7 +64,7 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { ret = append(ret, newDHCPClient(s.Addr)) continue case "quic": - ret = append(ret, &quicClient{addr: s.Addr}) + ret = append(ret, newDOQ(resolver, s.Addr, s.ProxyAdapter)) continue }