Skip to content

Commit ca24e51

Browse files
committed
Add a UDP connection pool
1 parent 5aec3d3 commit ca24e51

2 files changed

Lines changed: 62 additions & 6 deletions

File tree

dnscrypt-proxy/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ func (app *App) AppMain() {
153153
}
154154

155155
func (app *App) Stop(service service.Service) error {
156+
if app.proxy != nil && app.proxy.udpConnPool != nil {
157+
app.proxy.udpConnPool.Close()
158+
}
156159
if err := PidFileRemove(); err != nil {
157160
dlog.Warnf("Failed to remove the PID file: [%v]", err)
158161
}

dnscrypt-proxy/proxy.go

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
clocksmith "github.com/jedisct1/go-clocksmith"
1717
stamps "github.com/jedisct1/go-dnsstamps"
1818
"golang.org/x/crypto/curve25519"
19+
netproxy "golang.org/x/net/proxy"
1920
)
2021

2122
type Proxy struct {
@@ -108,6 +109,7 @@ type Proxy struct {
108109
SourceODoH bool
109110
listenersMu sync.Mutex
110111
ipCryptConfig *IPCryptConfig
112+
udpConnPool *UDPConnPool
111113
}
112114

113115
func (proxy *Proxy) registerUDPListener(conn *net.UDPConn) {
@@ -587,18 +589,68 @@ func (proxy *Proxy) exchangeWithUDPServer(
587589
if serverInfo.Relay != nil && serverInfo.Relay.Dnscrypt != nil {
588590
upstreamAddr = serverInfo.Relay.Dnscrypt.RelayUDPAddr
589591
}
590-
var err error
591-
var pc net.Conn
592+
592593
proxyDialer := proxy.xTransport.proxyDialer
593-
if proxyDialer == nil {
594-
pc, err = net.DialTimeout("udp", upstreamAddr.String(), serverInfo.Timeout)
595-
} else {
596-
pc, err = (*proxyDialer).Dial("udp", upstreamAddr.String())
594+
if proxyDialer != nil {
595+
return proxy.exchangeWithUDPServerViaProxy(serverInfo, sharedKey, encryptedQuery, clientNonce, upstreamAddr, proxyDialer)
597596
}
597+
598+
pc, err := proxy.udpConnPool.Get(upstreamAddr)
599+
if err != nil {
600+
return nil, err
601+
}
602+
603+
if err := pc.SetDeadline(time.Now().Add(serverInfo.Timeout)); err != nil {
604+
proxy.udpConnPool.Discard(pc)
605+
return nil, err
606+
}
607+
608+
query := encryptedQuery
609+
if serverInfo.Relay != nil && serverInfo.Relay.Dnscrypt != nil {
610+
proxy.prepareForRelay(serverInfo.UDPAddr.IP, serverInfo.UDPAddr.Port, &query)
611+
}
612+
613+
encryptedResponse := make([]byte, MaxDNSPacketSize)
614+
var readErr error
615+
for tries := 2; tries > 0; tries-- {
616+
if _, err := pc.Write(query); err != nil {
617+
proxy.udpConnPool.Discard(pc)
618+
return nil, err
619+
}
620+
length, err := pc.Read(encryptedResponse)
621+
if err == nil {
622+
encryptedResponse = encryptedResponse[:length]
623+
readErr = nil
624+
break
625+
}
626+
readErr = err
627+
dlog.Debugf("[%v] Retry on timeout", serverInfo.Name)
628+
}
629+
630+
if readErr != nil {
631+
proxy.udpConnPool.Discard(pc)
632+
return nil, readErr
633+
}
634+
635+
proxy.udpConnPool.Put(upstreamAddr, pc)
636+
637+
return proxy.Decrypt(serverInfo, sharedKey, encryptedResponse, clientNonce)
638+
}
639+
640+
func (proxy *Proxy) exchangeWithUDPServerViaProxy(
641+
serverInfo *ServerInfo,
642+
sharedKey *[32]byte,
643+
encryptedQuery []byte,
644+
clientNonce []byte,
645+
upstreamAddr *net.UDPAddr,
646+
proxyDialer *netproxy.Dialer,
647+
) ([]byte, error) {
648+
pc, err := (*proxyDialer).Dial("udp", upstreamAddr.String())
598649
if err != nil {
599650
return nil, err
600651
}
601652
defer pc.Close()
653+
602654
if err := pc.SetDeadline(time.Now().Add(serverInfo.Timeout)); err != nil {
603655
return nil, err
604656
}
@@ -856,5 +908,6 @@ func (proxy *Proxy) processIncomingQuery(
856908
func NewProxy() *Proxy {
857909
return &Proxy{
858910
serversInfo: NewServersInfo(),
911+
udpConnPool: NewUDPConnPool(),
859912
}
860913
}

0 commit comments

Comments
 (0)