From 4caa4e5bd45e5c834c2d417d06d276508b2f9621 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 25 Aug 2023 17:04:14 +0700 Subject: [PATCH] swarm: return a more meaningful error when dialing QUIC draft-29 (#2524) * swarm: return a more meaningful error when dialing QUIC draft-29 * Apply suggestions from code review Co-authored-by: Jorropo * Update p2p/net/swarm/swarm_dial.go * fix * better types --------- Co-authored-by: Jorropo --- p2p/net/swarm/dial_test.go | 9 +++++++++ p2p/net/swarm/swarm_dial.go | 25 ++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/p2p/net/swarm/dial_test.go b/p2p/net/swarm/dial_test.go index 324a98539..a614183bb 100644 --- a/p2p/net/swarm/dial_test.go +++ b/p2p/net/swarm/dial_test.go @@ -642,3 +642,12 @@ func TestDialSelf(t *testing.T) { _, err := s1.DialPeer(context.Background(), s1.LocalPeer()) require.ErrorIs(t, err, swarm.ErrDialToSelf, "expected error from self dial") } + +func TestDialQUICDraft29(t *testing.T) { + s := makeDialOnlySwarm(t) + id := testutil.RandPeerIDFatal(t) + s.Peerstore().AddAddr(id, ma.StringCast("/ip4/127.0.0.1/udp/1234/quic"), time.Hour) + _, err := s.DialPeer(context.Background(), id) + require.ErrorIs(t, err, swarm.ErrQUICDraft29) + require.ErrorIs(t, err, swarm.ErrNoTransport) +} diff --git a/p2p/net/swarm/swarm_dial.go b/p2p/net/swarm/swarm_dial.go index e17c27353..1e5638f37 100644 --- a/p2p/net/swarm/swarm_dial.go +++ b/p2p/net/swarm/swarm_dial.go @@ -14,8 +14,10 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peerstore" "github.com/libp2p/go-libp2p/core/transport" + ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" + mafmt "github.com/multiformats/go-multiaddr-fmt" manet "github.com/multiformats/go-multiaddr/net" ) @@ -65,6 +67,19 @@ var ( ErrGaterDisallowedConnection = errors.New("gater disallows connection to peer") ) +// ErrQUICDraft29 wraps ErrNoTransport and provide a more meaningful error message +var ErrQUICDraft29 errQUICDraft29 + +type errQUICDraft29 struct{} + +func (errQUICDraft29) Error() string { + return "QUIC draft-29 has been removed, QUIC (RFC 9000) is accessible with /quic-v1" +} + +func (errQUICDraft29) Unwrap() error { + return ErrNoTransport +} + // DialAttempts governs how many times a goroutine will try to dial a given peer. // Note: this is down to one, as we have _too many dials_ atm. To add back in, // add loop back in Dial(.) @@ -407,6 +422,8 @@ func (s *Swarm) nonProxyAddr(addr ma.Multiaddr) bool { return !t.Proxy() } +var quicDraft29DialMatcher = mafmt.And(mafmt.IP, mafmt.Base(ma.P_UDP), mafmt.Base(ma.P_QUIC)) + // filterKnownUndialables takes a list of multiaddrs, and removes those // that we definitely don't want to dial: addresses configured to be blocked, // IPv6 link-local addresses, addresses without a dial-capable transport, @@ -435,7 +452,13 @@ func (s *Swarm) filterKnownUndialables(p peer.ID, addrs []ma.Multiaddr) (goodAdd // filter addresses with no transport addrs = ma.FilterAddrs(addrs, func(a ma.Multiaddr) bool { if s.TransportForDialing(a) == nil { - addrErrs = append(addrErrs, TransportError{Address: a, Cause: ErrNoTransport}) + e := ErrNoTransport + // We used to support QUIC draft-29 for a long time. + // Provide a more useful error when attempting to dial a QUIC draft-29 address. + if quicDraft29DialMatcher.Matches(a) { + e = ErrQUICDraft29 + } + addrErrs = append(addrErrs, TransportError{Address: a, Cause: e}) return false } return true