layer2.tap

This Model Component provides the capability to insert a passive tap on any link within an experiment. This use case is explicitly for cases where the collector/analysis platform is placed within the experiment. Examples of collectors include Zeek, Splunk, Elastic Stack, etc.

This Model Component walks the graph looking for Edges that have the tap attribute set. Specifically, the tap attribute on the Edge must specify a list of collectors that will receive the mirrored traffic. The list of of collectors can contain either the actual Vertex object (recommended) or the name of the collector Vertex.

Once all tapped Edges are found, an additional IP network is added to all the specified collectors. Each collector gets its own IP subnet to communicate to its associated taps. This isolates the mirrored traffic from flowing over other taps in the experiment and thus eliminates the risk of accidentally duplicating traffic.

The following is the process that this model component follows to insert taps:

  • Tap objects are created from layer2.ovs.OpenvSwitch objects, which are Ubuntu1604Server with Open vSwitch (OVS) installed.

  • The specified link is then “broken” and reconnected at layer 2 through the tap object. The original edge is maintained to show the original logical connection between the two nodes. The new edges created are also decorated with base_objects.FalseEdge.

  • OVS is then set to create a bridge and add all layer 2 interfaces are added to the specified bridge.

    • This provides a place where the traffic can be mirrored or even man-in-the-middled if desired.

  • A new “monitor” network is added to the collector and all taps associated with that collector

  • GRE tunnel endpoints are created on both the tap and the collector.

    • This is the mechanism that delivers the mirrored traffic to the collector.

Attribute Depends:
  • graph

Attribute Provides:
  • tap

Model Component Dependencies:

Plugin

class layer2.tap_plugin.InsertTaps(graph, log)[source]

Bases: AbstractPlugin

This plugin inserts a passive tap on designated edges and tunnels all mirrored traffic to the “collector” (i.e. Splunk, Bro, etc) specified on the Edge.

Each “collector” gets an additional IP network in order to have the mirrored traffic from the taps GRE tunneled to it. Each tunnel gets its own interface of the form tap<integer> where integer is the GRE key. For example, if there is a tunnel between the “collector” and a tap using a GRE key of 1000 then the “collector” will have an interface named tap1000. The tapX interfaces should then be listened on by the collecting software (i.e Bro).

__annotations__ = {}
run(collector_network='10.100.0.0/16')[source]

Walk the graph and drop in passive taps on links that have been specified to be tapped.

Parameters:

collector_network (str, optional) – IP space to pull subnets from. The subnets are added to the various collectors and associated taps in order to tunnel mirrored traffic to the collector. Defaults to '10.100.0.0/16'.

Raises:

RuntimeError – If the collector specified on the Edge is not a name of the collector Vertex nor the actual Vertex object.

class layer2.tap_plugin._EdgeTapper(edge, network)[source]

Bases: object

A transient object used to tap an Edge.

__init__(edge, network)[source]

Initialize the Object.

Parameters:
  • edge (Edge) – The edge to tap.

  • network (netaddr.IPNetwork) – The network used by the tap VM and the associated collectors.

_gre_key

The initial GRE tunnel key to use.

Type:

int

_g

The NetworkX graph for the given edge.

Type:

ExperimentGraph

tapped_edge

The edge to tap.

Type:

Edge

network

The network used by the tap VM and the associated collectors.

Type:

netaddr.IPNetwork

_ips

An iterator for all the IP addresses in network.

Type:

iter

_bridge_name

The default name of the bridge. Initially "br0".

Type:

str

_tunnel_params

Any additional GRE tunnel parameters that are needed/used.

Type:

list

_create_switch(switch_name)[source]

Create a new base_objects.Switch.

Parameters:

switch_name (str) – The name of the new base_objects.Switch.

Returns:

The new base_objects.Switch.

Return type:

base_objects.Switch

_create_tap(tap_name)[source]

Create a new node that is a layer2.tap.Tap.

Parameters:

tap_name (str) – The name of the new layer2.tap.Tap.

Returns:

The newly created layer2.tap.Tap.

Return type:

Tap

_determine_edge_switch_and_endpoint()[source]

Determine the switch and the endpoint of the edge.

Returns:

A tuple that contains the Edge's terminal Vertex that is a base_objects.Switch and the Edge's terminal Vertex that is a VM.

Return type:

tuple(Switch, Vertex)

_gre_key = 1000
_mirror_traffic(tap, tap_ip, tap_collector_switch, collector_ips)[source]

Mirror traffic along the original tapped edge to the collectors.

Connect the tap to a “monitor” network so that mirrored traffic can be tunneled to the collector. In theory this could go over the same network that already exists, but you run the risk of tapping other mirrored traffic at upstream taps, therefore it’s best to isolate mirrored traffic to its own network.

Parameters:
  • tap (Vertex) – The tap VM from which traffic is mirrored.

  • tap_ip (netaddr.IPAddress) – The IP address of the tap VM on the collector subnet.

  • tap_collector_switch (Vertex) – The switch connecting the tap VM to the collectors.

  • collector_ips (dict) – A dictionary mapping collector vertices to their IP address in the subnet defined for this tap.

_reconstruct_edge(endpoint, orig_switch, tap, tap_switch)[source]

Reconstruct the original edge.

Using the the new tap switch, reconstruct the original edge so that it now connects the original switch to the endpoint via the tap and the tap switch.

Parameters:
  • endpoint (Vertex) – The VM endpoint of the edge to be reconstructed.

  • orig_switch (Vertex) – The original switch terminating the edge to be reconstructed.

  • tap (Vertex) – The new VM endpoint to add into the reconstructed edge segments.

  • tap_switch (Vertex) – The new switch to add into the reconstructed edge segments.

_refresh_endpoint_interface(endpoint, tap_switch)[source]

Refresh the endpoint interface.

Parameters:
  • endpoint (Vertex) – The VM endpoint to have it’s interface refreshed.

  • tap_switch (Vertex) – The new tap switch now connected to the VM endpoint.

Returns:

The new edge created by connecting the endpoint to the tap switch.

Return type:

Edge

Raises:

RuntimeError – If an interface cannot be found for tapping the endpoint.

_set_up_gre_tunnel_endpoint(collector, collector_ip, tap_ip)[source]

Add the tap via the GRE tunnel endpoint.

Parameters:
  • collector (Vertex) – The collector on which to set the tap.

  • collector_ip (netaddr.IPAddress) – The IP of the collector vertex in the subnet defined for this tap.

  • tap_ip (netaddr.IPAddress) – The IP of the tapping VM in the subnet defined for this tap.

_validate_collector(collector)[source]

Ensure that a given collector is a VM endpoint (or look it up).

Parameters:

collector (Vertex) – A collector to be validated (or, if the collector is provided as a name, find the corresponding Vertex.

Returns:

The validated collector vertex.

Return type:

Vertex

Raises:

RuntimeError – If the collector specified is not a name of the collector Vertex nor the actual Vertex object.

tap_edge(collectors)[source]

Tap the edge using all of the collectors.

For each tapped edge, break the current link and drop in the passive tap. Then hook up the link through the tap. Each tap then mirrors the traffic through a GRE tunnel back to the collector that was specified on the edge.

Parameters:

collectors (list) – A list of Vertex objects designated to tap the edge.

Available Objects

class layer2.tap.Tap(*args, **kwargs)[source]

Bases: object

Create a tap object. This is essentially an OpenvSwitch object with additional functions to man-in-the-middle and/or mirror traffic.

l2_mitm(bridge_name='br0')[source]

Create a layer 2 bridge that “breaks” the link, thus providing a position to mirror or man-in-the-middle traffic.

Note

This function will pick up all interfaces on the VM that are not configured to have an IP address. The absence of layer 3 configuration is assumed to mean that the interface is only a layer 2 interface.

Parameters:

bridge_name (str) – Name of the bridge to be created on the VM. All layer 2 interfaces then get dropped on the bridge

mirror_traffic(bridge, *tunnel_params)[source]

Once the layer 2 interfaces are all on the same bridge, mirror all traffic to the specified IP address. This is done by creating a GRE tunnel with the specified key. It is expected that the VM hosting the specified IP has a GRE endpoint configured.

Parameters:
  • bridge (str) – Name of the bridge holding the interfaces that will have their traffic mirrored.

  • *tunnel_params (tuple) – Each parameter set is a tuple in the form of (ip, key) where ip is the remote IP of the GRE tunnel and key is the GRE key, which is just an integer, but the key must be set in the same way on both the local and remote GRE endpoints. This key also helps us distinguish various port/mirror IDs.

Raises:

ValueError – If the tunnel parameters are not provided.