From 5c39d0f30245467e72947cc894dbe16ef04723df Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Tue, 7 Apr 2020 11:46:27 +0530 Subject: [PATCH 01/10] The Connection Gater interface. --- connmgr/conngating.go | 63 +++++++++++++++++++++++++++++++++++++++++++ control/disconnect.go | 4 +++ 2 files changed, 67 insertions(+) create mode 100644 connmgr/conngating.go create mode 100644 control/disconnect.go diff --git a/connmgr/conngating.go b/connmgr/conngating.go new file mode 100644 index 00000000..51fe5d85 --- /dev/null +++ b/connmgr/conngating.go @@ -0,0 +1,63 @@ +package connmgr + +import ( + "github.com/libp2p/go-libp2p-core/control" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/transport" + + ma "github.com/multiformats/go-multiaddr" +) + +// ConnectionGater can be implemented by a type that supports active +// inbound or outbound connection gating. +// +// A ConnectionGater will be consulted at various stages in the life cycle of a connection. +// The specific gating function that will be called depends on the lifecycle state of the +// connection during which Gating needs to be applied. +// +// `InterceptDial` and `InterceptPeerDial` are called when we try an outbound dial. +// +// `InterceptAccept` is called after we've accepted an inbound connection from a socket but before we +// begin upgrading it. +// +// `InterceptSecured` is called for inbound and outbound connections after we've negotiated +// the security protocol to use for the connection. +// +// `InterceptUpgraded` is called for inbound and outbound connections after we've finished upgrading +// a connection to have both security and stream multiplexing. +// +// This feature can be used to implement *strict* connection management +// behaviours, such as hard limiting of connections once a max count has been +// reached. +type ConnectionGater interface { + // InterceptDial tests whether we're permitted to dial the specified multiaddr. + // Insofar filter.Filters is concerned, this would map to its AddrBlock method, + // with the inverse condition. + // This is to be called by the network/swarm when dialling. + InterceptDial(ma.Multiaddr) (allow bool) + + // InterceptPeerDial tests whether we're permitted to Dial the specified peer. + // This is to be called by the network/swarm when dialling. + InterceptPeerDial(p peer.ID) (allow bool) + + // InterceptAccept tests whether an incipient inbound connection is allowed. + // network.ConnMultiaddrs is what we pass to the upgrader. + // This is intended to be called by the upgrader, or by the transport + // directly (e.g. QUIC, Bluetooth), straight after it's accepted a connection + // from its socket. + InterceptAccept(network.ConnMultiaddrs) (allow bool) + + // InterceptSecured tests whether a given connection, now authenticated, + // is allowed. + // This is intended to be called by the upgrader, after it has negotiated crypto, + // and before it negotiates the muxer, or by the directly by the transport, + // at the exact same checkpoint. + InterceptSecured(network.Direction, peer.ID, network.ConnMultiaddrs) (allow bool) + + // InterceptUpgraded tests whether a fully capable connection is allowed. + // At this point, we have a multiplexer, so the middleware can + // return a DisconnectReason and the swarm would use the control stream to convey + // it to the peer. + InterceptUpgraded(transport.CapableConn) (allow bool, reason control.DisconnectReason) +} \ No newline at end of file diff --git a/control/disconnect.go b/control/disconnect.go new file mode 100644 index 00000000..af235d4a --- /dev/null +++ b/control/disconnect.go @@ -0,0 +1,4 @@ +package control + +// DisconnectReason informs the receiver of the reason the connectedness is being terminated by the sender. +type DisconnectReason int From 27f200f8f2de68af6cf3bcd20175aac2e69fdab4 Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Thu, 9 Apr 2020 18:13:13 +0530 Subject: [PATCH 02/10] better docs --- connmgr/conngating.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/connmgr/conngating.go b/connmgr/conngating.go index 51fe5d85..56ef25c6 100644 --- a/connmgr/conngating.go +++ b/connmgr/conngating.go @@ -12,9 +12,10 @@ import ( // ConnectionGater can be implemented by a type that supports active // inbound or outbound connection gating. // -// A ConnectionGater will be consulted at various stages in the life cycle of a connection. -// The specific gating function that will be called depends on the lifecycle state of the -// connection during which Gating needs to be applied. +// A ConnectionGater will be consulted during different states in the life-cycle of a connection and +// the specific gating function that will be called depends on the lifecycle state of the +// connection. Hence, it is important to implement this interface keeping in mind the specific life cycle state +// at which you'd like to gate/block the connection. // // `InterceptDial` and `InterceptPeerDial` are called when we try an outbound dial. // @@ -60,4 +61,4 @@ type ConnectionGater interface { // return a DisconnectReason and the swarm would use the control stream to convey // it to the peer. InterceptUpgraded(transport.CapableConn) (allow bool, reason control.DisconnectReason) -} \ No newline at end of file +} From 2f4d34c727d992f9b79f61d73e0b3b131b2219e4 Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Thu, 9 Apr 2020 18:17:14 +0530 Subject: [PATCH 03/10] better docs --- connmgr/conngating.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/connmgr/conngating.go b/connmgr/conngating.go index 56ef25c6..80880884 100644 --- a/connmgr/conngating.go +++ b/connmgr/conngating.go @@ -13,8 +13,8 @@ import ( // inbound or outbound connection gating. // // A ConnectionGater will be consulted during different states in the life-cycle of a connection and -// the specific gating function that will be called depends on the lifecycle state of the -// connection. Hence, it is important to implement this interface keeping in mind the specific life cycle state +// the specific gating function that will be called depends on the life-cycle state of the +// connection. Hence, it is important to implement this interface keeping in mind the specific life-cycle state // at which you'd like to gate/block the connection. // // `InterceptDial` and `InterceptPeerDial` are called when we try an outbound dial. From 2a695419653d525ac9ba60b10e4135c79c669f0e Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Thu, 9 Apr 2020 20:25:15 +0530 Subject: [PATCH 04/10] change in docs --- connmgr/conngating.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/connmgr/conngating.go b/connmgr/conngating.go index 80880884..05ed6e03 100644 --- a/connmgr/conngating.go +++ b/connmgr/conngating.go @@ -31,6 +31,11 @@ import ( // This feature can be used to implement *strict* connection management // behaviours, such as hard limiting of connections once a max count has been // reached. +// +// If you'd like to send a disconnect control message to the remote peer with an appropriate +// reason, ONLY `InterceptUpgraded` should return reject the connection(with an appropriate reason) +// and all other methods should allow the connection as we can ONLY open control streams +// for upgraded connections. type ConnectionGater interface { // InterceptDial tests whether we're permitted to dial the specified multiaddr. // Insofar filter.Filters is concerned, this would map to its AddrBlock method, From a10491064e22ff4be8a936f847f33baca8340db8 Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Thu, 9 Apr 2020 20:35:22 +0530 Subject: [PATCH 05/10] doc changes --- connmgr/conngating.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/connmgr/conngating.go b/connmgr/conngating.go index 05ed6e03..5c642235 100644 --- a/connmgr/conngating.go +++ b/connmgr/conngating.go @@ -32,10 +32,12 @@ import ( // behaviours, such as hard limiting of connections once a max count has been // reached. // -// If you'd like to send a disconnect control message to the remote peer with an appropriate -// reason, ONLY `InterceptUpgraded` should return reject the connection(with an appropriate reason) -// and all other methods should allow the connection as we can ONLY open control streams +// If you'd like to send a disconnect control message to the remote peer for a gated inbound connection, +// ONLY `InterceptUpgraded` should reject the connection (with an appropriate disconenct reason). +// All other methods should allow the connection as we can ONLY open control streams // for upgraded connections. +// Note: There's no point in sending disconnect control messages for outbound connections, so we might +// as well close them as early in the cycle as possible. type ConnectionGater interface { // InterceptDial tests whether we're permitted to dial the specified multiaddr. // Insofar filter.Filters is concerned, this would map to its AddrBlock method, From f8bf7fa826587d2afef8e25ca1e5187229065d20 Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Thu, 9 Apr 2020 20:36:55 +0530 Subject: [PATCH 06/10] doc changes --- connmgr/conngating.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connmgr/conngating.go b/connmgr/conngating.go index 5c642235..9ea419c5 100644 --- a/connmgr/conngating.go +++ b/connmgr/conngating.go @@ -33,7 +33,7 @@ import ( // reached. // // If you'd like to send a disconnect control message to the remote peer for a gated inbound connection, -// ONLY `InterceptUpgraded` should reject the connection (with an appropriate disconenct reason). +// ONLY `InterceptUpgraded` should reject the connection (with an appropriate disconnect reason). // All other methods should allow the connection as we can ONLY open control streams // for upgraded connections. // Note: There's no point in sending disconnect control messages for outbound connections, so we might From 0ce93eb25877649a77f11e27185a1f288e1950e5 Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Mon, 13 Apr 2020 12:33:12 +0530 Subject: [PATCH 07/10] changes as per review --- connmgr/conngating.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/connmgr/conngating.go b/connmgr/conngating.go index 9ea419c5..5ae2fd6e 100644 --- a/connmgr/conngating.go +++ b/connmgr/conngating.go @@ -39,11 +39,11 @@ import ( // Note: There's no point in sending disconnect control messages for outbound connections, so we might // as well close them as early in the cycle as possible. type ConnectionGater interface { - // InterceptDial tests whether we're permitted to dial the specified multiaddr. + // InterceptDial tests whether we're permitted to dial the specified multiaddr for the given peer. // Insofar filter.Filters is concerned, this would map to its AddrBlock method, - // with the inverse condition. + // with the inverse condition on the given address. // This is to be called by the network/swarm when dialling. - InterceptDial(ma.Multiaddr) (allow bool) + InterceptDial(peer.ID, ma.Multiaddr) (allow bool) // InterceptPeerDial tests whether we're permitted to Dial the specified peer. // This is to be called by the network/swarm when dialling. From 7f44bb7684b566ed81d74ea9c0beb744a7aa64dd Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Mon, 13 Apr 2020 12:43:28 +0530 Subject: [PATCH 08/10] changes as per review --- connmgr/conngating.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/connmgr/conngating.go b/connmgr/conngating.go index 5ae2fd6e..14ac21bd 100644 --- a/connmgr/conngating.go +++ b/connmgr/conngating.go @@ -17,7 +17,7 @@ import ( // connection. Hence, it is important to implement this interface keeping in mind the specific life-cycle state // at which you'd like to gate/block the connection. // -// `InterceptDial` and `InterceptPeerDial` are called when we try an outbound dial. +// `InterceptPeerDial` and `InterceptPeerAddrDial` are called when we try an outbound dial. // // `InterceptAccept` is called after we've accepted an inbound connection from a socket but before we // begin upgrading it. @@ -39,16 +39,16 @@ import ( // Note: There's no point in sending disconnect control messages for outbound connections, so we might // as well close them as early in the cycle as possible. type ConnectionGater interface { - // InterceptDial tests whether we're permitted to dial the specified multiaddr for the given peer. - // Insofar filter.Filters is concerned, this would map to its AddrBlock method, - // with the inverse condition on the given address. - // This is to be called by the network/swarm when dialling. - InterceptDial(peer.ID, ma.Multiaddr) (allow bool) - // InterceptPeerDial tests whether we're permitted to Dial the specified peer. // This is to be called by the network/swarm when dialling. InterceptPeerDial(p peer.ID) (allow bool) + // InterceptPeerAddrDial tests whether we're permitted to dial the specified multiaddr for the given peer. + // Insofar filter.Filters is concerned, this would map to its AddrBlock method, + // with the inverse condition on the given address. + // This is to be called by the network/swarm when dialling. + InterceptPeerAddrDial(peer.ID, ma.Multiaddr) (allow bool) + // InterceptAccept tests whether an incipient inbound connection is allowed. // network.ConnMultiaddrs is what we pass to the upgrader. // This is intended to be called by the upgrader, or by the transport From c8df9235bae7b5c39f956b5589adc9c3da142599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 13 May 2020 13:06:42 +0100 Subject: [PATCH 09/10] review godocs; drop superfluous 'conn' prefix from files; rename methods. --- connmgr/conngating.go | 71 ----------------------- connmgr/gater.go | 91 ++++++++++++++++++++++++++++++ connmgr/{connmgr.go => manager.go} | 0 control/disconnect.go | 7 ++- 4 files changed, 97 insertions(+), 72 deletions(-) delete mode 100644 connmgr/conngating.go create mode 100644 connmgr/gater.go rename connmgr/{connmgr.go => manager.go} (100%) diff --git a/connmgr/conngating.go b/connmgr/conngating.go deleted file mode 100644 index 14ac21bd..00000000 --- a/connmgr/conngating.go +++ /dev/null @@ -1,71 +0,0 @@ -package connmgr - -import ( - "github.com/libp2p/go-libp2p-core/control" - "github.com/libp2p/go-libp2p-core/network" - "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-core/transport" - - ma "github.com/multiformats/go-multiaddr" -) - -// ConnectionGater can be implemented by a type that supports active -// inbound or outbound connection gating. -// -// A ConnectionGater will be consulted during different states in the life-cycle of a connection and -// the specific gating function that will be called depends on the life-cycle state of the -// connection. Hence, it is important to implement this interface keeping in mind the specific life-cycle state -// at which you'd like to gate/block the connection. -// -// `InterceptPeerDial` and `InterceptPeerAddrDial` are called when we try an outbound dial. -// -// `InterceptAccept` is called after we've accepted an inbound connection from a socket but before we -// begin upgrading it. -// -// `InterceptSecured` is called for inbound and outbound connections after we've negotiated -// the security protocol to use for the connection. -// -// `InterceptUpgraded` is called for inbound and outbound connections after we've finished upgrading -// a connection to have both security and stream multiplexing. -// -// This feature can be used to implement *strict* connection management -// behaviours, such as hard limiting of connections once a max count has been -// reached. -// -// If you'd like to send a disconnect control message to the remote peer for a gated inbound connection, -// ONLY `InterceptUpgraded` should reject the connection (with an appropriate disconnect reason). -// All other methods should allow the connection as we can ONLY open control streams -// for upgraded connections. -// Note: There's no point in sending disconnect control messages for outbound connections, so we might -// as well close them as early in the cycle as possible. -type ConnectionGater interface { - // InterceptPeerDial tests whether we're permitted to Dial the specified peer. - // This is to be called by the network/swarm when dialling. - InterceptPeerDial(p peer.ID) (allow bool) - - // InterceptPeerAddrDial tests whether we're permitted to dial the specified multiaddr for the given peer. - // Insofar filter.Filters is concerned, this would map to its AddrBlock method, - // with the inverse condition on the given address. - // This is to be called by the network/swarm when dialling. - InterceptPeerAddrDial(peer.ID, ma.Multiaddr) (allow bool) - - // InterceptAccept tests whether an incipient inbound connection is allowed. - // network.ConnMultiaddrs is what we pass to the upgrader. - // This is intended to be called by the upgrader, or by the transport - // directly (e.g. QUIC, Bluetooth), straight after it's accepted a connection - // from its socket. - InterceptAccept(network.ConnMultiaddrs) (allow bool) - - // InterceptSecured tests whether a given connection, now authenticated, - // is allowed. - // This is intended to be called by the upgrader, after it has negotiated crypto, - // and before it negotiates the muxer, or by the directly by the transport, - // at the exact same checkpoint. - InterceptSecured(network.Direction, peer.ID, network.ConnMultiaddrs) (allow bool) - - // InterceptUpgraded tests whether a fully capable connection is allowed. - // At this point, we have a multiplexer, so the middleware can - // return a DisconnectReason and the swarm would use the control stream to convey - // it to the peer. - InterceptUpgraded(transport.CapableConn) (allow bool, reason control.DisconnectReason) -} diff --git a/connmgr/gater.go b/connmgr/gater.go new file mode 100644 index 00000000..d4783b7f --- /dev/null +++ b/connmgr/gater.go @@ -0,0 +1,91 @@ +package connmgr + +import ( + "github.com/libp2p/go-libp2p-core/control" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/transport" + + ma "github.com/multiformats/go-multiaddr" +) + +// ConnectionGater can be implemented by a type that supports active +// inbound or outbound connection gating. +// +// ConnectionGaters are active, whereas ConnManagers tend to be passive. +// +// A ConnectionGater will be consulted during different states in the lifecycle +// of a connection being established/upgraded. Specific functions will be called +// throughout the process, to allow you to intercept the connection at that stage. +// +// InterceptPeerDial is called on an imminent outbound peer dial request, prior +// to the addresses of that peer being available/resolved. Blocking connections +// at this stage is typical for blacklisting scenarios. +// +// InterceptAddrDial is called on an imminent outbound dial to a peer on a +// particular address. Blocking connections at this stage is typical for +// address filtering. +// +// InterceptAccept is called as soon as a transport listener receives an +// inbound connection request, before any upgrade takes place. Transports who +// accept already secure and/or multiplexed connections (e.g. possibly QUIC) +// MUST call this method regardless, for correctness/consistency. +// +// InterceptSecured is called for both inbound and outbound connections, +// after a security handshake has taken place and we've authenticated the peer. +// +// InterceptUpgraded is called for inbound and outbound connections, after +// libp2p has finished upgrading the connection entirely to a secure, +// multiplexed channel. +// +// This interface can be used to implement *strict/active* connection management +// policies, such as hard limiting of connections once a maximum count has been +// reached, maintaining a peer blacklist, or limiting connections by transport +// quotas. +// +// EXPERIMENTAL: a DISCONNECT protocol/message will be supported in the future. +// This allows gaters and other components to communicate the intention behind +// a connection closure, to curtail potential reconnection attempts. +// +// For now, InterceptUpgraded can return a non-zero DisconnectReason when +// blocking a connection, but this interface is likely to change in the future +// as we solidify this feature. The reason why only this method can handle +// DisconnectReasons is that we require stream multiplexing capability to open a +// control protocol stream to transmit the message. +type ConnectionGater interface { + + // InterceptPeerDial tests whether we're permitted to Dial the specified peer. + // + // This is called by the network.Network implementation when dialling a peer. + InterceptPeerDial(p peer.ID) (allow bool) + + // InterceptAddrDial tests whether we're permitted to dial the specified + // multiaddr for the given peer. + // + // This is called by the network.Network implementation after it has + // resolved the peer's addrs, and prior to dialling each. + InterceptAddrDial(peer.ID, ma.Multiaddr) (allow bool) + + // InterceptAccept tests whether an incipient inbound connection is allowed. + // + // This is called by the upgrader, or by the transport directly (e.g. QUIC, + // Bluetooth), straight after it has accepted a connection from its socket. + InterceptAccept(network.ConnMultiaddrs) (allow bool) + + // InterceptSecured tests whether a given connection, now authenticated, + // is allowed. + // + // This is called by the upgrader, after it has performed the security + // handshake, and before it negotiates the muxer, or by the directly by the + // transport, at the exact same checkpoint. + InterceptSecured(network.Direction, peer.ID, network.ConnMultiaddrs) (allow bool) + + // InterceptUpgraded tests whether a fully capable connection is allowed. + // + // At this point, the connection a multiplexer has been selected. + // When rejecting a connection, the gater can return a DisconnectReason. + // Refer to the godoc on the ConnectionGater type for more information. + // + // NOTE: the go-libp2p implementation currently IGNORES the disconnect reason. + InterceptUpgraded(transport.CapableConn) (allow bool, reason control.DisconnectReason) +} diff --git a/connmgr/connmgr.go b/connmgr/manager.go similarity index 100% rename from connmgr/connmgr.go rename to connmgr/manager.go diff --git a/control/disconnect.go b/control/disconnect.go index af235d4a..ad1fc5b8 100644 --- a/control/disconnect.go +++ b/control/disconnect.go @@ -1,4 +1,9 @@ package control -// DisconnectReason informs the receiver of the reason the connectedness is being terminated by the sender. +// DisconnectReason communicates the reason why a connection is being closed. +// +// A zero value stands for "no reason" / NA. +// +// This is an EXPERIMENTAL type. It will change in the future. Refer to the +// connmgr.ConnectionGater godoc for more info. type DisconnectReason int From 32264f2111d56b982f47bb6623992e3e78710e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 13 May 2020 13:08:53 +0100 Subject: [PATCH 10/10] change signature of InterceptUpgraded to take network.Conn. --- connmgr/gater.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/connmgr/gater.go b/connmgr/gater.go index d4783b7f..5fc03c92 100644 --- a/connmgr/gater.go +++ b/connmgr/gater.go @@ -1,12 +1,11 @@ package connmgr import ( + ma "github.com/multiformats/go-multiaddr" + "github.com/libp2p/go-libp2p-core/control" "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p-core/transport" - - ma "github.com/multiformats/go-multiaddr" ) // ConnectionGater can be implemented by a type that supports active @@ -87,5 +86,5 @@ type ConnectionGater interface { // Refer to the godoc on the ConnectionGater type for more information. // // NOTE: the go-libp2p implementation currently IGNORES the disconnect reason. - InterceptUpgraded(transport.CapableConn) (allow bool, reason control.DisconnectReason) + InterceptUpgraded(network.Conn) (allow bool, reason control.DisconnectReason) }