Skip to content

Commit 1649719

Browse files
auricomclaude
andcommitted
feat(pkg/p2p): add disable_connection_gater flag to toggle no-op gater
Adds p2p.disable_connection_gater (default: true) so operators can re-enable peer-level connection filtering without redeploying a patched binary. When set to false, the connection gater is registered with the libp2p host and blocked_peers / allowed_peers config entries are enforced — useful when experiencing P2P flooding. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9c17057 commit 1649719

5 files changed

Lines changed: 42 additions & 14 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
### Fixed
1313

14-
- Replace persistent P2P connection gater with a no-op variant so stale blocklist entries can no longer prevent peers from connecting after a restart [#3273](https://github.com/evstack/ev-node/pull/3273)
14+
- Replace persistent P2P connection gater with a no-op variant so stale blocklist entries can no longer prevent peers from connecting after a restart. The new `p2p.disable_connection_gater` flag (default `true`) can be set to `false` to re-enable peer filtering when experiencing P2P flooding [#3273](https://github.com/evstack/ev-node/pull/3273)
1515
- Raft HA production hardening: leader fencing on SIGTERM, FSM data race, follower restart crash, log compaction config, and election timeout validation [#3230](https://github.com/evstack/ev-node/pull/3230)
1616

1717
### Changes

pkg/config/config.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ const (
102102
FlagP2PBlockedPeers = FlagPrefixEvnode + "p2p.blocked_peers"
103103
// FlagP2PAllowedPeers is a flag for specifying the P2P allowed peers
104104
FlagP2PAllowedPeers = FlagPrefixEvnode + "p2p.allowed_peers"
105+
// FlagP2PDisableConnectionGater disables the P2P connection gater (no-op mode).
106+
// Enabled by default; set to false to activate peer filtering when experiencing P2P flooding.
107+
FlagP2PDisableConnectionGater = FlagPrefixEvnode + "p2p.disable_connection_gater"
105108

106109
// Instrumentation configuration flags
107110

@@ -313,10 +316,11 @@ type LogConfig struct {
313316

314317
// P2PConfig contains all peer-to-peer networking configuration parameters
315318
type P2PConfig struct {
316-
ListenAddress string `mapstructure:"listen_address" yaml:"listen_address" comment:"Address to listen for incoming connections (host:port)"`
317-
Peers string `mapstructure:"peers" yaml:"peers" comment:"Comma-separated list of peers to connect to"`
318-
BlockedPeers string `mapstructure:"blocked_peers" yaml:"blocked_peers" comment:"Comma-separated list of peer IDs to block from connecting"`
319-
AllowedPeers string `mapstructure:"allowed_peers" yaml:"allowed_peers" comment:"Comma-separated list of peer IDs to allow connections from"`
319+
ListenAddress string `mapstructure:"listen_address" yaml:"listen_address" comment:"Address to listen for incoming connections (host:port)"`
320+
Peers string `mapstructure:"peers" yaml:"peers" comment:"Comma-separated list of peers to connect to"`
321+
BlockedPeers string `mapstructure:"blocked_peers" yaml:"blocked_peers" comment:"Comma-separated list of peer IDs to block from connecting"`
322+
AllowedPeers string `mapstructure:"allowed_peers" yaml:"allowed_peers" comment:"Comma-separated list of peer IDs to allow connections from"`
323+
DisableConnectionGater bool `mapstructure:"disable_connection_gater" yaml:"disable_connection_gater" comment:"Disable the P2P connection gater (no-op mode). Set to false to enforce peer filtering when experiencing P2P flooding."`
320324
}
321325

322326
// SignerConfig contains all signer configuration parameters
@@ -621,6 +625,7 @@ func AddFlags(cmd *cobra.Command) {
621625
cmd.Flags().String(FlagP2PPeers, def.P2P.Peers, "Comma separated list of seed nodes to connect to")
622626
cmd.Flags().String(FlagP2PBlockedPeers, def.P2P.BlockedPeers, "Comma separated list of nodes to ignore")
623627
cmd.Flags().String(FlagP2PAllowedPeers, def.P2P.AllowedPeers, "Comma separated list of nodes to whitelist")
628+
cmd.Flags().Bool(FlagP2PDisableConnectionGater, def.P2P.DisableConnectionGater, "Disable P2P connection gater (no-op mode); set to false to enforce peer filtering when experiencing P2P flooding")
624629

625630
// RPC configuration flags
626631
cmd.Flags().String(FlagRPCAddress, def.RPC.Address, "RPC server address (host:port)")

pkg/config/config_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ func TestAddFlags(t *testing.T) {
8484
assertFlagValue(t, flags, FlagP2PPeers, DefaultConfig().P2P.Peers)
8585
assertFlagValue(t, flags, FlagP2PBlockedPeers, DefaultConfig().P2P.BlockedPeers)
8686
assertFlagValue(t, flags, FlagP2PAllowedPeers, DefaultConfig().P2P.AllowedPeers)
87+
assertFlagValue(t, flags, FlagP2PDisableConnectionGater, DefaultConfig().P2P.DisableConnectionGater)
8788

8889
// Instrumentation flags
8990
instrDef := DefaultInstrumentationConfig()
@@ -143,7 +144,7 @@ func TestAddFlags(t *testing.T) {
143144
assertFlagValue(t, flags, FlagPruningInterval, DefaultConfig().Pruning.Interval.Duration)
144145

145146
// Count the number of flags we're explicitly checking
146-
expectedFlagCount := 81 // Update this number if you add more flag checks above
147+
expectedFlagCount := 82 // Update this number if you add more flag checks above
147148

148149
// Get the actual number of flags (both regular and persistent)
149150
actualFlagCount := 0

pkg/config/defaults.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ func DefaultConfig() Config {
5757
RootDir: DefaultRootDir,
5858
DBPath: "data",
5959
P2P: P2PConfig{
60-
ListenAddress: "/ip4/0.0.0.0/tcp/7676",
61-
Peers: "",
60+
ListenAddress: "/ip4/0.0.0.0/tcp/7676",
61+
Peers: "",
62+
DisableConnectionGater: true,
6263
},
6364
Node: NodeConfig{
6465
Aggregator: false,

pkg/p2p/client.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,17 @@ func NewClient(
8282
metrics *Metrics,
8383
) (*Client, error) {
8484

85-
// No-op gater: never persists or blocks any peer. The gater instance is kept
86-
// only because go-header's Exchange requires a *conngater.BasicConnectionGater
87-
// parameter. libp2p itself is not given this gater, so no connection is ever
88-
// filtered at the host level either.
89-
gater, err := conngater.NewBasicConnectionGater(nil)
85+
// When DisableConnectionGater is true (default) the gater is a no-op: it
86+
// uses an ephemeral in-memory store, is not registered with the libp2p host,
87+
// and never blocks any peer. The instance is kept only because go-header's
88+
// Exchange requires a *conngater.BasicConnectionGater parameter.
89+
// Set DisableConnectionGater=false to activate peer filtering (e.g. when
90+
// experiencing P2P flooding).
91+
var gaterDS datastore.Datastore
92+
if !conf.DisableConnectionGater {
93+
gaterDS = datastore.NewMapDatastore()
94+
}
95+
gater, err := conngater.NewBasicConnectionGater(gaterDS)
9096
if err != nil {
9197
return nil, fmt.Errorf("failed to create connection gater: %w", err)
9298
}
@@ -160,6 +166,17 @@ func (c *Client) startWithHost(ctx context.Context, h host.Host) error {
160166
c.logger.Info().Str("address", fmt.Sprintf("%s/p2p/%s", a, c.host.ID())).Msg("listening on address")
161167
}
162168

169+
if !c.conf.DisableConnectionGater {
170+
c.logger.Debug().Str("blacklist", c.conf.BlockedPeers).Msg("blocking blacklisted peers")
171+
if err := c.setupBlockedPeers(c.parseAddrInfoList(c.conf.BlockedPeers)); err != nil {
172+
return err
173+
}
174+
c.logger.Debug().Str("whitelist", c.conf.AllowedPeers).Msg("allowing whitelisted peers")
175+
if err := c.setupAllowedPeers(c.parseAddrInfoList(c.conf.AllowedPeers)); err != nil {
176+
return err
177+
}
178+
}
179+
163180
c.logger.Debug().Msg("setting up gossiping")
164181
if err := c.setupGossiping(ctx); err != nil {
165182
return err
@@ -334,7 +351,11 @@ func (c *Client) listen() (host.Host, error) {
334351
return nil, err
335352
}
336353

337-
return libp2p.New(libp2p.ListenAddrs(maddr), libp2p.Identity(c.privKey))
354+
opts := []libp2p.Option{libp2p.ListenAddrs(maddr), libp2p.Identity(c.privKey)}
355+
if !c.conf.DisableConnectionGater {
356+
opts = append(opts, libp2p.ConnectionGater(c.gater))
357+
}
358+
return libp2p.New(opts...)
338359
}
339360

340361
func (c *Client) setupDHT(ctx context.Context) error {

0 commit comments

Comments
 (0)