2019-09-25 13:51:13 +00:00
|
|
|
use std::fs::File;
|
|
|
|
use std::io::{BufRead, BufReader};
|
|
|
|
use std::path::Path;
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
2022-05-13 23:30:16 +00:00
|
|
|
use rustc_hash::FxHashMap;
|
|
|
|
|
|
|
|
use crate::errors::*;
|
|
|
|
|
2019-09-25 13:51:13 +00:00
|
|
|
const MAX_ITERATIONS: usize = 5;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct BlackListInner {
|
2019-12-01 00:46:23 +00:00
|
|
|
map: FxHashMap<Vec<u8>, ()>,
|
2019-09-25 13:51:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct BlackList {
|
|
|
|
inner: Arc<BlackListInner>,
|
|
|
|
max_iterations: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BlackList {
|
2019-12-01 00:46:23 +00:00
|
|
|
pub fn new(map: FxHashMap<Vec<u8>, ()>, max_iterations: usize) -> Self {
|
2019-09-25 13:51:13 +00:00
|
|
|
let inner = Arc::new(BlackListInner { map });
|
|
|
|
BlackList {
|
|
|
|
inner,
|
|
|
|
max_iterations,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-11 09:50:22 +00:00
|
|
|
pub fn load(path: impl AsRef<Path>) -> Result<Self, Error> {
|
2019-12-01 00:46:23 +00:00
|
|
|
let mut map = FxHashMap::default();
|
2019-09-25 13:51:13 +00:00
|
|
|
let fp = BufReader::new(File::open(path)?);
|
|
|
|
for (line_nb, line) in fp.lines().enumerate() {
|
|
|
|
let line = line?;
|
|
|
|
let mut line = line.trim();
|
|
|
|
if line.is_empty() || line.starts_with('#') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
while line.starts_with("*.") {
|
|
|
|
line = &line[2..];
|
|
|
|
}
|
|
|
|
while line.ends_with('.') {
|
|
|
|
line = &line[..line.len() - 1];
|
|
|
|
}
|
2020-04-20 14:24:18 +00:00
|
|
|
let qname = line.as_bytes().to_ascii_lowercase();
|
2019-09-25 13:51:13 +00:00
|
|
|
if qname.is_empty() {
|
2019-11-01 19:56:07 +00:00
|
|
|
bail!("Unexpected blacklist rule at line {}", line_nb)
|
2019-09-25 13:51:13 +00:00
|
|
|
}
|
|
|
|
map.insert(qname, ());
|
|
|
|
}
|
|
|
|
Ok(BlackList::new(map, MAX_ITERATIONS))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn find(&self, qname: &[u8]) -> bool {
|
2020-04-20 14:24:18 +00:00
|
|
|
let qname = qname.to_ascii_lowercase();
|
2019-09-25 13:51:13 +00:00
|
|
|
let mut qname = qname.as_slice();
|
|
|
|
let map = &self.inner.map;
|
|
|
|
let mut iterations = self.max_iterations;
|
|
|
|
while qname.len() >= 4 && iterations > 0 {
|
|
|
|
if map.contains_key(qname) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
let mut it = qname.splitn(2, |x| *x == b'.');
|
|
|
|
if it.next().is_none() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
qname = match it.next() {
|
|
|
|
None => break,
|
|
|
|
Some(qname) => qname,
|
|
|
|
};
|
|
|
|
iterations -= 1;
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|