module PacketFilter;

export {
	## Takes a :zeek:type:`port` and returns a BPF expression which will
	## match the port.
	##
	## p: The port.
	##
	## Returns: A valid BPF filter string for matching the port.
	global port_to_bpf: function(p: port): string;

	## Create a BPF filter to sample IPv4 and IPv6 traffic.
	##
	## num_parts: The number of parts the traffic should be split into.
	##
	## this_part: The part of the traffic this filter will accept (0-based).
	global sampling_filter: function(num_parts: count, this_part: count): string;

	## Combines two valid BPF filter strings with a string based operator
	## to form a new filter.
	##
	## lfilter: Filter which will go on the left side.
	##
	## op: Operation being applied (typically "or" or "and").
	##
	## rfilter: Filter which will go on the right side.
	##
	## Returns: A new string representing the two filters combined with
	##          the operator.  Either filter being an empty string will
	##          still result in a valid filter.
	global combine_filters: function(lfilter: string, op: string, rfilter: string): string;
}

function port_to_bpf(p: port): string
	{
	local tp = get_port_transport_proto(p);
	return cat(tp, " and ", fmt("port %d", p));
	}

function combine_filters(lfilter: string,  op: string, rfilter: string): string
	{
	if ( lfilter == "" && rfilter == "" )
		return "";
	else if ( lfilter == "" )
		return rfilter;
	else if ( rfilter == "" )
		return lfilter;
	else
		return fmt("(%s) %s (%s)", lfilter, op, rfilter);
	}

function sampling_filter(num_parts: count, this_part: count): string
	{
	local v4_filter = fmt("ip and ((ip[14:2]+ip[18:2]) - (%d*((ip[14:2]+ip[18:2])/%d)) == %d)", num_parts, num_parts, this_part);
	# TODO: this is probably a fairly suboptimal filter, but it should work for now.
	local v6_filter = fmt("ip6 and ((ip6[22:2]+ip6[38:2]) - (%d*((ip6[22:2]+ip6[38:2])/%d)) == %d)", num_parts, num_parts, this_part);
	return combine_filters(v4_filter, "or", v6_filter);
	}
