-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
quic / webtransport: make it possible to listen on the same address /…
… port (#1905) * quic: add an integration test for QUIC version support * quic: refactor the stateless reset test * quic: simplify the interface of the noreuseConn DecreaseCount now closes the underlying UDP conn, so that callers don't need to pay attention if they're dealing with a reuseConn or a noreuseConn. * implement a quicreuse to manage QUIC connections * quicreuse: introduce options * config: construct the quicreuse.ConnManager using fx * webtransport: use the quicreuse * add integration test for QUIC and WebTranport sharing the same UDP addr * Handle errors in accept loop goroutine * Add comment * Remove todo * Rename mutexes * Cleanup extra close * Only log on err * Use webtransport-go 0.4.0 * Fix expected error Co-authored-by: Marco Munizaga <[email protected]>
- Loading branch information
1 parent
9fad5b0
commit f732050
Showing
35 changed files
with
1,348 additions
and
601 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package config | ||
|
||
import ( | ||
"crypto/sha256" | ||
"io" | ||
|
||
"golang.org/x/crypto/hkdf" | ||
|
||
"github.com/libp2p/go-libp2p/core/crypto" | ||
|
||
"github.com/lucas-clemente/quic-go" | ||
) | ||
|
||
const statelessResetKeyInfo = "libp2p quic stateless reset key" | ||
|
||
func PrivKeyToStatelessResetKey(key crypto.PrivKey) (quic.StatelessResetKey, error) { | ||
var statelessResetKey quic.StatelessResetKey | ||
keyBytes, err := key.Raw() | ||
if err != nil { | ||
return statelessResetKey, err | ||
} | ||
keyReader := hkdf.New(sha256.New, keyBytes, nil, []byte(statelessResetKeyInfo)) | ||
if _, err := io.ReadFull(keyReader, statelessResetKey[:]); err != nil { | ||
return statelessResetKey, err | ||
} | ||
return statelessResetKey, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
package quic_test | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/libp2p/go-libp2p" | ||
"github.com/libp2p/go-libp2p/core/network" | ||
"github.com/libp2p/go-libp2p/core/peer" | ||
libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" | ||
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse" | ||
webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport" | ||
|
||
ma "github.com/multiformats/go-multiaddr" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func getQUICMultiaddrCode(addr ma.Multiaddr) int { | ||
if _, err := addr.ValueForProtocol(ma.P_QUIC); err == nil { | ||
return ma.P_QUIC | ||
} | ||
if _, err := addr.ValueForProtocol(ma.P_QUIC_V1); err == nil { | ||
return ma.P_QUIC_V1 | ||
} | ||
return 0 | ||
} | ||
|
||
func TestQUICVersions(t *testing.T) { | ||
h1, err := libp2p.New( | ||
libp2p.Transport(libp2pquic.NewTransport), | ||
libp2p.Transport(webtransport.New), | ||
libp2p.ListenAddrStrings( | ||
"/ip4/127.0.0.1/udp/12345/quic", // QUIC draft-29 | ||
"/ip4/127.0.0.1/udp/12345/quic-v1", // QUIC v1 | ||
), | ||
) | ||
require.NoError(t, err) | ||
defer h1.Close() | ||
|
||
addrs := h1.Addrs() | ||
require.Len(t, addrs, 2) | ||
var quicDraft29Addr, quicV1Addr ma.Multiaddr | ||
for _, addr := range addrs { | ||
switch getQUICMultiaddrCode(addr) { | ||
case ma.P_QUIC: | ||
quicDraft29Addr = addr | ||
case ma.P_QUIC_V1: | ||
quicV1Addr = addr | ||
} | ||
} | ||
require.NotNil(t, quicDraft29Addr, "expected to be listening on a QUIC draft-29 address") | ||
require.NotNil(t, quicV1Addr, "expected to be listening on a QUIC v1 address") | ||
|
||
// connect using QUIC draft-29 | ||
h2, err := libp2p.New( | ||
libp2p.Transport(libp2pquic.NewTransport), | ||
) | ||
require.NoError(t, err) | ||
require.NoError(t, h2.Connect(context.Background(), peer.AddrInfo{ID: h1.ID(), Addrs: []ma.Multiaddr{quicDraft29Addr}})) | ||
conns := h2.Network().ConnsToPeer(h1.ID()) | ||
require.Len(t, conns, 1) | ||
require.Equal(t, ma.P_QUIC, getQUICMultiaddrCode(conns[0].LocalMultiaddr())) | ||
require.Equal(t, ma.P_QUIC, getQUICMultiaddrCode(conns[0].RemoteMultiaddr())) | ||
h2.Close() | ||
|
||
// connect using QUIC v1 | ||
h3, err := libp2p.New( | ||
libp2p.Transport(libp2pquic.NewTransport), | ||
) | ||
require.NoError(t, err) | ||
require.NoError(t, h3.Connect(context.Background(), peer.AddrInfo{ID: h1.ID(), Addrs: []ma.Multiaddr{quicV1Addr}})) | ||
conns = h3.Network().ConnsToPeer(h1.ID()) | ||
require.Len(t, conns, 1) | ||
require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(conns[0].LocalMultiaddr())) | ||
require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(conns[0].RemoteMultiaddr())) | ||
h3.Close() | ||
} | ||
|
||
func TestDisableQUICDraft29(t *testing.T) { | ||
h1, err := libp2p.New( | ||
libp2p.QUICReuse(quicreuse.NewConnManager, quicreuse.DisableDraft29()), | ||
libp2p.Transport(libp2pquic.NewTransport), | ||
libp2p.Transport(webtransport.New), | ||
libp2p.ListenAddrStrings( | ||
"/ip4/127.0.0.1/udp/12346/quic", // QUIC draft-29 | ||
"/ip4/127.0.0.1/udp/12346/quic-v1", // QUIC v1 | ||
), | ||
) | ||
require.NoError(t, err) | ||
defer h1.Close() | ||
|
||
addrs := h1.Addrs() | ||
require.Len(t, addrs, 1) | ||
require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(addrs[0])) | ||
|
||
// connect using QUIC draft-29 | ||
h2, err := libp2p.New( | ||
libp2p.Transport(libp2pquic.NewTransport), | ||
) | ||
require.NoError(t, err) | ||
defer h2.Close() | ||
require.ErrorContains(t, | ||
h2.Connect(context.Background(), peer.AddrInfo{ID: h1.ID(), Addrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/udp/12346/quic")}}), | ||
"no compatible QUIC version found", | ||
) | ||
// make sure that dialing QUIC v1 works | ||
require.NoError(t, h2.Connect(context.Background(), peer.AddrInfo{ID: h1.ID(), Addrs: []ma.Multiaddr{addrs[0]}})) | ||
} | ||
|
||
func TestQUICAndWebTransport(t *testing.T) { | ||
h1, err := libp2p.New( | ||
libp2p.QUICReuse(quicreuse.NewConnManager, quicreuse.DisableDraft29()), | ||
libp2p.Transport(libp2pquic.NewTransport), | ||
libp2p.Transport(webtransport.New), | ||
libp2p.ListenAddrStrings( | ||
"/ip4/127.0.0.1/udp/12347/quic-v1", | ||
"/ip4/127.0.0.1/udp/12347/quic-v1/webtransport", | ||
), | ||
) | ||
require.NoError(t, err) | ||
defer h1.Close() | ||
|
||
addrs := h1.Addrs() | ||
require.Len(t, addrs, 2) | ||
require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(addrs[0])) | ||
require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(addrs[1])) | ||
var quicAddr, webtransportAddr ma.Multiaddr | ||
for _, addr := range addrs { | ||
if _, err := addr.ValueForProtocol(ma.P_WEBTRANSPORT); err == nil { | ||
webtransportAddr = addr | ||
} else { | ||
quicAddr = addr | ||
} | ||
} | ||
require.NotNil(t, webtransportAddr, "expected to have a WebTransport address") | ||
require.NotNil(t, quicAddr, "expected to have a QUIC v1 address") | ||
|
||
h2, err := libp2p.New( | ||
libp2p.Transport(libp2pquic.NewTransport), | ||
libp2p.NoListenAddrs, | ||
) | ||
require.NoError(t, err) | ||
require.NoError(t, h2.Connect(context.Background(), peer.AddrInfo{ID: h1.ID(), Addrs: h1.Addrs()})) | ||
for _, conns := range [][]network.Conn{h2.Network().ConnsToPeer(h1.ID()), h1.Network().ConnsToPeer(h2.ID())} { | ||
require.Len(t, conns, 1) | ||
if _, err := conns[0].LocalMultiaddr().ValueForProtocol(ma.P_WEBTRANSPORT); err == nil { | ||
t.Fatalf("expected a QUIC connection, got a WebTransport connection (%s <-> %s)", conns[0].LocalMultiaddr(), conns[0].RemoteMultiaddr()) | ||
} | ||
require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(conns[0].LocalMultiaddr())) | ||
require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(conns[0].RemoteMultiaddr())) | ||
} | ||
h2.Close() | ||
|
||
h3, err := libp2p.New( | ||
libp2p.Transport(webtransport.New), | ||
libp2p.NoListenAddrs, | ||
) | ||
require.NoError(t, err) | ||
require.NoError(t, h3.Connect(context.Background(), peer.AddrInfo{ID: h1.ID(), Addrs: h1.Addrs()})) | ||
for _, conns := range [][]network.Conn{h3.Network().ConnsToPeer(h1.ID()), h1.Network().ConnsToPeer(h3.ID())} { | ||
require.Len(t, conns, 1) | ||
if _, err := conns[0].LocalMultiaddr().ValueForProtocol(ma.P_WEBTRANSPORT); err != nil { | ||
t.Fatalf("expected a WebTransport connection, got a QUIC connection (%s <-> %s)", conns[0].LocalMultiaddr(), conns[0].RemoteMultiaddr()) | ||
} | ||
require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(conns[0].LocalMultiaddr())) | ||
require.Equal(t, ma.P_QUIC_V1, getQUICMultiaddrCode(conns[0].RemoteMultiaddr())) | ||
} | ||
h3.Close() | ||
} |
Oops, something went wrong.