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
 		}