1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! New datatypes are defined in this module.
//! Newly-defined datatypes must be added to the DATATYPES map in this module.

use lazy_static::lazy_static;
use proc_macro2::Span;
use quote::quote;
use retina_core::filter::{DataType, Level, SubscriptionSpec};
use std::collections::HashMap;

use crate::*;

lazy_static! {
    /// To add a datatype, add it to the DATATYPES map
    /// This is read by the filtergen crate to generate code
    pub static ref DATATYPES: HashMap<&'static str, DataType> = {
        HashMap::from([
            ("ConnRecord", DataType::new_default_connection("ConnRecord")),
            (
                "ConnDuration",
                DataType::new_default_connection("ConnDuration"),
            ),
            ("PktCount", DataType::new_default_connection("PktCount")),
            ("ByteCount", DataType::new_default_connection("ByteCount")),
            (
                "InterArrivals",
                DataType::new_default_connection("InterArrivals"),
            ),
            (
                "ConnHistory",
                DataType::new_default_connection("ConnHistory"),
            ),
            (
                "HttpTransaction",
                DataType::new_default_session(
                    "HttpTransaction",
                    HttpTransaction::stream_protocols(),
                ),
            ),
            (
                "DnsTransaction",
                DataType::new_default_session("DnsTransaction", DnsTransaction::stream_protocols()),
            ),
            (
                "TlsHandshake",
                DataType::new_default_session("TlsHandshake", TlsHandshake::stream_protocols()),
            ),
            (
                "QuicStream",
                DataType::new_default_session("QuicStream", QuicStream::stream_protocols()),
            ),
            ("ZcFrame", DataType::new_default_packet("ZcFrame")),
            ("Payload", DataType::new_default_packet("Payload")),
            ("PacketList", {
                DataType {
                    level: Level::Connection,
                    needs_parse: false,
                    track_sessions: false,
                    needs_update: false,
                    needs_update_reassembled: false,
                    track_packets: true,
                    stream_protos: vec![],
                    as_str: "PacketList",
                }
            }),
            ("SessionList", {
                DataType {
                    level: Level::Connection,
                    needs_parse: true,
                    track_sessions: true,
                    needs_update: false,
                    needs_update_reassembled: false,
                    track_packets: false,
                    stream_protos: vec!["tls", "dns", "http", "quic"],
                    as_str: "SessionList",
                }
            }),
            ("CoreId", { DataType::new_default_static("CoreId") }),
            ("FiveTuple", { DataType::new_default_static("FiveTuple") }),
            ("EtherTCI", { DataType::new_default_static("EtherTCI") }),
            ("EthAddr", { DataType::new_default_static("EthAddr") }),
            ("FilterStr", { DataType::new_default_static("FilterStr") }),
        ])
    };
}

// Special cases: have specific conditions in generated code
// \Note ideally these would be implemented more cleanly
lazy_static! {
    /// To avoid copying, the `Tracked` structure in the framework --
    /// built at compile time -- will track certain generic, raw datatypes
    /// if a subset of subscriptions require them.
    ///
    /// For example: buffering packets may be required as a pre-match action for a
    /// packet-level datatype; it may also be required if one or more subscriptions request
    /// a connection-level `PacketList`. Rather than maintaining these lists separately --
    /// one for filtering and one for delivery -- the tracked packets are stored once.
    ///
    /// Core ID is a special case, as it cannot be derived from connection,
    /// session, or packet data. It is simpler to define it as a directly tracked datatype.
    ///
    /// The directly tracked datatypes are: PacketList, SessionList, and CoreId
    #[doc(hidden)]
    pub static ref DIRECTLY_TRACKED: HashMap<&'static str, &'static str> = HashMap::from([
        ("PacketList", "packets"),
        ("SessionList", "sessions"),
        ("CoreId", "core_id")
    ]);

    /// See `FilterStr`
    #[doc(hidden)]
    pub static ref FILTER_STR: &'static str = "FilterStr";
}

/// A list of all packets (zero-copy) seen in the connection.
/// For TCP connections, these packets will be in post-reassembly order.
pub type PacketList = Vec<Mbuf>;
/// A list of all sessions (zero-copy) parsed in the connection.
pub type SessionList = Vec<Session>;

/// The string literal representing a matched filter.
pub type FilterStr<'a> = &'a str;

impl<'a> FromSubscription for FilterStr<'a> {
    fn from_subscription(spec: &SubscriptionSpec) -> proc_macro2::TokenStream {
        let str = syn::LitStr::new(&spec.filter, Span::call_site());
        quote! { &#str }
    }
}