Crate retina_filtergen

source ·
Expand description

A macro for defining filters in Retina.

filter is an attribute macro that parses a user-defined filter expression to generate sub-filters that are statically inlined at each processing layer. This verifies filter expressions at compile time and avoids overheads associated with interpreting filters at runtime.

Usage

use retina_core::config::default_config;
use retina_core::Runtime;
use retina_core::subscription::Connection;
use retina_filtergen::filter;

#[filter("(ipv4 and tcp.port >= 100 and tls.sni ~ 'netflix') or http")]
fn main() {
   let cfg = default_config();
   let callback = |conn: Connection| {
       println!("{:#?}", conn);
   };
   let mut runtime = Runtime::new(cfg, filter, callback).unwrap();
   runtime.run();
}

Syntax

The Retina filter syntax is similar to that of Wireshark display filters. However, Retina is capable of filtering on live traffic for online analysis, whereas display filters can only be applied for offline analysis.

A filter expression is a logical expression of constraints on attributes of the input traffic. Each constraint is either a binary predicate that compares the value of an entity’s attribute with a constant, or a unary predicate that matches against the entity itself.

Protocols

All protocol identifiers are valid as long as Retina contains an appropriate protocol module of the same name. The filter macro automatically generates filtering code using structs defined in the protocol’s corresponding parser module. The exception to this is ethernet, which Retina filters for by default.

For example, ipv4 and tls are filterable protocols because they are both protocol modules included in Retina.

Retina will also automatically expand filter expressions to their fully-qualified form. For example, the filter tcp is equivalent to (ipv4 and tcp) or (ipv6 and tcp).

Fields

All field identifiers are valid as long as Retina exposes a public accessor method for the corresponding protocol struct of the same name, and the method returns a supported RHS field type.

For example, ipv4.src_addr and tls.sni are both filterable fields because src_addr() is a public method associated with the Ipv4 struct that returns an Ipv4Addr, and sni() is a public method associated with the Tls struct that returns a String.

Retina also supports two combined fields: addr and port. Logically, these are equivalent to src_addr or dst_addr and src_port or dst_port, respectively, except in predicates that use the != comparison operator (details below).

Field types (RHS values)

TypeExample
IPv4 address1.2.3.4
IPv4 prefix1.2.3.4/24
IPv6 address2001:db8::1
IPv6 prefix2001:db8::1/64
Integer443
String'Safari'
Integer range1024..5000

Binary comparison operators

OperatorAliasDescriptionExample
=Equalsipv4.addr = 127.0.0.1
!=neNot equalsudp.dst_port != 53
>=geGreater than or equalstcp.port >= 1024
<=leLess than or equalstls.version <= 771
>gtGreater thanipv4.time_to_live > 64
<ltLess thanipv6.payload_length < 500
inIn a range, or in a subnetipv4.src_addr in 1.2.3.4/16
~matchesRegular expression matchtls.sni ~ 'netflix\\.com$'

Possible pitfalls involving !=

Retina differs from Wireshark behavior regarding the != operator. When applied to combined fields (i.e., addr or port), Retina follows connection-level semantics instead of packet-level semantics. For example, tcp.port != 80 is equivalent to tcp.src_port != 80 and tcp.dst_port != 80.

Regular expressions

Retina compiles regular expressions exactly once, using the regex and lazy_static crates. As of this writing, proc-macro crates like this one cannot export any items other than procedural macros, thus requiring applications that wish to use Retina’s regular expression filtering to specify regex and lazy_static as dependencies. Also note that regular expressions are written as normal strings in Rust, and not as raw string literals. They are allowed to match anywhere in the text, unless start (^) and end ($) anchors are used.

Logical operators

OperatorAliasDescriptionExample
andANDLogical ANDtcp.port = 443 and tls
orORLogical ORhttp.method = 'GET' or http.method = 'POST'

AND takes precedence over OR in the absence of parentheses.

Retina does not yet support the logical NOT operator. For some expressions, it can be approximated using the != binary comparison operator, taking the above mentioned pitfall into consideration.

Attribute Macros

  • Macro for generating filters.