Soft blacklist peer ids

Why make this change?

This change is useful so we can blacklist peer ids, without actually
disconnecting them, so that it's harder for them to tell that they are
being blacklisted. Envelopes will just be dropped.

What has changed?

In waku we pass a config with a list of hex-encoded peer ids, and we
check that against newly received envelopes.
If so we just drop the envelope and return
This commit is contained in:
Andrea Maria Piana 2020-09-09 10:10:01 +02:00
parent 19a82f68ad
commit e836ffb47f
5 changed files with 89 additions and 21 deletions

View File

@ -447,10 +447,11 @@ func createShhService(ctx *node.ServiceContext, whisperConfig *params.WhisperCon
func createWakuService(ctx *node.ServiceContext, wakuCfg *params.WakuConfig, clusterCfg *params.ClusterConfig) (*waku.Waku, error) {
cfg := &waku.Config{
MaxMessageSize: wakucommon.DefaultMaxMessageSize,
BloomFilterMode: wakuCfg.BloomFilterMode,
FullNode: wakuCfg.FullNode,
MinimumAcceptedPoW: params.WakuMinimumPoW,
MaxMessageSize: wakucommon.DefaultMaxMessageSize,
BloomFilterMode: wakuCfg.BloomFilterMode,
FullNode: wakuCfg.FullNode,
SoftBlacklistedPeerIDs: wakuCfg.SoftBlacklistedPeerIDs,
MinimumAcceptedPoW: params.WakuMinimumPoW,
}
if wakuCfg.MaxMessageSize > 0 {

View File

@ -208,6 +208,9 @@ type WakuConfig struct {
// BloomFilterMode tells us whether we should be sending a bloom
// filter rather than TopicInterest
BloomFilterMode bool
// SoftBlacklistedPeerIDs is a list of peer ids that should be soft-blacklisted (messages should be dropped but connection kept)
SoftBlacklistedPeerIDs []string
}
// ----------

View File

@ -24,13 +24,14 @@ import (
// Config represents the configuration state of a waku node.
type Config struct {
MaxMessageSize uint32 `toml:",omitempty"`
MinimumAcceptedPoW float64 `toml:",omitempty"`
BloomFilterMode bool `toml:",omitempty"` // when true, we only match against bloom filter
LightClient bool `toml:",omitempty"` // when true, it does not forward messages
FullNode bool `toml:",omitempty"` // when true, it forwards all messages
RestrictLightClientsConn bool `toml:",omitempty"` // when true, do not accept light client as peers if it is a light client itself
EnableConfirmations bool `toml:",omitempty"` // when true, sends message confirmations
MaxMessageSize uint32 `toml:",omitempty"`
MinimumAcceptedPoW float64 `toml:",omitempty"`
BloomFilterMode bool `toml:",omitempty"` // when true, we only match against bloom filter
LightClient bool `toml:",omitempty"` // when true, it does not forward messages
FullNode bool `toml:",omitempty"` // when true, it forwards all messages
RestrictLightClientsConn bool `toml:",omitempty"` // when true, do not accept light client as peers if it is a light client itself
EnableConfirmations bool `toml:",omitempty"` // when true, sends message confirmations
SoftBlacklistedPeerIDs []string `toml:",omitempty"`
}
var DefaultConfig = Config{

View File

@ -65,6 +65,7 @@ type settings struct {
BloomFilterTolerance []byte // Bloom filter tolerated by the waku node for a limited time
TopicInterest map[common.TopicType]bool // Topic interest for this node
TopicInterestTolerance map[common.TopicType]bool // Topic interest tolerated by the waku node for a limited time
SoftBlacklistedPeerIDs map[string]bool // SoftBlacklistedPeerIDs is a list of peer ids that we want to keep connected but silently drop any envelope from
BloomFilterMode bool // Whether we should match against bloom-filter only
LightClient bool // Light client mode enabled does not forward messages
RestrictLightClientsConn bool // Restrict connection between two light clients
@ -144,10 +145,15 @@ func New(cfg *Config, logger *zap.Logger) *Waku {
LightClient: cfg.LightClient,
FullNode: cfg.FullNode,
BloomFilterMode: cfg.BloomFilterMode,
SoftBlacklistedPeerIDs: make(map[string]bool),
RestrictLightClientsConn: cfg.RestrictLightClientsConn,
SyncAllowance: common.DefaultSyncAllowance,
}
for _, peerID := range cfg.SoftBlacklistedPeerIDs {
waku.settings.SoftBlacklistedPeerIDs[peerID] = true
}
if cfg.FullNode {
waku.settings.BloomFilter = common.MakeFullNodeBloom()
waku.settings.BloomFilterTolerance = common.MakeFullNodeBloom()
@ -1103,17 +1109,31 @@ func (w *Waku) HandlePeer(peer common.Peer, rw p2p.MsgReadWriter) error {
return err
}
func (w *Waku) softBlacklisted(peerID string) bool {
w.settingsMu.RLock()
defer w.settingsMu.RUnlock()
return w.settings.SoftBlacklistedPeerIDs[peerID]
}
func (w *Waku) OnNewEnvelopes(envelopes []*common.Envelope, peer common.Peer) ([]common.EnvelopeError, error) {
w.logger.Debug("received new envelopes", zap.Int("count", len(envelopes)))
envelopeErrors := make([]common.EnvelopeError, 0)
peerID := types.EncodeHex(peer.ID())
w.logger.Debug("received new envelopes", zap.Int("count", len(envelopes)), zap.String("peer", peerID))
trouble := false
if w.softBlacklisted(peerID) {
w.logger.Debug("peer is soft blacklisted", zap.String("peer", peerID))
return nil, nil
}
for _, env := range envelopes {
w.logger.Debug("received new envelope", zap.String("peer", peerID), zap.String("hash", env.Hash().Hex()))
cached, err := w.add(env, w.LightClientMode())
if err != nil {
_, isTimeSyncError := err.(common.TimeSyncError)
if !isTimeSyncError {
trouble = true
w.logger.Info("invalid envelope received", zap.Binary("peer", peer.ID()), zap.Error(err))
w.logger.Info("invalid envelope received", zap.String("peer", types.EncodeHex(peer.ID())), zap.Error(err))
}
envelopeErrors = append(envelopeErrors, common.ErrorToEnvelopeError(env.Hash(), err))
} else if cached {

View File

@ -31,9 +31,13 @@ import (
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/waku/common"
v0 "github.com/status-im/status-go/waku/v0"
v1 "github.com/status-im/status-go/waku/v1"
)
var seed int64
@ -49,19 +53,33 @@ func InitSingleTest() {
func TestBasic(t *testing.T) {
w := New(nil, nil)
p := w.Protocols()
waku := p[0]
if waku.Name != v0.Name {
t.Fatalf("failed Peer Name: %v.", waku.Name)
waku0 := p[0]
waku1 := p[1]
if waku0.Name != v0.Name {
t.Fatalf("failed Peer Name: %v.", waku0.Name)
}
if uint64(waku.Version) != v0.Version {
t.Fatalf("failed Peer Version: %v.", waku.Version)
if uint64(waku0.Version) != v0.Version {
t.Fatalf("failed Peer Version: %v.", waku0.Version)
}
if waku.Length != v0.NumberOfMessageCodes {
t.Fatalf("failed Peer Length: %v.", waku.Length)
if waku0.Length != v0.NumberOfMessageCodes {
t.Fatalf("failed Peer Length: %v.", waku0.Length)
}
if waku.Run == nil {
if waku0.Run == nil {
t.Fatalf("failed waku.Run.")
}
if waku1.Name != v1.Name {
t.Fatalf("failed Peer Name: %v.", waku1.Name)
}
if uint64(waku1.Version) != v1.Version {
t.Fatalf("failed Peer Version: %v.", waku1.Version)
}
if waku1.Length != v1.NumberOfMessageCodes {
t.Fatalf("failed Peer Length: %v.", waku1.Length)
}
if waku1.Run == nil {
t.Fatalf("failed waku.Run.")
}
if w.GetFilter("non-existent") != nil {
t.Fatalf("failed GetFilter.")
}
@ -1065,6 +1083,31 @@ func TestTopicInterest(t *testing.T) {
}
func TestOnNewEnvelopesSoftBlacklist(t *testing.T) {
w1 := New(nil, nil)
envelope := &common.Envelope{}
p2pPeer := p2p.NewPeer(enode.ID{0x4}, "test", []p2p.Cap{})
peer := v1.NewPeer(w1, p2pPeer, nil, nil)
// Pre-condition, we need to make sure this envelope returns an EnvelopeError
envelopeError, err := w1.OnNewEnvelopes([]*common.Envelope{envelope}, peer)
require.NoError(t, err)
// Make sure this envelope returns an error
require.NotNil(t, envelopeError)
// build black listed waku
cfg := &Config{
SoftBlacklistedPeerIDs: []string{types.EncodeHex(peer.ID())},
}
w2 := New(cfg, nil)
envelopeError, err = w2.OnNewEnvelopes([]*common.Envelope{envelope}, peer)
require.NoError(t, err)
// Since it's blacklisted, it will just drop envelopes, keep the connection open
require.Nil(t, envelopeError)
}
func handleError(t *testing.T, err error) {
if err != nil {
t.Logf("deferred function error: '%s'", err)