Skip to content

Commit b500369

Browse files
bors[bot]kc1116Misha
authored
Merge #4103
4103: Khalil/6474 Gossipsub RPC control message Spam protection: GRAFT & PRUNE r=kc1116 a=gomisha This PR adds spam protection for gossipsub RPC control messages (GRAFT & PRUNE). It adds a new [ControlMsgValidationInspector](https://github.com/dapperlabs/flow-go/compare/khalil/6474-graft-prune-spam?expand=1#diff-875c4aae39d07a22e184608be05abd0dce2447e593716de23cb70495d8c3ab2fR52) which is a gossipsub RPC inspector that performs the following validation on control messages for each of the control types (GRAFT & PRUNE). These protections are important due to the fact that RPC messages are processed synchronously by libp2p and a malicious actor could exhaust the nodes resources or degrade the nodes network performance by spamming costly control messages. - Ensure RPC messages with a count > configured upper threshold are immediately rejected - Ensure RPC messages for specific control type are not rate limited for peer - Ensure RPC messages for specific control type < safety threshold < upper threshold have valid topic ID's - Ensure RPC messages with a count < safety threshold bypass validation I suggest you start your review in the [inspector package](https://github.com/dapperlabs/flow-go/tree/khalil/6474-graft-prune-spam/network/p2p/inspector) which contains all the new inspector logic and the [control message validation inspector gossip spammer tests.](https://github.com/dapperlabs/flow-go/blob/khalil/6474-graft-prune-spam/insecure/rpc_inspector_test/control_message_validation_test.go) ref: https://github.com/dapperlabs/flow-go/pull/6555 author: `@kc1116` Co-authored-by: Khalil Claybon <[email protected]> Co-authored-by: Misha <[email protected]>
2 parents 31eef46 + 09a5704 commit b500369

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2268
-538
lines changed

cmd/access/node_builder/access_node_builder.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ import (
5353
"github.com/onflow/flow-go/module/executiondatasync/execution_data"
5454
finalizer "github.com/onflow/flow-go/module/finalizer/consensus"
5555
"github.com/onflow/flow-go/module/id"
56-
"github.com/onflow/flow-go/module/mempool/queue"
5756
"github.com/onflow/flow-go/module/mempool/stdmap"
5857
"github.com/onflow/flow-go/module/metrics"
5958
"github.com/onflow/flow-go/module/metrics/unstaked"
@@ -68,7 +67,6 @@ import (
6867
"github.com/onflow/flow-go/network/p2p/cache"
6968
"github.com/onflow/flow-go/network/p2p/connection"
7069
"github.com/onflow/flow-go/network/p2p/dht"
71-
"github.com/onflow/flow-go/network/p2p/distributor"
7270
"github.com/onflow/flow-go/network/p2p/middleware"
7371
"github.com/onflow/flow-go/network/p2p/p2pbuilder"
7472
"github.com/onflow/flow-go/network/p2p/subscription"
@@ -699,12 +697,7 @@ func (builder *FlowAccessNodeBuilder) InitIDProviders() {
699697
}
700698
builder.IDTranslator = translator.NewHierarchicalIDTranslator(idCache, translator.NewPublicNetworkIDTranslator())
701699

702-
heroStoreOpts := []queue.HeroStoreConfigOption{queue.WithHeroStoreSizeLimit(builder.DisallowListNotificationCacheSize)}
703-
if builder.HeroCacheMetricsEnable {
704-
collector := metrics.DisallowListNotificationQueueMetricFactory(builder.MetricsRegisterer)
705-
heroStoreOpts = append(heroStoreOpts, queue.WithHeroStoreCollector(collector))
706-
}
707-
builder.NodeDisallowListDistributor = distributor.DefaultDisallowListNotificationDistributor(builder.Logger, heroStoreOpts...)
700+
builder.NodeDisallowListDistributor = cmd.BuildDisallowListNotificationDisseminator(builder.DisallowListNotificationCacheSize, builder.MetricsRegisterer, builder.Logger, builder.MetricsEnabled)
708701

709702
// The following wrapper allows to disallow-list byzantine nodes via an admin command:
710703
// the wrapper overrides the 'Ejected' flag of disallow-listed nodes to true

cmd/node_builder.go

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/onflow/flow-go/network/p2p"
3131
"github.com/onflow/flow-go/network/p2p/connection"
3232
"github.com/onflow/flow-go/network/p2p/dns"
33+
"github.com/onflow/flow-go/network/p2p/inspector/validation"
3334
"github.com/onflow/flow-go/network/p2p/middleware"
3435
"github.com/onflow/flow-go/network/p2p/unicast"
3536
"github.com/onflow/flow-go/state/protocol"
@@ -188,33 +189,36 @@ type NetworkConfig struct {
188189
// PreferredUnicastProtocols list of unicast protocols in preferred order
189190
PreferredUnicastProtocols []string
190191
NetworkReceivedMessageCacheSize uint32
191-
// UnicastRateLimitDryRun will disable connection disconnects and gating when unicast rate limiters are configured
192-
UnicastRateLimitDryRun bool
193-
//UnicastRateLimitLockoutDuration the number of seconds a peer will be forced to wait before being allowed to successful reconnect to the node
194-
// after being rate limited.
195-
UnicastRateLimitLockoutDuration time.Duration
196-
// UnicastMessageRateLimit amount of unicast messages that can be sent by a peer per second.
197-
UnicastMessageRateLimit int
198-
// UnicastBandwidthRateLimit bandwidth size in bytes a peer is allowed to send via unicast streams per second.
199-
UnicastBandwidthRateLimit int
200-
// UnicastBandwidthBurstLimit bandwidth size in bytes a peer is allowed to send via unicast streams at once.
201-
UnicastBandwidthBurstLimit int
202-
// PeerUpdateInterval interval used by the libp2p node peer manager component to periodically request peer updates.
203-
PeerUpdateInterval time.Duration
204-
// UnicastMessageTimeout how long a unicast transmission can take to complete.
205-
UnicastMessageTimeout time.Duration
192+
193+
PeerUpdateInterval time.Duration
194+
UnicastMessageTimeout time.Duration
195+
DNSCacheTTL time.Duration
196+
LibP2PResourceManagerConfig *p2pbuilder.ResourceManagerConfig
197+
ConnectionManagerConfig *connection.ManagerConfig
206198
// UnicastCreateStreamRetryDelay initial delay used in the exponential backoff for create stream retries
207199
UnicastCreateStreamRetryDelay time.Duration
208-
// DNSCacheTTL time to live for DNS cache
209-
DNSCacheTTL time.Duration
210-
// LibP2PResourceManagerConfig configuration for p2pbuilder.ResourceManagerConfig
211-
LibP2PResourceManagerConfig *p2pbuilder.ResourceManagerConfig
212-
// ConnectionManagerConfig configuration for connection.ManagerConfig=
213-
ConnectionManagerConfig *connection.ManagerConfig
214200
// size of the queue for notifications about new peers in the disallow list.
215201
DisallowListNotificationCacheSize uint32
216202
// size of the queue for notifications about gossipsub RPC inspections.
217203
GossipSubRPCInspectorNotificationCacheSize uint32
204+
GossipSubRPCInspectorCacheSize uint32
205+
UnicastRateLimitersConfig *UnicastRateLimitersConfig
206+
GossipSubRPCValidationConfigs *p2pbuilder.GossipSubRPCValidationConfigs
207+
}
208+
209+
// UnicastRateLimitersConfig unicast rate limiter configuration for the message and bandwidth rate limiters.
210+
type UnicastRateLimitersConfig struct {
211+
// DryRun setting this to true will disable connection disconnects and gating when unicast rate limiters are configured
212+
DryRun bool
213+
// LockoutDuration the number of seconds a peer will be forced to wait before being allowed to successful reconnect to the node
214+
// after being rate limited.
215+
LockoutDuration time.Duration
216+
// MessageRateLimit amount of unicast messages that can be sent by a peer per second.
217+
MessageRateLimit int
218+
// BandwidthRateLimit bandwidth size in bytes a peer is allowed to send via unicast streams per second.
219+
BandwidthRateLimit int
220+
// BandwidthBurstLimit bandwidth size in bytes a peer is allowed to send via unicast streams at once.
221+
BandwidthBurstLimit int
218222
}
219223

220224
// NodeConfig contains all the derived parameters such the NodeID, private keys etc. and initialized instances of
@@ -272,6 +276,8 @@ type NodeConfig struct {
272276
UnicastRateLimiterDistributor p2p.UnicastRateLimiterDistributor
273277
// NodeDisallowListDistributor notifies consumers of updates to disallow listing of nodes.
274278
NodeDisallowListDistributor p2p.DisallowListNotificationDistributor
279+
// GossipSubInspectorNotifDistributor notifies consumers when an invalid RPC message is encountered.
280+
GossipSubInspectorNotifDistributor p2p.GossipSubInspectorNotificationDistributor
275281
}
276282

277283
func DefaultBaseConfig() *BaseConfig {
@@ -288,19 +294,33 @@ func DefaultBaseConfig() *BaseConfig {
288294
PeerUpdateInterval: connection.DefaultPeerUpdateInterval,
289295
UnicastMessageTimeout: middleware.DefaultUnicastTimeout,
290296
NetworkReceivedMessageCacheSize: p2p.DefaultReceiveCacheSize,
291-
// By default we let networking layer trim connections to all nodes that
292-
// are no longer part of protocol state.
293-
NetworkConnectionPruning: connection.ConnectionPruningEnabled,
294-
GossipSubConfig: p2pbuilder.DefaultGossipSubConfig(),
295-
UnicastMessageRateLimit: 0,
296-
UnicastBandwidthRateLimit: 0,
297-
UnicastBandwidthBurstLimit: middleware.LargeMsgMaxUnicastMsgSize,
298-
UnicastRateLimitLockoutDuration: 10,
299-
UnicastRateLimitDryRun: true,
297+
UnicastRateLimitersConfig: &UnicastRateLimitersConfig{
298+
DryRun: true,
299+
LockoutDuration: 10,
300+
MessageRateLimit: 0,
301+
BandwidthRateLimit: 0,
302+
BandwidthBurstLimit: middleware.LargeMsgMaxUnicastMsgSize,
303+
},
304+
GossipSubRPCValidationConfigs: &p2pbuilder.GossipSubRPCValidationConfigs{
305+
NumberOfWorkers: validation.DefaultNumberOfWorkers,
306+
GraftLimits: map[string]int{
307+
validation.DiscardThresholdMapKey: validation.DefaultGraftDiscardThreshold,
308+
validation.SafetyThresholdMapKey: validation.DefaultGraftSafetyThreshold,
309+
validation.RateLimitMapKey: validation.DefaultGraftRateLimit,
310+
},
311+
PruneLimits: map[string]int{
312+
validation.DiscardThresholdMapKey: validation.DefaultPruneDiscardThreshold,
313+
validation.SafetyThresholdMapKey: validation.DefaultPruneSafetyThreshold,
314+
validation.RateLimitMapKey: validation.DefaultPruneRateLimit,
315+
},
316+
},
300317
DNSCacheTTL: dns.DefaultTimeToLive,
301318
LibP2PResourceManagerConfig: p2pbuilder.DefaultResourceManagerConfig(),
302319
ConnectionManagerConfig: connection.DefaultConnManagerConfig(),
320+
NetworkConnectionPruning: connection.ConnectionPruningEnabled,
321+
GossipSubConfig: p2pbuilder.DefaultGossipSubConfig(),
303322
GossipSubRPCInspectorNotificationCacheSize: distributor.DefaultGossipSubInspectorNotificationQueueCacheSize,
323+
GossipSubRPCInspectorCacheSize: validation.DefaultControlMsgValidationInspectorQueueCacheSize,
304324
DisallowListNotificationCacheSize: distributor.DefaultDisallowListNotificationQueueCacheSize,
305325
},
306326
nodeIDHex: NotSet,

cmd/observer/node_builder/observer_builder.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ import (
4848
finalizer "github.com/onflow/flow-go/module/finalizer/consensus"
4949
"github.com/onflow/flow-go/module/id"
5050
"github.com/onflow/flow-go/module/local"
51-
"github.com/onflow/flow-go/module/mempool/queue"
5251
"github.com/onflow/flow-go/module/metrics"
5352
"github.com/onflow/flow-go/module/state_synchronization"
5453
edrequester "github.com/onflow/flow-go/module/state_synchronization/requester"
@@ -62,7 +61,6 @@ import (
6261
"github.com/onflow/flow-go/network/p2p/blob"
6362
"github.com/onflow/flow-go/network/p2p/cache"
6463
p2pdht "github.com/onflow/flow-go/network/p2p/dht"
65-
"github.com/onflow/flow-go/network/p2p/distributor"
6664
"github.com/onflow/flow-go/network/p2p/keyutils"
6765
"github.com/onflow/flow-go/network/p2p/middleware"
6866
"github.com/onflow/flow-go/network/p2p/p2pbuilder"
@@ -729,13 +727,7 @@ func (builder *ObserverServiceBuilder) InitIDProviders() {
729727
}
730728
builder.IDTranslator = translator.NewHierarchicalIDTranslator(idCache, translator.NewPublicNetworkIDTranslator())
731729

732-
heroStoreOpts := []queue.HeroStoreConfigOption{queue.WithHeroStoreSizeLimit(builder.DisallowListNotificationCacheSize)}
733-
if builder.HeroCacheMetricsEnable {
734-
collector := metrics.DisallowListNotificationQueueMetricFactory(builder.MetricsRegisterer)
735-
heroStoreOpts = append(heroStoreOpts, queue.WithHeroStoreCollector(collector))
736-
}
737-
738-
builder.NodeDisallowListDistributor = distributor.DefaultDisallowListNotificationDistributor(builder.Logger, heroStoreOpts...)
730+
builder.NodeDisallowListDistributor = cmd.BuildDisallowListNotificationDisseminator(builder.DisallowListNotificationCacheSize, builder.MetricsRegisterer, builder.Logger, builder.MetricsEnabled)
739731

740732
// The following wrapper allows to black-list byzantine nodes via an admin command:
741733
// the wrapper overrides the 'Ejected' flag of disallow-listed nodes to true
@@ -866,6 +858,13 @@ func (builder *ObserverServiceBuilder) initLibP2PFactory(networkKey crypto.Priva
866858
builder.IdentityProvider,
867859
builder.GossipSubConfig.LocalMeshLogInterval)
868860

861+
builder.GossipSubInspectorNotifDistributor = cmd.BuildGossipsubRPCValidationInspectorNotificationDisseminator(builder.GossipSubRPCInspectorNotificationCacheSize, builder.MetricsRegisterer, builder.Logger, builder.MetricsEnabled)
862+
heroStoreOpts := cmd.BuildGossipsubRPCValidationInspectorHeroStoreOpts(builder.GossipSubRPCInspectorCacheSize, builder.MetricsRegisterer, builder.MetricsEnabled)
863+
rpcValidationInspector, err := p2pbuilder.BuildGossipSubRPCValidationInspector(builder.Logger, builder.SporkID, builder.GossipSubRPCValidationConfigs, builder.GossipSubInspectorNotifDistributor, heroStoreOpts...)
864+
if err != nil {
865+
return nil, fmt.Errorf("failed to create gossipsub rpc validation inspector: %w", err)
866+
}
867+
869868
node, err := p2pbuilder.NewNodeBuilder(
870869
builder.Logger,
871870
builder.Metrics.Network,
@@ -889,6 +888,7 @@ func (builder *ObserverServiceBuilder) initLibP2PFactory(networkKey crypto.Priva
889888
SetStreamCreationRetryInterval(builder.UnicastCreateStreamRetryDelay).
890889
SetGossipSubTracer(meshTracer).
891890
SetGossipSubScoreTracerInterval(builder.GossipSubConfig.ScoreTracerInterval).
891+
SetGossipSubValidationInspector(rpcValidationInspector).
892892
Build()
893893

894894
if err != nil {

0 commit comments

Comments
 (0)