Skip to content

Commit

Permalink
Pull request 257: 331-upd-quic-go
Browse files Browse the repository at this point in the history
Merge in GO/dnsproxy from 331-upd-quic-go to master

Closes #331.

Squashed commit of the following:

commit df11453
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Jun 5 19:10:10 2023 +0300

    all: imp docs

commit 8f27eb6
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Jun 5 18:55:58 2023 +0300

    proxyutil: rm depr

commit 4c72117
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Jun 5 18:49:06 2023 +0300

    upstream: fit into 100 cols

commit e67ff14
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Jun 5 17:29:49 2023 +0300

    all: upd dnsproxy
  • Loading branch information
EugeneOne1 committed Jun 6, 2023
1 parent 8956a92 commit af10111
Show file tree
Hide file tree
Showing 91 changed files with 1,994 additions and 1,732 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/jessevdk/go-flags v1.5.0
github.com/miekg/dns v1.1.50
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/quic-go/quic-go v0.33.0
github.com/quic-go/quic-go v0.35.1
github.com/stretchr/testify v1.8.2
golang.org/x/exp v0.0.0-20230306221820-f0f767cdffd6
golang.org/x/net v0.8.0
Expand All @@ -31,8 +31,8 @@ require (
github.com/onsi/ginkgo/v2 v2.7.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-19 v0.2.1 // indirect
github.com/quic-go/qtls-go1-20 v0.1.1 // indirect
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/text v0.8.0 // indirect
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A=
github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA=
github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.35.1 h1:b0kzj6b/cQAf05cT0CkQubHM31wiA+xH3IBkxP62poo=
github.com/quic-go/quic-go v0.35.1/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
Expand Down
79 changes: 58 additions & 21 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,28 +64,54 @@ type Proxy struct {
// See https://golang.org/pkg/sync/atomic/#pkg-note-BUG.
counter uint64

started bool // Started flag
// started indicates if the proxy has been started.
started bool

// Listeners
// --

udpListen []*net.UDPConn // UDP listen connections
tcpListen []net.Listener // TCP listeners
tlsListen []net.Listener // TLS listeners
quicListen []quic.EarlyListener // QUIC listeners
httpsListen []net.Listener // HTTPS listeners
httpsServer *http.Server // HTTPS server instance
h3Listen []quic.EarlyListener // HTTP/3 listeners
h3Server *http3.Server // HTTP/3 server instance
dnsCryptUDPListen []*net.UDPConn // UDP listen connections for DNSCrypt
dnsCryptTCPListen []net.Listener // TCP listeners for DNSCrypt
dnsCryptServer *dnscrypt.Server // DNSCrypt server instance
// udpListen are the listened UDP connections.
udpListen []*net.UDPConn

// tcpListen are the listened TCP connections.
tcpListen []net.Listener

// tlsListen are the listened TCP connections with TLS.
tlsListen []net.Listener

// quicListen are the listened QUIC connections.
quicListen []*quic.EarlyListener

// httpsListen are the listened HTTPS connections.
httpsListen []net.Listener

// h3Listen are the listened HTTP/3 connections.
h3Listen []*quic.EarlyListener

// httpsServer serves queries received over HTTPS.
httpsServer *http.Server

// h3Server serves queries received over HTTP/3.
h3Server *http3.Server

// dnsCryptUDPListen are the listened UDP connections for DNSCrypt.
dnsCryptUDPListen []*net.UDPConn

// dnsCryptTCPListen are the listened TCP connections for DNSCrypt.
dnsCryptTCPListen []net.Listener

// dnsCryptServer serves DNSCrypt queries.
dnsCryptServer *dnscrypt.Server

// Upstream
// --

upstreamRttStats map[string]int // Map of upstream addresses and their rtt. Used to sort upstreams "from fast to slow"
rttLock sync.Mutex // Synchronizes access to the upstreamRttStats map
// upstreamRttStats is a map of upstream addresses and their rtt. Used to
// sort upstreams by their latency.
upstreamRttStats map[string]int

// rttLock protects upstreamRttStats.
rttLock sync.Mutex

// DNS64 (in case dnsproxy works in a NAT64/DNS64 network)
// --
Expand All @@ -98,8 +124,11 @@ type Proxy struct {
// Ratelimit
// --

ratelimitBuckets *gocache.Cache // where the ratelimiters are stored, per IP
ratelimitLock sync.Mutex // Synchronizes access to ratelimitBuckets
// ratelimitBuckets is a storage for ratelimiters for individual IPs.
ratelimitBuckets *gocache.Cache

// ratelimitLock protects ratelimitBuckets.
ratelimitLock sync.Mutex

// proxyVerifier checks if the proxy is in the trusted list.
proxyVerifier netutil.SubnetSet
Expand All @@ -109,21 +138,28 @@ type Proxy struct {

// cache is used to cache requests. It is disabled if nil.
cache *cache

// shortFlighter is used to resolve the expired cached requests without
// repetitions.
shortFlighter *optimisticResolver

// FastestAddr module
// --

fastestAddr *fastip.FastestAddr // fastest-addr module
// fastestAddr finds the fastest IP address for the resolved domain.
fastestAddr *fastip.FastestAddr

// Other
// --

bytesPool *sync.Pool // bytes pool to avoid unnecessary allocations when reading DNS packets
udpOOBSize int // size for received OOB data
sync.RWMutex // protects parallel access to proxy structures
// bytesPool is a pool of byte slices used to read DNS packets.
bytesPool *sync.Pool

// udpOOBSize is the size of the out-of-band data for UDP connections.
udpOOBSize int

// RWMutex protects the whole proxy.
sync.RWMutex

// requestGoroutinesSema limits the number of simultaneous requests.
//
Expand All @@ -135,7 +171,8 @@ type Proxy struct {
// See also: https://github.com/AdguardTeam/AdGuardHome/issues/2242.
requestGoroutinesSema semaphore

Config // proxy configuration
// Config is the proxy configuration.
Config
}

// Init populates fields of p but does not start listeners.
Expand Down
2 changes: 1 addition & 1 deletion proxy/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (p *Proxy) startListeners(ctx context.Context) error {
}

for _, l := range p.h3Listen {
go func(l quic.EarlyListener) { _ = p.h3Server.ServeListener(l) }(l)
go func(l *quic.EarlyListener) { _ = p.h3Server.ServeListener(l) }(l)
}

for _, l := range p.quicListen {
Expand Down
2 changes: 1 addition & 1 deletion proxy/server_https_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ func createTestHTTPClient(dnsProxy *Proxy, caPem []byte, http3Enabled bool) (cli
cfg *quic.Config,
) (quic.EarlyConnection, error) {
addr := dnsProxy.Addr(ProtoHTTPS).String()
return quic.DialAddrEarlyContext(ctx, addr, tlsCfg, cfg)
return quic.DialAddrEarly(ctx, addr, tlsCfg, cfg)
},
TLSClientConfig: tlsClientConfig,
QuicConfig: &quic.Config{},
Expand Down
6 changes: 2 additions & 4 deletions proxy/server_quic.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (p *Proxy) createQUICListeners() error {
// quicPacketLoop listens for incoming QUIC packets.
//
// See also the comment on Proxy.requestGoroutinesSema.
func (p *Proxy) quicPacketLoop(l quic.EarlyListener, requestGoroutinesSema semaphore) {
func (p *Proxy) quicPacketLoop(l *quic.EarlyListener, requestGoroutinesSema semaphore) {
log.Info("Entering the DNS-over-QUIC listener loop on %s", l.Addr())
for {
conn, err := l.Accept(context.Background())
Expand Down Expand Up @@ -374,9 +374,7 @@ func newServerQUICConfig() (conf *quic.Config) {
MaxIncomingUniStreams: math.MaxUint16,
RequireAddressValidation: v.requiresValidation,
// Enable 0-RTT by default for all connections on the server-side.
Allow0RTT: func(net.Addr) (ok bool) {
return true
},
Allow0RTT: true,
}
}

Expand Down
4 changes: 2 additions & 2 deletions proxy/server_quic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestQuicProxy(t *testing.T) {
addr := dnsProxy.Addr(ProtoQUIC)

// Open a QUIC connection.
conn, err := quic.DialAddrEarly(addr.String(), tlsConfig, nil)
conn, err := quic.DialAddrEarly(context.Background(), addr.String(), tlsConfig, nil)
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
return conn.CloseWithError(DoQCodeNoError, "")
Expand Down Expand Up @@ -95,7 +95,7 @@ func TestQuicProxy_largePackets(t *testing.T) {
addr := dnsProxy.Addr(ProtoQUIC)

// Open a QUIC connection.
conn, err := quic.DialAddrEarly(addr.String(), tlsConfig, nil)
conn, err := quic.DialAddrEarly(context.Background(), addr.String(), tlsConfig, nil)
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
return conn.CloseWithError(DoQCodeNoError, "")
Expand Down
87 changes: 16 additions & 71 deletions proxyutil/dns.go
Original file line number Diff line number Diff line change
@@ -1,83 +1,14 @@
// Package proxyutil contains helper functions that are used in all other
// dnsproxy packages.
package proxyutil

import (
"encoding/binary"
"fmt"
"io"
"net"

"github.com/AdguardTeam/golibs/errors"
"github.com/miekg/dns"
)

// ErrTooLarge means that a DNS message is larger than 64KiB.
//
// Deprecated: This constant is deprecated and will be removed in a future
// release.
const ErrTooLarge errors.Error = "dns message is too large"

// DNSSize returns if buffer size *advertised* in the requests OPT record.
// Or when the request was over TCP, we return the maximum allowed size of 64K.
//
// Deprecated: This function is deprecated and will be removed in a future
// release.
func DNSSize(isUDP bool, r *dns.Msg) int {
var size uint16
if o := r.IsEdns0(); o != nil {
size = o.UDPSize()
}

if !isUDP {
return dns.MaxMsgSize
}

if size < dns.MinMsgSize {
return dns.MinMsgSize
}

// normalize size
return int(size)
}

// ReadPrefixed reads a DNS message with a 2-byte prefix containing message
// length from conn.
//
// Deprecated: This function is deprecated and will be removed in a future
// release.
func ReadPrefixed(conn net.Conn) ([]byte, error) {
l := make([]byte, 2)
_, err := conn.Read(l)
if err != nil {
return nil, fmt.Errorf("reading len: %w", err)
}

packetLen := binary.BigEndian.Uint16(l)
if packetLen > dns.MaxMsgSize {
return nil, ErrTooLarge
}

buf := make([]byte, packetLen)
_, err = io.ReadFull(conn, buf)
if err != nil {
return nil, fmt.Errorf("reading msg: %w", err)
}

return buf, nil
}

// WritePrefixed writes a DNS message to a TCP connection it first writes
// a 2-byte prefix followed by the message itself.
//
// Deprecated: This function is deprecated and will be removed in a future
// release.
func WritePrefixed(b []byte, conn net.Conn) error {
l := make([]byte, 2)
binary.BigEndian.PutUint16(l, uint16(len(b)))
_, err := (&net.Buffers{l, b}).WriteTo(conn)

return err
}

// AddPrefix adds a 2-byte prefix with the DNS message length.
func AddPrefix(b []byte) (m []byte) {
m = make([]byte, 2+len(b))
Expand All @@ -86,3 +17,17 @@ func AddPrefix(b []byte) (m []byte) {

return m
}

// IPFromRR returns the IP address from rr if any.
func IPFromRR(rr dns.RR) (ip net.IP) {
switch rr := rr.(type) {
case *dns.A:
ip = rr.A.To4()
case *dns.AAAA:
ip = rr.AAAA
default:
// Go on.
}

return ip
}

0 comments on commit af10111

Please sign in to comment.