Skip to content

Commit

Permalink
Merge branch 'master' into AGDNS-1982-fix-before-handler
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneOne1 committed Apr 8, 2024
2 parents 7259240 + 0e2cfca commit 28d2c84
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 118 deletions.
2 changes: 1 addition & 1 deletion fastip/fastest.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (f *FastestAddr) ExchangeFastest(req *dns.Msg, ups []upstream.Upstream) (
for _, r := range replies {
for _, rr := range r.Resp.Answer {
ip := ipFromRR(rr)
if !ipSet.Has(ip) && ip != (netip.Addr{}) {
if ip.IsValid() && !ip.IsUnspecified() {
ipSet.Add(ip)
}
}
Expand Down
2 changes: 1 addition & 1 deletion 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.58
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/quic-go/quic-go v0.41.0
github.com/quic-go/quic-go v0.42.0
github.com/stretchr/testify v1.9.0
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8
golang.org/x/net v0.23.0
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ 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/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k=
github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
Expand All @@ -69,6 +69,8 @@ golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
Expand Down
25 changes: 17 additions & 8 deletions proxy/server_quic.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net"
"time"

"github.com/AdguardTeam/dnsproxy/internal/bootstrap"
"github.com/AdguardTeam/dnsproxy/proxyutil"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
Expand Down Expand Up @@ -64,10 +65,21 @@ const (
func (p *Proxy) createQUICListeners() error {
for _, a := range p.QUICListenAddr {
log.Info("Creating a QUIC listener")

conn, err := net.ListenUDP(bootstrap.NetworkUDP, a)
if err != nil {
return fmt.Errorf("listening to %s: %w", a, err)
}

v := newQUICAddrValidator(quicAddrValidatorCacheSize, quicAddrValidatorCacheTTL)
transport := &quic.Transport{
Conn: conn,
VerifySourceAddress: v.requiresValidation,
}

tlsConfig := p.TLSConfig.Clone()
tlsConfig.NextProtos = compatProtoDQ
quicListen, err := quic.ListenAddrEarly(
a.String(),
quicListen, err := transport.ListenEarly(
tlsConfig,
newServerQUICConfig(),
)
Expand Down Expand Up @@ -393,13 +405,10 @@ func closeQUICConn(conn quic.Connection, code quic.ApplicationErrorCode) {
// newServerQUICConfig creates *quic.Config populated with the default settings.
// This function is supposed to be used for both DoQ and DoH3 server.
func newServerQUICConfig() (conf *quic.Config) {
v := newQUICAddrValidator(quicAddrValidatorCacheSize, quicAddrValidatorCacheTTL)

return &quic.Config{
MaxIdleTimeout: maxQUICIdleTimeout,
MaxIncomingStreams: math.MaxUint16,
MaxIncomingUniStreams: math.MaxUint16,
RequireAddressValidation: v.requiresValidation,
MaxIdleTimeout: maxQUICIdleTimeout,
MaxIncomingStreams: math.MaxUint16,
MaxIncomingUniStreams: math.MaxUint16,
// Enable 0-RTT by default for all connections on the server-side.
Allow0RTT: true,
}
Expand Down
129 changes: 66 additions & 63 deletions upstream/doh_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (
"fmt"
"net"
"net/http"
"strconv"
"net/netip"
"net/url"
"sync/atomic"
"testing"
"time"
Expand Down Expand Up @@ -197,74 +198,69 @@ func TestUpstreamDoH_serverRestart(t *testing.T) {
testCases := []struct {
name string
httpVersions []HTTPVersion
}{
{
name: "http2",
httpVersions: []HTTPVersion{HTTPVersion11, HTTPVersion2},
},
{
name: "http3",
httpVersions: []HTTPVersion{HTTPVersion3},
},
}
}{{
name: "http2",
httpVersions: []HTTPVersion{HTTPVersion11, HTTPVersion2},
}, {
name: "http3",
httpVersions: []HTTPVersion{HTTPVersion3},
}}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Run the first server instance.
srv := startDoHServer(t, testDoHServerOptions{
http3Enabled: true,
})

// Create a DNS-over-HTTPS upstream.
address := fmt.Sprintf("https://%s/dns-query", srv.addr)
u, err := AddressToUpstream(
address,
&Options{
var addr netip.AddrPort
var upsAddr string
var u Upstream

t.Run("first_try", func(t *testing.T) {
srv := startDoHServer(t, testDoHServerOptions{
http3Enabled: true,
})
t.Cleanup(srv.Shutdown)

addr = netip.MustParseAddrPort(srv.addr)
upsAddr = (&url.URL{
Scheme: "https",
Host: addr.String(),
Path: "dns-query",
}).String()

var err error
u, err = AddressToUpstream(upsAddr, &Options{
InsecureSkipVerify: true,
HTTPVersions: tc.httpVersions,
Timeout: time.Second,
},
)
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, u.Close)

// Test that the upstream works properly.
checkUpstream(t, u, address)
})
require.NoError(t, err)

// Now let's restart the server on the same address.
_, portStr, err := net.SplitHostPort(srv.addr)
require.NoError(t, err)
port, err := strconv.Atoi(portStr)
require.NoError(t, err)
checkUpstream(t, u, upsAddr)
})
require.False(t, t.Failed())
testutil.CleanupAndRequireSuccess(t, u.Close)

// Shutdown the first server.
srv.Shutdown()
t.Run("second_try", func(t *testing.T) {
srv := startDoHServer(t, testDoHServerOptions{
http3Enabled: true,
port: int(addr.Port()),
})
t.Cleanup(srv.Shutdown)

// Start the new one on the same port.
srv = startDoHServer(t, testDoHServerOptions{
http3Enabled: true,
port: port,
checkUpstream(t, u, upsAddr)
})
require.False(t, t.Failed())

// Check that everything works after restart.
checkUpstream(t, u, address)

// Stop the server again.
srv.Shutdown()
t.Run("retry", func(t *testing.T) {
_, err := u.Exchange(createTestMessage())
require.Error(t, err)

// Now try to send a message and make sure that it returns an error.
_, err = u.Exchange(createTestMessage())
require.Error(t, err)
srv := startDoHServer(t, testDoHServerOptions{
http3Enabled: true,
port: int(addr.Port()),
})
t.Cleanup(srv.Shutdown)

// Start the server one more time.
srv = startDoHServer(t, testDoHServerOptions{
http3Enabled: true,
port: port,
checkUpstream(t, u, upsAddr)
})
defer srv.Shutdown()

// Check that everything works after the second restart.
checkUpstream(t, u, address)
})
}
}
Expand Down Expand Up @@ -429,17 +425,24 @@ func startDoHServer(

// Listen UDP for the H3 server. Reuse the same port as was used for the
// TCP listener.
udpAddr, uErr := net.ResolveUDPAddr("udp", fmt.Sprintf("127.0.0.1:%d", tcpAddr.Port))
require.NoError(t, uErr)
var udpAddr *net.UDPAddr
udpAddr, err = net.ResolveUDPAddr("udp", fmt.Sprintf("127.0.0.1:%d", tcpAddr.Port))
require.NoError(t, err)

var conn net.PacketConn
conn, err = net.ListenUDP("udp", udpAddr)
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, conn.Close)

transport := &quic.Transport{
Conn: conn,
VerifySourceAddress: func(net.Addr) bool { return false },
}

// QUIC configuration with the 0-RTT support enabled by default.
quicConfig := &quic.Config{
RequireAddressValidation: func(net.Addr) (ok bool) {
return true
},
listenerH3, err = transport.ListenEarly(tlsConfigH3, &quic.Config{
Allow0RTT: true,
}
listenerH3, err = quic.ListenAddrEarly(udpAddr.String(), tlsConfigH3, quicConfig)
})
require.NoError(t, err)

// Run the H3 server.
Expand Down
96 changes: 53 additions & 43 deletions upstream/doq_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import (
"fmt"
"io"
"net"
"strconv"
"net/netip"
"net/url"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -81,51 +82,50 @@ func TestUpstreamDoQ_serverRestart(t *testing.T) {
// 0-RTT connections.
tlsConf, rootCAs := createServerTLSConfig(t, "127.0.0.1")

// Run the first server instance.
srv := startDoQServer(t, tlsConf, 0)

// Create a DNS-over-QUIC upstream.
address := fmt.Sprintf("quic://%s", srv.addr)
u, err := AddressToUpstream(address, &Options{
InsecureSkipVerify: true,
Timeout: 250 * time.Millisecond,
RootCAs: rootCAs,
})
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, u.Close)

// Test that the upstream works properly.
checkUpstream(t, u, address)
var addr netip.AddrPort
var upsStr string
var u Upstream

// Now let's restart the server on the same address.
_, portStr, err := net.SplitHostPort(srv.addr)
require.NoError(t, err)
t.Run("first_try", func(t *testing.T) {
srv := startDoQServer(t, tlsConf, 0)
testutil.CleanupAndRequireSuccess(t, srv.Shutdown)

port, err := strconv.Atoi(portStr)
require.NoError(t, err)
addr = netip.MustParseAddrPort(srv.addr)
upsStr = (&url.URL{
Scheme: "quic",
Host: addr.String(),
}).String()

// Shutdown the first server.
require.NoError(t, srv.Shutdown())
var err error
u, err = AddressToUpstream(upsStr, &Options{
InsecureSkipVerify: true,
Timeout: 250 * time.Millisecond,
RootCAs: rootCAs,
})
require.NoError(t, err)

// Start the new one on the same port.
srv = startDoQServer(t, tlsConf, port)
checkUpstream(t, u, upsStr)
})
require.False(t, t.Failed())
testutil.CleanupAndRequireSuccess(t, u.Close)

// Check that everything works after restart.
checkUpstream(t, u, address)
t.Run("second_try", func(t *testing.T) {
srv := startDoQServer(t, tlsConf, int(addr.Port()))
testutil.CleanupAndRequireSuccess(t, srv.Shutdown)

// Stop the server again.
require.NoError(t, srv.Shutdown())
checkUpstream(t, u, upsStr)
})
require.False(t, t.Failed())

// Now try to send a message and make sure that it returns an error.
_, err = u.Exchange(createTestMessage())
require.Error(t, err)
t.Run("retry", func(t *testing.T) {
_, err := u.Exchange(createTestMessage())
require.Error(t, err)

// Start the server one more time.
srv = startDoQServer(t, tlsConf, port)
testutil.CleanupAndRequireSuccess(t, srv.Shutdown)
srv := startDoQServer(t, tlsConf, int(addr.Port()))
testutil.CleanupAndRequireSuccess(t, srv.Shutdown)

// Check that everything works after the second restart.
checkUpstream(t, u, address)
checkUpstream(t, u, upsStr)
})
}

func TestUpstreamDoQ_0RTT(t *testing.T) {
Expand Down Expand Up @@ -275,14 +275,24 @@ func (s *testDoQServer) handleQUICStream(stream quic.Stream) (err error) {
func startDoQServer(t *testing.T, tlsConf *tls.Config, port int) (s *testDoQServer) {
tlsConf.NextProtos = []string{NextProtoDQ}

listen, err := quic.ListenAddrEarly(
fmt.Sprintf("127.0.0.1:%d", port),
udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("127.0.0.1:%d", port))
require.NoError(t, err)

conn, err := net.ListenUDP("udp", udpAddr)
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, conn.Close)

transport := &quic.Transport{
Conn: conn,
// Necessary for 0-RTT.
VerifySourceAddress: func(a net.Addr) bool {
return true
},
}

listen, err := transport.ListenEarly(
tlsConf,
&quic.Config{
// Necessary for 0-RTT.
RequireAddressValidation: func(net.Addr) (ok bool) {
return false
},
Allow0RTT: true,
},
)
Expand Down

0 comments on commit 28d2c84

Please sign in to comment.