working base

This commit is contained in:
Pascal Engélibert 2025-04-06 00:03:47 +02:00
commit 616c17501a
11 changed files with 1142 additions and 243 deletions

View file

@ -1,143 +1,41 @@
use regex::{Regex, RegexSet};
use regex::bytes::RegexSet;
#[derive(Clone, Debug)]
#[derive(Clone, Copy, Debug)]
pub enum Action {
Allow,
Challenge,
Drop,
}
#[derive(Clone, Debug)]
pub enum Filter {
Bool(bool),
FirstLineMatch(String),
HeaderLineMatch(String),
And(Vec<Filter>),
Or(Vec<Filter>),
Not(Box<Filter>),
}
impl Filter {
fn compile<'a>(
&'a self,
first_line_regexes: &mut Vec<&'a str>,
header_line_regexes: &mut Vec<&'a str>,
) -> CompiledFilter {
match self {
Filter::Bool(v) => CompiledFilter::Bool(*v),
Filter::And(filters) => CompiledFilter::And(
filters
.iter()
.map(|filter| filter.compile(first_line_regexes, header_line_regexes))
.collect(),
),
Filter::Or(filters) => CompiledFilter::Or(
filters
.iter()
.map(|filter| filter.compile(first_line_regexes, header_line_regexes))
.collect(),
),
Filter::Not(filter) => CompiledFilter::Not(Box::new(
filter.compile(first_line_regexes, header_line_regexes),
)),
Filter::FirstLineMatch(regex) => {
let filter = CompiledFilter::FirstLineMatch(first_line_regexes.len());
first_line_regexes.push(regex);
filter
}
Filter::HeaderLineMatch(regex) => {
let filter = CompiledFilter::HeaderLineMatch(header_line_regexes.len());
header_line_regexes.push(regex);
filter
}
}
}
}
#[derive(Clone, Debug)]
pub struct Policy {
pub name: String,
pub filter: Filter,
pub action: Action,
pub priority: i32,
}
pub enum CompiledFilter {
Bool(bool),
FirstLineMatch(usize),
HeaderLineMatch(usize),
And(Vec<CompiledFilter>),
Or(Vec<CompiledFilter>),
Not(Box<CompiledFilter>),
}
pub struct CompiledPolicy {
pub name: String,
pub filter: CompiledFilter,
pub priority: i32,
pub first_line_regex: String,
pub action: Action,
}
pub struct CompiledPolicies {
pub first_line_regex_set: Option<RegexSet>,
pub header_line_regex_set: Option<RegexSet>,
pub policies: Vec<CompiledPolicy>,
pub first_line_regex_set: RegexSet,
pub policies: Vec<Policy>,
}
impl CompiledPolicies {
pub fn new<'a>(policies: impl IntoIterator<Item = &'a Policy>) -> Self {
pub fn new(policies: Vec<Policy>) -> Self {
let mut first_line_regexes = Vec::new();
let mut header_line_regexes = Vec::new();
let mut compiled_policies = Vec::new();
for policy in policies {
let compiled_policy = CompiledPolicy {
name: policy.name.clone(),
filter: policy
.filter
.compile(&mut first_line_regexes, &mut header_line_regexes),
priority: policy.priority,
action: policy.action.clone(),
};
compiled_policies.push(compiled_policy);
for policy in policies.iter() {
first_line_regexes.push(&policy.first_line_regex);
}
CompiledPolicies {
first_line_regex_set: if first_line_regexes.is_empty() {
None
} else {
Some(RegexSet::new(&first_line_regexes).unwrap())
},
header_line_regex_set: if header_line_regexes.is_empty() {
None
} else {
Some(RegexSet::new(&header_line_regexes).unwrap())
},
policies: compiled_policies,
first_line_regex_set: RegexSet::new(&first_line_regexes).unwrap(),
policies,
}
}
pub fn evaluate<'a>(
&self,
mut header_lines: impl Iterator<Item = &'a [u8]>,
) -> Result<Option<&CompiledPolicy>, PolicyEvaluationError> {
let mut best_policy = None;
let mut best_priority = i32::MAX;
pub fn evaluate(&self, first_line: &[u8]) -> Option<&Policy> {
let matches = self.first_line_regex_set.matches(first_line);
let first_line = header_lines
.next()
.ok_or(PolicyEvaluationError::NoFirstLine)?;
if let Some(first_line_regex_set) = &self.first_line_regex_set {
//let matches = first_line_regex_set.matches(first_line);
}
Ok(best_policy)
matches.into_iter().next().map(|i| &self.policies[i])
}
}
#[derive(Debug)]
pub enum PolicyEvaluationError {
/// First HTTP line is too long or absent
NoFirstLine,
}