diff --git a/Cargo.toml b/Cargo.toml index 6b2ae635..0b3e14cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,8 @@ members = [ # Exclude from compilation; many subscriptions takes a long time to compile # "examples/filter_stats", "examples/protocols", + "examples/basic", + "examples/basic_file", ] resolver = "2" diff --git a/README.md b/README.md index 0b15dca9..5c8b2f74 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Fork or clone the main git repository: `git clone git@github.com:stanford-esrg/retina.git` -Write your first Retina application (see [examples](https://github.com/stanford-esrg/retina/tree/main/examples) and [documentation](https://stanford-esrg.github.io/retina/retina_core/index.html)). +Write your first Retina application (see [examples](https://github.com/stanford-esrg/retina/tree/main/examples); `basic` and `basic_file` are good starters). Writing a Retina application consists of defining one or more subscriptions. A subscription is defined by (1) [writing a filter](https://stanford-esrg.github.io/retina/retina_filtergen/index.html) to describe what subset of network traffic you're interested in, (2) choosing [data types to subscribe to](https://stanford-esrg.github.io/retina/retina_datatypes/index.html), and (3) defining a callback function that takes in a subscribable data type and performs operations on the filtered, delivered data. diff --git a/examples/basic/Cargo.toml b/examples/basic/Cargo.toml new file mode 100644 index 00000000..936aa41d --- /dev/null +++ b/examples/basic/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "basic" +version = "0.1.0" +edition = "2021" + +[dependencies] +env_logger = "0.8.4" +retina-core = { path = "../../core" } +retina-filtergen = { path = "../../filtergen" } +retina-datatypes = { path = "../../datatypes" } +lazy_static = "1.4.0" +serde = { version = "1.0", features = ["derive"] } +regex = "1.7.3" \ No newline at end of file diff --git a/examples/basic/README.md b/examples/basic/README.md new file mode 100644 index 00000000..7709a23d --- /dev/null +++ b/examples/basic/README.md @@ -0,0 +1,3 @@ +# Basic + +An introductory example that logs TLS and DNS transactions, each with associated connection metrics. \ No newline at end of file diff --git a/examples/basic/src/main.rs b/examples/basic/src/main.rs new file mode 100644 index 00000000..8bc126e8 --- /dev/null +++ b/examples/basic/src/main.rs @@ -0,0 +1,24 @@ +use retina_core::{config::default_config, Runtime}; +use retina_datatypes::{ConnRecord, DnsTransaction, TlsHandshake}; +use retina_filtergen::{filter, retina_main}; + +#[filter("tls")] +fn tls_cb(tls: &TlsHandshake, conn_record: &ConnRecord) { + println!("Tls SNI: {}, conn. metrics: {:?}", tls.sni(), conn_record); +} + +#[filter("dns")] +fn dns_cb(dns: &DnsTransaction, conn_record: &ConnRecord) { + println!( + "DNS query domain: {}, conn. metrics: {:?}", + dns.query_domain(), + conn_record + ); +} + +#[retina_main(2)] +fn main() { + let config = default_config(); + let mut runtime: Runtime = Runtime::new(config, filter).unwrap(); + runtime.run(); +} diff --git a/examples/basic_file/Cargo.toml b/examples/basic_file/Cargo.toml new file mode 100644 index 00000000..02abc60e --- /dev/null +++ b/examples/basic_file/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "basic_file" +version = "0.1.0" +edition = "2021" + +[dependencies] +env_logger = "0.8.4" +retina-core = { path = "../../core" } +retina-filtergen = { path = "../../filtergen" } +retina-datatypes = { path = "../../datatypes" } +lazy_static = "1.4.0" +serde = { version = "1.0", features = ["derive"] } +regex = "1.7.3" \ No newline at end of file diff --git a/examples/basic_file/README.md b/examples/basic_file/README.md new file mode 100644 index 00000000..f763d210 --- /dev/null +++ b/examples/basic_file/README.md @@ -0,0 +1,3 @@ +# Basic (from specification TOML file) + +Basic application demonstrating the from-TOML file interface. Logs TLS handshakes matching certain SNIs to a file. \ No newline at end of file diff --git a/examples/basic_file/spec.toml b/examples/basic_file/spec.toml new file mode 100644 index 00000000..e4e9c429 --- /dev/null +++ b/examples/basic_file/spec.toml @@ -0,0 +1,23 @@ +[[subscriptions]] +filter = "tls.sni ~ '^.*\\.com$'" +datatypes = [ + "TlsHandshake", + "FilterStr", +] +callback = "tls_cb" + +[[subscriptions]] +filter = "tls.sni ~ '^.*\\.net$'" +datatypes = [ + "TlsHandshake", + "FilterStr", +] +callback = "tls_cb" + +[[subscriptions]] +filter = "tls.sni ~ '^.*\\.edu$'" +datatypes = [ + "TlsHandshake", + "FilterStr", +] +callback = "tls_cb" \ No newline at end of file diff --git a/examples/basic_file/src/main.rs b/examples/basic_file/src/main.rs new file mode 100644 index 00000000..0aa76143 --- /dev/null +++ b/examples/basic_file/src/main.rs @@ -0,0 +1,14 @@ +use retina_core::{config::default_config, Runtime}; +use retina_datatypes::{FilterStr, TlsHandshake}; +use retina_filtergen::subscription; + +fn tls_cb(tls: &TlsHandshake, filter_str: &FilterStr) { + println!("Matched filter {}: {:?}", filter_str, tls); +} + +#[subscription("./examples/basic_file/spec.toml")] +fn main() { + let config = default_config(); + let mut runtime: Runtime = Runtime::new(config, filter).unwrap(); + runtime.run(); +} diff --git a/filtergen/src/lib.rs b/filtergen/src/lib.rs index 71369fd1..ed57867a 100644 --- a/filtergen/src/lib.rs +++ b/filtergen/src/lib.rs @@ -294,7 +294,9 @@ fn generate(input: syn::ItemFn, config: SubscriptionConfig) -> TokenStream { quote! { use retina_core::filter::actions::*; + // Import potentially-needed traits use retina_core::subscription::{Trackable, Subscribable}; + use retina_datatypes::{FromSession, Tracked, FromMbuf, StaticData}; #subscribable