Implement support for server-side blacklists
parent
80e70eace4
commit
518f0ce17d
@ -0,0 +1,76 @@
|
|||||||
|
use crate::errors::*;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader};
|
||||||
|
use std::path::Path;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
const MAX_ITERATIONS: usize = 5;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BlackListInner {
|
||||||
|
map: HashMap<Vec<u8>, ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct BlackList {
|
||||||
|
inner: Arc<BlackListInner>,
|
||||||
|
max_iterations: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlackList {
|
||||||
|
pub fn new(map: HashMap<Vec<u8>, ()>, max_iterations: usize) -> Self {
|
||||||
|
let inner = Arc::new(BlackListInner { map });
|
||||||
|
BlackList {
|
||||||
|
inner,
|
||||||
|
max_iterations,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
let qname = line.as_bytes().to_vec().to_ascii_lowercase();
|
||||||
|
if qname.is_empty() {
|
||||||
|
bail!(format_err!("Unexpected blacklist rule at line {}", line_nb))
|
||||||
|
}
|
||||||
|
map.insert(qname, ());
|
||||||
|
}
|
||||||
|
Ok(BlackList::new(map, MAX_ITERATIONS))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find(&self, qname: &[u8]) -> bool {
|
||||||
|
let qname = qname.to_vec().to_ascii_lowercase();
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue