Skip to content

Commit

Permalink
feat: add DisableReuseport option
Browse files Browse the repository at this point in the history
Signed-off-by: gfanton <8671905+gfanton@users.noreply.github.com>
  • Loading branch information
gfanton committed Aug 16, 2022
1 parent 24b27cc commit 21d5011
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 49 deletions.
11 changes: 10 additions & 1 deletion p2p/transport/quic/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package libp2pquic

import (
"context"
"net"

ic "github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/network"
Expand All @@ -12,9 +13,17 @@ import (
ma "github.com/multiformats/go-multiaddr"
)

type pConn interface {
net.PacketConn

// count conn reference
DecreaseCount()
IncreaseCount()
}

type conn struct {
quicConn quic.Connection
pconn *reuseConn
pconn pConn
transport *transport
scope network.ConnManagementScope

Expand Down
136 changes: 114 additions & 22 deletions p2p/transport/quic/conn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ import (

//go:generate sh -c "mockgen -package libp2pquic -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p-core/connmgr ConnectionGater && goimports -w mock_connection_gater_test.go"

type connTestCase struct {
Name string
Options []Option
}

var connTestCases = []*connTestCase{
{"reuseport_on", []Option{}},
{"reuseport_off", []Option{DisableReuseport()}},
}

func createPeer(t *testing.T) (peer.ID, ic.PrivKey) {
var priv ic.PrivKey
var err error
Expand All @@ -52,20 +62,29 @@ func createPeer(t *testing.T) (peer.ID, ic.PrivKey) {

func runServer(t *testing.T, tr tpt.Transport, addr string) tpt.Listener {
t.Helper()

ln, err := tr.Listen(ma.StringCast(addr))
require.NoError(t, err)
return ln
}

func TestHandshake(t *testing.T) {
for _, tc := range connTestCases {
t.Run(tc.Name, func(t *testing.T) {
testHandshake(t, tc)
})
}
}

func testHandshake(t *testing.T, tc *connTestCase) {
serverID, serverKey := createPeer(t)
clientID, clientKey := createPeer(t)
serverTransport, err := NewTransport(serverKey, nil, nil, nil)
serverTransport, err := NewTransport(serverKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer serverTransport.(io.Closer).Close()

handshake := func(t *testing.T, ln tpt.Listener) {
clientTransport, err := NewTransport(clientKey, nil, nil, nil)
clientTransport, err := NewTransport(clientKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer clientTransport.(io.Closer).Close()
conn, err := clientTransport.Dial(context.Background(), ln.Multiaddr(), serverID)
Expand Down Expand Up @@ -100,22 +119,30 @@ func TestHandshake(t *testing.T) {
}

func TestResourceManagerSuccess(t *testing.T) {
for _, tc := range connTestCases {
t.Run(tc.Name, func(t *testing.T) {
testResourceManagerSuccess(t, tc)
})
}
}

func testResourceManagerSuccess(t *testing.T, tc *connTestCase) {
serverID, serverKey := createPeer(t)
clientID, clientKey := createPeer(t)

ctrl := gomock.NewController(t)
defer ctrl.Finish()

serverRcmgr := mocknetwork.NewMockResourceManager(ctrl)
serverTransport, err := NewTransport(serverKey, nil, nil, serverRcmgr)
serverTransport, err := NewTransport(serverKey, nil, nil, serverRcmgr, tc.Options...)
require.NoError(t, err)
defer serverTransport.(io.Closer).Close()
ln, err := serverTransport.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic"))
require.NoError(t, err)
defer ln.Close()

clientRcmgr := mocknetwork.NewMockResourceManager(ctrl)
clientTransport, err := NewTransport(clientKey, nil, nil, clientRcmgr)
clientTransport, err := NewTransport(clientKey, nil, nil, clientRcmgr, tc.Options...)
require.NoError(t, err)
defer clientTransport.(io.Closer).Close()

Expand Down Expand Up @@ -143,12 +170,20 @@ func TestResourceManagerSuccess(t *testing.T) {
}

func TestResourceManagerDialDenied(t *testing.T) {
for _, tc := range connTestCases {
t.Run(tc.Name, func(t *testing.T) {
testResourceManagerDialDenied(t, tc)
})
}
}

func testResourceManagerDialDenied(t *testing.T, tc *connTestCase) {
_, clientKey := createPeer(t)
ctrl := gomock.NewController(t)
defer ctrl.Finish()

rcmgr := mocknetwork.NewMockResourceManager(ctrl)
clientTransport, err := NewTransport(clientKey, nil, nil, rcmgr)
clientTransport, err := NewTransport(clientKey, nil, nil, rcmgr, tc.Options...)
require.NoError(t, err)
defer clientTransport.(io.Closer).Close()

Expand All @@ -163,16 +198,25 @@ func TestResourceManagerDialDenied(t *testing.T) {

_, err = clientTransport.Dial(context.Background(), target, p)
require.ErrorIs(t, err, rerr)

}

func TestResourceManagerAcceptDenied(t *testing.T) {
for _, tc := range connTestCases {
t.Run(tc.Name, func(t *testing.T) {
testResourceManagerAcceptDenied(t, tc)
})
}
}

func testResourceManagerAcceptDenied(t *testing.T, tc *connTestCase) {
serverID, serverKey := createPeer(t)
clientID, clientKey := createPeer(t)
ctrl := gomock.NewController(t)
defer ctrl.Finish()

clientRcmgr := mocknetwork.NewMockResourceManager(ctrl)
clientTransport, err := NewTransport(clientKey, nil, nil, clientRcmgr)
clientTransport, err := NewTransport(clientKey, nil, nil, clientRcmgr, tc.Options...)
require.NoError(t, err)
defer clientTransport.(io.Closer).Close()

Expand All @@ -184,7 +228,7 @@ func TestResourceManagerAcceptDenied(t *testing.T) {
serverConnScope.EXPECT().SetPeer(clientID).Return(rerr),
serverConnScope.EXPECT().Done(),
)
serverTransport, err := NewTransport(serverKey, nil, nil, serverRcmgr)
serverTransport, err := NewTransport(serverKey, nil, nil, serverRcmgr, tc.Options...)
require.NoError(t, err)
defer serverTransport.(io.Closer).Close()
ln, err := serverTransport.Listen(ma.StringCast("/ip4/127.0.0.1/udp/0/quic"))
Expand Down Expand Up @@ -216,16 +260,24 @@ func TestResourceManagerAcceptDenied(t *testing.T) {
}

func TestStreams(t *testing.T) {
for _, tc := range connTestCases {
t.Run(tc.Name, func(t *testing.T) {
testStreams(t, tc)
})
}
}

func testStreams(t *testing.T, tc *connTestCase) {
serverID, serverKey := createPeer(t)
_, clientKey := createPeer(t)

serverTransport, err := NewTransport(serverKey, nil, nil, nil)
serverTransport, err := NewTransport(serverKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer serverTransport.(io.Closer).Close()
ln := runServer(t, serverTransport, "/ip4/127.0.0.1/udp/0/quic")
defer ln.Close()

clientTransport, err := NewTransport(clientKey, nil, nil, nil)
clientTransport, err := NewTransport(clientKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer clientTransport.(io.Closer).Close()
conn, err := clientTransport.Dial(context.Background(), ln.Multiaddr(), serverID)
Expand All @@ -248,16 +300,24 @@ func TestStreams(t *testing.T) {
}

func TestHandshakeFailPeerIDMismatch(t *testing.T) {
for _, tc := range connTestCases {
t.Run(tc.Name, func(t *testing.T) {
testHandshakeFailPeerIDMismatch(t, tc)
})
}
}

func testHandshakeFailPeerIDMismatch(t *testing.T, tc *connTestCase) {
_, serverKey := createPeer(t)
_, clientKey := createPeer(t)
thirdPartyID, _ := createPeer(t)

serverTransport, err := NewTransport(serverKey, nil, nil, nil)
serverTransport, err := NewTransport(serverKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer serverTransport.(io.Closer).Close()
ln := runServer(t, serverTransport, "/ip4/127.0.0.1/udp/0/quic")

clientTransport, err := NewTransport(clientKey, nil, nil, nil)
clientTransport, err := NewTransport(clientKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
// dial, but expect the wrong peer ID
_, err = clientTransport.Dial(context.Background(), ln.Multiaddr(), thirdPartyID)
Expand All @@ -282,6 +342,14 @@ func TestHandshakeFailPeerIDMismatch(t *testing.T) {
}

func TestConnectionGating(t *testing.T) {
for _, tc := range connTestCases {
t.Run(tc.Name, func(t *testing.T) {
testConnectionGating(t, tc)
})
}
}

func testConnectionGating(t *testing.T, tc *connTestCase) {
serverID, serverKey := createPeer(t)
_, clientKey := createPeer(t)

Expand All @@ -290,7 +358,7 @@ func TestConnectionGating(t *testing.T) {
cg := NewMockConnectionGater(mockCtrl)

t.Run("accepted connections", func(t *testing.T) {
serverTransport, err := NewTransport(serverKey, nil, cg, nil)
serverTransport, err := NewTransport(serverKey, nil, cg, nil, tc.Options...)
defer serverTransport.(io.Closer).Close()
require.NoError(t, err)
ln := runServer(t, serverTransport, "/ip4/127.0.0.1/udp/0/quic")
Expand All @@ -305,7 +373,7 @@ func TestConnectionGating(t *testing.T) {
require.NoError(t, err)
}()

clientTransport, err := NewTransport(clientKey, nil, nil, nil)
clientTransport, err := NewTransport(clientKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer clientTransport.(io.Closer).Close()
// make sure that connection attempts fails
Expand Down Expand Up @@ -335,7 +403,7 @@ func TestConnectionGating(t *testing.T) {
})

t.Run("secured connections", func(t *testing.T) {
serverTransport, err := NewTransport(serverKey, nil, nil, nil)
serverTransport, err := NewTransport(serverKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer serverTransport.(io.Closer).Close()
ln := runServer(t, serverTransport, "/ip4/127.0.0.1/udp/0/quic")
Expand All @@ -344,7 +412,7 @@ func TestConnectionGating(t *testing.T) {
cg := NewMockConnectionGater(mockCtrl)
cg.EXPECT().InterceptSecured(gomock.Any(), gomock.Any(), gomock.Any())

clientTransport, err := NewTransport(clientKey, nil, cg, nil)
clientTransport, err := NewTransport(clientKey, nil, cg, nil, tc.Options...)
require.NoError(t, err)
defer clientTransport.(io.Closer).Close()

Expand All @@ -363,16 +431,24 @@ func TestConnectionGating(t *testing.T) {
}

func TestDialTwo(t *testing.T) {
for _, tc := range connTestCases {
t.Run(tc.Name, func(t *testing.T) {
testDialTwo(t, tc)
})
}
}

func testDialTwo(t *testing.T, tc *connTestCase) {
serverID, serverKey := createPeer(t)
_, clientKey := createPeer(t)
serverID2, serverKey2 := createPeer(t)

serverTransport, err := NewTransport(serverKey, nil, nil, nil)
serverTransport, err := NewTransport(serverKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer serverTransport.(io.Closer).Close()
ln1 := runServer(t, serverTransport, "/ip4/127.0.0.1/udp/0/quic")
defer ln1.Close()
serverTransport2, err := NewTransport(serverKey2, nil, nil, nil)
serverTransport2, err := NewTransport(serverKey2, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer serverTransport2.(io.Closer).Close()
ln2 := runServer(t, serverTransport2, "/ip4/127.0.0.1/udp/0/quic")
Expand All @@ -398,7 +474,7 @@ func TestDialTwo(t *testing.T) {
}
}()

clientTransport, err := NewTransport(clientKey, nil, nil, nil)
clientTransport, err := NewTransport(clientKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer clientTransport.(io.Closer).Close()
c1, err := clientTransport.Dial(context.Background(), ln1.Multiaddr(), serverID)
Expand Down Expand Up @@ -435,6 +511,14 @@ func TestDialTwo(t *testing.T) {
}

func TestStatelessReset(t *testing.T) {
for _, tc := range connTestCases {
t.Run(tc.Name, func(t *testing.T) {
testStatelessReset(t, tc)
})
}
}

func testStatelessReset(t *testing.T, tc *connTestCase) {
origGarbageCollectInterval := garbageCollectInterval
origMaxUnusedDuration := maxUnusedDuration

Expand All @@ -449,7 +533,7 @@ func TestStatelessReset(t *testing.T) {
serverID, serverKey := createPeer(t)
_, clientKey := createPeer(t)

serverTransport, err := NewTransport(serverKey, nil, nil, nil)
serverTransport, err := NewTransport(serverKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer serverTransport.(io.Closer).Close()
ln := runServer(t, serverTransport, "/ip4/127.0.0.1/udp/0/quic")
Expand All @@ -466,7 +550,7 @@ func TestStatelessReset(t *testing.T) {
defer proxy.Close()

// establish a connection
clientTransport, err := NewTransport(clientKey, nil, nil, nil)
clientTransport, err := NewTransport(clientKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer clientTransport.(io.Closer).Close()
proxyAddr, err := toQuicMultiaddr(proxy.LocalAddr())
Expand Down Expand Up @@ -512,10 +596,18 @@ func TestStatelessReset(t *testing.T) {
}

func TestHolePunching(t *testing.T) {
for _, tc := range connTestCases {
t.Run(tc.Name, func(t *testing.T) {
testHolePunching(t, tc)
})
}
}

func testHolePunching(t *testing.T, tc *connTestCase) {
serverID, serverKey := createPeer(t)
clientID, clientKey := createPeer(t)

t1, err := NewTransport(serverKey, nil, nil, nil)
t1, err := NewTransport(serverKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer t1.(io.Closer).Close()
laddr, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/0/quic")
Expand All @@ -529,7 +621,7 @@ func TestHolePunching(t *testing.T) {
require.Error(t, err, "didn't expect to accept any connections")
}()

t2, err := NewTransport(clientKey, nil, nil, nil)
t2, err := NewTransport(clientKey, nil, nil, nil, tc.Options...)
require.NoError(t, err)
defer t2.(io.Closer).Close()
ln2, err := t2.Listen(laddr)
Expand Down
Loading

0 comments on commit 21d5011

Please sign in to comment.