xdp-zeek

Zeek XDP Filtering

Uses XDP in order to "shunt" traffic - that way, Zeek doesn't waste its time analyzing packets that won't get any useful information, like encrypted sessions:

global xdp_prog: opaque of XDP::Program;

event zeek_init()
	{
	local opts: XDP::ShuntOptions = [
		$attach_mode=XDP::SKB, # SKB is more for testing, NATIVE is better
		$conn_id_map_max_size=131072, # A bit over the max number of shunted connections
		$ip_pair_map_max_size=1, # We can't remove the map, so make it very small
	];
	xdp_prog = XDP::start_shunt(opts);
	}

event XDP::ShuntConnID::first_fin(cid: conn_id)
	{
	local stats = XDP::ShuntConnID::unshunt(xdp_prog, cid);
	if ( stats$present )
		{
		print fmt("Unshunted connection from %s:%d->%s:%d. Transmitted %d bytes and %d packets. Last packet was at %s.",
		    cid$orig_h, cid$orig_p, cid$resp_h, cid$resp_p,
		    stats$bytes_from_orig + stats$bytes_from_resp,
		    stats$packets_from_orig + stats$packets_from_resp,
		    stats$timestamp);
		}
	}

event ssl_established(c: connection)
	{
	print "Shunting", c$id;
	XDP::ShuntConnID::shunt(xdp_prog, c$id);
	}

event zeek_done()
	{
	XDP::end_shunt(xdp_prog);
	}

IP Pairs

Shunting with IP pairs is similar:

global xdp_prog: opaque of XDP::Program;

event zeek_init()
	{
	local opts: XDP::ShuntOptions = [
		$attach_mode=XDP::SKB, # SKB is more for testing, NATIVE is better
		$conn_id_map_max_size=1, # We can't remove the map, so make it very small
		$ip_pair_map_max_size=131072, # A bit over the max number of shunted connections
	];
	xdp_prog = XDP::start_shunt(opts);
	}

event XDP::ShuntIPPair::first_fin(pair: XDP::ip_pair)
	{
	local stats = XDP::ShuntIPPair::unshunt(xdp_prog, pair$ip1, pair$ip2);
	if ( stats$present )
		{
		print fmt("Unshunted connection from %s->%s. Transmitted %d bytes and %d packets. Last packet was at %s.",
		    pair$ip1, pair$ip2, stats$bytes_from_orig +
		    stats$bytes_from_resp, stats$packets_from_orig +
		    stats$packets_from_resp, stats$timestamp);
		}
	}

event ssl_established(c: connection)
	{
	print "Shunting", c$id;
	XDP::ShuntIPPair::shunt(xdp_prog, c$id$orig_h, c$id$resp_h);
	}

event zeek_done()
	{
	XDP::end_shunt(xdp_prog);
	}

Internals

This plugin uses XDP (eXpress Data Path) in order to filter traffic before it reaches user applications, like Zeek. This is filtering purely on the network device that Zeek sees traffic from.

The XDP program itself simply checks if a certain IP pair or 5-tuple are in the "shunting map." This map is managed entirely from user space, that is, the Zeek program.

Any shunted connections keep state about certain statistics, such as the last packet seen and how many bytes/packets were seen from each direction. This may help the user determine how effective the shunting was, or simply unshunt connections after a certain time elapsed without any traffic.

Shunting may raise some Zeek events, namely for FIN and RST TCP packets. This is done via BPF ring buffers.

TODOs

  • Add (better) way to filter the returned maps before converting to Zeek vals
  • Potentially split the IP pair and conn id shunting in different XDP programs
  • Test it

Package Version :