From ee3cc3b8110793e03e204f45bfbd6806937b5ddd Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Wed, 8 Jun 2022 15:55:11 -0700 Subject: [PATCH 01/24] Add design doc --- docs/allowlist.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 docs/allowlist.md diff --git a/docs/allowlist.md b/docs/allowlist.md new file mode 100644 index 0000000..1819039 --- /dev/null +++ b/docs/allowlist.md @@ -0,0 +1,51 @@ +# 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. + +## 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 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. Otherwise, it uses the normal system and transient resource +scopes as it does today. + +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. From dd0cde1cfd8d2ceddd3db7075bac915c1c7b21bf Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Thu, 9 Jun 2022 22:26:24 -0700 Subject: [PATCH 02/24] Add allowlist impl Accepts multiaddrs that define who is allowed. --- allowlist.go | 230 ++++++++++++++++++++++++++++++++++++++++++++++ allowlist_test.go | 220 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 450 insertions(+) create mode 100644 allowlist.go create mode 100644 allowlist_test.go diff --git a/allowlist.go b/allowlist.go new file mode 100644 index 0000000..8f38806 --- /dev/null +++ b/allowlist.go @@ -0,0 +1,230 @@ +package rcmgr + +import ( + "bytes" + "errors" + "net" + + "github.com/libp2p/go-libp2p-core/peer" + "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" +) + +type allowlist struct { + // TODO do we want to make this lookup faster? + + // Any peer with these IPs are allowed + allowedIPs []net.IP + allowedNetworks []*net.IPNet + + // Only the specified peers can use these IPs + allowedPeerByIP map[peer.ID][]net.IP + allowedPeerByNetwork map[peer.ID][]*net.IPNet +} + +func newAllowList() allowlist { + return allowlist{ + allowedPeerByIP: make(map[peer.ID][]net.IP), + allowedPeerByNetwork: make(map[peer.ID][]*net.IPNet), + } +} + +func toIPOrIPNet(ma multiaddr.Multiaddr) (net.IP, *net.IPNet, string, error) { + var ipString string + var mask string + var allowedPeer string + + multiaddr.ForEach(ma, func(c multiaddr.Component) bool { + if c.Protocol().Code == multiaddr.P_IP4 || c.Protocol().Code == multiaddr.P_IP6 { + ipString = c.Value() + } + if c.Protocol().Code == multiaddr.P_IPCIDR { + mask = c.Value() + } + if c.Protocol().Code == multiaddr.P_P2P { + allowedPeer = c.Value() + } + return ipString == "" || mask == "" || allowedPeer == "" + }) + + if ipString == "" { + return nil, nil, allowedPeer, errors.New("missing ip address") + } + + if mask == "" { + ip := net.ParseIP(ipString) + if ip == nil { + return nil, nil, allowedPeer, errors.New("invalid ip address") + } + return ip, nil, allowedPeer, nil + } + + _, ipnet, err := net.ParseCIDR(ipString + "/" + mask) + return nil, ipnet, allowedPeer, err + +} + +func (al *allowlist) Add(ma multiaddr.Multiaddr) error { + ip, ipnet, allowedPeerStr, err := toIPOrIPNet(ma) + if err != nil { + return err + } + + if allowedPeerStr != "" { + // We have a peerID constraint + allowedPeer, err := peer.Decode(allowedPeerStr) + if err != nil { + return err + } + if ip != nil { + al.allowedPeerByIP[allowedPeer] = append(al.allowedPeerByIP[allowedPeer], ip) + } else if ipnet != nil { + al.allowedPeerByNetwork[allowedPeer] = append(al.allowedPeerByNetwork[allowedPeer], ipnet) + } + } else { + if ip != nil { + al.allowedIPs = append(al.allowedIPs, ip) + } else if ipnet != nil { + al.allowedNetworks = append(al.allowedNetworks, ipnet) + } + } + return nil +} + +func (al *allowlist) Remove(ma multiaddr.Multiaddr) error { + ip, ipnet, allowedPeerStr, err := toIPOrIPNet(ma) + if err != nil { + return err + } + ipList := al.allowedIPs + ipNetList := al.allowedNetworks + + var allowedPeer peer.ID + if allowedPeerStr != "" { + // We have a peerID constraint + allowedPeer, err = peer.Decode(allowedPeerStr) + if err != nil { + return err + } + ipList = al.allowedPeerByIP[allowedPeer] + ipNetList = al.allowedPeerByNetwork[allowedPeer] + } + + if ip != nil { + i := len(ipList) + for i > 0 { + i-- + if ipList[i].Equal(ip) { + if i == len(ipList)-1 { + // Trim this element from the end + ipList = ipList[:i] + } else { + // swap remove + ipList[i] = ipList[len(ipList)-1] + ipList = ipList[:len(ipList)-1] + } + } + } + } else if ipnet != nil { + i := len(ipNetList) + for i > 0 { + i-- + if ipNetList[i].IP.Equal(ipnet.IP) && bytes.Equal(ipNetList[i].Mask, ipnet.Mask) { + if i == len(ipNetList)-1 { + // Trim this element from the end + ipNetList = ipNetList[:i] + } else { + // swap remove + ipNetList[i] = ipNetList[len(ipNetList)-1] + ipNetList = ipNetList[:len(ipNetList)-1] + } + } + } + } + + if allowedPeer != "" { + al.allowedPeerByIP[allowedPeer] = ipList + al.allowedPeerByNetwork[allowedPeer] = ipNetList + } else { + al.allowedIPs = ipList + al.allowedNetworks = ipNetList + } + + return nil +} + +func (al *allowlist) Allowed(ma multiaddr.Multiaddr) bool { + ip, err := manet.ToIP(ma) + if err != nil { + return false + } + + for _, allowedIP := range al.allowedIPs { + if allowedIP.Equal(ip) { + return true + } + } + + for _, network := range al.allowedNetworks { + if network.Contains(ip) { + return true + } + } + + for _, allowedIPs := range al.allowedPeerByIP { + for _, allowedIP := range allowedIPs { + if allowedIP.Equal(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 + } + + for _, allowedIP := range al.allowedIPs { + if allowedIP.Equal(ip) { + // We found a match that isn't constrained by a peerID + return true + } + } + + for _, network := range al.allowedNetworks { + if network.Contains(ip) { + // We found a match that isn't constrained by a peerID + return true + } + } + + if expectedIPs, ok := al.allowedPeerByIP[peerID]; ok { + for _, expectedIP := range expectedIPs { + if expectedIP.Equal(ip) { + return true + } + } + } + + if expectedNetworks, ok := al.allowedPeerByNetwork[peerID]; ok { + for _, expectedNetwork := range expectedNetworks { + if expectedNetwork.Contains(ip) { + return true + } + } + } + + return false +} diff --git a/allowlist_test.go b/allowlist_test.go new file mode 100644 index 0000000..2974644 --- /dev/null +++ b/allowlist_test.go @@ -0,0 +1,220 @@ +package rcmgr + +import ( + "fmt" + "testing" + + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/test" + "github.com/multiformats/go-multiaddr" +) + +func TestAllowed(t *testing.T) { + allowlist := newAllowList() + ma, _ := multiaddr.NewMultiaddr("/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 TestAllowedNetwork(t *testing.T) { + allowlist := newAllowList() + ma, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.0/ipcidr/24") + err := allowlist.Add(ma) + if err != nil { + t.Fatalf("failed to add ip4: %s", err) + } + + ma2, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.20/tcp/1234") + if !allowlist.Allowed(ma2) { + t.Fatalf("addr should be allowed") + } +} + +func TestAllowedPeerOnIP(t *testing.T) { + allowlist := newAllowList() + p, err := test.RandPeerID() + if err != nil { + t.Fatalf("failed to gen peer ip4: %s", err) + } + + ma, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.4/p2p/" + peer.Encode(p)) + err = allowlist.Add(ma) + if err != nil { + t.Fatalf("failed to add ip4: %s", err) + } + + ma2, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.4") + if !allowlist.AllowedPeerAndMultiaddr(p, ma2) { + t.Fatalf("addr should be allowed") + } +} + +func TestAllowedPeerOnNetwork(t *testing.T) { + allowlist := newAllowList() + p, err := test.RandPeerID() + if err != nil { + t.Fatalf("failed to gen peer ip4: %s", err) + } + + ma, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.0/ipcidr/24/p2p/" + peer.Encode(p)) + err = allowlist.Add(ma) + if err != nil { + t.Fatalf("failed to add ip4: %s", err) + } + + ma2, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.4") + if !allowlist.AllowedPeerAndMultiaddr(p, ma2) { + t.Fatalf("addr should be allowed") + } +} + +func TestAllowedWithPeer(t *testing.T) { + type testcase struct { + name string + allowlist []string + endpoint multiaddr.Multiaddr + peer peer.ID + isAllowed bool + } + + peerA := test.RandPeerIDFatal(t) + peerB := test.RandPeerIDFatal(t) + multiaddrA, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.4/tcp/1234") + multiaddrB, _ := multiaddr.NewMultiaddr("/ip4/2.2.3.4/tcp/1234") + + testcases := []testcase{ + { + name: "Blocked", + isAllowed: false, + allowlist: []string{"/ip4/1.2.3.1"}, + endpoint: multiaddrA, + peer: peerA, + }, + { + name: "Blocked wrong peer", + isAllowed: false, + allowlist: []string{"/ip4/1.2.3.4" + "/p2p/" + peer.Encode(peerB)}, + endpoint: multiaddrA, + peer: peerA, + }, + { + name: "allowed on network", + isAllowed: true, + allowlist: []string{"/ip4/1.2.3.0/ipcidr/24"}, + endpoint: multiaddrA, + peer: peerA, + }, + { + name: "Blocked peer not on network", + isAllowed: true, + allowlist: []string{"/ip4/1.2.3.0/ipcidr/24"}, + endpoint: multiaddrA, + peer: peerA, + }, { + name: "allowed. right network, right peer", + isAllowed: true, + allowlist: []string{"/ip4/1.2.3.0/ipcidr/24" + "/p2p/" + peer.Encode(peerA)}, + endpoint: multiaddrA, + peer: peerA, + }, { + name: "allowed. right network, no peer", + isAllowed: true, + allowlist: []string{"/ip4/1.2.3.0/ipcidr/24"}, + endpoint: multiaddrA, + peer: peerA, + }, + { + name: "Blocked. right network, wrong peer", + isAllowed: false, + allowlist: []string{"/ip4/1.2.3.0/ipcidr/24" + "/p2p/" + peer.Encode(peerB)}, + endpoint: multiaddrA, + peer: peerA, + }, + { + name: "allowed peer any ip", + isAllowed: true, + allowlist: []string{"/ip4/0.0.0.0/ipcidr/0"}, + endpoint: multiaddrA, + peer: peerA, + }, + { + name: "allowed peer multiple ips in allowlist", + isAllowed: 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", + isAllowed: 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.AllowedPeerAndMultiaddr(tc.peer, tc.endpoint) != tc.isAllowed { + t.Fatalf("%v: expected %v", !tc.isAllowed, tc.isAllowed) + } + }) + } + +} + +func TestRemoved(t *testing.T) { + type testCase struct { + name string + allowedMA string + } + peerA := test.RandPeerIDFatal(t) + maA, _ := multiaddr.NewMultiaddr("/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, err := multiaddr.NewMultiaddr(tc.allowedMA) + if err != nil { + t.Fatalf("failed to parse ma: %s", err) + } + + 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") + } + }) + } +} From 1fcd41c41828c3af762789b32b20e0dc773b874e Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Thu, 9 Jun 2022 22:33:18 -0700 Subject: [PATCH 03/24] Add allowlist to rcmgr --- rcmgr.go | 119 ++++++++++++++++++++++++++++++++++++++++++++------ rcmgr_test.go | 15 ++++--- 2 files changed, 115 insertions(+), 19 deletions(-) diff --git a/rcmgr.go b/rcmgr.go index bebae9b..c262a8d 100644 --- a/rcmgr.go +++ b/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 @@ -89,10 +95,12 @@ var _ network.PeerScope = (*peerScope)(nil) type connectionScope struct { *resourceScope - dir network.Direction - usefd bool - rcmgr *resourceManager - peer *peerScope + dir network.Direction + usefd bool + isAllowlisted bool + rcmgr *resourceManager + peer *peerScope + endpoint multiaddr.Multiaddr } var _ network.ConnScope = (*connectionScope)(nil) @@ -117,11 +125,13 @@ 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, - svc: make(map[string]*serviceScope), - proto: make(map[protocol.ID]*protocolScope), - peer: make(map[peer.ID]*peerScope), + limits: limits, + allowlist: &allowlist, + svc: make(map[string]*serviceScope), + proto: make(map[protocol.ID]*protocolScope), + peer: make(map[peer.ID]*peerScope), } for _, opt := range opts { @@ -255,8 +265,14 @@ 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) { + allowed := r.allowlist.Allowed(endpoint) + var conn *connectionScope + if allowed { + conn = newAllowListedConnectionScope(dir, usefd, r.limits.GetConnLimits(), r) + } else { + conn = newConnectionScope(dir, usefd, r.limits.GetConnLimits(), r) + } if err := conn.AddConn(dir, usefd); err != nil { conn.Done() @@ -419,6 +435,17 @@ func newConnectionScope(dir network.Direction, usefd bool, limit Limit, rcmgr *r } } +func newAllowListedConnectionScope(dir network.Direction, usefd bool, limit Limit, rcmgr *resourceManager) *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, + } +} + func newStreamScope(dir network.Direction, limit Limit, peer *peerScope, rcmgr *resourceManager) *streamScope { return &streamScope{ resourceScope: newResourceScope(limit, @@ -500,13 +527,79 @@ 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.system.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 { + // TODO check if this connectionscope is part of the allowlist and do the peer checking if so. s.Lock() defer s.Unlock() 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.transient + } + + if s.isAllowlisted && !s.rcmgr.allowlist.AllowedPeerAndMultiaddr(p, s.endpoint) { + // This is not a 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 + } + } + s.peer = s.rcmgr.getPeerScope(p) // juggle resources from transient scope to peer scope @@ -518,13 +611,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 diff --git a/rcmgr_test.go b/rcmgr_test.go index a18815c..4bb8106 100644 --- a/rcmgr_test.go +++ b/rcmgr_test.go @@ -6,8 +6,11 @@ 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" ) +var dummyMA, _ = multiaddr.NewMultiaddr("/ip4/1.2.3.4/tcp/1234") + func TestResourceManager(t *testing.T) { peerA := peer.ID("A") peerB := peer.ID("B") @@ -242,7 +245,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 +260,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 +280,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 +318,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 +353,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) } From 23ec39d74e4d5482253f1e58095400b35a27c190 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 13 Jun 2022 16:26:59 -0700 Subject: [PATCH 04/24] Simplify by removing ip addr, only networks. Adds a benchmark --- allowlist.go | 87 ++++------------ allowlist_test.go | 251 ++++++++++++++++++++++++++-------------------- 2 files changed, 167 insertions(+), 171 deletions(-) diff --git a/allowlist.go b/allowlist.go index 8f38806..9d4e7ab 100644 --- a/allowlist.go +++ b/allowlist.go @@ -14,28 +14,27 @@ type allowlist struct { // TODO do we want to make this lookup faster? // Any peer with these IPs are allowed - allowedIPs []net.IP allowedNetworks []*net.IPNet // Only the specified peers can use these IPs - allowedPeerByIP map[peer.ID][]net.IP allowedPeerByNetwork map[peer.ID][]*net.IPNet } func newAllowList() allowlist { return allowlist{ - allowedPeerByIP: make(map[peer.ID][]net.IP), allowedPeerByNetwork: make(map[peer.ID][]*net.IPNet), } } -func toIPOrIPNet(ma multiaddr.Multiaddr) (net.IP, *net.IPNet, string, error) { +func toIPNet(ma multiaddr.Multiaddr) (*net.IPNet, string, error) { var ipString string var mask string var allowedPeer string + 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 { @@ -48,24 +47,32 @@ func toIPOrIPNet(ma multiaddr.Multiaddr) (net.IP, *net.IPNet, string, error) { }) if ipString == "" { - return nil, nil, allowedPeer, errors.New("missing ip address") + return nil, allowedPeer, errors.New("missing ip address") } if mask == "" { ip := net.ParseIP(ipString) if ip == nil { - return nil, nil, allowedPeer, errors.New("invalid ip address") + return nil, allowedPeer, errors.New("invalid ip address") } - return ip, nil, allowedPeer, nil + 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 nil, ipnet, allowedPeer, err + return ipnet, allowedPeer, err } func (al *allowlist) Add(ma multiaddr.Multiaddr) error { - ip, ipnet, allowedPeerStr, err := toIPOrIPNet(ma) + ipnet, allowedPeerStr, err := toIPNet(ma) if err != nil { return err } @@ -76,15 +83,11 @@ func (al *allowlist) Add(ma multiaddr.Multiaddr) error { if err != nil { return err } - if ip != nil { - al.allowedPeerByIP[allowedPeer] = append(al.allowedPeerByIP[allowedPeer], ip) - } else if ipnet != nil { + if ipnet != nil { al.allowedPeerByNetwork[allowedPeer] = append(al.allowedPeerByNetwork[allowedPeer], ipnet) } } else { - if ip != nil { - al.allowedIPs = append(al.allowedIPs, ip) - } else if ipnet != nil { + if ipnet != nil { al.allowedNetworks = append(al.allowedNetworks, ipnet) } } @@ -92,11 +95,10 @@ func (al *allowlist) Add(ma multiaddr.Multiaddr) error { } func (al *allowlist) Remove(ma multiaddr.Multiaddr) error { - ip, ipnet, allowedPeerStr, err := toIPOrIPNet(ma) + ipnet, allowedPeerStr, err := toIPNet(ma) if err != nil { return err } - ipList := al.allowedIPs ipNetList := al.allowedNetworks var allowedPeer peer.ID @@ -106,26 +108,10 @@ func (al *allowlist) Remove(ma multiaddr.Multiaddr) error { if err != nil { return err } - ipList = al.allowedPeerByIP[allowedPeer] ipNetList = al.allowedPeerByNetwork[allowedPeer] } - if ip != nil { - i := len(ipList) - for i > 0 { - i-- - if ipList[i].Equal(ip) { - if i == len(ipList)-1 { - // Trim this element from the end - ipList = ipList[:i] - } else { - // swap remove - ipList[i] = ipList[len(ipList)-1] - ipList = ipList[:len(ipList)-1] - } - } - } - } else if ipnet != nil { + if ipnet != nil { i := len(ipNetList) for i > 0 { i-- @@ -143,10 +129,8 @@ func (al *allowlist) Remove(ma multiaddr.Multiaddr) error { } if allowedPeer != "" { - al.allowedPeerByIP[allowedPeer] = ipList al.allowedPeerByNetwork[allowedPeer] = ipNetList } else { - al.allowedIPs = ipList al.allowedNetworks = ipNetList } @@ -159,26 +143,14 @@ func (al *allowlist) Allowed(ma multiaddr.Multiaddr) bool { return false } - for _, allowedIP := range al.allowedIPs { - if allowedIP.Equal(ip) { - return true - } - } - + _ = ip for _, network := range al.allowedNetworks { + _ = network if network.Contains(ip) { return true } } - for _, allowedIPs := range al.allowedPeerByIP { - for _, allowedIP := range allowedIPs { - if allowedIP.Equal(ip) { - return true - } - } - } - for _, allowedNetworks := range al.allowedPeerByNetwork { for _, network := range allowedNetworks { if network.Contains(ip) { @@ -196,13 +168,6 @@ func (al *allowlist) AllowedPeerAndMultiaddr(peerID peer.ID, ma multiaddr.Multia return false } - for _, allowedIP := range al.allowedIPs { - if allowedIP.Equal(ip) { - // We found a match that isn't constrained by a peerID - return true - } - } - for _, network := range al.allowedNetworks { if network.Contains(ip) { // We found a match that isn't constrained by a peerID @@ -210,14 +175,6 @@ func (al *allowlist) AllowedPeerAndMultiaddr(peerID peer.ID, ma multiaddr.Multia } } - if expectedIPs, ok := al.allowedPeerByIP[peerID]; ok { - for _, expectedIP := range expectedIPs { - if expectedIP.Equal(ip) { - return true - } - } - } - if expectedNetworks, ok := al.allowedPeerByNetwork[peerID]; ok { for _, expectedNetwork := range expectedNetworks { if expectedNetwork.Contains(ip) { diff --git a/allowlist_test.go b/allowlist_test.go index 2974644..d9245b2 100644 --- a/allowlist_test.go +++ b/allowlist_test.go @@ -1,7 +1,9 @@ package rcmgr import ( + "crypto/rand" "fmt" + "net" "testing" "github.com/libp2p/go-libp2p-core/peer" @@ -9,7 +11,7 @@ import ( "github.com/multiformats/go-multiaddr" ) -func TestAllowed(t *testing.T) { +func TestAllowedSimple(t *testing.T) { allowlist := newAllowList() ma, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.4/tcp/1234") err := allowlist.Add(ma) @@ -22,65 +24,16 @@ func TestAllowed(t *testing.T) { } } -func TestAllowedNetwork(t *testing.T) { - allowlist := newAllowList() - ma, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.0/ipcidr/24") - err := allowlist.Add(ma) - if err != nil { - t.Fatalf("failed to add ip4: %s", err) - } - - ma2, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.20/tcp/1234") - if !allowlist.Allowed(ma2) { - t.Fatalf("addr should be allowed") - } -} - -func TestAllowedPeerOnIP(t *testing.T) { - allowlist := newAllowList() - p, err := test.RandPeerID() - if err != nil { - t.Fatalf("failed to gen peer ip4: %s", err) - } - - ma, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.4/p2p/" + peer.Encode(p)) - err = allowlist.Add(ma) - if err != nil { - t.Fatalf("failed to add ip4: %s", err) - } - - ma2, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.4") - if !allowlist.AllowedPeerAndMultiaddr(p, ma2) { - t.Fatalf("addr should be allowed") - } -} - -func TestAllowedPeerOnNetwork(t *testing.T) { - allowlist := newAllowList() - p, err := test.RandPeerID() - if err != nil { - t.Fatalf("failed to gen peer ip4: %s", err) - } - - ma, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.0/ipcidr/24/p2p/" + peer.Encode(p)) - err = allowlist.Add(ma) - if err != nil { - t.Fatalf("failed to add ip4: %s", err) - } - - ma2, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.4") - if !allowlist.AllowedPeerAndMultiaddr(p, ma2) { - t.Fatalf("addr should be allowed") - } -} - func TestAllowedWithPeer(t *testing.T) { type testcase struct { name string allowlist []string endpoint multiaddr.Multiaddr peer peer.ID - isAllowed bool + // Is this endpoint allowed? (We don't have peer info yet) + isConnAllowed bool + // Is this peer + endpoint allowed? + isAllowedWithPeer bool } peerA := test.RandPeerIDFatal(t) @@ -90,72 +43,82 @@ func TestAllowedWithPeer(t *testing.T) { testcases := []testcase{ { - name: "Blocked", - isAllowed: false, - allowlist: []string{"/ip4/1.2.3.1"}, - endpoint: multiaddrA, - peer: peerA, + name: "Blocked", + isConnAllowed: false, + isAllowedWithPeer: false, + allowlist: []string{"/ip4/1.2.3.1"}, + endpoint: multiaddrA, + peer: peerA, }, { - name: "Blocked wrong peer", - isAllowed: false, - allowlist: []string{"/ip4/1.2.3.4" + "/p2p/" + peer.Encode(peerB)}, - 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", - isAllowed: true, - allowlist: []string{"/ip4/1.2.3.0/ipcidr/24"}, - 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", - isAllowed: 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", - isAllowed: true, - allowlist: []string{"/ip4/1.2.3.0/ipcidr/24" + "/p2p/" + peer.Encode(peerA)}, - 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", - isAllowed: true, - allowlist: []string{"/ip4/1.2.3.0/ipcidr/24"}, - 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", - isAllowed: false, - allowlist: []string{"/ip4/1.2.3.0/ipcidr/24" + "/p2p/" + peer.Encode(peerB)}, - 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", - isAllowed: true, - allowlist: []string{"/ip4/0.0.0.0/ipcidr/0"}, - 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", - isAllowed: 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/2.2.3.4/p2p/" + peer.Encode(peerA)}, + endpoint: multiaddrA, + peer: peerA, }, { - name: "allowed peer multiple ips in allowlist", - isAllowed: 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, + 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, }, } @@ -170,8 +133,8 @@ func TestAllowedWithPeer(t *testing.T) { allowlist.Add(ma) } - if allowlist.AllowedPeerAndMultiaddr(tc.peer, tc.endpoint) != tc.isAllowed { - t.Fatalf("%v: expected %v", !tc.isAllowed, tc.isAllowed) + if allowlist.AllowedPeerAndMultiaddr(tc.peer, tc.endpoint) != tc.isAllowedWithPeer { + t.Fatalf("%v: expected %v", !tc.isAllowedWithPeer, tc.isAllowedWithPeer) } }) } @@ -218,3 +181,79 @@ func TestRemoved(t *testing.T) { }) } } + +// 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 + + peers := make([]peer.ID, countOfTotalPeersForTest) + mas := make([]multiaddr.Multiaddr, countOfTotalPeersForTest) + for i := 0; i < countOfTotalPeersForTest; i++ { + peers[i] = test.RandPeerIDFatal(b) + + ip := make([]byte, 16) + n, err := rand.Reader.Read(ip) + if err != nil || n != 16 { + b.Fatalf("Failed to generate IPv4 address") + } + + var ipString string + + if i%ratioOfIPV6 == 0 { + // IPv4 + ip6 := net.IP(ip) + peers[i] = test.RandPeerIDFatal(b) + ipString = "/ip6/" + ip6.String() + } else { + // IPv4 + ip4 := net.IPv4(ip[0], ip[1], ip[2], ip[3]) + peers[i] = test.RandPeerIDFatal(b) + ipString = "/ip4/" + ip4.String() + } + + var ma multiaddr.Multiaddr + if i%ratioOfSpecifiedPeers == 0 { + ma, err = multiaddr.NewMultiaddr(ipString + "/p2p/" + peer.Encode(peers[i])) + } else { + ma, err = multiaddr.NewMultiaddr(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)]) + } + } +} From 78498fbd88198ae809e7dc21e65cab021e39e2bc Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 13 Jun 2022 16:29:28 -0700 Subject: [PATCH 05/24] Add comment --- allowlist.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/allowlist.go b/allowlist.go index 9d4e7ab..325b7fe 100644 --- a/allowlist.go +++ b/allowlist.go @@ -11,7 +11,10 @@ import ( ) type allowlist struct { - // TODO do we want to make this lookup faster? + // 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 From 7ecf0fc714a317d9c9dc1a21f443481cae84d6de Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 13 Jun 2022 16:33:37 -0700 Subject: [PATCH 06/24] Cleanup --- allowlist_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/allowlist_test.go b/allowlist_test.go index d9245b2..79f5744 100644 --- a/allowlist_test.go +++ b/allowlist_test.go @@ -133,6 +133,10 @@ func TestAllowedWithPeer(t *testing.T) { 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) } @@ -200,34 +204,30 @@ func BenchmarkAllowlistCheck(b *testing.B) { countOfTotalPeersForTest := 100_000 - peers := make([]peer.ID, countOfTotalPeersForTest) mas := make([]multiaddr.Multiaddr, countOfTotalPeersForTest) for i := 0; i < countOfTotalPeersForTest; i++ { - peers[i] = test.RandPeerIDFatal(b) ip := make([]byte, 16) n, err := rand.Reader.Read(ip) if err != nil || n != 16 { - b.Fatalf("Failed to generate IPv4 address") + b.Fatalf("Failed to generate IP address") } var ipString string if i%ratioOfIPV6 == 0 { - // IPv4 + // IPv6 ip6 := net.IP(ip) - peers[i] = test.RandPeerIDFatal(b) ipString = "/ip6/" + ip6.String() } else { // IPv4 ip4 := net.IPv4(ip[0], ip[1], ip[2], ip[3]) - peers[i] = test.RandPeerIDFatal(b) ipString = "/ip4/" + ip4.String() } var ma multiaddr.Multiaddr if i%ratioOfSpecifiedPeers == 0 { - ma, err = multiaddr.NewMultiaddr(ipString + "/p2p/" + peer.Encode(peers[i])) + ma, err = multiaddr.NewMultiaddr(ipString + "/p2p/" + peer.Encode(test.RandPeerIDFatal(b))) } else { ma, err = multiaddr.NewMultiaddr(ipString) } From 297cd00321b29b0faea1e8ebee06889f6a316aff Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 13 Jun 2022 16:39:00 -0700 Subject: [PATCH 07/24] Fix comment --- rcmgr.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rcmgr.go b/rcmgr.go index c262a8d..2315d8b 100644 --- a/rcmgr.go +++ b/rcmgr.go @@ -571,7 +571,6 @@ func (s *connectionScope) transferAllowedToStandard() (err error) { } func (s *connectionScope) SetPeer(p peer.ID) error { - // TODO check if this connectionscope is part of the allowlist and do the peer checking if so. s.Lock() defer s.Unlock() @@ -588,10 +587,10 @@ func (s *connectionScope) SetPeer(p peer.ID) error { } if s.isAllowlisted && !s.rcmgr.allowlist.AllowedPeerAndMultiaddr(p, s.endpoint) { - // This is not a allowed peer + multiaddr combination. We need to + // 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 + // 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 { From 84ca9d337a7da7b33d36d1236f6a80215d15e989 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Tue, 14 Jun 2022 11:46:26 -0700 Subject: [PATCH 08/24] PR comments --- allowlist.go | 75 +++++++++++++++++++++++------------------------ allowlist_test.go | 23 +++++++-------- rcmgr.go | 2 +- 3 files changed, 47 insertions(+), 53 deletions(-) diff --git a/allowlist.go b/allowlist.go index 325b7fe..0bb73fe 100644 --- a/allowlist.go +++ b/allowlist.go @@ -3,6 +3,7 @@ package rcmgr import ( "bytes" "errors" + "fmt" "net" "github.com/libp2p/go-libp2p-core/peer" @@ -23,16 +24,17 @@ type allowlist struct { allowedPeerByNetwork map[peer.ID][]*net.IPNet } -func newAllowList() allowlist { +func newAllowlist() allowlist { return allowlist{ allowedPeerByNetwork: make(map[peer.ID][]*net.IPNet), } } -func toIPNet(ma multiaddr.Multiaddr) (*net.IPNet, string, error) { +func toIPNet(ma multiaddr.Multiaddr) (*net.IPNet, peer.ID, error) { var ipString string var mask string - var allowedPeer string + var allowedPeerStr string + var allowedPeer peer.ID var isIPV4 bool multiaddr.ForEach(ma, func(c multiaddr.Component) bool { @@ -44,15 +46,23 @@ func toIPNet(ma multiaddr.Multiaddr) (*net.IPNet, string, error) { mask = c.Value() } if c.Protocol().Code == multiaddr.P_P2P { - allowedPeer = c.Value() + allowedPeerStr = c.Value() } - return ipString == "" || mask == "" || allowedPeer == "" + 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 { @@ -74,59 +84,48 @@ func toIPNet(ma multiaddr.Multiaddr) (*net.IPNet, string, error) { } +// 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 and /ip4/1.2.3.4 are valid. +// /p2p/QmFoo is not valid. func (al *allowlist) Add(ma multiaddr.Multiaddr) error { - ipnet, allowedPeerStr, err := toIPNet(ma) + ipnet, allowedPeer, err := toIPNet(ma) if err != nil { return err } - if allowedPeerStr != "" { + if allowedPeer != peer.ID("") { // We have a peerID constraint - allowedPeer, err := peer.Decode(allowedPeerStr) - if err != nil { - return err - } - if ipnet != nil { - al.allowedPeerByNetwork[allowedPeer] = append(al.allowedPeerByNetwork[allowedPeer], ipnet) - } + al.allowedPeerByNetwork[allowedPeer] = append(al.allowedPeerByNetwork[allowedPeer], ipnet) } else { - if ipnet != nil { - al.allowedNetworks = append(al.allowedNetworks, ipnet) - } + al.allowedNetworks = append(al.allowedNetworks, ipnet) } return nil } func (al *allowlist) Remove(ma multiaddr.Multiaddr) error { - ipnet, allowedPeerStr, err := toIPNet(ma) + ipnet, allowedPeer, err := toIPNet(ma) if err != nil { return err } ipNetList := al.allowedNetworks - var allowedPeer peer.ID - if allowedPeerStr != "" { + if allowedPeer != peer.ID("") { // We have a peerID constraint - allowedPeer, err = peer.Decode(allowedPeerStr) - if err != nil { - return err - } ipNetList = al.allowedPeerByNetwork[allowedPeer] } - if ipnet != nil { - i := len(ipNetList) - for i > 0 { - i-- - if ipNetList[i].IP.Equal(ipnet.IP) && bytes.Equal(ipNetList[i].Mask, ipnet.Mask) { - if i == len(ipNetList)-1 { - // Trim this element from the end - ipNetList = ipNetList[:i] - } else { - // swap remove - ipNetList[i] = ipNetList[len(ipNetList)-1] - ipNetList = ipNetList[:len(ipNetList)-1] - } + i := len(ipNetList) + for i > 0 { + i-- + if ipNetList[i].IP.Equal(ipnet.IP) && bytes.Equal(ipNetList[i].Mask, ipnet.Mask) { + if i == len(ipNetList)-1 { + // Trim this element from the end + ipNetList = ipNetList[:i] + } else { + // swap remove + ipNetList[i] = ipNetList[len(ipNetList)-1] + ipNetList = ipNetList[:len(ipNetList)-1] } } } @@ -146,9 +145,7 @@ func (al *allowlist) Allowed(ma multiaddr.Multiaddr) bool { return false } - _ = ip for _, network := range al.allowedNetworks { - _ = network if network.Contains(ip) { return true } diff --git a/allowlist_test.go b/allowlist_test.go index 79f5744..3a8e9f9 100644 --- a/allowlist_test.go +++ b/allowlist_test.go @@ -12,8 +12,8 @@ import ( ) func TestAllowedSimple(t *testing.T) { - allowlist := newAllowList() - ma, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.4/tcp/1234") + 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) @@ -124,7 +124,7 @@ func TestAllowedWithPeer(t *testing.T) { for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { - allowlist := newAllowList() + allowlist := newAllowlist() for _, maStr := range tc.allowlist { ma, err := multiaddr.NewMultiaddr(maStr) if err != nil { @@ -151,7 +151,7 @@ func TestRemoved(t *testing.T) { allowedMA string } peerA := test.RandPeerIDFatal(t) - maA, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.4") + maA := multiaddr.StringCast("/ip4/1.2.3.4") testCases := []testCase{ {name: "ip4", allowedMA: "/ip4/1.2.3.4"}, @@ -162,13 +162,10 @@ func TestRemoved(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - allowlist := newAllowList() - ma, err := multiaddr.NewMultiaddr(tc.allowedMA) - if err != nil { - t.Fatalf("failed to parse ma: %s", err) - } + allowlist := newAllowlist() + ma := multiaddr.StringCast(tc.allowedMA) - err = allowlist.Add(ma) + err := allowlist.Add(ma) if err != nil { t.Fatalf("failed to add ip4: %s", err) } @@ -188,7 +185,7 @@ func TestRemoved(t *testing.T) { // BenchmarkAllowlistCheck benchmarks the allowlist with plausible conditions. func BenchmarkAllowlistCheck(b *testing.B) { - allowlist := newAllowList() + allowlist := newAllowlist() // How often do we expect a peer to be specified? 1 in N ratioOfSpecifiedPeers := 10 @@ -227,9 +224,9 @@ func BenchmarkAllowlistCheck(b *testing.B) { var ma multiaddr.Multiaddr if i%ratioOfSpecifiedPeers == 0 { - ma, err = multiaddr.NewMultiaddr(ipString + "/p2p/" + peer.Encode(test.RandPeerIDFatal(b))) + ma = multiaddr.StringCast(ipString + "/p2p/" + peer.Encode(test.RandPeerIDFatal(b))) } else { - ma, err = multiaddr.NewMultiaddr(ipString) + ma = multiaddr.StringCast(ipString) } if err != nil { b.Fatalf("Failed to generate multiaddr: %v", ipString) diff --git a/rcmgr.go b/rcmgr.go index 2315d8b..8a91700 100644 --- a/rcmgr.go +++ b/rcmgr.go @@ -125,7 +125,7 @@ var _ network.StreamManagementScope = (*streamScope)(nil) type Option func(*resourceManager) error func NewResourceManager(limits Limiter, opts ...Option) (network.ResourceManager, error) { - allowlist := newAllowList() + allowlist := newAllowlist() r := &resourceManager{ limits: limits, allowlist: &allowlist, From 539b1476fcac1ba185c049d520867f9af7a59f15 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Tue, 14 Jun 2022 11:48:56 -0700 Subject: [PATCH 09/24] Use the same standard limits for the allowlistedSystem and allowlistedTransient --- rcmgr.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rcmgr.go b/rcmgr.go index 8a91700..b5c28c2 100644 --- a/rcmgr.go +++ b/rcmgr.go @@ -149,6 +149,11 @@ func NewResourceManager(limits Limiter, opts ...Option) (network.ResourceManager r.transient = newTransientScope(limits.GetTransientLimits(), r) r.transient.IncRef() + r.allowlistedSystem = newSystemScope(limits.GetSystemLimits(), r) + r.allowlistedSystem.IncRef() + r.allowlistedTransient = newTransientScope(limits.GetTransientLimits(), r) + r.allowlistedTransient.IncRef() + r.cancelCtx, r.cancel = context.WithCancel(context.Background()) r.wg.Add(1) From dc09a97d9b9aef8cf0c7c0bac71cdc7df04cff19 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Wed, 15 Jun 2022 15:21:39 -0700 Subject: [PATCH 10/24] Fix allowlist system instantiation --- rcmgr.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/rcmgr.go b/rcmgr.go index b5c28c2..a0f75e5 100644 --- a/rcmgr.go +++ b/rcmgr.go @@ -144,14 +144,14 @@ 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) + r.allowlistedSystem = newSystemScope(limits.GetSystemLimits(), r, "allowlistedSystem") r.allowlistedSystem.IncRef() - r.allowlistedTransient = newTransientScope(limits.GetTransientLimits(), r) + r.allowlistedTransient = newTransientScope(limits.GetTransientLimits(), r, "allowlistedTransient", r.allowlistedSystem.resourceScope) r.allowlistedTransient.IncRef() r.cancelCtx, r.cancel = context.WithCancel(context.Background()) @@ -384,17 +384,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, } } From a41033230f25f225a227948478af481ca7c48f41 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Wed, 15 Jun 2022 15:25:40 -0700 Subject: [PATCH 11/24] Persist endpoint --- rcmgr.go | 1 + 1 file changed, 1 insertion(+) diff --git a/rcmgr.go b/rcmgr.go index a0f75e5..7256f13 100644 --- a/rcmgr.go +++ b/rcmgr.go @@ -278,6 +278,7 @@ func (r *resourceManager) OpenConnection(dir network.Direction, usefd bool, endp } else { conn = newConnectionScope(dir, usefd, r.limits.GetConnLimits(), r) } + conn.endpoint = endpoint if err := conn.AddConn(dir, usefd); err != nil { conn.Done() From 1bf5e930ee94f59fb1b3c0f15abaa721bf7c0ba4 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 27 Jun 2022 13:59:26 -0700 Subject: [PATCH 12/24] Fuse with if above --- rcmgr.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/rcmgr.go b/rcmgr.go index 7256f13..63ce9cf 100644 --- a/rcmgr.go +++ b/rcmgr.go @@ -590,18 +590,18 @@ func (s *connectionScope) SetPeer(p peer.ID) error { if s.isAllowlisted { system = s.rcmgr.allowlistedSystem transient = s.rcmgr.transient - } - if s.isAllowlisted && !s.rcmgr.allowlist.AllowedPeerAndMultiaddr(p, s.endpoint) { - // 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 + if !s.rcmgr.allowlist.AllowedPeerAndMultiaddr(p, s.endpoint) { + // 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 + } } } From fd82a9fe0140f3a2ada8f768467ef630e335c387 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 27 Jun 2022 14:40:07 -0700 Subject: [PATCH 13/24] Protect inner data with RWMutex --- allowlist.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/allowlist.go b/allowlist.go index 0bb73fe..efe37a3 100644 --- a/allowlist.go +++ b/allowlist.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net" + "sync" "github.com/libp2p/go-libp2p-core/peer" "github.com/multiformats/go-multiaddr" @@ -12,6 +13,7 @@ import ( ) 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). @@ -89,6 +91,8 @@ func toIPNet(ma multiaddr.Multiaddr) (*net.IPNet, peer.ID, error) { // e.g. /ip4/1.2.3.4/p2p/QmFoo and /ip4/1.2.3.4 are valid. // /p2p/QmFoo is not valid. func (al *allowlist) Add(ma multiaddr.Multiaddr) error { + al.mu.Lock() + defer al.mu.Unlock() ipnet, allowedPeer, err := toIPNet(ma) if err != nil { return err @@ -104,6 +108,9 @@ func (al *allowlist) Add(ma multiaddr.Multiaddr) error { } func (al *allowlist) Remove(ma multiaddr.Multiaddr) error { + al.mu.Lock() + defer al.mu.Unlock() + ipnet, allowedPeer, err := toIPNet(ma) if err != nil { return err @@ -140,6 +147,8 @@ func (al *allowlist) Remove(ma multiaddr.Multiaddr) error { } func (al *allowlist) Allowed(ma multiaddr.Multiaddr) bool { + al.mu.RLock() + defer al.mu.RUnlock() ip, err := manet.ToIP(ma) if err != nil { return false @@ -163,6 +172,8 @@ func (al *allowlist) Allowed(ma multiaddr.Multiaddr) bool { } func (al *allowlist) AllowedPeerAndMultiaddr(peerID peer.ID, ma multiaddr.Multiaddr) bool { + al.mu.RLock() + defer al.mu.RUnlock() ip, err := manet.ToIP(ma) if err != nil { return false From 61008b316cd64938dc41634e347c5d381618b2d9 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 27 Jun 2022 15:04:27 -0700 Subject: [PATCH 14/24] Only use allowlist if the normal resource scopes would have failed --- rcmgr.go | 53 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/rcmgr.go b/rcmgr.go index 63ce9cf..ee1a488 100644 --- a/rcmgr.go +++ b/rcmgr.go @@ -271,16 +271,22 @@ func (r *resourceManager) nextStreamId() int64 { } func (r *resourceManager) OpenConnection(dir network.Direction, usefd bool, endpoint multiaddr.Multiaddr) (network.ConnManagementScope, error) { - allowed := r.allowlist.Allowed(endpoint) var conn *connectionScope - if allowed { - conn = newAllowListedConnectionScope(dir, usefd, r.limits.GetConnLimits(), r) - } else { - conn = newConnectionScope(dir, usefd, r.limits.GetConnLimits(), r) - } - conn.endpoint = endpoint + 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 @@ -430,25 +436,28 @@ 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}, fmt.Sprintf("conn-%d", rcmgr.nextConnId()), rcmgr.trace, rcmgr.metrics), - dir: dir, - usefd: usefd, - rcmgr: rcmgr, + dir: dir, + usefd: usefd, + rcmgr: rcmgr, + endpoint: endpoint, } } -func newAllowListedConnectionScope(dir network.Direction, usefd bool, limit Limit, rcmgr *resourceManager) *connectionScope { +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, + dir: dir, + usefd: usefd, + rcmgr: rcmgr, + endpoint: endpoint, + isAllowlisted: true, } } @@ -533,14 +542,14 @@ func (s *connectionScope) PeerScope() network.PeerScope { return s.peer } -// transferAllowedToStandard Transfers this connection scope from being part of +// 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.system.resourceScope + transientScope := s.rcmgr.transient.resourceScope stat := s.resourceScope.rc.stat() @@ -589,9 +598,11 @@ func (s *connectionScope) SetPeer(p peer.ID) error { if s.isAllowlisted { system = s.rcmgr.allowlistedSystem - transient = s.rcmgr.transient + 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 @@ -602,6 +613,10 @@ func (s *connectionScope) SetPeer(p peer.ID) error { // 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 } } From 5f5fdb3b6c0f790f706e2199b5ce0bf64150052d Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 27 Jun 2022 15:30:03 -0700 Subject: [PATCH 15/24] Update comment --- allowlist.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/allowlist.go b/allowlist.go index efe37a3..df0e90c 100644 --- a/allowlist.go +++ b/allowlist.go @@ -88,7 +88,7 @@ func toIPNet(ma multiaddr.Multiaddr) (*net.IPNet, peer.ID, error) { // 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 and /ip4/1.2.3.4 are valid. +// 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 { al.mu.Lock() From a5e8e04ea97bd49fb9fd9ec154a56d436970d754 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 27 Jun 2022 15:30:21 -0700 Subject: [PATCH 16/24] Allowlist test with rcmgr --- rcmgr_test.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/rcmgr_test.go b/rcmgr_test.go index 4bb8106..1822817 100644 --- a/rcmgr_test.go +++ b/rcmgr_test.go @@ -6,6 +6,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/libp2p/go-libp2p-core/test" "github.com/multiformats/go-multiaddr" ) @@ -1001,3 +1002,69 @@ func TestResourceManager(t *testing.T) { } } + +func TestResourceManagerWithAllowlist(t *testing.T) { + limits := NewDefaultLimiter() + limits.SystemLimits = limits.SystemLimits.WithConnLimit(0, 0, 0) + limits.TransientLimits = limits.SystemLimits.WithConnLimit(0, 0, 0) + rcmgr, err := NewResourceManager(limits) + if err != nil { + t.Fatal(err) + } + + peerA := test.RandPeerIDFatal(t) + + { + // 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() + allowlist := r.allowlist + + allowlist.Add(multiaddr.StringCast("/ip4/1.2.3.4")) + allowlist.Add(multiaddr.StringCast("/ip4/4.3.2.1/p2p/" + peerA.String())) + } + + // 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) + } + +} From 2bb066a2ce17122ef411bb50fe8f2173399c1899 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 27 Jun 2022 15:39:26 -0700 Subject: [PATCH 17/24] Export Allowlist type --- allowlist.go | 21 ++++++++++++++------- rcmgr.go | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/allowlist.go b/allowlist.go index df0e90c..722e576 100644 --- a/allowlist.go +++ b/allowlist.go @@ -12,7 +12,7 @@ import ( manet "github.com/multiformats/go-multiaddr/net" ) -type allowlist struct { +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 @@ -26,8 +26,8 @@ type allowlist struct { allowedPeerByNetwork map[peer.ID][]*net.IPNet } -func newAllowlist() allowlist { - return allowlist{ +func newAllowlist() Allowlist { + return Allowlist{ allowedPeerByNetwork: make(map[peer.ID][]*net.IPNet), } } @@ -90,7 +90,7 @@ func toIPNet(ma multiaddr.Multiaddr) (*net.IPNet, peer.ID, error) { // 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 { +func (al *Allowlist) Add(ma multiaddr.Multiaddr) error { al.mu.Lock() defer al.mu.Unlock() ipnet, allowedPeer, err := toIPNet(ma) @@ -100,6 +100,9 @@ func (al *allowlist) Add(ma multiaddr.Multiaddr) error { 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) @@ -107,7 +110,7 @@ func (al *allowlist) Add(ma multiaddr.Multiaddr) error { return nil } -func (al *allowlist) Remove(ma multiaddr.Multiaddr) error { +func (al *Allowlist) Remove(ma multiaddr.Multiaddr) error { al.mu.Lock() defer al.mu.Unlock() @@ -122,6 +125,10 @@ func (al *allowlist) Remove(ma multiaddr.Multiaddr) error { ipNetList = al.allowedPeerByNetwork[allowedPeer] } + if ipNetList == nil { + return nil + } + i := len(ipNetList) for i > 0 { i-- @@ -146,7 +153,7 @@ func (al *allowlist) Remove(ma multiaddr.Multiaddr) error { return nil } -func (al *allowlist) Allowed(ma multiaddr.Multiaddr) bool { +func (al *Allowlist) Allowed(ma multiaddr.Multiaddr) bool { al.mu.RLock() defer al.mu.RUnlock() ip, err := manet.ToIP(ma) @@ -171,7 +178,7 @@ func (al *allowlist) Allowed(ma multiaddr.Multiaddr) bool { return false } -func (al *allowlist) AllowedPeerAndMultiaddr(peerID peer.ID, ma multiaddr.Multiaddr) bool { +func (al *Allowlist) AllowedPeerAndMultiaddr(peerID peer.ID, ma multiaddr.Multiaddr) bool { al.mu.RLock() defer al.mu.RUnlock() ip, err := manet.ToIP(ma) diff --git a/rcmgr.go b/rcmgr.go index ee1a488..663f0e3 100644 --- a/rcmgr.go +++ b/rcmgr.go @@ -22,7 +22,7 @@ type resourceManager struct { trace *trace metrics *metrics - allowlist *allowlist + allowlist *Allowlist system *systemScope transient *transientScope From 8c5643aa2f6f828235c6c946e15a4c806f6def0a Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 27 Jun 2022 15:42:00 -0700 Subject: [PATCH 18/24] Add GetAllowlist() --- rcmgr.go | 4 ++++ rcmgr_test.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/rcmgr.go b/rcmgr.go index 663f0e3..2be9113 100644 --- a/rcmgr.go +++ b/rcmgr.go @@ -162,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) } diff --git a/rcmgr_test.go b/rcmgr_test.go index 1822817..bf530c0 100644 --- a/rcmgr_test.go +++ b/rcmgr_test.go @@ -1022,7 +1022,7 @@ func TestResourceManagerWithAllowlist(t *testing.T) { r.allowlistedSystem.IncRef() r.allowlistedTransient = newTransientScope(limits.GetTransientLimits().WithConnLimit(1, 1, 1), r, "allowlistedTransient", r.allowlistedSystem.resourceScope) r.allowlistedTransient.IncRef() - allowlist := r.allowlist + allowlist := r.GetAllowlist() allowlist.Add(multiaddr.StringCast("/ip4/1.2.3.4")) allowlist.Add(multiaddr.StringCast("/ip4/4.3.2.1/p2p/" + peerA.String())) From 374b297cee17bc0b73480e738e65137795570bdd Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 27 Jun 2022 15:47:51 -0700 Subject: [PATCH 19/24] Add WithAllowlistedMultiaddr option --- allowlist.go | 13 +++++++++++++ rcmgr_test.go | 14 ++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/allowlist.go b/allowlist.go index 722e576..9e919c5 100644 --- a/allowlist.go +++ b/allowlist.go @@ -26,6 +26,19 @@ type Allowlist struct { 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), diff --git a/rcmgr_test.go b/rcmgr_test.go index bf530c0..1656a0d 100644 --- a/rcmgr_test.go +++ b/rcmgr_test.go @@ -1004,16 +1004,19 @@ 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) + 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) } - peerA := test.RandPeerIDFatal(t) - { // Setup allowlist. TODO, replace this with a config once config changes are in r := rcmgr.(*resourceManager) @@ -1022,10 +1025,6 @@ func TestResourceManagerWithAllowlist(t *testing.T) { r.allowlistedSystem.IncRef() r.allowlistedTransient = newTransientScope(limits.GetTransientLimits().WithConnLimit(1, 1, 1), r, "allowlistedTransient", r.allowlistedSystem.resourceScope) r.allowlistedTransient.IncRef() - allowlist := r.GetAllowlist() - - allowlist.Add(multiaddr.StringCast("/ip4/1.2.3.4")) - allowlist.Add(multiaddr.StringCast("/ip4/4.3.2.1/p2p/" + peerA.String())) } // A connection comes in from a non-allowlisted ip address @@ -1066,5 +1065,4 @@ func TestResourceManagerWithAllowlist(t *testing.T) { if err != nil { t.Fatal(err) } - } From 600191a10c392829607a2c1eb2cf4f3ae761521b Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 27 Jun 2022 15:54:42 -0700 Subject: [PATCH 20/24] Update allowlist design doc with no extra cost for happy path --- allowlist_test.go | 8 ++++++++ docs/allowlist.md | 13 ++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/allowlist_test.go b/allowlist_test.go index 3a8e9f9..713e5b8 100644 --- a/allowlist_test.go +++ b/allowlist_test.go @@ -112,6 +112,14 @@ func TestAllowedWithPeer(t *testing.T) { 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, diff --git a/docs/allowlist.md b/docs/allowlist.md index 1819039..4ada09c 100644 --- a/docs/allowlist.md +++ b/docs/allowlist.md @@ -20,6 +20,8 @@ This is the problem that the Allowlist is designed to solve. - 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 @@ -38,11 +40,12 @@ For example, an allowlist set could look like: /ip4/1.2.3.0/ipcidr/24 ``` -When a new connection is opened, the resource manager 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. Otherwise, it uses the normal system and transient resource -scopes as it does today. +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 From 7aecdc148d16e3f53cc6c3e36ecdeceec0b6ebe5 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Wed, 29 Jun 2022 21:18:16 -0700 Subject: [PATCH 21/24] PR nits --- allowlist.go | 24 ++++++++++++++---------- allowlist_test.go | 4 ++-- rcmgr_test.go | 2 +- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/allowlist.go b/allowlist.go index 9e919c5..6a4fb1c 100644 --- a/allowlist.go +++ b/allowlist.go @@ -104,12 +104,12 @@ func toIPNet(ma multiaddr.Multiaddr) (*net.IPNet, peer.ID, error) { // 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 { - al.mu.Lock() - defer al.mu.Unlock() 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 @@ -124,16 +124,16 @@ func (al *Allowlist) Add(ma multiaddr.Multiaddr) error { } func (al *Allowlist) Remove(ma multiaddr.Multiaddr) error { - al.mu.Lock() - defer al.mu.Unlock() - ipnet, allowedPeer, err := toIPNet(ma) if err != nil { return err } + al.mu.Lock() + defer al.mu.Unlock() + ipNetList := al.allowedNetworks - if allowedPeer != peer.ID("") { + if allowedPeer != "" { // We have a peerID constraint ipNetList = al.allowedPeerByNetwork[allowedPeer] } @@ -149,10 +149,14 @@ func (al *Allowlist) Remove(ma multiaddr.Multiaddr) error { if i == len(ipNetList)-1 { // Trim this element from the end ipNetList = ipNetList[:i] + // We only remove one thing + break } else { // swap remove ipNetList[i] = ipNetList[len(ipNetList)-1] ipNetList = ipNetList[:len(ipNetList)-1] + // We only remove one thing + break } } } @@ -167,12 +171,12 @@ func (al *Allowlist) Remove(ma multiaddr.Multiaddr) error { } func (al *Allowlist) Allowed(ma multiaddr.Multiaddr) bool { - al.mu.RLock() - defer al.mu.RUnlock() 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) { @@ -192,12 +196,12 @@ func (al *Allowlist) Allowed(ma multiaddr.Multiaddr) bool { } func (al *Allowlist) AllowedPeerAndMultiaddr(peerID peer.ID, ma multiaddr.Multiaddr) bool { - al.mu.RLock() - defer al.mu.RUnlock() 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) { diff --git a/allowlist_test.go b/allowlist_test.go index 713e5b8..7f5267e 100644 --- a/allowlist_test.go +++ b/allowlist_test.go @@ -38,8 +38,8 @@ func TestAllowedWithPeer(t *testing.T) { peerA := test.RandPeerIDFatal(t) peerB := test.RandPeerIDFatal(t) - multiaddrA, _ := multiaddr.NewMultiaddr("/ip4/1.2.3.4/tcp/1234") - multiaddrB, _ := multiaddr.NewMultiaddr("/ip4/2.2.3.4/tcp/1234") + multiaddrA := multiaddr.StringCast("/ip4/1.2.3.4/tcp/1234") + multiaddrB := multiaddr.StringCast("/ip4/2.2.3.4/tcp/1234") testcases := []testcase{ { diff --git a/rcmgr_test.go b/rcmgr_test.go index 1656a0d..fdf8dbf 100644 --- a/rcmgr_test.go +++ b/rcmgr_test.go @@ -10,7 +10,7 @@ import ( "github.com/multiformats/go-multiaddr" ) -var dummyMA, _ = multiaddr.NewMultiaddr("/ip4/1.2.3.4/tcp/1234") +var dummyMA = multiaddr.StringCast("/ip4/1.2.3.4/tcp/1234") func TestResourceManager(t *testing.T) { peerA := peer.ID("A") From 6edfbe4b5c297fd1895f35d9f97de4ac9c351912 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Thu, 30 Jun 2022 09:55:46 -0700 Subject: [PATCH 22/24] Remove branch --- allowlist.go | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/allowlist.go b/allowlist.go index 6a4fb1c..fd72af0 100644 --- a/allowlist.go +++ b/allowlist.go @@ -146,18 +146,11 @@ func (al *Allowlist) Remove(ma multiaddr.Multiaddr) error { for i > 0 { i-- if ipNetList[i].IP.Equal(ipnet.IP) && bytes.Equal(ipNetList[i].Mask, ipnet.Mask) { - if i == len(ipNetList)-1 { - // Trim this element from the end - ipNetList = ipNetList[:i] - // We only remove one thing - break - } else { - // swap remove - ipNetList[i] = ipNetList[len(ipNetList)-1] - ipNetList = ipNetList[:len(ipNetList)-1] - // We only remove one thing - break - } + // swap remove + ipNetList[i] = ipNetList[len(ipNetList)-1] + ipNetList = ipNetList[:len(ipNetList)-1] + // We only remove one thing + break } } From 8eac037a9ddd203431ba9ea32f2c41535985ce51 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Thu, 30 Jun 2022 15:34:57 -0700 Subject: [PATCH 23/24] Update deps --- go.mod | 22 +++++++++++++--------- go.sum | 54 +++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 39e437a..3c2ea2d 100644 --- a/go.mod +++ b/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 ) diff --git a/go.sum b/go.sum index b78292d..9ecb0a1 100644 --- a/go.sum +++ b/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= @@ -59,16 +77,22 @@ github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ8 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 +102,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 +119,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 +141,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= From 0487d3e13bec1b0641a24332c553d81121e5930a Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Thu, 30 Jun 2022 16:53:48 -0700 Subject: [PATCH 24/24] Mod tidy --- go.sum | 1 - 1 file changed, 1 deletion(-) diff --git a/go.sum b/go.sum index 9ecb0a1..f4ec102 100644 --- a/go.sum +++ b/go.sum @@ -75,7 +75,6 @@ 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=