Rewrite the project
The previous project architecture was far too complicated and hard to maintain. The new one is much more simple. Although procedural macros are cools, they are a no-go on Rust-OpenSMTPD. Reports and filter are implemented (except data-line) but untested.
This commit is contained in:
parent
fc072743ad
commit
a6d4dd21c1
48 changed files with 1723 additions and 1493 deletions
159
src/parsers/entry.rs
Normal file
159
src/parsers/entry.rs
Normal file
|
@ -0,0 +1,159 @@
|
|||
use super::{parse_data_structure, parse_delimiter, parse_string_parameter};
|
||||
use crate::Event;
|
||||
use crate::FilterPhase;
|
||||
use crate::SubSystem;
|
||||
use crate::TimeVal;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::streaming::tag;
|
||||
use nom::character::streaming::digit1;
|
||||
use nom::combinator::map_res;
|
||||
use nom::IResult;
|
||||
|
||||
pub struct ReportEntry {
|
||||
pub version: String,
|
||||
pub timestamp: TimeVal,
|
||||
pub subsystem: SubSystem,
|
||||
pub event: Event,
|
||||
pub session_id: String,
|
||||
}
|
||||
|
||||
pub struct FilterEntry {
|
||||
pub version: String,
|
||||
pub timestamp: TimeVal,
|
||||
pub subsystem: SubSystem,
|
||||
pub phase: FilterPhase,
|
||||
pub session_id: String,
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
pub struct DataLineEntry {
|
||||
pub session_id: String,
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
pub(crate) enum EntryOption {
|
||||
Report(ReportEntry),
|
||||
Filter(FilterEntry),
|
||||
DataLine(DataLineEntry),
|
||||
}
|
||||
|
||||
pub(crate) fn parse_entry(input: &[u8]) -> IResult<&[u8], EntryOption> {
|
||||
let (input, entry) = alt((
|
||||
parse_report_entry_meta,
|
||||
alt((parse_filter_entry_meta, parse_data_line_entry_meta)),
|
||||
))(input)?;
|
||||
Ok((input, entry))
|
||||
}
|
||||
|
||||
fn parse_report_entry_meta(input: &[u8]) -> IResult<&[u8], EntryOption> {
|
||||
let (input, _) = tag("report")(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, entry) = parse_report_entry(input)?;
|
||||
Ok((input, EntryOption::Report(entry)))
|
||||
}
|
||||
|
||||
fn parse_filter_entry_meta(input: &[u8]) -> IResult<&[u8], EntryOption> {
|
||||
let (input, _) = tag("filter")(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, entry) = parse_filter_entry(input)?;
|
||||
Ok((input, EntryOption::Filter(entry)))
|
||||
}
|
||||
|
||||
fn parse_data_line_entry_meta(input: &[u8]) -> IResult<&[u8], EntryOption> {
|
||||
let (input, _) = tag("filter-dataline")(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, data_line) = parse_data_line_entry(input)?;
|
||||
Ok((input, EntryOption::DataLine(data_line)))
|
||||
}
|
||||
|
||||
fn parse_report_entry(input: &[u8]) -> IResult<&[u8], ReportEntry> {
|
||||
let (input, version) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, timestamp) = parse_timestamp(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, subsystem) = parse_data_structure::<SubSystem>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, event) = parse_data_structure::<Event>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, session_id) = parse_string_parameter(input)?;
|
||||
let entry = ReportEntry {
|
||||
version,
|
||||
timestamp,
|
||||
subsystem,
|
||||
event,
|
||||
session_id,
|
||||
};
|
||||
Ok((input, entry))
|
||||
}
|
||||
|
||||
fn parse_filter_entry(input: &[u8]) -> IResult<&[u8], FilterEntry> {
|
||||
let (input, version) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, timestamp) = parse_timestamp(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, subsystem) = parse_data_structure::<SubSystem>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, phase) = parse_data_structure::<FilterPhase>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, session_id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, token) = parse_string_parameter(input)?;
|
||||
let entry = FilterEntry {
|
||||
version,
|
||||
timestamp,
|
||||
subsystem,
|
||||
phase,
|
||||
session_id,
|
||||
token,
|
||||
};
|
||||
Ok((input, entry))
|
||||
}
|
||||
|
||||
fn parse_data_line_entry(input: &[u8]) -> IResult<&[u8], DataLineEntry> {
|
||||
let (input, session_id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, token) = parse_string_parameter(input)?;
|
||||
let entry = DataLineEntry { session_id, token };
|
||||
Ok((input, entry))
|
||||
}
|
||||
|
||||
fn parse_timestamp(input: &[u8]) -> IResult<&[u8], TimeVal> {
|
||||
let (input, sec) = map_res(digit1, |s| String::from_utf8_lossy(s).parse::<i64>())(input)?;
|
||||
let (input, _) = tag(".")(input)?;
|
||||
let (input, usec) = map_res(digit1, |s| {
|
||||
format!("{:0<6}", String::from_utf8_lossy(s)).parse::<i64>()
|
||||
})(input)?;
|
||||
let timestamp = TimeVal { sec, usec };
|
||||
Ok((input, timestamp))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_report_link_connect() {
|
||||
let input = b"report|0.5|1576146008.06099|smtp-in|link-connect|7641df9771b4ed00|mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25";
|
||||
let res = parse_entry(input);
|
||||
assert!(res.is_ok());
|
||||
let (_, res) = res.unwrap();
|
||||
let res = match res {
|
||||
EntryOption::Report(r) => r,
|
||||
_ => {
|
||||
assert!(false);
|
||||
return;
|
||||
}
|
||||
};
|
||||
assert_eq!(res.version, String::from("0.5"));
|
||||
assert_eq!(
|
||||
res.timestamp,
|
||||
TimeVal {
|
||||
sec: 1576146008,
|
||||
usec: 60990
|
||||
}
|
||||
);
|
||||
assert_eq!(res.subsystem, SubSystem::SmtpIn);
|
||||
assert_eq!(res.event, Event::LinkConnect);
|
||||
assert_eq!(res.session_id, String::from("7641df9771b4ed00"));
|
||||
}
|
||||
}
|
Reference in a new issue