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

p2p-circuit v2 #125

Merged
merged 66 commits into from
Jul 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
9957868
v2 client scaffolding
vyzo Feb 4, 2021
07c94b2
gomod: go-libp2p-core and go-libp2p-transport-upgrader feature depend…
vyzo Feb 4, 2021
00f66ac
Conn implements network.ConnStat
vyzo Feb 4, 2021
2a4f0fe
add reservation stub
vyzo Feb 4, 2021
d65387b
utilities
vyzo Feb 4, 2021
2158d4e
dial scaffolding and v1 compat dialing
vyzo Feb 4, 2021
4cf0099
stream handling scaffolding and v1 incoming connection handling
vyzo Feb 4, 2021
08e8616
implement hop tagging
vyzo Feb 4, 2021
5775e43
export timeout variables
vyzo Feb 4, 2021
3a20a7d
v2 protobuf
vyzo Feb 4, 2021
67cdcee
v2 client protocol implementation
vyzo Feb 4, 2021
8abf64d
implement Reserve
vyzo Feb 4, 2021
5fa453e
go get go-libp2p-swarm@feat/transient-conns
vyzo Feb 4, 2021
7ebd713
implement client.New
vyzo Feb 4, 2021
7cd275a
rework pb status codes
vyzo Feb 5, 2021
7805167
client responds with UNEXPECTED_MESSAGE when it's actually an unexpec…
vyzo Feb 5, 2021
e4a463f
relay scaffolding, reservation implementation
vyzo Feb 5, 2021
66e3654
implement relaying
vyzo Feb 5, 2021
5e1217a
implement missing details
vyzo Feb 5, 2021
ff9fdfc
add options for resources/limit
vyzo Feb 5, 2021
cbe4fcb
gc idle conn counts
vyzo Feb 6, 2021
e36365e
fix clown shoes in cancellation check
vyzo Feb 7, 2021
1fbd2d4
end to end relay test
vyzo Feb 11, 2021
71d18fd
untag peers with expired reservations
vyzo Feb 11, 2021
c679386
add time limit test
vyzo Feb 12, 2021
20bdb29
better debug log for accepted conns
vyzo Feb 12, 2021
d9dd2e8
add data limit test
vyzo Feb 12, 2021
529b09f
add v2-v1 compatibility tests
vyzo Feb 12, 2021
c278b2c
godocs
vyzo Feb 12, 2021
017982a
add WithACL relay option
vyzo Feb 12, 2021
2dda598
only return public relay addrs in reservation record
vyzo Feb 13, 2021
96e502e
remove the refresh restriction madness
vyzo Feb 15, 2021
6eaf6e1
set default limit Data to 128K
vyzo Feb 15, 2021
92c0e0b
fix typo in AllowReserve godoc
vyzo Feb 15, 2021
1f294d2
fix some small issues
vyzo Feb 15, 2021
13a9ed7
fix tests
vyzo Feb 15, 2021
6c7540c
address review comments
vyzo Feb 15, 2021
3087bec
humor aarsh and add initializers for slices
vyzo Feb 15, 2021
b47c119
comment nitpicks
vyzo Feb 15, 2021
82f3808
fix bug in slice pre-allocations
vyzo Feb 15, 2021
57b0a29
add deadline to connectV1
vyzo Feb 16, 2021
6fed031
make Relay.Close thread-safe
vyzo Feb 16, 2021
7e8bef0
untag peers with reservations when closing the relay
vyzo Feb 16, 2021
49e9649
gomod: get go-libp2p-asn-util
vyzo Feb 16, 2021
5b7a615
add IP/ASN reservation constraints
vyzo Feb 16, 2021
6389453
gomod: update deps
vyzo Feb 17, 2021
148d307
fix e2e test
vyzo Feb 17, 2021
68d07f5
increase default limit duration to 2min
vyzo Feb 18, 2021
526fc92
update protocol for vouched relay addrs; provide absolute expiration …
vyzo Feb 18, 2021
6d34d5b
update for reservation changes
vyzo Feb 18, 2021
16d5616
add voucher to the reservation pb
vyzo Feb 18, 2021
1cec70e
TODO about reservation vouchers
vyzo Feb 18, 2021
4ec7298
deduplicate protocol ID definitions between relay and client
vyzo Feb 19, 2021
c7b3913
add reservation vouchers
vyzo Feb 19, 2021
533abb2
emit and consume reservation vouchers
vyzo Feb 19, 2021
a3d765a
improve limit data test
vyzo Feb 24, 2021
75b4777
deduplicate concurrent relay dials to the samke peer
vyzo Feb 24, 2021
470c088
improve dialer deduplication
vyzo Feb 25, 2021
2333151
add a short timeout to dialing the relay in order to aid deduplication
vyzo Mar 9, 2021
84c6610
gomod: fix go1.16 madness
vyzo Mar 9, 2021
30b71a3
spec compliance: don't include p2p-circuit in reservation addrs
vyzo Jun 4, 2021
ffa309e
spec compliance: refuse reservation and connection attempts over rela…
vyzo Jun 4, 2021
12eefbc
test shim: add empty file in test directory
vyzo Jun 4, 2021
b4d0d1a
spec compliance: update protobuf
vyzo Jun 4, 2021
e1bbd83
spec compliance: use libp2p envelopes for reservation vouchers
vyzo Jun 4, 2021
97ec1d6
fix staticcheck
marten-seemann Jun 30, 2021
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
9 changes: 6 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ require (
github.com/gogo/protobuf v1.3.1
github.com/ipfs/go-log v1.0.4
github.com/libp2p/go-buffer-pool v0.0.2
github.com/libp2p/go-libp2p-asn-util v0.0.0-20210211060025-0db24c10d3bd
github.com/libp2p/go-libp2p-blankhost v0.2.0
github.com/libp2p/go-libp2p-core v0.7.0
github.com/libp2p/go-libp2p-swarm v0.3.0
github.com/libp2p/go-libp2p-transport-upgrader v0.3.0
github.com/libp2p/go-libp2p-core v0.8.3
github.com/libp2p/go-libp2p-peerstore v0.2.6
github.com/libp2p/go-libp2p-swarm v0.4.3
github.com/libp2p/go-libp2p-transport-upgrader v0.4.2
github.com/libp2p/go-msgio v0.0.6
github.com/libp2p/go-tcp-transport v0.2.0
github.com/multiformats/go-multiaddr v0.3.1
github.com/multiformats/go-varint v0.0.6
)
249 changes: 224 additions & 25 deletions go.sum

Large diffs are not rendered by default.

66 changes: 66 additions & 0 deletions v2/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package client

import (
"context"
"sync"

"github.com/libp2p/go-libp2p-circuit/v2/proto"

"github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/peer"

logging "github.com/ipfs/go-log"
tptu "github.com/libp2p/go-libp2p-transport-upgrader"
)

var log = logging.Logger("p2p-circuit")

// Client implements the client-side of the p2p-circuit/v2 protocol:
// - it implements dialing through v2 relays
// - it listens for incoming connections through v2 relays.
//
// For backwards compatibility with v1 relays and older nodes, the client will
// also accept relay connections through v1 relays and fallback dial peers using p2p-circuit/v1.
// This allows us to use the v2 code as drop in replacement for v1 in a host without breaking
// existing code and interoperability with older nodes.
type Client struct {
ctx context.Context
host host.Host
upgrader *tptu.Upgrader

incoming chan accept

mx sync.Mutex
activeDials map[peer.ID]*completion
hopCount map[peer.ID]int
}

type accept struct {
conn *Conn
writeResponse func() error
}

type completion struct {
ch chan struct{}
relay peer.ID
err error
}

// New constructs a new p2p-circuit/v2 client, attached to the given host and using the given
// upgrader to perform connection upgrades.
func New(ctx context.Context, h host.Host, upgrader *tptu.Upgrader) (*Client, error) {
return &Client{
ctx: ctx,
host: h,
upgrader: upgrader,
incoming: make(chan accept),
activeDials: make(map[peer.ID]*completion),
hopCount: make(map[peer.ID]int),
}, nil
}

// Start registers the circuit (client) protocol stream handlers
func (c *Client) Start() {
c.host.SetStreamHandler(proto.ProtoIDv1, c.handleStreamV1)
c.host.SetStreamHandler(proto.ProtoIDv2Stop, c.handleStreamV2)
}
145 changes: 145 additions & 0 deletions v2/client/conn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package client

import (
"fmt"
"net"
"time"

"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"

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

// HopTagWeight is the connection manager weight for connections carrying relay hop streams
var HopTagWeight = 5

type statLimitDuration struct{}
type statLimitData struct{}

var (
StatLimitDuration = statLimitDuration{}
StatLimitData = statLimitData{}
)

type Conn struct {
stream network.Stream
remote peer.AddrInfo
stat network.Stat

client *Client
}

type NetAddr struct {
Relay string
Remote string
}

var _ net.Addr = (*NetAddr)(nil)

func (n *NetAddr) Network() string {
return "libp2p-circuit-relay"
}

func (n *NetAddr) String() string {
return fmt.Sprintf("relay[%s-%s]", n.Remote, n.Relay)
}

// Conn interface
var _ manet.Conn = (*Conn)(nil)

func (c *Conn) Close() error {
c.untagHop()
return c.stream.Reset()
}

func (c *Conn) Read(buf []byte) (int, error) {
return c.stream.Read(buf)
}

func (c *Conn) Write(buf []byte) (int, error) {
return c.stream.Write(buf)
}

func (c *Conn) SetDeadline(t time.Time) error {
return c.stream.SetDeadline(t)
}

func (c *Conn) SetReadDeadline(t time.Time) error {
return c.stream.SetReadDeadline(t)
}

func (c *Conn) SetWriteDeadline(t time.Time) error {
return c.stream.SetWriteDeadline(t)
}

// TODO: is it okay to cast c.Conn().RemotePeer() into a multiaddr? might be "user input"
func (c *Conn) RemoteMultiaddr() ma.Multiaddr {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please can we add a unit test for this one function ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ugh.... maybe, I am not inclined to do it right now.

// TODO: We should be able to do this directly without converting to/from a string.
relayAddr, err := ma.NewComponent(
ma.ProtocolWithCode(ma.P_P2P).Name,
c.stream.Conn().RemotePeer().Pretty(),
)
if err != nil {
panic(err)
}
return ma.Join(c.stream.Conn().RemoteMultiaddr(), relayAddr, circuitAddr)
}

func (c *Conn) LocalMultiaddr() ma.Multiaddr {
return c.stream.Conn().LocalMultiaddr()
}

func (c *Conn) LocalAddr() net.Addr {
na, err := manet.ToNetAddr(c.stream.Conn().LocalMultiaddr())
if err != nil {
log.Error("failed to convert local multiaddr to net addr:", err)
return nil
}
return na
}

func (c *Conn) RemoteAddr() net.Addr {
return &NetAddr{
Relay: c.stream.Conn().RemotePeer().Pretty(),
Remote: c.remote.ID.Pretty(),
}
}

// ConnStat interface
var _ network.ConnStat = (*Conn)(nil)

func (c *Conn) Stat() network.Stat {
return c.stat
}

// tagHop tags the underlying relay connection so that it can be (somewhat) protected from the
// connection manager as it is an important connection that proxies other connections.
// This is handled here so that the user code doesnt need to bother with this and avoid
// clown shoes situations where a high value peer connection is behind a relayed connection and it is
// implicitly because the connection manager closed the underlying relay connection.
func (c *Conn) tagHop() {
vyzo marked this conversation as resolved.
Show resolved Hide resolved
c.client.mx.Lock()
defer c.client.mx.Unlock()

p := c.stream.Conn().RemotePeer()
c.client.hopCount[p]++
if c.client.hopCount[p] == 1 {
c.client.host.ConnManager().TagPeer(p, "relay-hop-stream", HopTagWeight)
}
}

// untagHop removes the relay-hop-stream tag if necessary; it is invoked when a relayed connection
// is closed.
func (c *Conn) untagHop() {
c.client.mx.Lock()
defer c.client.mx.Unlock()

p := c.stream.Conn().RemotePeer()
c.client.hopCount[p]--
if c.client.hopCount[p] == 0 {
c.client.host.ConnManager().UntagPeer(p, "relay-hop-stream")
delete(c.client.hopCount, p)
}
}
Loading