corruptnet

package
v0.29.0-stable-cadence-4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 10, 2022 License: AGPL-3.0 Imports: 47 Imported by: 1

README

Corruptible Conduit Framework

Corruptible Conduit Framework is an integration testing framework for Byzantine Fault Tolerant (BFT) setups. As shown by figure below, this framework is composed of Corruptible Conduits and Corruptible Conduit Factory. A Corruptible Conduit Factory (CCF) is configured on each node that is meant to play malicious during the test scenario. The CCF utilizes Corruptible Conduits (CC)s to connect the engines of its node to the networking adaptor. In contrast to the normal conduits, the CCs do not relay the events from their engine to the network adaptor. Instead, they relay the events from their engine to the CCF. On receiving an event from a CC, the CCF forwards the message to a remote attacker. The attacker is in charge of orchestrating specific attacks through its programmable attack vectors. The attacker controls the set of malicious nodes. All messages from engines of attacker-controlled corrupted nodes are directly wired to the attacker. The attacker runs its registered attack vectors on each received message from its corrupted nodes' engines. As the result of running the attack vectors, the attacker may ask CCF of some corrupted nodes to send some certain messages on its behalf. In this way, the Corruptible Conduit Framework empowers testing attack vectors by just replacing the default conduit factory of malicious nodes with a CCF, and without any further modification to the application-layer implementation of the node.

Corruptible Conduit Framework

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AcceptAllTopicValidator

func AcceptAllTopicValidator(lg zerolog.Logger, c network.Codec) pubsub.ValidatorEx

AcceptAllTopicValidator pubsub validator func that does not perform any validation, it will only attempt to decode the message and update the rawMsg.ValidatorData needed for further processing by the middleware receive loop. Malformed messages that fail to unmarshal or decode will result in a pubsub.ValidationReject result returned.

func NewCorruptLibP2PNode

func NewCorruptLibP2PNode(logger zerolog.Logger, host host.Host, pCache *p2pnode.ProtocolPeerCache, uniMgr *unicast.Manager, peerManager *connection.PeerManager) p2p.LibP2PNode

NewCorruptLibP2PNode returns corrupted libP2PNode that will subscribe to topics using the AcceptAllTopicValidator.

func NewCorruptLibP2PNodeFactory

func NewCorruptLibP2PNodeFactory(
	log zerolog.Logger,
	chainID flow.ChainID,
	address string,
	flowKey fcrypto.PrivateKey,
	sporkId flow.Identifier,
	idProvider module.IdentityProvider,
	metrics module.NetworkMetrics,
	resolver madns.BasicResolver,
	peerScoringEnabled bool,
	role string,
	onInterceptPeerDialFilters,
	onInterceptSecuredFilters []p2p.PeerFilter,
	connectionPruning bool,
	updateInterval time.Duration,
) p2pbuilder.LibP2PFactoryFunc

NewCorruptLibP2PNodeFactory wrapper around the original DefaultLibP2PNodeFactory. Nodes returned from this factory func will be corrupted libp2p nodes.

Types

type Conduit

type Conduit struct {
	// contains filtered or unexported fields
}

Conduit implements a corruptible conduit that sends all incoming events to its registered controller (i.e., factory) without dispatching them to the networking layer.

func (*Conduit) Close

func (c *Conduit) Close() error

Close informs the conduit controller that the engine is not going to use this conduit anymore.

func (*Conduit) Multicast

func (c *Conduit) Multicast(event interface{}, num uint, targetIDs ...flow.Identifier) error

Multicast sends the incoming events as multicast events to the controller of this conduit (i.e., its factory) to handle.

func (*Conduit) Publish

func (c *Conduit) Publish(event interface{}, targetIDs ...flow.Identifier) error

Publish sends the incoming events as publish events to the controller of this conduit (i.e., its factory) to handle.

func (*Conduit) Unicast

func (c *Conduit) Unicast(event interface{}, targetID flow.Identifier) error

Unicast sends the incoming events as unicast events to the controller of this conduit (i.e., its factory) to handle.

type ConduitFactory

type ConduitFactory struct {
	// contains filtered or unexported fields
}

ConduitFactory implements a corrupt conduit factory, that creates corrupt conduits.

func NewCorruptConduitFactory

func NewCorruptConduitFactory(logger zerolog.Logger, chainId flow.ChainID) *ConduitFactory

func (*ConduitFactory) NewConduit

func (c *ConduitFactory) NewConduit(ctx context.Context, channel channels.Channel) (network.Conduit, error)

NewConduit creates a conduit on the specified channel. Prior to creating any conduit, the factory requires an Adapter to be registered with it.

func (*ConduitFactory) RegisterAdapter

func (c *ConduitFactory) RegisterAdapter(adapter network.Adapter) error

RegisterAdapter sets the Adapter component of the factory. The Adapter is a wrapper around the Network layer that only exposes the set of methods that are needed by a conduit.

func (*ConduitFactory) RegisterEgressController

func (c *ConduitFactory) RegisterEgressController(controller insecure.EgressController) error

RegisterEgressController sets the EgressController component of the factory.

func (*ConduitFactory) SendOnFlowNetwork

func (c *ConduitFactory) SendOnFlowNetwork(event interface{},
	channel channels.Channel,
	protocol insecure.Protocol,
	num uint, targetIds ...flow.Identifier) error

SendOnFlowNetwork dispatches the given event to the networking layer of the node in order to be delivered through the specified protocol to the target identifiers.

func (*ConduitFactory) UnregisterChannel

func (c *ConduitFactory) UnregisterChannel(channel channels.Channel) error

UnregisterChannel is called by the slave conduits of this factory to let it know that the corresponding engine of the conduit is not going to use it anymore, so the channel can be closed safely.

type CorruptP2PNode

type CorruptP2PNode struct {
	*p2pnode.Node
	// contains filtered or unexported fields
}

CorruptP2PNode is a wrapper around the original LibP2P node.

func (*CorruptP2PNode) Subscribe

Subscribe subscribes the node to the given topic with a noop topic validator. All errors returned from this function can be considered benign.

type MessageProcessor

type MessageProcessor struct {
	// contains filtered or unexported fields
}

func NewCorruptMessageProcessor

func NewCorruptMessageProcessor(logger zerolog.Logger, originalProcessor flownet.MessageProcessor, ingressController insecure.IngressController) *MessageProcessor

func (*MessageProcessor) Process

func (m *MessageProcessor) Process(channel channels.Channel, originID flow.Identifier, event interface{}) error

Process implements handling ingress (incoming) messages from the honest Flow network (via network.MessageProcessor interface). If an Attacker is registered on the Corrupt Network, then these ingress messages are passed to the Attacker (by the Corrupt Network). If an Attacker is not registered on the Corrupt Network, then these ingress messages are passed to the original (honest) Message Processor.

type Network

type Network struct {
	*component.ComponentManager
	// contains filtered or unexported fields
}

Network is a wrapper around the original flow network, that allows a remote attack orchestrator to take control over its ingress and egress traffic flows. A remote attack orchestrator can register itself to this corrupt network. Whenever any corrupt conduit receives an event from its engine, it relays the event to this network, which in turn is relayed to the register attack orchestrator. The attack orchestrator can asynchronously dictate to the network to send messages on behalf of the node. Honest message flow: Engine -> Conduit -> Flow Networking Layer -> Deliver to targets

Corrupt message flow: Engine -> Corrupt Conduit -> Corrupt Network -> Attack Orchestrator (corrupts or passes through) -> Corrupt Network -> Flow Networking Layer

func NewCorruptNetwork

func NewCorruptNetwork(
	logger zerolog.Logger,
	chainId flow.ChainID,
	address string,
	me module.Local,
	codec flownet.Codec,
	flowNetwork flownet.Network,
	conduitFactory insecure.CorruptConduitFactory) (*Network, error)

func (*Network) AttackerRegistered

func (n *Network) AttackerRegistered() bool

AttackerRegistered returns whether an attack orchestrator has registered on this corrupt network instance.

func (*Network) ConnectAttacker

func (n *Network) ConnectAttacker(_ *empty.Empty, stream insecure.CorruptNetwork_ConnectAttackerServer) error

ConnectAttacker is a blocking Server Streaming gRPC end-point for this corrupt network that registers an attacker to the corrupt network, so that the attacker can control its ingress and egress traffic flow.

An attack orchestrator (i.e., client) remote call to this function will return immediately on the attack orchestrator's side. However, here on the server (i.e., corrupt network) side, the call remains blocking through the lifecycle of the server. The reason is the local gRPC stub on this corrupt network (i.e., server) acts as a broker between client call to this server method. The broker returns the call on the client side immediately by creating the stream from server to the client, i.e., server streaming. However, that stream is only alive through the lifecycle of the server. So, this method should only return when the server is really shut down, hence closing the stream on the client side, as client should expect no more messages streamed from server.

Registering an attack orchestrator on a networking layer is an exactly-once immutable operation, any second attempt after a successful registration returns an error.

func (*Network) EngineClosingChannel

func (n *Network) EngineClosingChannel(channel channels.Channel) error

EngineClosingChannel is called by the conduits of this corrupt network to let it know that the corresponding engine of the conduit is not going to use it anymore, so the channel can be closed safely.

func (*Network) HandleIncomingEvent

func (n *Network) HandleIncomingEvent(event interface{}, channel channels.Channel, originId flow.Identifier) bool

HandleIncomingEvent is called on the incoming messages to this corrupt node. Returns true if an attacker is registered and false otherwise. Honest node (i.e., not running with a corrupt network) message flow: Flow Networking Layer -> Honest Engine Corrupt node (i.e., running with a corrupt network) message flow (with attacker registered): Flow Networking Layer -> Corrupt Network -> Attack Orchestrator (mute or passthrough) -> Corrupt Network -> Honest / Corrupt Engine

func (*Network) HandleOutgoingEvent

func (n *Network) HandleOutgoingEvent(
	event interface{},
	channel channels.Channel,
	protocol insecure.Protocol,
	num uint32,
	targetIds ...flow.Identifier) error

HandleOutgoingEvent is called by the conduits generated by this network to relay their outgoing events. If there is an attack orchestrator connected to this network, the event is dispatched to it. Otherwise, the network follows the correct protocol path by sending the message down to the original networking layer of Flow to deliver to its targets.

func (*Network) ProcessAttackerMessage

func (n *Network) ProcessAttackerMessage(stream insecure.CorruptNetwork_ProcessAttackerMessageServer) error

ProcessAttackerMessage is the central place for the corrupt network to process messages from an attacker. The messages coming from an attacker can be destined to this corrupt node (on behalf of another node) (ingress message) or to another node (on behalf of this corrupt node) (egress message). This is a Client Streaming gRPC end-point that allows a registered attack orchestrator to dictate messages to this corrupt network. The first call to this Client Streaming gRPC method creates the "stream" from attack orchestrator (i.e., client) to this corrupt network (i.e., server), where attack orchestrator can send messages through that stream to the corrupt network.

Messages sent from attack orchestrator to this corrupt network are considered dictated in the sense that they are sent on behalf of this corrupt network instance on the original Flow network to other Flow nodes.

Returns a fatal error and crashes if message from attacker is invalid (i.e. contains both ingress and egress message or neither ingress nor egress message).

func (*Network) Register

func (n *Network) Register(channel channels.Channel, messageProcessor flownet.MessageProcessor) (flownet.Conduit, error)

Register serves as the typical network registration of the given message processor on the channel. Except, it first wraps the given processor around a corrupt message processor, and then registers the corrupt message processor to the original Flow network. Returns a non nil error if fails to register the corrupt message processor with the original Flow network.

func (*Network) RegisterBlobService

func (n *Network) RegisterBlobService(channel channels.Channel, store datastore.Batching, opts ...flownet.BlobServiceOption) (flownet.BlobService,
	error)

RegisterBlobService directly invokes the corresponding method on the underlying Flow network instance. It does not perform any corruption and passes everything through as it is. Returns a non nil error if fails to register with original Flow network.

func (*Network) RegisterPingService

func (n *Network) RegisterPingService(pingProtocolID protocol.ID, pingInfoProvider flownet.PingInfoProvider) (flownet.PingService, error)

RegisterPingService directly invokes the corresponding method on the underlying Flow network instance. It does not perform any corruption and passes everything through as it is. Returns a non nil error if fails to register with original Flow network.

func (*Network) ServerAddress

func (n *Network) ServerAddress() string

ServerAddress returns listen address of the gRPC server that is running by this corrupt network.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL