Skip to content

Commit 7ce02f0

Browse files
committed
Added FlatNetworkFilterList implementation.
Added raw_line field to flatbuffers for testing.
1 parent d7ba6ae commit 7ce02f0

13 files changed

+718
-76
lines changed

src/blocker.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,14 @@ pub enum BlockerError {
8787
// pass empty set for the rest
8888
static NO_TAGS: Lazy<HashSet<String>> = Lazy::new(HashSet::new);
8989

90+
#[cfg(feature = "flatbuffers-storage")]
91+
pub type Blocker = GenericBlocker<crate::flat_network_filter_list::FlatNetworkFilterList>;
92+
93+
#[cfg(not(feature = "flatbuffers-storage"))]
94+
pub type Blocker = GenericBlocker<crate::network_filter_list::NetworkFilterList>;
95+
9096
/// Stores network filters for efficient querying.
91-
pub struct Blocker<NetworkFilterListType = NetworkFilterList>
97+
pub struct GenericBlocker<NetworkFilterListType>
9298
where
9399
NetworkFilterList: NetworkFilterListTrait,
94100
{
@@ -115,7 +121,7 @@ where
115121
pub(crate) regex_manager: std::sync::Mutex<RegexManager>,
116122
}
117123

118-
impl<NetworkFilterListType> Blocker<NetworkFilterListType>
124+
impl<NetworkFilterListType> GenericBlocker<NetworkFilterListType>
119125
where
120126
NetworkFilterListType: NetworkFilterListTrait,
121127
{
@@ -383,13 +389,13 @@ where
383389
return None;
384390
}
385391

386-
let mut disabled_directives: HashSet<&str> = HashSet::new();
387-
let mut enabled_directives: HashSet<&str> = HashSet::new();
392+
let mut disabled_directives: HashSet<String> = HashSet::new();
393+
let mut enabled_directives: HashSet<String> = HashSet::new();
388394

389395
for filter in filters {
390396
if filter.is_exception() {
391397
if filter.is_csp() {
392-
if let Some(csp_directive) = &filter.modifier_option {
398+
if let Some(csp_directive) = filter.modifier_option {
393399
disabled_directives.insert(csp_directive);
394400
} else {
395401
// Exception filters with empty `csp` options will disable all CSP
@@ -398,7 +404,7 @@ where
398404
}
399405
}
400406
} else if filter.is_csp() {
401-
if let Some(csp_directive) = &filter.modifier_option {
407+
if let Some(csp_directive) = filter.modifier_option {
402408
enabled_directives.insert(csp_directive);
403409
}
404410
}
@@ -407,7 +413,7 @@ where
407413
let mut remaining_directives = enabled_directives.difference(&disabled_directives);
408414

409415
let mut merged = if let Some(directive) = remaining_directives.next() {
410-
String::from(*directive)
416+
directive.to_string()
411417
} else {
412418
return None;
413419
};

src/filters/fb_network.rs

+307
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
use std::collections::HashMap;
2+
use std::vec;
3+
4+
use flatbuffers::WIPOffset;
5+
6+
use crate::filters::network::{
7+
NetworkFilter, NetworkFilterMask, NetworkFilterMaskHelper, NetworkMatchable,
8+
};
9+
10+
use crate::flat_network_filter_list::FlatNetworkFilterList;
11+
use crate::regex_manager::RegexManager;
12+
use crate::request::Request;
13+
use crate::utils::Hash;
14+
15+
#[allow(dead_code, unused_imports, unsafe_code)]
16+
#[path = "../flatbuffers/fb_network_filter_generated.rs"]
17+
pub mod flat;
18+
use flat::fb;
19+
20+
pub struct FlatNetworkFiltersListBuilder<'a> {
21+
builder: flatbuffers::FlatBufferBuilder<'a>,
22+
filters: Vec<WIPOffset<fb::NetworkFilter<'a>>>,
23+
24+
unique_domains: Vec<Hash>,
25+
unique_domains_map: HashMap<Hash, u16>,
26+
}
27+
28+
impl<'a> FlatNetworkFiltersListBuilder<'a> {
29+
pub fn new() -> Self {
30+
Self {
31+
builder: flatbuffers::FlatBufferBuilder::new(),
32+
filters: vec![],
33+
unique_domains: vec![],
34+
unique_domains_map: HashMap::new(),
35+
}
36+
}
37+
38+
fn get_or_insert(&mut self, h: &Hash) -> u16 {
39+
if let Some(&index) = self.unique_domains_map.get(h) {
40+
return index;
41+
}
42+
let index = self.unique_domains.len() as u16;
43+
self.unique_domains.push(*h);
44+
self.unique_domains_map.insert(*h, index);
45+
return index;
46+
}
47+
48+
pub fn add(&mut self, network_filter: &NetworkFilter) -> u32 {
49+
let opt_domains = network_filter.opt_domains.as_ref().map(|v| {
50+
let mut o: Vec<u16> = v.iter().map(|x| self.get_or_insert(x)).collect();
51+
o.sort_unstable();
52+
o.dedup();
53+
self.builder.create_vector(&o)
54+
});
55+
56+
let opt_not_domains = network_filter.opt_not_domains.as_ref().map(|v| {
57+
let mut o: Vec<u16> = v.iter().map(|x| self.get_or_insert(x)).collect();
58+
o.sort_unstable();
59+
o.dedup();
60+
self.builder.create_vector(&o)
61+
});
62+
63+
let modifier_option = network_filter
64+
.modifier_option
65+
.as_ref()
66+
.map(|s| self.builder.create_string(&s));
67+
68+
let hostname = network_filter
69+
.hostname
70+
.as_ref()
71+
.map(|s| self.builder.create_string(&s));
72+
73+
let tag = network_filter
74+
.tag
75+
.as_ref()
76+
.map(|s| self.builder.create_string(&s));
77+
78+
let patterns = if network_filter.filter.iter().len() > 0 {
79+
let offsets: Vec<WIPOffset<&str>> = network_filter
80+
.filter
81+
.iter()
82+
.map(|s| self.builder.create_string(s))
83+
.collect();
84+
Some(self.builder.create_vector(&offsets))
85+
} else {
86+
None
87+
};
88+
89+
let raw_line = network_filter
90+
.raw_line
91+
.as_ref()
92+
.map(|v| self.builder.create_string(v.as_str()));
93+
94+
let filter = fb::NetworkFilter::create(
95+
&mut self.builder,
96+
&fb::NetworkFilterArgs {
97+
mask: network_filter.mask.bits(),
98+
patterns: patterns,
99+
modifier_option: modifier_option,
100+
opt_domains: opt_domains,
101+
opt_not_domains: opt_not_domains,
102+
hostname: hostname,
103+
tag: tag,
104+
raw_line: raw_line,
105+
},
106+
);
107+
108+
self.filters.push(filter);
109+
u32::try_from(self.filters.len() - 1).expect("< u32::MAX")
110+
}
111+
112+
pub fn finish(&mut self) -> Vec<u8> {
113+
let filters = self.builder.create_vector(&self.filters);
114+
115+
let unique_domains = self.builder.create_vector(&self.unique_domains);
116+
117+
let storage = fb::NetworkFilterList::create(
118+
&mut self.builder,
119+
&&fb::NetworkFilterListArgs {
120+
network_filters: Some(filters),
121+
unique_domains_hashes: Some(unique_domains),
122+
},
123+
);
124+
self.builder.finish(storage, None);
125+
126+
let binary = Vec::from(self.builder.finished_data());
127+
binary
128+
}
129+
}
130+
pub struct FlatPatterns<'a> {
131+
patterns: Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<&'a str>>>,
132+
}
133+
134+
impl<'a> FlatPatterns<'a> {
135+
#[inline(always)]
136+
pub fn new(
137+
patterns: Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<&'a str>>>,
138+
) -> Self {
139+
Self { patterns }
140+
}
141+
142+
#[inline(always)]
143+
pub fn iter(&self) -> FlatPatternsIterator {
144+
FlatPatternsIterator {
145+
patterns: self,
146+
len: self.patterns.map_or(0, |d| d.len()),
147+
index: 0,
148+
}
149+
}
150+
}
151+
152+
pub struct FlatPatternsIterator<'a> {
153+
patterns: &'a FlatPatterns<'a>,
154+
len: usize,
155+
index: usize,
156+
}
157+
158+
impl<'a> Iterator for FlatPatternsIterator<'a> {
159+
type Item = &'a str;
160+
161+
#[inline(always)]
162+
fn next(&mut self) -> Option<Self::Item> {
163+
self.patterns.patterns.map_or(None, |fi| {
164+
if self.index < self.len {
165+
self.index += 1;
166+
Some(fi.get(self.index - 1))
167+
} else {
168+
None
169+
}
170+
})
171+
}
172+
}
173+
174+
// Implement ExactSizeIterator for FilterPartIterator
175+
impl<'a> ExactSizeIterator for FlatPatternsIterator<'a> {
176+
#[inline(always)]
177+
fn len(&self) -> usize {
178+
self.len
179+
}
180+
}
181+
182+
pub struct FlatNetworkFilter<'a> {
183+
key: u64,
184+
owner: &'a FlatNetworkFilterList,
185+
fb_filter: &'a fb::NetworkFilter<'a>,
186+
187+
pub mask: NetworkFilterMask,
188+
}
189+
190+
impl<'a> FlatNetworkFilter<'a> {
191+
#[inline(always)]
192+
pub fn new(
193+
filter: &'a fb::NetworkFilter<'a>,
194+
index: u32,
195+
owner: &'a FlatNetworkFilterList,
196+
) -> Self {
197+
let list_address: *const FlatNetworkFilterList = owner as *const FlatNetworkFilterList;
198+
199+
Self {
200+
fb_filter: filter,
201+
key: index as u64 | (((list_address) as u64) << 32),
202+
mask: NetworkFilterMask::from_bits_retain(filter.mask()),
203+
owner: owner,
204+
}
205+
}
206+
207+
#[inline(always)]
208+
pub fn tag(&self) -> Option<&'a str> {
209+
self.fb_filter.tag()
210+
}
211+
212+
#[inline(always)]
213+
pub fn modifier_option(&self) -> Option<String> {
214+
self.fb_filter.modifier_option().map(|o| o.to_string())
215+
}
216+
217+
#[inline(always)]
218+
pub fn include_domains(&self) -> Option<&[u16]> {
219+
self.fb_filter.opt_domains().map(|data| {
220+
let bytes = data.bytes();
221+
unsafe {
222+
std::slice::from_raw_parts(
223+
bytes.as_ptr() as *const u16,
224+
bytes.len() / std::mem::size_of::<u16>(),
225+
)
226+
}
227+
})
228+
}
229+
230+
#[inline(always)]
231+
pub fn exclude_domains(&self) -> Option<&[u16]> {
232+
self.fb_filter.opt_not_domains().map(|data| {
233+
let bytes = data.bytes();
234+
unsafe {
235+
std::slice::from_raw_parts(
236+
bytes.as_ptr() as *const u16,
237+
bytes.len() / std::mem::size_of::<u16>(),
238+
)
239+
}
240+
})
241+
}
242+
243+
#[inline(always)]
244+
pub fn hostname(&self) -> Option<&'a str> {
245+
if self.mask.is_hostname_anchor() {
246+
self.fb_filter.hostname()
247+
} else {
248+
None
249+
}
250+
}
251+
252+
#[inline(always)]
253+
pub fn patterns(&self) -> FlatPatterns {
254+
FlatPatterns::new(self.fb_filter.patterns())
255+
}
256+
257+
#[inline(always)]
258+
pub fn raw_line(&self) -> Option<String> {
259+
self.fb_filter.raw_line().map(|v| v.to_string())
260+
}
261+
}
262+
263+
impl<'a> NetworkFilterMaskHelper for FlatNetworkFilter<'a> {
264+
#[inline]
265+
fn has_flag(&self, v: NetworkFilterMask) -> bool {
266+
self.mask.contains(v)
267+
}
268+
}
269+
270+
impl<'a> NetworkMatchable for FlatNetworkFilter<'a> {
271+
fn matches(&self, request: &Request, regex_manager: &mut RegexManager) -> bool {
272+
use crate::filters::network_matchers::{
273+
check_excluded_domains_mapped, check_included_domains_mapped, check_options,
274+
check_pattern,
275+
};
276+
if !check_options(self.mask, request) {
277+
return false;
278+
}
279+
if !check_included_domains_mapped(
280+
self.include_domains(),
281+
request,
282+
&self.owner.domain_hashes_mapping,
283+
) {
284+
return false;
285+
}
286+
if !check_excluded_domains_mapped(
287+
self.exclude_domains(),
288+
request,
289+
&self.owner.domain_hashes_mapping,
290+
) {
291+
return false;
292+
}
293+
check_pattern(
294+
self.mask,
295+
self.patterns().iter(),
296+
self.hostname(),
297+
self.key,
298+
request,
299+
regex_manager,
300+
)
301+
}
302+
303+
#[cfg(test)]
304+
fn matches_test(&self, request: &Request) -> bool {
305+
self.matches(request, &mut RegexManager::default())
306+
}
307+
}

src/filters/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ mod network_matchers;
55

66
pub mod cosmetic;
77
pub mod network;
8+
9+
#[cfg(feature = "flatbuffers-storage")]
10+
pub mod fb_network;

0 commit comments

Comments
 (0)