retina_filtergen/session_filter.rs
1use heck::CamelCase;
2use proc_macro2::{Ident, Span};
3use quote::quote;
4
5use retina_core::filter::ast::*;
6use retina_core::filter::ptree::{PNode, PTree, Terminate};
7
8use crate::util::binary_to_tokens;
9
10pub(crate) fn gen_session_filter(
11 ptree: &PTree,
12 statics: &mut Vec<proc_macro2::TokenStream>,
13 ct_nodes: Vec<usize>,
14) -> proc_macro2::TokenStream {
15 if ptree.root.is_terminal {
16 // only ethernet - no filter specified
17 return quote! {
18 true
19 };
20 }
21
22 let mut body: Vec<proc_macro2::TokenStream> = vec![];
23 let session_subtrees = ct_nodes
24 .into_iter()
25 .map(|id| ptree.get_subtree(id).unwrap())
26 .collect::<Vec<_>>();
27
28 for node in session_subtrees.iter() {
29 add_node_match_arm(&mut body, statics, node);
30 }
31
32 quote! {
33 match idx {
34 #( #body )*
35 _ => return false,
36 }
37 }
38}
39
40fn add_node_match_arm(
41 code: &mut Vec<proc_macro2::TokenStream>,
42 statics: &mut Vec<proc_macro2::TokenStream>,
43 node: &PNode,
44) {
45 let idx_lit = syn::LitInt::new(&node.id.to_string(), Span::call_site());
46 if node.is_terminal {
47 code.push(quote! {
48 #idx_lit => return true,
49 })
50 } else {
51 assert!(matches!(node.terminates, Terminate::Connection));
52 let mut body: Vec<proc_macro2::TokenStream> = vec![];
53 gen_session_filter_util(&mut body, statics, node);
54
55 let service = node.pred.get_protocol().name();
56 let proto_name = Ident::new(service, Span::call_site());
57 let proto_variant = Ident::new(&service.to_camel_case(), Span::call_site());
58
59 code.push(quote! {
60 #idx_lit => {
61 if let retina_core::protocols::stream::SessionData::#proto_variant(#proto_name) = &session.data {
62 #( #body )*
63 }
64 return false;
65
66 }
67 })
68 }
69}
70
71// fn add_parser_match_arm(
72// code: &mut Vec<proc_macro2::TokenStream>,
73// statics: &mut Vec<proc_macro2::TokenStream>,
74// node: &PNode,
75// protocol: &ProtocolName,
76// ) {
77// assert!(node.pred.is_unary());
78// assert!(node.pred.on_connection() || node.pred.on_session());
79
80// let ident = Ident::new(
81// &(protocol.name().to_owned() + "sessions"),
82// Span::call_site(),
83// );
84// let ident_type = Ident::new(&protocol.name().to_camel_case(), Span::call_site());
85
86// let mut body: Vec<proc_macro2::TokenStream> = vec![];
87// if node.is_terminal {
88// // node terminates a stream filter pattern
89// body.push(quote! {
90// return true;
91// });
92// } else {
93// add_conditional_filter(&mut body, statics, node);
94// }
95
96// code.push(quote! {
97// retina_core::protocols::stream::Parser::#ident_type(#ident) => {
98// #( #body )*
99// }
100// })
101// }
102
103// fn add_conditional_filter(
104// code: &mut Vec<proc_macro2::TokenStream>,
105// statics: &mut Vec<proc_macro2::TokenStream>,
106// node: &PNode,
107// ) {
108// let mut body_filter_all: Vec<proc_macro2::TokenStream> = vec![];
109// let mut body_filter_back: Vec<proc_macro2::TokenStream> = vec![];
110
111// add_filter_match_arm(&mut body_filter_all, &mut body_filter_back, statics, node);
112// code.push(quote! {
113// if check_all {
114// #( #body_filter_all )*
115// } else {
116// #( #body_filter_back )*
117// }
118// })
119// }
120
121// fn add_filter_match_arm(
122// body_filter_all: &mut Vec<proc_macro2::TokenStream>,
123// body_filter_back: &mut Vec<proc_macro2::TokenStream>,
124// statics: &mut Vec<proc_macro2::TokenStream>,
125// node: &PNode,
126// ) {
127// let ident = Ident::new(node.pred.get_protocol().name(), Span::call_site());
128// let ident_mixed = Ident::new(
129// &(node.pred.get_protocol().name().to_owned() + "sessions"),
130// Span::call_site(),
131// );
132// let mut body_all: Vec<proc_macro2::TokenStream> = vec![];
133// let mut body_back: Vec<proc_macro2::TokenStream> = vec![];
134// gen_session_filter_util(&mut body_all, &mut body_back, statics, node);
135
136// body_filter_all.push(quote! {
137// #ident_mixed.parser.retain(|#ident|{
138// #( #body_all )*
139// });
140// return !(#ident_mixed.parser.is_empty());
141// });
142// body_filter_back.push(quote! {
143// let #ident = #ident_mixed.parser.back().unwrap();
144// #( #body_back )*
145// });
146// }
147
148fn gen_session_filter_util(
149 code: &mut Vec<proc_macro2::TokenStream>,
150 statics: &mut Vec<proc_macro2::TokenStream>,
151 node: &PNode,
152) {
153 for child in node.children.iter() {
154 assert!(node.pred.on_connection() || node.pred.on_session());
155 match &child.pred {
156 Predicate::Unary { .. } => {
157 panic!("Found unary predicate in session filter pattern");
158 }
159 Predicate::Binary {
160 protocol,
161 field,
162 op,
163 value,
164 } => {
165 assert!(protocol.name() == node.pred.get_protocol().name());
166 add_binary_pred(code, statics, child, protocol, field, op, value);
167 }
168 }
169 }
170}
171
172#[allow(clippy::too_many_arguments)]
173fn add_binary_pred(
174 code: &mut Vec<proc_macro2::TokenStream>,
175 statics: &mut Vec<proc_macro2::TokenStream>,
176 node: &PNode,
177 protocol: &ProtocolName,
178 field: &FieldName,
179 op: &BinOp,
180 value: &Value,
181) {
182 let mut body: Vec<proc_macro2::TokenStream> = vec![];
183 gen_session_filter_util(&mut body, statics, node);
184 if node.is_terminal {
185 // node terminates a session filter pattern
186 body.push(quote! {
187 return true;
188 });
189 }
190
191 let pred_tokenstream = binary_to_tokens(protocol, field, op, value, statics);
192 code.push(quote! {
193 if #pred_tokenstream {
194 #( #body )*
195 }
196 });
197}