mirror of
https://github.com/libp2p/go-libp2p-resource-manager.git
synced 2025-03-10 17:20:39 +08:00
commit
6607ffe4dc
215
allowlist.go
Normal file
215
allowlist.go
Normal file
@ -0,0 +1,215 @@
|
||||
package rcmgr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
type Allowlist struct {
|
||||
mu sync.RWMutex
|
||||
// a simple structure of lists of networks. There is probably a faster way
|
||||
// to check if an IP address is in this network than iterating over this
|
||||
// list, but this is good enough for small numbers of networks (<1_000).
|
||||
// Analyze the benchmark before trying to optimize this.
|
||||
|
||||
// Any peer with these IPs are allowed
|
||||
allowedNetworks []*net.IPNet
|
||||
|
||||
// Only the specified peers can use these IPs
|
||||
allowedPeerByNetwork map[peer.ID][]*net.IPNet
|
||||
}
|
||||
|
||||
// WithAllowlistedMultiaddrs sets the multiaddrs to be in the allowlist
|
||||
func WithAllowlistedMultiaddrs(mas []multiaddr.Multiaddr) Option {
|
||||
return func(rm *resourceManager) error {
|
||||
for _, ma := range mas {
|
||||
err := rm.allowlist.Add(ma)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func newAllowlist() Allowlist {
|
||||
return Allowlist{
|
||||
allowedPeerByNetwork: make(map[peer.ID][]*net.IPNet),
|
||||
}
|
||||
}
|
||||
|
||||
func toIPNet(ma multiaddr.Multiaddr) (*net.IPNet, peer.ID, error) {
|
||||
var ipString string
|
||||
var mask string
|
||||
var allowedPeerStr string
|
||||
var allowedPeer peer.ID
|
||||
var isIPV4 bool
|
||||
|
||||
multiaddr.ForEach(ma, func(c multiaddr.Component) bool {
|
||||
if c.Protocol().Code == multiaddr.P_IP4 || c.Protocol().Code == multiaddr.P_IP6 {
|
||||
isIPV4 = c.Protocol().Code == multiaddr.P_IP4
|
||||
ipString = c.Value()
|
||||
}
|
||||
if c.Protocol().Code == multiaddr.P_IPCIDR {
|
||||
mask = c.Value()
|
||||
}
|
||||
if c.Protocol().Code == multiaddr.P_P2P {
|
||||
allowedPeerStr = c.Value()
|
||||
}
|
||||
return ipString == "" || mask == "" || allowedPeerStr == ""
|
||||
})
|
||||
|
||||
if ipString == "" {
|
||||
return nil, allowedPeer, errors.New("missing ip address")
|
||||
}
|
||||
|
||||
if allowedPeerStr != "" {
|
||||
var err error
|
||||
allowedPeer, err = peer.Decode(allowedPeerStr)
|
||||
if err != nil {
|
||||
return nil, allowedPeer, fmt.Errorf("failed to decode allowed peer: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if mask == "" {
|
||||
ip := net.ParseIP(ipString)
|
||||
if ip == nil {
|
||||
return nil, allowedPeer, errors.New("invalid ip address")
|
||||
}
|
||||
var mask net.IPMask
|
||||
if isIPV4 {
|
||||
mask = net.CIDRMask(32, 32)
|
||||
} else {
|
||||
mask = net.CIDRMask(128, 128)
|
||||
}
|
||||
|
||||
net := &net.IPNet{IP: ip, Mask: mask}
|
||||
return net, allowedPeer, nil
|
||||
}
|
||||
|
||||
_, ipnet, err := net.ParseCIDR(ipString + "/" + mask)
|
||||
return ipnet, allowedPeer, err
|
||||
|
||||
}
|
||||
|
||||
// Add takes a multiaddr and adds it to the allowlist. The multiaddr should be
|
||||
// an ip address of the peer with or without a `/p2p` protocol.
|
||||
// e.g. /ip4/1.2.3.4/p2p/QmFoo, /ip4/1.2.3.4, and /ip4/1.2.3.0/ipcidr/24 are valid.
|
||||
// /p2p/QmFoo is not valid.
|
||||
func (al *Allowlist) Add(ma multiaddr.Multiaddr) error {
|
||||
ipnet, allowedPeer, err := toIPNet(ma)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
al.mu.Lock()
|
||||
defer al.mu.Unlock()
|
||||
|
||||
if allowedPeer != peer.ID("") {
|
||||
// We have a peerID constraint
|
||||
if al.allowedPeerByNetwork == nil {
|
||||
al.allowedPeerByNetwork = make(map[peer.ID][]*net.IPNet)
|
||||
}
|
||||
al.allowedPeerByNetwork[allowedPeer] = append(al.allowedPeerByNetwork[allowedPeer], ipnet)
|
||||
} else {
|
||||
al.allowedNetworks = append(al.allowedNetworks, ipnet)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (al *Allowlist) Remove(ma multiaddr.Multiaddr) error {
|
||||
ipnet, allowedPeer, err := toIPNet(ma)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
al.mu.Lock()
|
||||
defer al.mu.Unlock()
|
||||
|
||||
ipNetList := al.allowedNetworks
|
||||
|
||||
if allowedPeer != "" {
|
||||
// We have a peerID constraint
|
||||
ipNetList = al.allowedPeerByNetwork[allowedPeer]
|
||||
}
|
||||
|
||||
if ipNetList == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
i := len(ipNetList)
|
||||
for i > 0 {
|
||||
i--
|
||||
if ipNetList[i].IP.Equal(ipnet.IP) && bytes.Equal(ipNetList[i].Mask, ipnet.Mask) {
|
||||
// swap remove
|
||||
ipNetList[i] = ipNetList[len(ipNetList)-1]
|
||||
ipNetList = ipNetList[:len(ipNetList)-1]
|
||||
// We only remove one thing
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if allowedPeer != "" {
|
||||
al.allowedPeerByNetwork[allowedPeer] = ipNetList
|
||||
} else {
|
||||
al.allowedNetworks = ipNetList
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (al *Allowlist) Allowed(ma multiaddr.Multiaddr) bool {
|
||||
ip, err := manet.ToIP(ma)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
al.mu.RLock()
|
||||
defer al.mu.RUnlock()
|
||||
|
||||
for _, network := range al.allowedNetworks {
|
||||
if network.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for _, allowedNetworks := range al.allowedPeerByNetwork {
|
||||
for _, network := range allowedNetworks {
|
||||
if network.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (al *Allowlist) AllowedPeerAndMultiaddr(peerID peer.ID, ma multiaddr.Multiaddr) bool {
|
||||
ip, err := manet.ToIP(ma)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
al.mu.RLock()
|
||||
defer al.mu.RUnlock()
|
||||
|
||||
for _, network := range al.allowedNetworks {
|
||||
if network.Contains(ip) {
|
||||
// We found a match that isn't constrained by a peerID
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if expectedNetworks, ok := al.allowedPeerByNetwork[peerID]; ok {
|
||||
for _, expectedNetwork := range expectedNetworks {
|
||||
if expectedNetwork.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
264
allowlist_test.go
Normal file
264
allowlist_test.go
Normal file
@ -0,0 +1,264 @@
|
||||
package rcmgr
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/libp2p/go-libp2p-core/test"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
func TestAllowedSimple(t *testing.T) {
|
||||
allowlist := newAllowlist()
|
||||
ma := multiaddr.StringCast("/ip4/1.2.3.4/tcp/1234")
|
||||
err := allowlist.Add(ma)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add ip4: %s", err)
|
||||
}
|
||||
|
||||
if !allowlist.Allowed(ma) {
|
||||
t.Fatalf("addr should be allowed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowedWithPeer(t *testing.T) {
|
||||
type testcase struct {
|
||||
name string
|
||||
allowlist []string
|
||||
endpoint multiaddr.Multiaddr
|
||||
peer peer.ID
|
||||
// Is this endpoint allowed? (We don't have peer info yet)
|
||||
isConnAllowed bool
|
||||
// Is this peer + endpoint allowed?
|
||||
isAllowedWithPeer bool
|
||||
}
|
||||
|
||||
peerA := test.RandPeerIDFatal(t)
|
||||
peerB := test.RandPeerIDFatal(t)
|
||||
multiaddrA := multiaddr.StringCast("/ip4/1.2.3.4/tcp/1234")
|
||||
multiaddrB := multiaddr.StringCast("/ip4/2.2.3.4/tcp/1234")
|
||||
|
||||
testcases := []testcase{
|
||||
{
|
||||
name: "Blocked",
|
||||
isConnAllowed: false,
|
||||
isAllowedWithPeer: false,
|
||||
allowlist: []string{"/ip4/1.2.3.1"},
|
||||
endpoint: multiaddrA,
|
||||
peer: peerA,
|
||||
},
|
||||
{
|
||||
name: "Blocked wrong peer",
|
||||
isConnAllowed: true,
|
||||
isAllowedWithPeer: false,
|
||||
allowlist: []string{"/ip4/1.2.3.4" + "/p2p/" + peer.Encode(peerB)},
|
||||
endpoint: multiaddrA,
|
||||
peer: peerA,
|
||||
},
|
||||
{
|
||||
name: "allowed on network",
|
||||
isConnAllowed: true,
|
||||
isAllowedWithPeer: true,
|
||||
allowlist: []string{"/ip4/1.2.3.0/ipcidr/24"},
|
||||
endpoint: multiaddrA,
|
||||
peer: peerA,
|
||||
},
|
||||
{
|
||||
name: "Blocked peer not on network",
|
||||
isConnAllowed: true,
|
||||
isAllowedWithPeer: true,
|
||||
allowlist: []string{"/ip4/1.2.3.0/ipcidr/24"},
|
||||
endpoint: multiaddrA,
|
||||
peer: peerA,
|
||||
}, {
|
||||
name: "allowed. right network, right peer",
|
||||
isConnAllowed: true,
|
||||
isAllowedWithPeer: true,
|
||||
allowlist: []string{"/ip4/1.2.3.0/ipcidr/24" + "/p2p/" + peer.Encode(peerA)},
|
||||
endpoint: multiaddrA,
|
||||
peer: peerA,
|
||||
}, {
|
||||
name: "allowed. right network, no peer",
|
||||
isConnAllowed: true,
|
||||
isAllowedWithPeer: true,
|
||||
allowlist: []string{"/ip4/1.2.3.0/ipcidr/24"},
|
||||
endpoint: multiaddrA,
|
||||
peer: peerA,
|
||||
},
|
||||
{
|
||||
name: "Blocked. right network, wrong peer",
|
||||
isConnAllowed: true,
|
||||
isAllowedWithPeer: false,
|
||||
allowlist: []string{"/ip4/1.2.3.0/ipcidr/24" + "/p2p/" + peer.Encode(peerB)},
|
||||
endpoint: multiaddrA,
|
||||
peer: peerA,
|
||||
},
|
||||
{
|
||||
name: "allowed peer any ip",
|
||||
isConnAllowed: true,
|
||||
isAllowedWithPeer: true,
|
||||
allowlist: []string{"/ip4/0.0.0.0/ipcidr/0"},
|
||||
endpoint: multiaddrA,
|
||||
peer: peerA,
|
||||
},
|
||||
{
|
||||
name: "allowed peer multiple ips in allowlist",
|
||||
isConnAllowed: true,
|
||||
isAllowedWithPeer: true,
|
||||
allowlist: []string{"/ip4/1.2.3.4/p2p/" + peer.Encode(peerA), "/ip4/2.2.3.4/p2p/" + peer.Encode(peerA)},
|
||||
endpoint: multiaddrA,
|
||||
peer: peerA,
|
||||
},
|
||||
{
|
||||
name: "allowed peer multiple ips in allowlist",
|
||||
isConnAllowed: true,
|
||||
isAllowedWithPeer: true,
|
||||
allowlist: []string{"/ip4/1.2.3.4/p2p/" + peer.Encode(peerA), "/ip4/1.2.3.4/p2p/" + peer.Encode(peerA)},
|
||||
endpoint: multiaddrA,
|
||||
peer: peerA,
|
||||
},
|
||||
{
|
||||
name: "allowed peer multiple ips in allowlist",
|
||||
isConnAllowed: true,
|
||||
isAllowedWithPeer: true,
|
||||
allowlist: []string{"/ip4/1.2.3.4/p2p/" + peer.Encode(peerA), "/ip4/2.2.3.4/p2p/" + peer.Encode(peerA)},
|
||||
endpoint: multiaddrB,
|
||||
peer: peerA,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
allowlist := newAllowlist()
|
||||
for _, maStr := range tc.allowlist {
|
||||
ma, err := multiaddr.NewMultiaddr(maStr)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to parse multiaddr: %s", err)
|
||||
}
|
||||
allowlist.Add(ma)
|
||||
}
|
||||
|
||||
if allowlist.Allowed(tc.endpoint) != tc.isConnAllowed {
|
||||
t.Fatalf("%v: expected %v", !tc.isConnAllowed, tc.isConnAllowed)
|
||||
}
|
||||
|
||||
if allowlist.AllowedPeerAndMultiaddr(tc.peer, tc.endpoint) != tc.isAllowedWithPeer {
|
||||
t.Fatalf("%v: expected %v", !tc.isAllowedWithPeer, tc.isAllowedWithPeer)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestRemoved(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
allowedMA string
|
||||
}
|
||||
peerA := test.RandPeerIDFatal(t)
|
||||
maA := multiaddr.StringCast("/ip4/1.2.3.4")
|
||||
|
||||
testCases := []testCase{
|
||||
{name: "ip4", allowedMA: "/ip4/1.2.3.4"},
|
||||
{name: "ip4 with peer", allowedMA: "/ip4/1.2.3.4/p2p/" + peer.Encode(peerA)},
|
||||
{name: "ip4 network", allowedMA: "/ip4/0.0.0.0/ipcidr/0"},
|
||||
{name: "ip4 network with peer", allowedMA: "/ip4/0.0.0.0/ipcidr/0/p2p/" + peer.Encode(peerA)},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
allowlist := newAllowlist()
|
||||
ma := multiaddr.StringCast(tc.allowedMA)
|
||||
|
||||
err := allowlist.Add(ma)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add ip4: %s", err)
|
||||
}
|
||||
|
||||
if !allowlist.AllowedPeerAndMultiaddr(peerA, maA) {
|
||||
t.Fatalf("addr should be allowed")
|
||||
}
|
||||
|
||||
allowlist.Remove((ma))
|
||||
|
||||
if allowlist.AllowedPeerAndMultiaddr(peerA, maA) {
|
||||
t.Fatalf("addr should not be allowed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkAllowlistCheck benchmarks the allowlist with plausible conditions.
|
||||
func BenchmarkAllowlistCheck(b *testing.B) {
|
||||
allowlist := newAllowlist()
|
||||
|
||||
// How often do we expect a peer to be specified? 1 in N
|
||||
ratioOfSpecifiedPeers := 10
|
||||
|
||||
// How often do we expect an allowlist hit? 1 in N
|
||||
ratioOfAllowlistHit := 100
|
||||
|
||||
// How many multiaddrs in our allowlist?
|
||||
howManyMultiaddrsInAllowList := 1_000
|
||||
|
||||
// How often is the IP addr an IPV6? 1 in N
|
||||
ratioOfIPV6 := 20
|
||||
|
||||
countOfTotalPeersForTest := 100_000
|
||||
|
||||
mas := make([]multiaddr.Multiaddr, countOfTotalPeersForTest)
|
||||
for i := 0; i < countOfTotalPeersForTest; i++ {
|
||||
|
||||
ip := make([]byte, 16)
|
||||
n, err := rand.Reader.Read(ip)
|
||||
if err != nil || n != 16 {
|
||||
b.Fatalf("Failed to generate IP address")
|
||||
}
|
||||
|
||||
var ipString string
|
||||
|
||||
if i%ratioOfIPV6 == 0 {
|
||||
// IPv6
|
||||
ip6 := net.IP(ip)
|
||||
ipString = "/ip6/" + ip6.String()
|
||||
} else {
|
||||
// IPv4
|
||||
ip4 := net.IPv4(ip[0], ip[1], ip[2], ip[3])
|
||||
ipString = "/ip4/" + ip4.String()
|
||||
}
|
||||
|
||||
var ma multiaddr.Multiaddr
|
||||
if i%ratioOfSpecifiedPeers == 0 {
|
||||
ma = multiaddr.StringCast(ipString + "/p2p/" + peer.Encode(test.RandPeerIDFatal(b)))
|
||||
} else {
|
||||
ma = multiaddr.StringCast(ipString)
|
||||
}
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to generate multiaddr: %v", ipString)
|
||||
}
|
||||
|
||||
mas[i] = ma
|
||||
}
|
||||
|
||||
for _, ma := range mas[:howManyMultiaddrsInAllowList] {
|
||||
err := allowlist.Add(ma)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to add multiaddr")
|
||||
}
|
||||
}
|
||||
|
||||
masInAllowList := mas[:howManyMultiaddrsInAllowList]
|
||||
masNotInAllowList := mas[howManyMultiaddrsInAllowList:]
|
||||
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
if n%ratioOfAllowlistHit == 0 {
|
||||
allowlist.Allowed(masInAllowList[n%len(masInAllowList)])
|
||||
} else {
|
||||
allowlist.Allowed(masNotInAllowList[n%len(masNotInAllowList)])
|
||||
}
|
||||
}
|
||||
}
|
54
docs/allowlist.md
Normal file
54
docs/allowlist.md
Normal file
@ -0,0 +1,54 @@
|
||||
# Allowlist
|
||||
|
||||
Imagine you have a node that is getting overloaded by possibly malicious
|
||||
incoming connections. This node won't be able to accept incoming connections
|
||||
from peers it _knows_ to be good. This node would effectively be _eclipsed_ from
|
||||
the network since no other nodes will be able to connect to it.
|
||||
|
||||
This is the problem that the Allowlist is designed to solve.
|
||||
|
||||
## Design Goals
|
||||
|
||||
- We should not fail to allocate a resource for an allowlisted peer because the
|
||||
normal transient and system scopes are at their limits. This is the minimum
|
||||
bar to avoid eclipse attacks.
|
||||
- Minimal changes to resource manager and existing code (e.g. go-libp2p).
|
||||
- The allowlist scope itself is limited to avoid giving an allowlisted peer the
|
||||
ability to DoS a node.
|
||||
- PeerIDs can optionally be fed into the allowlist. This will give an extra
|
||||
step of verification before continuing to allow the peer to open streams.
|
||||
- A peer may be able to open a connection, but after the handshake, if it's
|
||||
not an expected peer id we move it to the normal system scope.
|
||||
- We can have multiple PeerIDs for a given IP addr.
|
||||
- No extra cost for the happy path when we are still below system and transient
|
||||
limits.
|
||||
|
||||
## Proposed change
|
||||
|
||||
Add a change to `ResourceManager.OpenConnection` so that it accepts a multiaddr
|
||||
parameter of the endpoint the connection is for.
|
||||
|
||||
Add a change to `ResourceManager` to initialize it with a set of allowlisted
|
||||
multiaddrs. This set can be modified at runtime as well for dynamic updating.
|
||||
|
||||
For example, an allowlist set could look like:
|
||||
```
|
||||
/ip4/1.1.1.1
|
||||
/ip6/2345:0425:2CA1::0567:5673:23b5
|
||||
/ip4/192.168.1.1/p2p/qmFoo
|
||||
/ip4/192.168.1.1/p2p/qmBar
|
||||
/ip4/1.2.3.0/ipcidr/24
|
||||
```
|
||||
|
||||
When a new connection is opened, the resource manager tries to allocate with the
|
||||
normal system and transient resource scopes. If that fails, it checks if the
|
||||
multiaddr matches an item in the set of allowlisted multiaddrs. If so, it
|
||||
creates the connection resource scope using the allowlisted specific system and
|
||||
transient resource scopes. If it wasn't an allowlisted multiaddr it fails as
|
||||
before.
|
||||
|
||||
When an allowlisted connection is tied to a peer id and transfered with
|
||||
`ConnManagementScope.SetPeer`, we check if that peer id matches the expected
|
||||
value in the allowlist (if it exists). If it does not match, we attempt to
|
||||
transfer this resource to the normal system and peer scope. If that transfer
|
||||
fails we close the connection.
|
22
go.mod
22
go.mod
@ -3,36 +3,40 @@ module github.com/libp2p/go-libp2p-resource-manager
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/ipfs/go-log/v2 v2.5.0
|
||||
github.com/libp2p/go-libp2p-core v0.14.0
|
||||
github.com/ipfs/go-log/v2 v2.5.1
|
||||
github.com/libp2p/go-libp2p-core v0.19.0
|
||||
github.com/multiformats/go-multiaddr v0.6.0
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
|
||||
github.com/stretchr/testify v1.7.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/btcsuite/btcd v0.20.1-beta // indirect
|
||||
github.com/btcsuite/btcd v0.22.1 // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.3 // indirect
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.1 // indirect
|
||||
github.com/ipfs/go-cid v0.0.7 // indirect
|
||||
github.com/ipfs/go-cid v0.2.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.4 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
|
||||
github.com/libp2p/go-openssl v0.0.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
|
||||
github.com/minio/sha256-simd v0.1.1 // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.0.3 // indirect
|
||||
github.com/multiformats/go-base36 v0.1.0 // indirect
|
||||
github.com/multiformats/go-multiaddr v0.4.1 // indirect
|
||||
github.com/multiformats/go-multibase v0.0.3 // indirect
|
||||
github.com/multiformats/go-multihash v0.0.14 // indirect
|
||||
github.com/multiformats/go-multicodec v0.4.1 // indirect
|
||||
github.com/multiformats/go-multihash v0.0.15 // indirect
|
||||
github.com/multiformats/go-varint v0.0.6 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.19.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf // indirect
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
)
|
||||
|
55
go.sum
55
go.sum
@ -1,13 +1,22 @@
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
|
||||
github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
|
||||
github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=
|
||||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
@ -15,20 +24,29 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
||||
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY=
|
||||
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
|
||||
github.com/ipfs/go-log/v2 v2.5.0 h1:+MhAooFd9XZNvR0i9FriKW6HB0ql7HNXUuflWtc0dd4=
|
||||
github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
|
||||
github.com/ipfs/go-cid v0.2.0 h1:01JTiihFq9en9Vz0lc0VDWvZe/uBonGpzo4THP0vcQ0=
|
||||
github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro=
|
||||
github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
|
||||
github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.4 h1:g0I61F2K2DjRHz1cnxlkNSBIaePVoJIjjnHui8QHbiw=
|
||||
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
@ -37,8 +55,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=
|
||||
github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
|
||||
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
|
||||
github.com/libp2p/go-libp2p-core v0.14.0 h1:0kYSgiK/D7Eo28GTuRXo5YHsWwAisVpFCqCVPUd/vJs=
|
||||
github.com/libp2p/go-libp2p-core v0.14.0/go.mod h1:tLasfcVdTXnixsLB0QYaT1syJOhsbrhG7q6pGrHtBg8=
|
||||
github.com/libp2p/go-libp2p-core v0.19.0 h1:KDw7hanmh0EuVdZqsHCAzmkdiYMk5uR5h0UGSCVTxSU=
|
||||
github.com/libp2p/go-libp2p-core v0.19.0/go.mod h1:AkA+FUKQfYt1FLNef5fOPlo/naAWjKy/RCjkcPjqzYg=
|
||||
github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA=
|
||||
github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw=
|
||||
github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
|
||||
@ -47,8 +65,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
|
||||
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
@ -57,18 +75,23 @@ github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp
|
||||
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
|
||||
github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=
|
||||
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
|
||||
github.com/multiformats/go-multiaddr v0.4.1 h1:Pq37uLx3hsyNlTDir7FZyU8+cFCTqd5y1KiM2IzOutI=
|
||||
github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM=
|
||||
github.com/multiformats/go-multiaddr v0.6.0 h1:qMnoOPj2s8xxPU5kZ57Cqdr0hHhARz7mFsPMIiYNqzg=
|
||||
github.com/multiformats/go-multiaddr v0.6.0/go.mod h1:F4IpaKZuPP360tOMn2Tpyu0At8w23aRyVqeK0DbFeGM=
|
||||
github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk=
|
||||
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
|
||||
github.com/multiformats/go-multicodec v0.4.1 h1:BSJbf+zpghcZMZrwTYBGwy0CPcVZGWiC72Cp8bBd4R4=
|
||||
github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ=
|
||||
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
|
||||
github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I=
|
||||
github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
|
||||
github.com/multiformats/go-multihash v0.0.15 h1:hWOPdrNqDjwHDx82vsYGSDZNyktOJJ2dzZJzFkOV1jM=
|
||||
github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg=
|
||||
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
|
||||
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||
@ -78,7 +101,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
|
||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
@ -96,14 +118,20 @@ go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o=
|
||||
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -112,11 +140,14 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
|
145
rcmgr.go
145
rcmgr.go
@ -9,6 +9,7 @@ import (
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/libp2p/go-libp2p-core/protocol"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
)
|
||||
@ -21,9 +22,14 @@ type resourceManager struct {
|
||||
trace *trace
|
||||
metrics *metrics
|
||||
|
||||
allowlist *Allowlist
|
||||
|
||||
system *systemScope
|
||||
transient *transientScope
|
||||
|
||||
allowlistedSystem *systemScope
|
||||
allowlistedTransient *transientScope
|
||||
|
||||
cancelCtx context.Context
|
||||
cancel func()
|
||||
wg sync.WaitGroup
|
||||
@ -91,8 +97,10 @@ type connectionScope struct {
|
||||
|
||||
dir network.Direction
|
||||
usefd bool
|
||||
isAllowlisted bool
|
||||
rcmgr *resourceManager
|
||||
peer *peerScope
|
||||
endpoint multiaddr.Multiaddr
|
||||
}
|
||||
|
||||
var _ network.ConnScope = (*connectionScope)(nil)
|
||||
@ -117,8 +125,10 @@ var _ network.StreamManagementScope = (*streamScope)(nil)
|
||||
type Option func(*resourceManager) error
|
||||
|
||||
func NewResourceManager(limits Limiter, opts ...Option) (network.ResourceManager, error) {
|
||||
allowlist := newAllowlist()
|
||||
r := &resourceManager{
|
||||
limits: limits,
|
||||
allowlist: &allowlist,
|
||||
svc: make(map[string]*serviceScope),
|
||||
proto: make(map[protocol.ID]*protocolScope),
|
||||
peer: make(map[peer.ID]*peerScope),
|
||||
@ -134,11 +144,16 @@ func NewResourceManager(limits Limiter, opts ...Option) (network.ResourceManager
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.system = newSystemScope(limits.GetSystemLimits(), r)
|
||||
r.system = newSystemScope(limits.GetSystemLimits(), r, "system")
|
||||
r.system.IncRef()
|
||||
r.transient = newTransientScope(limits.GetTransientLimits(), r)
|
||||
r.transient = newTransientScope(limits.GetTransientLimits(), r, "transient", r.system.resourceScope)
|
||||
r.transient.IncRef()
|
||||
|
||||
r.allowlistedSystem = newSystemScope(limits.GetSystemLimits(), r, "allowlistedSystem")
|
||||
r.allowlistedSystem.IncRef()
|
||||
r.allowlistedTransient = newTransientScope(limits.GetTransientLimits(), r, "allowlistedTransient", r.allowlistedSystem.resourceScope)
|
||||
r.allowlistedTransient.IncRef()
|
||||
|
||||
r.cancelCtx, r.cancel = context.WithCancel(context.Background())
|
||||
|
||||
r.wg.Add(1)
|
||||
@ -147,6 +162,10 @@ func NewResourceManager(limits Limiter, opts ...Option) (network.ResourceManager
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *resourceManager) GetAllowlist() *Allowlist {
|
||||
return r.allowlist
|
||||
}
|
||||
|
||||
func (r *resourceManager) ViewSystem(f func(network.ResourceScope) error) error {
|
||||
return f(r.system)
|
||||
}
|
||||
@ -255,10 +274,23 @@ func (r *resourceManager) nextStreamId() int64 {
|
||||
return r.streamId
|
||||
}
|
||||
|
||||
func (r *resourceManager) OpenConnection(dir network.Direction, usefd bool) (network.ConnManagementScope, error) {
|
||||
conn := newConnectionScope(dir, usefd, r.limits.GetConnLimits(), r)
|
||||
func (r *resourceManager) OpenConnection(dir network.Direction, usefd bool, endpoint multiaddr.Multiaddr) (network.ConnManagementScope, error) {
|
||||
var conn *connectionScope
|
||||
conn = newConnectionScope(dir, usefd, r.limits.GetConnLimits(), r, endpoint)
|
||||
|
||||
if err := conn.AddConn(dir, usefd); err != nil {
|
||||
err := conn.AddConn(dir, usefd)
|
||||
if err != nil {
|
||||
// Try again if this is an allowlisted connection
|
||||
// Failed to open connection, let's see if this was allowlisted and try again
|
||||
allowed := r.allowlist.Allowed(endpoint)
|
||||
if allowed {
|
||||
conn.Done()
|
||||
conn = newAllowListedConnectionScope(dir, usefd, r.limits.GetConnLimits(), r, endpoint)
|
||||
err = conn.AddConn(dir, usefd)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
conn.Done()
|
||||
r.metrics.BlockConn(dir, usefd)
|
||||
return nil, err
|
||||
@ -363,17 +395,17 @@ func (r *resourceManager) gc() {
|
||||
}
|
||||
}
|
||||
|
||||
func newSystemScope(limit Limit, rcmgr *resourceManager) *systemScope {
|
||||
func newSystemScope(limit Limit, rcmgr *resourceManager, name string) *systemScope {
|
||||
return &systemScope{
|
||||
resourceScope: newResourceScope(limit, nil, "system", rcmgr.trace, rcmgr.metrics),
|
||||
resourceScope: newResourceScope(limit, nil, name, rcmgr.trace, rcmgr.metrics),
|
||||
}
|
||||
}
|
||||
|
||||
func newTransientScope(limit Limit, rcmgr *resourceManager) *transientScope {
|
||||
func newTransientScope(limit Limit, rcmgr *resourceManager, name string, systemScope *resourceScope) *transientScope {
|
||||
return &transientScope{
|
||||
resourceScope: newResourceScope(limit,
|
||||
[]*resourceScope{rcmgr.system.resourceScope},
|
||||
"transient", rcmgr.trace, rcmgr.metrics),
|
||||
[]*resourceScope{systemScope},
|
||||
name, rcmgr.trace, rcmgr.metrics),
|
||||
system: rcmgr.system,
|
||||
}
|
||||
}
|
||||
@ -408,7 +440,7 @@ func newPeerScope(p peer.ID, limit Limit, rcmgr *resourceManager) *peerScope {
|
||||
}
|
||||
}
|
||||
|
||||
func newConnectionScope(dir network.Direction, usefd bool, limit Limit, rcmgr *resourceManager) *connectionScope {
|
||||
func newConnectionScope(dir network.Direction, usefd bool, limit Limit, rcmgr *resourceManager, endpoint multiaddr.Multiaddr) *connectionScope {
|
||||
return &connectionScope{
|
||||
resourceScope: newResourceScope(limit,
|
||||
[]*resourceScope{rcmgr.transient.resourceScope, rcmgr.system.resourceScope},
|
||||
@ -416,6 +448,20 @@ func newConnectionScope(dir network.Direction, usefd bool, limit Limit, rcmgr *r
|
||||
dir: dir,
|
||||
usefd: usefd,
|
||||
rcmgr: rcmgr,
|
||||
endpoint: endpoint,
|
||||
}
|
||||
}
|
||||
|
||||
func newAllowListedConnectionScope(dir network.Direction, usefd bool, limit Limit, rcmgr *resourceManager, endpoint multiaddr.Multiaddr) *connectionScope {
|
||||
return &connectionScope{
|
||||
resourceScope: newResourceScope(limit,
|
||||
[]*resourceScope{rcmgr.allowlistedTransient.resourceScope, rcmgr.allowlistedSystem.resourceScope},
|
||||
fmt.Sprintf("conn-%d", rcmgr.nextConnId()), rcmgr.trace, rcmgr.metrics),
|
||||
dir: dir,
|
||||
usefd: usefd,
|
||||
rcmgr: rcmgr,
|
||||
endpoint: endpoint,
|
||||
isAllowlisted: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -500,6 +546,49 @@ func (s *connectionScope) PeerScope() network.PeerScope {
|
||||
return s.peer
|
||||
}
|
||||
|
||||
// transferAllowedToStandard transfers this connection scope from being part of
|
||||
// the allowlist set of scopes to being part of the standard set of scopes.
|
||||
// Happens when we first allowlisted this connection due to its IP, but later
|
||||
// discovered that the peer id not what we expected.
|
||||
func (s *connectionScope) transferAllowedToStandard() (err error) {
|
||||
|
||||
systemScope := s.rcmgr.system.resourceScope
|
||||
transientScope := s.rcmgr.transient.resourceScope
|
||||
|
||||
stat := s.resourceScope.rc.stat()
|
||||
|
||||
for _, scope := range s.edges {
|
||||
scope.ReleaseForChild(stat)
|
||||
scope.DecRef() // removed from edges
|
||||
}
|
||||
s.edges = nil
|
||||
|
||||
if err := systemScope.ReserveForChild(stat); err != nil {
|
||||
return err
|
||||
}
|
||||
systemScope.IncRef()
|
||||
|
||||
// Undo this if we fail later
|
||||
defer func() {
|
||||
if err != nil {
|
||||
systemScope.ReleaseForChild(stat)
|
||||
systemScope.DecRef()
|
||||
}
|
||||
}()
|
||||
|
||||
if err := transientScope.ReserveForChild(stat); err != nil {
|
||||
return err
|
||||
}
|
||||
transientScope.IncRef()
|
||||
|
||||
// Update edges
|
||||
s.edges = []*resourceScope{
|
||||
systemScope,
|
||||
transientScope,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *connectionScope) SetPeer(p peer.ID) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
@ -507,6 +596,34 @@ func (s *connectionScope) SetPeer(p peer.ID) error {
|
||||
if s.peer != nil {
|
||||
return fmt.Errorf("connection scope already attached to a peer")
|
||||
}
|
||||
|
||||
system := s.rcmgr.system
|
||||
transient := s.rcmgr.transient
|
||||
|
||||
if s.isAllowlisted {
|
||||
system = s.rcmgr.allowlistedSystem
|
||||
transient = s.rcmgr.allowlistedTransient
|
||||
|
||||
if !s.rcmgr.allowlist.AllowedPeerAndMultiaddr(p, s.endpoint) {
|
||||
s.isAllowlisted = false
|
||||
|
||||
// This is not an allowed peer + multiaddr combination. We need to
|
||||
// transfer this connection to the general scope. We'll do this first by
|
||||
// transferring the connection to the system and transient scopes, then
|
||||
// continue on with this function. The idea is that a connection
|
||||
// shouldn't get the benefit of evading the transient scope because it
|
||||
// was _almost_ an allowlisted connection.
|
||||
if err := s.transferAllowedToStandard(); err != nil {
|
||||
// Failed to transfer this connection to the standard scopes
|
||||
return err
|
||||
}
|
||||
|
||||
// set the system and transient scopes to the non-allowlisted ones
|
||||
system = s.rcmgr.system
|
||||
transient = s.rcmgr.transient
|
||||
}
|
||||
}
|
||||
|
||||
s.peer = s.rcmgr.getPeerScope(p)
|
||||
|
||||
// juggle resources from transient scope to peer scope
|
||||
@ -518,13 +635,13 @@ func (s *connectionScope) SetPeer(p peer.ID) error {
|
||||
return err
|
||||
}
|
||||
|
||||
s.rcmgr.transient.ReleaseForChild(stat)
|
||||
s.rcmgr.transient.DecRef() // removed from edges
|
||||
transient.ReleaseForChild(stat)
|
||||
transient.DecRef() // removed from edges
|
||||
|
||||
// update edges
|
||||
edges := []*resourceScope{
|
||||
s.peer.resourceScope,
|
||||
s.rcmgr.system.resourceScope,
|
||||
system.resourceScope,
|
||||
}
|
||||
s.resourceScope.edges = edges
|
||||
|
||||
|
@ -6,8 +6,12 @@ import (
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/libp2p/go-libp2p-core/protocol"
|
||||
"github.com/libp2p/go-libp2p-core/test"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
var dummyMA = multiaddr.StringCast("/ip4/1.2.3.4/tcp/1234")
|
||||
|
||||
func TestResourceManager(t *testing.T) {
|
||||
peerA := peer.ID("A")
|
||||
peerB := peer.ID("B")
|
||||
@ -242,7 +246,7 @@ func TestResourceManager(t *testing.T) {
|
||||
})
|
||||
|
||||
// open an inbound connection, using an fd
|
||||
conn, err := mgr.OpenConnection(network.DirInbound, true)
|
||||
conn, err := mgr.OpenConnection(network.DirInbound, true, dummyMA)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -257,10 +261,10 @@ func TestResourceManager(t *testing.T) {
|
||||
})
|
||||
|
||||
// the connection is transient, we shouldn't be able to open a second one
|
||||
if _, err := mgr.OpenConnection(network.DirInbound, true); err == nil {
|
||||
if _, err := mgr.OpenConnection(network.DirInbound, true, dummyMA); err == nil {
|
||||
t.Fatal("expected OpenConnection to fail")
|
||||
}
|
||||
if _, err := mgr.OpenConnection(network.DirInbound, false); err == nil {
|
||||
if _, err := mgr.OpenConnection(network.DirInbound, false, dummyMA); err == nil {
|
||||
t.Fatal("expected OpenConnection to fail")
|
||||
}
|
||||
|
||||
@ -277,7 +281,7 @@ func TestResourceManager(t *testing.T) {
|
||||
})
|
||||
|
||||
// open another inbound connection, using an fd
|
||||
conn1, err := mgr.OpenConnection(network.DirInbound, true)
|
||||
conn1, err := mgr.OpenConnection(network.DirInbound, true, dummyMA)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -315,7 +319,7 @@ func TestResourceManager(t *testing.T) {
|
||||
})
|
||||
|
||||
// we should be able to open a second transient connection now
|
||||
conn2, err := mgr.OpenConnection(network.DirInbound, true)
|
||||
conn2, err := mgr.OpenConnection(network.DirInbound, true, dummyMA)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -350,7 +354,7 @@ func TestResourceManager(t *testing.T) {
|
||||
// close it and reopen without using an FD -- we should be able to attach now
|
||||
conn2.Done()
|
||||
|
||||
conn2, err = mgr.OpenConnection(network.DirInbound, false)
|
||||
conn2, err = mgr.OpenConnection(network.DirInbound, false, dummyMA)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -998,3 +1002,67 @@ func TestResourceManager(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestResourceManagerWithAllowlist(t *testing.T) {
|
||||
peerA := test.RandPeerIDFatal(t)
|
||||
|
||||
limits := NewDefaultLimiter()
|
||||
limits.SystemLimits = limits.SystemLimits.WithConnLimit(0, 0, 0)
|
||||
limits.TransientLimits = limits.SystemLimits.WithConnLimit(0, 0, 0)
|
||||
rcmgr, err := NewResourceManager(limits, WithAllowlistedMultiaddrs([]multiaddr.Multiaddr{
|
||||
multiaddr.StringCast("/ip4/1.2.3.4"),
|
||||
multiaddr.StringCast("/ip4/4.3.2.1/p2p/" + peerA.String()),
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
{
|
||||
// Setup allowlist. TODO, replace this with a config once config changes are in
|
||||
r := rcmgr.(*resourceManager)
|
||||
|
||||
r.allowlistedSystem = newSystemScope(limits.GetSystemLimits().WithConnLimit(2, 1, 2), r, "allowlistedSystem")
|
||||
r.allowlistedSystem.IncRef()
|
||||
r.allowlistedTransient = newTransientScope(limits.GetTransientLimits().WithConnLimit(1, 1, 1), r, "allowlistedTransient", r.allowlistedSystem.resourceScope)
|
||||
r.allowlistedTransient.IncRef()
|
||||
}
|
||||
|
||||
// A connection comes in from a non-allowlisted ip address
|
||||
_, err = rcmgr.OpenConnection(network.DirInbound, true, multiaddr.StringCast("/ip4/1.2.3.5"))
|
||||
if err == nil {
|
||||
t.Fatalf("Expected this to fail. err=%v", err)
|
||||
}
|
||||
|
||||
// A connection comes in from an allowlisted ip address
|
||||
connScope, err := rcmgr.OpenConnection(network.DirInbound, true, multiaddr.StringCast("/ip4/1.2.3.4"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = connScope.SetPeer(test.RandPeerIDFatal(t))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// A connection comes in that looks like it should be allowlisted, but then has the wrong peer id.
|
||||
connScope, err = rcmgr.OpenConnection(network.DirInbound, true, multiaddr.StringCast("/ip4/4.3.2.1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = connScope.SetPeer(test.RandPeerIDFatal(t))
|
||||
if err == nil {
|
||||
t.Fatalf("Expected this to fail. err=%v", err)
|
||||
}
|
||||
|
||||
// A connection comes in that looks like it should be allowlisted, and it has the allowlisted peer id
|
||||
connScope, err = rcmgr.OpenConnection(network.DirInbound, true, multiaddr.StringCast("/ip4/4.3.2.1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = connScope.SetPeer(peerA)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user