Skip to content
This repository has been archived by the owner on May 26, 2022. It is now read-only.

gate QUIC connections via new ConnectionGater #152

Merged
merged 6 commits into from
May 19, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 38 additions & 10 deletions conn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,51 @@ import (
"io/ioutil"
mrand "math/rand"
"net"
"sync"
"sync/atomic"
"time"

"github.com/libp2p/go-libp2p-core/control"
ic "github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
tpt "github.com/libp2p/go-libp2p-core/transport"
filter "github.com/libp2p/go-maddr-filter"

quicproxy "github.com/lucas-clemente/quic-go/integrationtests/tools/proxy"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr-net"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

type localhostMockGater struct {
Copy link
Collaborator Author

@aarshkshah1992 aarshkshah1992 May 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@raulk I know this will make you cringe and add some entropy to thy life. But, I have added a TODO at libp2p/go-libp2p#930 to replace this with the "Functional Gater" that we plan to implement.

For all that you hold dear on this good Earth, rest assured, this shall be fixed.

lk sync.Mutex
allowAll bool
}

func (c *localhostMockGater) InterceptAccept(addrs network.ConnMultiaddrs) bool {
c.lk.Lock()
defer c.lk.Unlock()
return c.allowAll || !manet.IsIPLoopback(addrs.RemoteMultiaddr())
}

func (c *localhostMockGater) InterceptPeerDial(p peer.ID) (allow bool) {
return true
}

func (c *localhostMockGater) InterceptAddrDial(peer.ID, ma.Multiaddr) (allow bool) {
return true
}

func (c *localhostMockGater) InterceptSecured(network.Direction, peer.ID, network.ConnMultiaddrs) (allow bool) {
return true
}

func (c *localhostMockGater) InterceptUpgraded(network.Conn) (allow bool, reason control.DisconnectReason) {
return true, 0
}

var _ = Describe("Connection", func() {
var (
serverKey, clientKey ic.PrivKey
Expand Down Expand Up @@ -166,17 +197,12 @@ var _ = Describe("Connection", func() {
})

It("filters addresses", func() {
filters := filter.NewFilters()
ipNet := net.IPNet{
IP: net.IPv4(127, 0, 0, 1),
Mask: net.IPv4Mask(255, 255, 255, 255),
}
filters.AddFilter(ipNet, filter.ActionDeny)
testMA, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234/quic")
Expect(err).ToNot(HaveOccurred())
Expect(filters.AddrBlocked(testMA)).To(BeTrue())
cg := &localhostMockGater{}
Expect(cg.InterceptAccept(&connAddrs{rmAddr: testMA})).To(BeFalse())
raulk marked this conversation as resolved.
Show resolved Hide resolved

serverTransport, err := NewTransport(serverKey, nil, filters)
serverTransport, err := NewTransport(serverKey, nil, cg)
Expect(err).ToNot(HaveOccurred())
ln := runServer(serverTransport, "/ip4/127.0.0.1/udp/0/quic")
defer ln.Close()
Expand All @@ -192,7 +218,9 @@ var _ = Describe("Connection", func() {

// now allow the address and make sure the connection goes through
clientTransport.(*transport).clientConfig.HandshakeTimeout = 2 * time.Second
filters.AddFilter(ipNet, filter.ActionAccept)
cg.lk.Lock()
cg.allowAll = true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A test for InterceptSecured would be great (mostly for regression testing).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done.

cg.lk.Unlock()
conn, err := clientTransport.Dial(context.Background(), ln.Multiaddr(), serverID)
Expect(err).ToNot(HaveOccurred())
conn.Close()
Expand Down
36 changes: 30 additions & 6 deletions filtered_conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,38 @@ package libp2pquic
import (
"net"

filter "github.com/libp2p/go-maddr-filter"
"github.com/libp2p/go-libp2p-core/connmgr"

ma "github.com/multiformats/go-multiaddr"
)

type connAddrs struct {
lmAddr ma.Multiaddr
rmAddr ma.Multiaddr
}

func (c *connAddrs) LocalMultiaddr() ma.Multiaddr {
return c.lmAddr
}

func (c *connAddrs) RemoteMultiaddr() ma.Multiaddr {
return c.rmAddr
}

type filteredConn struct {
net.PacketConn

filters *filter.Filters
lmAddr ma.Multiaddr
gater connmgr.ConnectionGater
}

func newFilteredConn(c net.PacketConn, filters *filter.Filters) net.PacketConn {
return &filteredConn{PacketConn: c, filters: filters}
func newFilteredConn(c net.PacketConn, gater connmgr.ConnectionGater) net.PacketConn {
lmAddr, err := toQuicMultiaddr(c.LocalAddr())
if err != nil {
panic(err)
}

return &filteredConn{PacketConn: c, gater: gater, lmAddr: lmAddr}
}

func (c *filteredConn) ReadFrom(b []byte) (n int, addr net.Addr, rerr error) {
Expand All @@ -23,11 +44,14 @@ func (c *filteredConn) ReadFrom(b []byte) (n int, addr net.Addr, rerr error) {
if n < 1 || b[0]&0x80 == 0 {
return
}
maddr, err := toQuicMultiaddr(addr)
rmAddr, err := toQuicMultiaddr(addr)
if err != nil {
panic(err)
}
if !c.filters.AddrBlocked(maddr) {

connAddrs := &connAddrs{lmAddr: c.lmAddr, rmAddr: rmAddr}

if c.gater.InterceptAccept(connAddrs) {
return
}
raulk marked this conversation as resolved.
Show resolved Hide resolved
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.13

require (
github.com/ipfs/go-log v1.0.4
github.com/libp2p/go-libp2p-core v0.5.3
github.com/libp2p/go-libp2p-core v0.5.5
github.com/libp2p/go-libp2p-tls v0.1.3
github.com/libp2p/go-maddr-filter v0.0.5
github.com/libp2p/go-netroute v0.1.2
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS
github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco=
github.com/libp2p/go-libp2p-core v0.5.3 h1:b9W3w7AZR2n/YJhG8d0qPFGhGhCWKIvPuJgp4hhc4MM=
github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
github.com/libp2p/go-libp2p-core v0.5.5 h1:/yiFUZDoBWqvpWeHHJ1iA8SOs5obT1/+UdNfckwD57M=
github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM=
github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM=
github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=
github.com/libp2p/go-maddr-filter v0.0.5 h1:CW3AgbMO6vUvT4kf87y4N+0P8KUl2aqLYhrGyDUbLSg=
Expand All @@ -121,6 +123,8 @@ github.com/libp2p/go-netroute v0.1.2 h1:UHhB35chwgvcRI392znJA3RCBtZ3MpE3ahNCN5MR
github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=
github.com/libp2p/go-openssl v0.0.4 h1:d27YZvLoTyMhIN4njrkr8zMDOM4lfpHIp6A+TK9fovg=
github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
github.com/libp2p/go-openssl v0.0.5 h1:pQkejVhF0xp08D4CQUcw8t+BFJeXowja6RVcb5p++EA=
github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
github.com/libp2p/go-sockaddr v0.0.2 h1:tCuXfpA9rq7llM/v834RKc/Xvovy/AqM9kHvTV/jY/Q=
github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
github.com/lucas-clemente/quic-go v0.15.7 h1:Pu7To5/G9JoP1mwlrcIvfV8ByPBlCzif3MCl8+1W83I=
Expand Down
10 changes: 10 additions & 0 deletions listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package libp2pquic
import (
"context"
"crypto/tls"
"fmt"
"net"

ic "github.com/libp2p/go-libp2p-core/crypto"
n "github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
tpt "github.com/libp2p/go-libp2p-core/transport"

p2ptls "github.com/libp2p/go-libp2p-tls"

quic "github.com/lucas-clemente/quic-go"
Expand Down Expand Up @@ -79,6 +82,7 @@ func (l *listener) setupConn(sess quic.Session) (tpt.CapableConn, error) {
if err != nil {
return nil, err
}

remotePeerID, err := peer.IDFromPublicKey(remotePubKey)
if err != nil {
return nil, err
Expand All @@ -87,6 +91,12 @@ func (l *listener) setupConn(sess quic.Session) (tpt.CapableConn, error) {
if err != nil {
return nil, err
}

connaddrs := &connAddrs{lmAddr: l.localMultiaddr, rmAddr: remoteMultiaddr}
if l.transport.gater != nil && !l.transport.gater.InterceptSecured(n.DirInbound, remotePeerID, connaddrs) {
return nil, fmt.Errorf("secured connection gated")
}

return &conn{
sess: sess,
transport: l.transport,
Expand Down
19 changes: 10 additions & 9 deletions reuse.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import (
"sync"
"time"

filter "github.com/libp2p/go-maddr-filter"
"github.com/libp2p/go-libp2p-core/connmgr"

"github.com/libp2p/go-netroute"
)

Expand All @@ -23,9 +24,9 @@ type reuseConn struct {
unusedSince time.Time
}

func newReuseConn(conn net.PacketConn, filters *filter.Filters) *reuseConn {
if filters != nil {
conn = newFilteredConn(conn, filters)
func newReuseConn(conn net.PacketConn, gater connmgr.ConnectionGater) *reuseConn {
if gater != nil {
conn = newFilteredConn(conn, gater)
}
return &reuseConn{PacketConn: conn}
}
Expand Down Expand Up @@ -55,7 +56,7 @@ func (c *reuseConn) ShouldGarbageCollect(now time.Time) bool {
type reuse struct {
mutex sync.Mutex

filters *filter.Filters
gater connmgr.ConnectionGater

garbageCollectorRunning bool

Expand All @@ -64,9 +65,9 @@ type reuse struct {
global map[int]*reuseConn
}

func newReuse(filters *filter.Filters) *reuse {
func newReuse(gater connmgr.ConnectionGater) *reuse {
return &reuse{
filters: filters,
gater: gater,
unicast: make(map[string]map[int]*reuseConn),
global: make(map[int]*reuseConn),
}
Expand Down Expand Up @@ -168,7 +169,7 @@ func (r *reuse) dialLocked(network string, raddr *net.UDPAddr, source *net.IP) (
if err != nil {
return nil, err
}
rconn := newReuseConn(conn, r.filters)
rconn := newReuseConn(conn, r.gater)
r.global[conn.LocalAddr().(*net.UDPAddr).Port] = rconn
return rconn, nil
}
Expand All @@ -180,7 +181,7 @@ func (r *reuse) Listen(network string, laddr *net.UDPAddr) (*reuseConn, error) {
}
localAddr := conn.LocalAddr().(*net.UDPAddr)

rconn := newReuseConn(conn, r.filters)
rconn := newReuseConn(conn, r.gater)
rconn.IncreaseCount()

r.mutex.Lock()
Expand Down
24 changes: 18 additions & 6 deletions transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ package libp2pquic
import (
"context"
"errors"
"fmt"
"io"
"net"

"github.com/libp2p/go-libp2p-core/connmgr"
n "github.com/libp2p/go-libp2p-core/network"

"github.com/minio/sha256-simd"
"golang.org/x/crypto/hkdf"

Expand All @@ -15,7 +19,6 @@ import (
"github.com/libp2p/go-libp2p-core/pnet"
tpt "github.com/libp2p/go-libp2p-core/transport"
p2ptls "github.com/libp2p/go-libp2p-tls"
filter "github.com/libp2p/go-maddr-filter"
quic "github.com/lucas-clemente/quic-go"
ma "github.com/multiformats/go-multiaddr"
mafmt "github.com/multiformats/go-multiaddr-fmt"
Expand Down Expand Up @@ -43,9 +46,9 @@ type connManager struct {
reuseUDP6 *reuse
}

func newConnManager(filters *filter.Filters) (*connManager, error) {
reuseUDP4 := newReuse(filters)
reuseUDP6 := newReuse(filters)
func newConnManager(gater connmgr.ConnectionGater) (*connManager, error) {
reuseUDP4 := newReuse(gater)
reuseUDP6 := newReuse(gater)

return &connManager{
reuseUDP4: reuseUDP4,
Expand Down Expand Up @@ -88,12 +91,13 @@ type transport struct {
connManager *connManager
serverConfig *quic.Config
clientConfig *quic.Config
gater connmgr.ConnectionGater
}

var _ tpt.Transport = &transport{}

// NewTransport creates a new QUIC transport
func NewTransport(key ic.PrivKey, psk pnet.PSK, filters *filter.Filters) (tpt.Transport, error) {
func NewTransport(key ic.PrivKey, psk pnet.PSK, gater connmgr.ConnectionGater) (tpt.Transport, error) {
if len(psk) > 0 {
log.Error("QUIC doesn't support private networks yet.")
return nil, errors.New("QUIC doesn't support private networks yet")
Expand All @@ -106,7 +110,7 @@ func NewTransport(key ic.PrivKey, psk pnet.PSK, filters *filter.Filters) (tpt.Tr
if err != nil {
return nil, err
}
connManager, err := newConnManager(filters)
connManager, err := newConnManager(gater)
if err != nil {
return nil, err
}
Expand All @@ -128,6 +132,7 @@ func NewTransport(key ic.PrivKey, psk pnet.PSK, filters *filter.Filters) (tpt.Tr
connManager: connManager,
serverConfig: config,
clientConfig: config.Clone(),
gater: gater,
}
t.serverConfig.GetLogWriter = getLogWriterFor("server")
t.clientConfig.GetLogWriter = getLogWriterFor("client")
Expand Down Expand Up @@ -178,6 +183,13 @@ func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tp
pconn.DecreaseCount()
return nil, err
}

connaddrs := &connAddrs{lmAddr: localMultiaddr, rmAddr: remoteMultiaddr}
if t.gater != nil && !t.gater.InterceptSecured(n.DirOutbound, p, connaddrs) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to close the connection at this point. Otherwise the peer will never know that we closed the connection. As from quic-go's point of view the connection is fully established, there won't be any connection-level timeout here either.

pconn.DecreaseCount()
return nil, fmt.Errorf("secured connection gated")
}

return &conn{
sess: sess,
transport: t,
Expand Down