Compare commits
10 commits
5f1d45ca0c
...
847fbd6213
Author | SHA1 | Date | |
---|---|---|---|
|
847fbd6213 | ||
|
d9b89beb3f | ||
|
28e93f0353 | ||
|
a28b8846a2 | ||
|
e0ab5ca6fa | ||
|
20493e9dec | ||
|
e8f99f957d | ||
|
0fe864e6db | ||
|
e83af3d3e5 | ||
|
ecf0ca1191 |
31 changed files with 1409 additions and 1390 deletions
9
.editorconfig
Normal file
9
.editorconfig
Normal file
|
@ -0,0 +1,9 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = tab
|
||||
indent_size = tab
|
||||
trim_trailing_whitespace = true
|
1
.rustfmt.toml
Normal file
1
.rustfmt.toml
Normal file
|
@ -0,0 +1 @@
|
|||
hard_tabs = true
|
|
@ -10,6 +10,10 @@ rust:
|
|||
- "1.46.0"
|
||||
- "1.47.0"
|
||||
- "1.48.0"
|
||||
- "1.49.0"
|
||||
- "1.50.0"
|
||||
- "1.51.0"
|
||||
- "1.52.1"
|
||||
- "stable"
|
||||
- "beta"
|
||||
- "nightly"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"opensmtpd",
|
||||
"opensmtpd-derive"
|
||||
"opensmtpd",
|
||||
"opensmtpd-derive"
|
||||
]
|
||||
|
|
|
@ -17,3 +17,8 @@ Read the documentation on [docs.rs](https://docs.rs/opensmtpd/).
|
|||
# Requirements
|
||||
|
||||
Rust 1.43 or newer.
|
||||
|
||||
|
||||
# Status
|
||||
|
||||
Abandoned (at least temporarily).
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "opensmtpd_derive"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
authors = ["Rodolphe Bréard <rodolphe@what.tf>"]
|
||||
edition = "2018"
|
||||
description = "Interface for OpenSMTPD filters"
|
||||
|
|
|
@ -5,14 +5,14 @@ use syn::{parse_macro_input, Ident, ItemFn};
|
|||
|
||||
#[proc_macro_attribute]
|
||||
pub fn register(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let item = parse_macro_input!(input as ItemFn);
|
||||
let fn_name = item.sig.ident.to_string().replacen("on_", "has_", 1);
|
||||
let fn_name = Ident::new(&fn_name, Span::call_site());
|
||||
let output = quote! {
|
||||
fn #fn_name(&self) -> bool {
|
||||
true
|
||||
}
|
||||
#item
|
||||
};
|
||||
output.into()
|
||||
let item = parse_macro_input!(input as ItemFn);
|
||||
let fn_name = item.sig.ident.to_string().replacen("on_", "has_", 1);
|
||||
let fn_name = Ident::new(&fn_name, Span::call_site());
|
||||
let output = quote! {
|
||||
fn #fn_name(&self) -> bool {
|
||||
true
|
||||
}
|
||||
#item
|
||||
};
|
||||
output.into()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "opensmtpd"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
authors = ["Rodolphe Bréard <rodolphe@what.tf>"]
|
||||
edition = "2018"
|
||||
description = "Interface for OpenSMTPD filters"
|
||||
|
@ -18,7 +18,7 @@ opensmtpd_derive = { version = "0.4", path = "../opensmtpd-derive" }
|
|||
pretty-hex = "0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
simplelog = "0.9"
|
||||
simplelog = "0.10"
|
||||
|
||||
[[example]]
|
||||
name = "counter"
|
||||
|
|
|
@ -8,48 +8,48 @@ pub const DEFAULT_LOG_FILE: &str = "/tmp/counter.log";
|
|||
|
||||
#[derive(Default)]
|
||||
struct MyCounter {
|
||||
nb_connected: u64,
|
||||
nb_total: u64,
|
||||
nb_connected: u64,
|
||||
nb_total: u64,
|
||||
}
|
||||
|
||||
impl Filter for MyCounter {
|
||||
#[register]
|
||||
fn on_report_link_connect(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_rdns: &str,
|
||||
_fcrdns: &str,
|
||||
_src: &Address,
|
||||
_dest: &Address,
|
||||
) {
|
||||
self.nb_connected += 1;
|
||||
self.nb_total += 1;
|
||||
log::info!(
|
||||
"New client (connected: {}, total: {})",
|
||||
self.nb_connected,
|
||||
self.nb_total
|
||||
);
|
||||
}
|
||||
#[register]
|
||||
fn on_report_link_connect(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_rdns: &str,
|
||||
_fcrdns: &str,
|
||||
_src: &Address,
|
||||
_dest: &Address,
|
||||
) {
|
||||
self.nb_connected += 1;
|
||||
self.nb_total += 1;
|
||||
log::info!(
|
||||
"New client (connected: {}, total: {})",
|
||||
self.nb_connected,
|
||||
self.nb_total
|
||||
);
|
||||
}
|
||||
|
||||
#[register]
|
||||
fn on_report_link_disconnect(&mut self, _entry: &ReportEntry) {
|
||||
self.nb_connected -= 1;
|
||||
log::info!(
|
||||
"Client left (connected: {}, total: {})",
|
||||
self.nb_connected,
|
||||
self.nb_total
|
||||
);
|
||||
}
|
||||
#[register]
|
||||
fn on_report_link_disconnect(&mut self, _entry: &ReportEntry) {
|
||||
self.nb_connected -= 1;
|
||||
log::info!(
|
||||
"Client left (connected: {}, total: {})",
|
||||
self.nb_connected,
|
||||
self.nb_total
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let log_file = std::env::var("LOG_FILE").unwrap_or(String::from(DEFAULT_LOG_FILE));
|
||||
WriteLogger::init(
|
||||
LevelFilter::Info,
|
||||
Config::default(),
|
||||
File::create(&log_file).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut my_counter: MyCounter = Default::default();
|
||||
run_filter(&mut my_counter);
|
||||
let log_file = std::env::var("LOG_FILE").unwrap_or(String::from(DEFAULT_LOG_FILE));
|
||||
WriteLogger::init(
|
||||
LevelFilter::Info,
|
||||
Config::default(),
|
||||
File::create(&log_file).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut my_counter: MyCounter = Default::default();
|
||||
run_filter(&mut my_counter);
|
||||
}
|
||||
|
|
|
@ -7,21 +7,21 @@ pub const HEADER_LEN: usize = 17;
|
|||
struct RmXOriginatingIp {}
|
||||
|
||||
impl Filter for RmXOriginatingIp {
|
||||
#[register]
|
||||
fn on_filter_data_line(&mut self, entry: &FilterEntry, data_line: &[u8]) {
|
||||
if data_line.len() >= HEADER_LEN {
|
||||
let head_start = data_line[..HEADER_LEN].to_vec();
|
||||
if let Ok(s) = String::from_utf8(head_start) {
|
||||
if s.to_lowercase() == HEADER_NAME {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return_data_line(entry, data_line);
|
||||
}
|
||||
#[register]
|
||||
fn on_filter_data_line(&mut self, entry: &FilterEntry, data_line: &[u8]) {
|
||||
if data_line.len() >= HEADER_LEN {
|
||||
let head_start = data_line[..HEADER_LEN].to_vec();
|
||||
if let Ok(s) = String::from_utf8(head_start) {
|
||||
if s.to_lowercase() == HEADER_NAME {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return_data_line(entry, data_line);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut my_filter = RmXOriginatingIp {};
|
||||
run_filter(&mut my_filter);
|
||||
let mut my_filter = RmXOriginatingIp {};
|
||||
run_filter(&mut my_filter);
|
||||
}
|
||||
|
|
|
@ -2,15 +2,15 @@ use crate::FilterEntry;
|
|||
use std::io::{self, Write};
|
||||
|
||||
pub fn return_data_line(entry: &FilterEntry, data_line: &[u8]) {
|
||||
let mut data_line = data_line.to_vec();
|
||||
data_line.retain(|&c| c != 0x0d && c != 0x0a);
|
||||
print!("filter-dataline|{}|{}|", entry.session_id, entry.token);
|
||||
io::stdout().write_all(&data_line).unwrap();
|
||||
println!();
|
||||
log::trace!(
|
||||
"Sent filter-dataline (session:id: {}, token: {}){}",
|
||||
entry.session_id,
|
||||
entry.token,
|
||||
crate::error::get_pretty_hex(&data_line)
|
||||
);
|
||||
let mut data_line = data_line.to_vec();
|
||||
data_line.retain(|&c| c != 0x0d && c != 0x0a);
|
||||
print!("filter-dataline|{}|{}|", entry.session_id, entry.token);
|
||||
io::stdout().write_all(&data_line).unwrap();
|
||||
println!();
|
||||
log::trace!(
|
||||
"Sent filter-dataline (session:id: {}, token: {}){}",
|
||||
entry.session_id,
|
||||
entry.token,
|
||||
crate::error::get_pretty_hex(&data_line)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,18 +3,18 @@ use std::path::PathBuf;
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum Address {
|
||||
Ip(SocketAddr),
|
||||
UnixSocket(PathBuf),
|
||||
Ip(SocketAddr),
|
||||
UnixSocket(PathBuf),
|
||||
}
|
||||
|
||||
impl ToString for Address {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Address::Ip(a) => a.to_string(),
|
||||
Address::UnixSocket(a) => match a.clone().into_os_string().into_string() {
|
||||
Ok(s) => s,
|
||||
Err(_) => String::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Address::Ip(a) => a.to_string(),
|
||||
Address::UnixSocket(a) => match a.clone().into_os_string().into_string() {
|
||||
Ok(s) => s,
|
||||
Err(_) => String::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,30 +2,30 @@ use std::str::FromStr;
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum AuthResult {
|
||||
Pass,
|
||||
Fail,
|
||||
Error,
|
||||
Pass,
|
||||
Fail,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl ToString for AuthResult {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
AuthResult::Pass => String::from("pass"),
|
||||
AuthResult::Fail => String::from("fail"),
|
||||
AuthResult::Error => String::from("error"),
|
||||
}
|
||||
}
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
AuthResult::Pass => String::from("pass"),
|
||||
AuthResult::Fail => String::from("fail"),
|
||||
AuthResult::Error => String::from("error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for AuthResult {
|
||||
type Err = ();
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"pass" => Ok(AuthResult::Pass),
|
||||
"fail" => Ok(AuthResult::Fail),
|
||||
"error" => Ok(AuthResult::Error),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"pass" => Ok(AuthResult::Pass),
|
||||
"fail" => Ok(AuthResult::Fail),
|
||||
"error" => Ok(AuthResult::Error),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,78 +2,78 @@ use std::str::FromStr;
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Event {
|
||||
LinkAuth,
|
||||
LinkConnect,
|
||||
LinkDisconnect,
|
||||
LinkGreeting,
|
||||
LinkIdentify,
|
||||
LinkTls,
|
||||
TxBegin,
|
||||
TxMail,
|
||||
TxReset,
|
||||
TxRcpt,
|
||||
TxEnvelope,
|
||||
TxData,
|
||||
TxCommit,
|
||||
TxRollback,
|
||||
ProtocolClient,
|
||||
ProtocolServer,
|
||||
FilterResponse,
|
||||
FilterReport,
|
||||
Timeout,
|
||||
LinkAuth,
|
||||
LinkConnect,
|
||||
LinkDisconnect,
|
||||
LinkGreeting,
|
||||
LinkIdentify,
|
||||
LinkTls,
|
||||
TxBegin,
|
||||
TxMail,
|
||||
TxReset,
|
||||
TxRcpt,
|
||||
TxEnvelope,
|
||||
TxData,
|
||||
TxCommit,
|
||||
TxRollback,
|
||||
ProtocolClient,
|
||||
ProtocolServer,
|
||||
FilterResponse,
|
||||
FilterReport,
|
||||
Timeout,
|
||||
}
|
||||
|
||||
impl ToString for Event {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Event::LinkAuth => String::from("link-auth"),
|
||||
Event::LinkConnect => String::from("link-connect"),
|
||||
Event::LinkDisconnect => String::from("link-disconnect"),
|
||||
Event::LinkGreeting => String::from("link-greeting"),
|
||||
Event::LinkIdentify => String::from("link-identify"),
|
||||
Event::LinkTls => String::from("link-tls"),
|
||||
Event::TxBegin => String::from("tx-begin"),
|
||||
Event::TxMail => String::from("tx-mail"),
|
||||
Event::TxReset => String::from("tx-reset"),
|
||||
Event::TxRcpt => String::from("tx-rcpt"),
|
||||
Event::TxEnvelope => String::from("tx-envelope"),
|
||||
Event::TxData => String::from("tx-data"),
|
||||
Event::TxCommit => String::from("tx-commit"),
|
||||
Event::TxRollback => String::from("tx-rollback"),
|
||||
Event::ProtocolClient => String::from("protocol-client"),
|
||||
Event::ProtocolServer => String::from("protocol-server"),
|
||||
Event::FilterResponse => String::from("filter-response"),
|
||||
Event::FilterReport => String::from("filter-report"),
|
||||
Event::Timeout => String::from("timeout"),
|
||||
}
|
||||
}
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Event::LinkAuth => String::from("link-auth"),
|
||||
Event::LinkConnect => String::from("link-connect"),
|
||||
Event::LinkDisconnect => String::from("link-disconnect"),
|
||||
Event::LinkGreeting => String::from("link-greeting"),
|
||||
Event::LinkIdentify => String::from("link-identify"),
|
||||
Event::LinkTls => String::from("link-tls"),
|
||||
Event::TxBegin => String::from("tx-begin"),
|
||||
Event::TxMail => String::from("tx-mail"),
|
||||
Event::TxReset => String::from("tx-reset"),
|
||||
Event::TxRcpt => String::from("tx-rcpt"),
|
||||
Event::TxEnvelope => String::from("tx-envelope"),
|
||||
Event::TxData => String::from("tx-data"),
|
||||
Event::TxCommit => String::from("tx-commit"),
|
||||
Event::TxRollback => String::from("tx-rollback"),
|
||||
Event::ProtocolClient => String::from("protocol-client"),
|
||||
Event::ProtocolServer => String::from("protocol-server"),
|
||||
Event::FilterResponse => String::from("filter-response"),
|
||||
Event::FilterReport => String::from("filter-report"),
|
||||
Event::Timeout => String::from("timeout"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Event {
|
||||
type Err = ();
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"link-auth" => Ok(Event::LinkAuth),
|
||||
"link-connect" => Ok(Event::LinkConnect),
|
||||
"link-disconnect" => Ok(Event::LinkDisconnect),
|
||||
"link-greeting" => Ok(Event::LinkGreeting),
|
||||
"link-identify" => Ok(Event::LinkIdentify),
|
||||
"link-tls" => Ok(Event::LinkTls),
|
||||
"tx-begin" => Ok(Event::TxBegin),
|
||||
"tx-mail" => Ok(Event::TxMail),
|
||||
"tx-reset" => Ok(Event::TxReset),
|
||||
"tx-rcpt" => Ok(Event::TxRcpt),
|
||||
"tx-envelope" => Ok(Event::TxEnvelope),
|
||||
"tx-data" => Ok(Event::TxData),
|
||||
"tx-commit" => Ok(Event::TxCommit),
|
||||
"tx-rollback" => Ok(Event::TxRollback),
|
||||
"protocol-client" => Ok(Event::ProtocolClient),
|
||||
"protocol-server" => Ok(Event::ProtocolServer),
|
||||
"filter-response" => Ok(Event::FilterResponse),
|
||||
"filter-report" => Ok(Event::FilterReport),
|
||||
"timeout" => Ok(Event::Timeout),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"link-auth" => Ok(Event::LinkAuth),
|
||||
"link-connect" => Ok(Event::LinkConnect),
|
||||
"link-disconnect" => Ok(Event::LinkDisconnect),
|
||||
"link-greeting" => Ok(Event::LinkGreeting),
|
||||
"link-identify" => Ok(Event::LinkIdentify),
|
||||
"link-tls" => Ok(Event::LinkTls),
|
||||
"tx-begin" => Ok(Event::TxBegin),
|
||||
"tx-mail" => Ok(Event::TxMail),
|
||||
"tx-reset" => Ok(Event::TxReset),
|
||||
"tx-rcpt" => Ok(Event::TxRcpt),
|
||||
"tx-envelope" => Ok(Event::TxEnvelope),
|
||||
"tx-data" => Ok(Event::TxData),
|
||||
"tx-commit" => Ok(Event::TxCommit),
|
||||
"tx-rollback" => Ok(Event::TxRollback),
|
||||
"protocol-client" => Ok(Event::ProtocolClient),
|
||||
"protocol-server" => Ok(Event::ProtocolServer),
|
||||
"filter-response" => Ok(Event::FilterResponse),
|
||||
"filter-report" => Ok(Event::FilterReport),
|
||||
"timeout" => Ok(Event::Timeout),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,27 +2,27 @@ use std::str::FromStr;
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum FilterKind {
|
||||
Builtin,
|
||||
Proc,
|
||||
Builtin,
|
||||
Proc,
|
||||
}
|
||||
|
||||
impl ToString for FilterKind {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
FilterKind::Builtin => String::from("builtin"),
|
||||
FilterKind::Proc => String::from("proc"),
|
||||
}
|
||||
}
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
FilterKind::Builtin => String::from("builtin"),
|
||||
FilterKind::Proc => String::from("proc"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for FilterKind {
|
||||
type Err = ();
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"builtin" => Ok(FilterKind::Builtin),
|
||||
"proc" => Ok(FilterKind::Proc),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"builtin" => Ok(FilterKind::Builtin),
|
||||
"proc" => Ok(FilterKind::Proc),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,51 +2,51 @@ use std::str::FromStr;
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum FilterPhase {
|
||||
Connect,
|
||||
Helo,
|
||||
Ehlo,
|
||||
StartTls,
|
||||
Auth,
|
||||
MailFrom,
|
||||
RcptTo,
|
||||
Data,
|
||||
DataLine,
|
||||
Commit,
|
||||
Connect,
|
||||
Helo,
|
||||
Ehlo,
|
||||
StartTls,
|
||||
Auth,
|
||||
MailFrom,
|
||||
RcptTo,
|
||||
Data,
|
||||
DataLine,
|
||||
Commit,
|
||||
}
|
||||
|
||||
impl ToString for FilterPhase {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
FilterPhase::Connect => String::from("connect"),
|
||||
FilterPhase::Helo => String::from("helo"),
|
||||
FilterPhase::Ehlo => String::from("ehlo"),
|
||||
FilterPhase::StartTls => String::from("starttls"),
|
||||
FilterPhase::Auth => String::from("auth"),
|
||||
FilterPhase::MailFrom => String::from("mail-from"),
|
||||
FilterPhase::RcptTo => String::from("rcpt-to"),
|
||||
FilterPhase::Data => String::from("data"),
|
||||
FilterPhase::DataLine => String::from("data-line"),
|
||||
FilterPhase::Commit => String::from("commit"),
|
||||
}
|
||||
}
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
FilterPhase::Connect => String::from("connect"),
|
||||
FilterPhase::Helo => String::from("helo"),
|
||||
FilterPhase::Ehlo => String::from("ehlo"),
|
||||
FilterPhase::StartTls => String::from("starttls"),
|
||||
FilterPhase::Auth => String::from("auth"),
|
||||
FilterPhase::MailFrom => String::from("mail-from"),
|
||||
FilterPhase::RcptTo => String::from("rcpt-to"),
|
||||
FilterPhase::Data => String::from("data"),
|
||||
FilterPhase::DataLine => String::from("data-line"),
|
||||
FilterPhase::Commit => String::from("commit"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for FilterPhase {
|
||||
type Err = ();
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"connect" => Ok(FilterPhase::Connect),
|
||||
"helo" => Ok(FilterPhase::Helo),
|
||||
"ehlo" => Ok(FilterPhase::Ehlo),
|
||||
"starttls" => Ok(FilterPhase::StartTls),
|
||||
"auth" => Ok(FilterPhase::Auth),
|
||||
"mail-from" => Ok(FilterPhase::MailFrom),
|
||||
"rcpt-to" => Ok(FilterPhase::RcptTo),
|
||||
"data" => Ok(FilterPhase::Data),
|
||||
"data-line" => Ok(FilterPhase::DataLine),
|
||||
"commit" => Ok(FilterPhase::Commit),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"connect" => Ok(FilterPhase::Connect),
|
||||
"helo" => Ok(FilterPhase::Helo),
|
||||
"ehlo" => Ok(FilterPhase::Ehlo),
|
||||
"starttls" => Ok(FilterPhase::StartTls),
|
||||
"auth" => Ok(FilterPhase::Auth),
|
||||
"mail-from" => Ok(FilterPhase::MailFrom),
|
||||
"rcpt-to" => Ok(FilterPhase::RcptTo),
|
||||
"data" => Ok(FilterPhase::Data),
|
||||
"data-line" => Ok(FilterPhase::DataLine),
|
||||
"commit" => Ok(FilterPhase::Commit),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,23 +2,23 @@ use crate::SmtpStatusCode;
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum FilterResponse {
|
||||
Proceed,
|
||||
Junk,
|
||||
Reject(SmtpStatusCode),
|
||||
Disconnect(SmtpStatusCode),
|
||||
Rewrite(String),
|
||||
Report(String),
|
||||
Proceed,
|
||||
Junk,
|
||||
Reject(SmtpStatusCode),
|
||||
Disconnect(SmtpStatusCode),
|
||||
Rewrite(String),
|
||||
Report(String),
|
||||
}
|
||||
|
||||
impl ToString for FilterResponse {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
FilterResponse::Proceed => String::from("proceed"),
|
||||
FilterResponse::Junk => String::from("junk"),
|
||||
FilterResponse::Reject(e) => format!("reject|{}", e.to_string()),
|
||||
FilterResponse::Disconnect(e) => format!("disconnect|{}", e.to_string()),
|
||||
FilterResponse::Rewrite(s) => format!("rewrite|{}", s),
|
||||
FilterResponse::Report(s) => format!("report|{}", s),
|
||||
}
|
||||
}
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
FilterResponse::Proceed => String::from("proceed"),
|
||||
FilterResponse::Junk => String::from("junk"),
|
||||
FilterResponse::Reject(e) => format!("reject|{}", e.to_string()),
|
||||
FilterResponse::Disconnect(e) => format!("disconnect|{}", e.to_string()),
|
||||
FilterResponse::Rewrite(s) => format!("rewrite|{}", s),
|
||||
FilterResponse::Report(s) => format!("report|{}", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,30 +2,30 @@ use std::str::FromStr;
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum MailResult {
|
||||
Ok,
|
||||
PermFail,
|
||||
TempFail,
|
||||
Ok,
|
||||
PermFail,
|
||||
TempFail,
|
||||
}
|
||||
|
||||
impl ToString for MailResult {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
MailResult::Ok => String::from("ok"),
|
||||
MailResult::PermFail => String::from("permfail"),
|
||||
MailResult::TempFail => String::from("tempfail"),
|
||||
}
|
||||
}
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
MailResult::Ok => String::from("ok"),
|
||||
MailResult::PermFail => String::from("permfail"),
|
||||
MailResult::TempFail => String::from("tempfail"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for MailResult {
|
||||
type Err = ();
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"ok" => Ok(MailResult::Ok),
|
||||
"permfail" => Ok(MailResult::PermFail),
|
||||
"tempfail" => Ok(MailResult::TempFail),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"ok" => Ok(MailResult::Ok),
|
||||
"permfail" => Ok(MailResult::PermFail),
|
||||
"tempfail" => Ok(MailResult::TempFail),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,27 +2,27 @@ use std::str::FromStr;
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Method {
|
||||
Helo,
|
||||
Ehlo,
|
||||
Helo,
|
||||
Ehlo,
|
||||
}
|
||||
|
||||
impl ToString for Method {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Method::Helo => String::from("HELO"),
|
||||
Method::Ehlo => String::from("EHLO"),
|
||||
}
|
||||
}
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Method::Helo => String::from("HELO"),
|
||||
Method::Ehlo => String::from("EHLO"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Method {
|
||||
type Err = ();
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"HELO" => Ok(Method::Helo),
|
||||
"EHLO" => Ok(Method::Ehlo),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"HELO" => Ok(Method::Helo),
|
||||
"EHLO" => Ok(Method::Ehlo),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,116 +1,116 @@
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct SmtpStatusCode {
|
||||
pub number: usize,
|
||||
pub text: String,
|
||||
pub number: usize,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl SmtpStatusCode {
|
||||
pub fn from_number(error_number: usize) -> Self {
|
||||
match error_number {
|
||||
211 => SmtpStatusCode {
|
||||
number: 211,
|
||||
text: String::from("System status"),
|
||||
},
|
||||
220 => SmtpStatusCode {
|
||||
number: 220,
|
||||
text: String::from("Service ready"),
|
||||
},
|
||||
250 => SmtpStatusCode {
|
||||
number: 250,
|
||||
text: String::from("Requested mail action okay, completed"),
|
||||
},
|
||||
251 => SmtpStatusCode {
|
||||
number: 251,
|
||||
text: String::from("User not local; will forward"),
|
||||
},
|
||||
252 => SmtpStatusCode {
|
||||
number: 252,
|
||||
text: String::from(
|
||||
"Cannot verify the user, but it will try to deliver the message anyway",
|
||||
),
|
||||
},
|
||||
354 => SmtpStatusCode {
|
||||
number: 354,
|
||||
text: String::from("Start mail input"),
|
||||
},
|
||||
421 => SmtpStatusCode {
|
||||
number: 421,
|
||||
text: String::from("Service is unavailable because the server is shutting down"),
|
||||
},
|
||||
450 => SmtpStatusCode {
|
||||
number: 450,
|
||||
text: String::from("Requested mail action not taken: mailbox unavailable"),
|
||||
},
|
||||
451 => SmtpStatusCode {
|
||||
number: 451,
|
||||
text: String::from("Requested action aborted: local error in processing"),
|
||||
},
|
||||
452 => SmtpStatusCode {
|
||||
number: 452,
|
||||
text: String::from("Requested action not taken: insufficient system storage"),
|
||||
},
|
||||
455 => SmtpStatusCode {
|
||||
number: 455,
|
||||
text: String::from("Server unable to accommodate parameters"),
|
||||
},
|
||||
500 => SmtpStatusCode {
|
||||
number: 500,
|
||||
text: String::from("Syntax error, command unrecognized"),
|
||||
},
|
||||
501 => SmtpStatusCode {
|
||||
number: 501,
|
||||
text: String::from("Syntax error in parameters or arguments"),
|
||||
},
|
||||
502 => SmtpStatusCode {
|
||||
number: 502,
|
||||
text: String::from("Command not implemented"),
|
||||
},
|
||||
503 => SmtpStatusCode {
|
||||
number: 503,
|
||||
text: String::from("Bad sequence of commands"),
|
||||
},
|
||||
504 => SmtpStatusCode {
|
||||
number: 504,
|
||||
text: String::from("Command parameter is not implemented"),
|
||||
},
|
||||
521 => SmtpStatusCode {
|
||||
number: 521,
|
||||
text: String::from("Server does not accept mail"),
|
||||
},
|
||||
523 => SmtpStatusCode {
|
||||
number: 523,
|
||||
text: String::from("Encryption Needed"),
|
||||
},
|
||||
550 => SmtpStatusCode {
|
||||
number: 550,
|
||||
text: String::from("Requested action not taken: mailbox unavailable"),
|
||||
},
|
||||
552 => SmtpStatusCode {
|
||||
number: 552,
|
||||
text: String::from("Requested mail action aborted: exceeded storage allocation"),
|
||||
},
|
||||
553 => SmtpStatusCode {
|
||||
number: 553,
|
||||
text: String::from("Requested action not taken: mailbox name not allowed"),
|
||||
},
|
||||
554 => SmtpStatusCode {
|
||||
number: 554,
|
||||
text: String::from("Transaction has failed"),
|
||||
},
|
||||
556 => SmtpStatusCode {
|
||||
number: 556,
|
||||
text: String::from("Domain does not accept mail"),
|
||||
},
|
||||
nb => SmtpStatusCode {
|
||||
number: nb,
|
||||
text: String::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn from_number(error_number: usize) -> Self {
|
||||
match error_number {
|
||||
211 => SmtpStatusCode {
|
||||
number: 211,
|
||||
text: String::from("System status"),
|
||||
},
|
||||
220 => SmtpStatusCode {
|
||||
number: 220,
|
||||
text: String::from("Service ready"),
|
||||
},
|
||||
250 => SmtpStatusCode {
|
||||
number: 250,
|
||||
text: String::from("Requested mail action okay, completed"),
|
||||
},
|
||||
251 => SmtpStatusCode {
|
||||
number: 251,
|
||||
text: String::from("User not local; will forward"),
|
||||
},
|
||||
252 => SmtpStatusCode {
|
||||
number: 252,
|
||||
text: String::from(
|
||||
"Cannot verify the user, but it will try to deliver the message anyway",
|
||||
),
|
||||
},
|
||||
354 => SmtpStatusCode {
|
||||
number: 354,
|
||||
text: String::from("Start mail input"),
|
||||
},
|
||||
421 => SmtpStatusCode {
|
||||
number: 421,
|
||||
text: String::from("Service is unavailable because the server is shutting down"),
|
||||
},
|
||||
450 => SmtpStatusCode {
|
||||
number: 450,
|
||||
text: String::from("Requested mail action not taken: mailbox unavailable"),
|
||||
},
|
||||
451 => SmtpStatusCode {
|
||||
number: 451,
|
||||
text: String::from("Requested action aborted: local error in processing"),
|
||||
},
|
||||
452 => SmtpStatusCode {
|
||||
number: 452,
|
||||
text: String::from("Requested action not taken: insufficient system storage"),
|
||||
},
|
||||
455 => SmtpStatusCode {
|
||||
number: 455,
|
||||
text: String::from("Server unable to accommodate parameters"),
|
||||
},
|
||||
500 => SmtpStatusCode {
|
||||
number: 500,
|
||||
text: String::from("Syntax error, command unrecognized"),
|
||||
},
|
||||
501 => SmtpStatusCode {
|
||||
number: 501,
|
||||
text: String::from("Syntax error in parameters or arguments"),
|
||||
},
|
||||
502 => SmtpStatusCode {
|
||||
number: 502,
|
||||
text: String::from("Command not implemented"),
|
||||
},
|
||||
503 => SmtpStatusCode {
|
||||
number: 503,
|
||||
text: String::from("Bad sequence of commands"),
|
||||
},
|
||||
504 => SmtpStatusCode {
|
||||
number: 504,
|
||||
text: String::from("Command parameter is not implemented"),
|
||||
},
|
||||
521 => SmtpStatusCode {
|
||||
number: 521,
|
||||
text: String::from("Server does not accept mail"),
|
||||
},
|
||||
523 => SmtpStatusCode {
|
||||
number: 523,
|
||||
text: String::from("Encryption Needed"),
|
||||
},
|
||||
550 => SmtpStatusCode {
|
||||
number: 550,
|
||||
text: String::from("Requested action not taken: mailbox unavailable"),
|
||||
},
|
||||
552 => SmtpStatusCode {
|
||||
number: 552,
|
||||
text: String::from("Requested mail action aborted: exceeded storage allocation"),
|
||||
},
|
||||
553 => SmtpStatusCode {
|
||||
number: 553,
|
||||
text: String::from("Requested action not taken: mailbox name not allowed"),
|
||||
},
|
||||
554 => SmtpStatusCode {
|
||||
number: 554,
|
||||
text: String::from("Transaction has failed"),
|
||||
},
|
||||
556 => SmtpStatusCode {
|
||||
number: 556,
|
||||
text: String::from("Domain does not accept mail"),
|
||||
},
|
||||
nb => SmtpStatusCode {
|
||||
number: nb,
|
||||
text: String::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for SmtpStatusCode {
|
||||
fn to_string(&self) -> String {
|
||||
format!("{} {}", self.number, self.text)
|
||||
}
|
||||
fn to_string(&self) -> String {
|
||||
format!("{} {}", self.number, self.text)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,24 +2,24 @@ use std::str::FromStr;
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum SubSystem {
|
||||
SmtpIn,
|
||||
SmtpIn,
|
||||
}
|
||||
|
||||
impl ToString for SubSystem {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
SubSystem::SmtpIn => String::from("smtp-in"),
|
||||
}
|
||||
}
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
SubSystem::SmtpIn => String::from("smtp-in"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for SubSystem {
|
||||
type Err = ();
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"smtp-in" => Ok(SubSystem::SmtpIn),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"smtp-in" => Ok(SubSystem::SmtpIn),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct TimeVal {
|
||||
pub sec: i64,
|
||||
pub usec: i64,
|
||||
pub sec: i64,
|
||||
pub usec: i64,
|
||||
}
|
||||
|
||||
impl ToString for TimeVal {
|
||||
fn to_string(&self) -> String {
|
||||
format!("{}.{}", self.sec, self.usec)
|
||||
}
|
||||
fn to_string(&self) -> String {
|
||||
format!("{}.{}", self.sec, self.usec)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,25 +3,25 @@ use nom::Err;
|
|||
use pretty_hex::pretty_hex;
|
||||
|
||||
fn error_to_string(e: Error<&[u8]>) -> String {
|
||||
format!(
|
||||
"parsing error: {:?}: input:{}",
|
||||
e.code,
|
||||
get_pretty_hex(&e.input)
|
||||
)
|
||||
format!(
|
||||
"parsing error: {:?}: input:{}",
|
||||
e.code,
|
||||
get_pretty_hex(&e.input)
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn get_pretty_hex(input: &[u8]) -> String {
|
||||
let mut s = String::new();
|
||||
for l in pretty_hex(&input).split('\n') {
|
||||
s += &format!("\n{}", l);
|
||||
}
|
||||
s
|
||||
let mut s = String::new();
|
||||
for l in pretty_hex(&input).split('\n') {
|
||||
s += &format!("\n{}", l);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
pub(crate) fn nom_err_to_string(e: Err<Error<&[u8]>>) -> String {
|
||||
match e {
|
||||
Err::Incomplete(_) => e.to_string(),
|
||||
Err::Error(er) => error_to_string(er),
|
||||
Err::Failure(er) => error_to_string(er),
|
||||
}
|
||||
match e {
|
||||
Err::Incomplete(_) => e.to_string(),
|
||||
Err::Error(er) => error_to_string(er),
|
||||
Err::Failure(er) => error_to_string(er),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,253 +1,253 @@
|
|||
use crate::{
|
||||
Address, AuthResult, FilterEntry, FilterKind, FilterPhase, FilterResponse, MailResult, Method,
|
||||
ReportEntry,
|
||||
Address, AuthResult, FilterEntry, FilterKind, FilterPhase, FilterResponse, MailResult, Method,
|
||||
ReportEntry,
|
||||
};
|
||||
|
||||
pub trait Filter {
|
||||
fn on_filter_auth(&mut self, _entry: &FilterEntry, _auth: &str) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_auth(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_filter_auth(&mut self, _entry: &FilterEntry, _auth: &str) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_auth(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_filter_commit(&mut self, _entry: &FilterEntry) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_commit(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_filter_commit(&mut self, _entry: &FilterEntry) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_commit(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_filter_connect(
|
||||
&mut self,
|
||||
_entry: &FilterEntry,
|
||||
_rdns: &str,
|
||||
_fcrdns: &str,
|
||||
_src: &Address,
|
||||
_dest: &Address,
|
||||
) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_connect(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_filter_connect(
|
||||
&mut self,
|
||||
_entry: &FilterEntry,
|
||||
_rdns: &str,
|
||||
_fcrdns: &str,
|
||||
_src: &Address,
|
||||
_dest: &Address,
|
||||
) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_connect(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_filter_data(&mut self, _entry: &FilterEntry) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_data(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_filter_data(&mut self, _entry: &FilterEntry) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_data(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_filter_data_line(&mut self, _entry: &FilterEntry, _data_line: &[u8]) {}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_data_line(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_filter_data_line(&mut self, _entry: &FilterEntry, _data_line: &[u8]) {}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_data_line(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_filter_ehlo(&mut self, _entry: &FilterEntry, _identity: &str) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_ehlo(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_filter_ehlo(&mut self, _entry: &FilterEntry, _identity: &str) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_ehlo(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_filter_helo(&mut self, _entry: &FilterEntry, _identity: &str) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_helo(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_filter_helo(&mut self, _entry: &FilterEntry, _identity: &str) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_helo(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_filter_mail_from(&mut self, _entry: &FilterEntry, _address: &str) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_mail_from(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_filter_mail_from(&mut self, _entry: &FilterEntry, _address: &str) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_mail_from(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_filter_rcpt_to(&mut self, _entry: &FilterEntry, _address: &str) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_rcpt_to(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_filter_rcpt_to(&mut self, _entry: &FilterEntry, _address: &str) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_rcpt_to(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_filter_starttls(&mut self, _entry: &FilterEntry, _tls_string: &str) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_starttls(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_filter_starttls(&mut self, _entry: &FilterEntry, _tls_string: &str) -> FilterResponse {
|
||||
FilterResponse::Proceed
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_filter_starttls(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_link_auth(&mut self, _entry: &ReportEntry, _username: &str, _result: AuthResult) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_link_auth(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_link_auth(&mut self, _entry: &ReportEntry, _username: &str, _result: AuthResult) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_link_auth(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_link_connect(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_rdns: &str,
|
||||
_fcrdns: &str,
|
||||
_src: &Address,
|
||||
_dest: &Address,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_link_connect(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_link_connect(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_rdns: &str,
|
||||
_fcrdns: &str,
|
||||
_src: &Address,
|
||||
_dest: &Address,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_link_connect(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_link_disconnect(&mut self, _entry: &ReportEntry) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_link_disconnect(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_link_disconnect(&mut self, _entry: &ReportEntry) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_link_disconnect(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_link_greeting(&mut self, _entry: &ReportEntry, _hostname: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_link_greeting(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_link_greeting(&mut self, _entry: &ReportEntry, _hostname: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_link_greeting(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_link_identify(&mut self, _entry: &ReportEntry, _method: Method, _identity: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_link_identify(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_link_identify(&mut self, _entry: &ReportEntry, _method: Method, _identity: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_link_identify(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_link_tls(&mut self, _entry: &ReportEntry, _tls_string: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_link_tls(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_link_tls(&mut self, _entry: &ReportEntry, _tls_string: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_link_tls(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_tx_begin(&mut self, _entry: &ReportEntry, _message_id: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_begin(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_tx_begin(&mut self, _entry: &ReportEntry, _message_id: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_begin(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_tx_mail(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_message_id: &str,
|
||||
_result: MailResult,
|
||||
_address: &str,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_mail(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_tx_mail(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_message_id: &str,
|
||||
_result: MailResult,
|
||||
_address: &str,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_mail(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_tx_reset(&mut self, _entry: &ReportEntry, _message_id: &Option<String>) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_reset(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_tx_reset(&mut self, _entry: &ReportEntry, _message_id: &Option<String>) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_reset(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_tx_rcpt(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_message_id: &str,
|
||||
_result: MailResult,
|
||||
_address: &str,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_rcpt(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_tx_rcpt(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_message_id: &str,
|
||||
_result: MailResult,
|
||||
_address: &str,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_rcpt(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_tx_envelope(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_message_id: &str,
|
||||
_envelope_id: &str,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_envelope(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_tx_envelope(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_message_id: &str,
|
||||
_envelope_id: &str,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_envelope(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_tx_data(&mut self, _entry: &ReportEntry, _message_id: &str, _result: MailResult) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_data(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_tx_data(&mut self, _entry: &ReportEntry, _message_id: &str, _result: MailResult) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_data(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_tx_commit(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_message_id: &str,
|
||||
_message_size: usize,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_commit(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_tx_commit(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_message_id: &str,
|
||||
_message_size: usize,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_commit(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_tx_rollback(&mut self, _entry: &ReportEntry, _message_id: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_rollback(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_tx_rollback(&mut self, _entry: &ReportEntry, _message_id: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_tx_rollback(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_protocol_client(&mut self, _entry: &ReportEntry, _command: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_protocol_client(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_protocol_client(&mut self, _entry: &ReportEntry, _command: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_protocol_client(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_protocol_server(&mut self, _entry: &ReportEntry, _response: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_protocol_server(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_protocol_server(&mut self, _entry: &ReportEntry, _response: &str) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_protocol_server(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_filter_response(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_phase: FilterPhase,
|
||||
_response: &str,
|
||||
_param: &Option<String>,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_filter_response(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_filter_response(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_phase: FilterPhase,
|
||||
_response: &str,
|
||||
_param: &Option<String>,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_filter_response(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_filter_report(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_filter_kind: FilterKind,
|
||||
_name: &str,
|
||||
_message: &str,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_filter_report(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_filter_report(
|
||||
&mut self,
|
||||
_entry: &ReportEntry,
|
||||
_filter_kind: FilterKind,
|
||||
_name: &str,
|
||||
_message: &str,
|
||||
) {
|
||||
}
|
||||
#[doc(hidden)]
|
||||
fn has_report_filter_report(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn on_report_timeout(&mut self, _entry: &ReportEntry) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_timeout(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn on_report_timeout(&mut self, _entry: &ReportEntry) {}
|
||||
#[doc(hidden)]
|
||||
fn has_report_timeout(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,39 +3,39 @@ use std::io::{self, ErrorKind, Read};
|
|||
use std::sync::mpsc::Sender;
|
||||
|
||||
pub(crate) fn read_stdin(tx: &Sender<Vec<u8>>) {
|
||||
if let Err(e) = do_read_stdin(tx) {
|
||||
log::error!("{}", e);
|
||||
}
|
||||
if let Err(e) = do_read_stdin(tx) {
|
||||
log::error!("{}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn do_read_stdin(tx: &Sender<Vec<u8>>) -> Result<(), String> {
|
||||
let mut read_buffer: [u8; crate::BUFFER_SIZE] = [0; crate::BUFFER_SIZE];
|
||||
let mut line_buffer: Vec<u8> = Vec::with_capacity(crate::BUFFER_SIZE);
|
||||
let mut stdin = io::stdin();
|
||||
loop {
|
||||
read_buffer.copy_from_slice(&[0; crate::BUFFER_SIZE]);
|
||||
let len = match stdin.read(&mut read_buffer) {
|
||||
Ok(n) => n,
|
||||
Err(e) => match e.kind() {
|
||||
ErrorKind::Interrupted => {
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
return Err(e.to_string());
|
||||
}
|
||||
},
|
||||
};
|
||||
if len == 0 {
|
||||
return Err(String::from("unable to read on stdin"));
|
||||
}
|
||||
line_buffer.extend_from_slice(&read_buffer[..len]);
|
||||
while let Some(id) = line_buffer.iter().position(|i| *i == b'\n') {
|
||||
let pos = id + 1;
|
||||
let mut line = Vec::with_capacity(pos);
|
||||
line.extend_from_slice(&line_buffer[..pos]);
|
||||
log::trace!("new line:{}", get_pretty_hex(&line));
|
||||
tx.send(line).unwrap();
|
||||
line_buffer.drain(..pos);
|
||||
}
|
||||
}
|
||||
let mut read_buffer: [u8; crate::BUFFER_SIZE] = [0; crate::BUFFER_SIZE];
|
||||
let mut line_buffer: Vec<u8> = Vec::with_capacity(crate::BUFFER_SIZE);
|
||||
let mut stdin = io::stdin();
|
||||
loop {
|
||||
read_buffer.copy_from_slice(&[0; crate::BUFFER_SIZE]);
|
||||
let len = match stdin.read(&mut read_buffer) {
|
||||
Ok(n) => n,
|
||||
Err(e) => match e.kind() {
|
||||
ErrorKind::Interrupted => {
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
return Err(e.to_string());
|
||||
}
|
||||
},
|
||||
};
|
||||
if len == 0 {
|
||||
return Err(String::from("unable to read on stdin"));
|
||||
}
|
||||
line_buffer.extend_from_slice(&read_buffer[..len]);
|
||||
while let Some(id) = line_buffer.iter().position(|i| *i == b'\n') {
|
||||
let pos = id + 1;
|
||||
let mut line = Vec::with_capacity(pos);
|
||||
line.extend_from_slice(&line_buffer[..pos]);
|
||||
log::trace!("new line:{}", get_pretty_hex(&line));
|
||||
tx.send(line).unwrap();
|
||||
line_buffer.drain(..pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,19 +56,19 @@
|
|||
//! use opensmtpd_derive::register;
|
||||
//!
|
||||
//! struct MyCounter {
|
||||
//! nb: u64,
|
||||
//! nb: u64,
|
||||
//! }
|
||||
//!
|
||||
//! impl Filter for MyCounter {
|
||||
//! #[register]
|
||||
//! fn on_report_link_disconnect(&mut self, _entry: &ReportEntry) {
|
||||
//! self.nb + 1;
|
||||
//! }
|
||||
//! #[register]
|
||||
//! fn on_report_link_disconnect(&mut self, _entry: &ReportEntry) {
|
||||
//! self.nb + 1;
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut my_counter = MyCounter { nb: 0, };
|
||||
//! run_filter(&mut my_counter);
|
||||
//! let mut my_counter = MyCounter { nb: 0, };
|
||||
//! run_filter(&mut my_counter);
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
@ -88,23 +88,23 @@
|
|||
//! struct RmXOriginatingIp {}
|
||||
//!
|
||||
//! impl Filter for RmXOriginatingIp {
|
||||
//! #[register]
|
||||
//! fn on_filter_data_line(&mut self, entry: &FilterEntry, data_line: &[u8]) {
|
||||
//! if data_line.len() >= HEADER_LEN {
|
||||
//! let head_start = data_line[..HEADER_LEN].to_vec();
|
||||
//! if let Ok(s) = String::from_utf8(head_start) {
|
||||
//! if s.to_lowercase() == HEADER_NAME {
|
||||
//! return;
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! return_data_line(entry, data_line);
|
||||
//! }
|
||||
//! #[register]
|
||||
//! fn on_filter_data_line(&mut self, entry: &FilterEntry, data_line: &[u8]) {
|
||||
//! if data_line.len() >= HEADER_LEN {
|
||||
//! let head_start = data_line[..HEADER_LEN].to_vec();
|
||||
//! if let Ok(s) = String::from_utf8(head_start) {
|
||||
//! if s.to_lowercase() == HEADER_NAME {
|
||||
//! return;
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! return_data_line(entry, data_line);
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let mut my_filter = RmXOriginatingIp {};
|
||||
//! run_filter(&mut my_filter);
|
||||
//! let mut my_filter = RmXOriginatingIp {};
|
||||
//! run_filter(&mut my_filter);
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
@ -162,123 +162,123 @@ use std::thread;
|
|||
const BUFFER_SIZE: usize = 4096;
|
||||
|
||||
macro_rules! recv {
|
||||
($rx: ident) => {
|
||||
match $rx.recv() {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
log::error!("{}", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
($rx: ident) => {
|
||||
match $rx.recv() {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
log::error!("{}", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn run_filter<T>(user_object: &mut T)
|
||||
where
|
||||
T: Filter,
|
||||
T: Filter,
|
||||
{
|
||||
// IO init
|
||||
let (tx, rx) = channel::<Vec<u8>>();
|
||||
thread::spawn(move || {
|
||||
io::read_stdin(&tx);
|
||||
});
|
||||
// IO init
|
||||
let (tx, rx) = channel::<Vec<u8>>();
|
||||
thread::spawn(move || {
|
||||
io::read_stdin(&tx);
|
||||
});
|
||||
|
||||
// Handshake
|
||||
let mut handshake_buffer: Vec<u8> = Vec::with_capacity(BUFFER_SIZE);
|
||||
let handshake = loop {
|
||||
let buffer = recv!(rx);
|
||||
handshake_buffer.extend_from_slice(&buffer);
|
||||
if let Ok((_, handshake)) = parse_handshake(&handshake_buffer) {
|
||||
break handshake;
|
||||
}
|
||||
};
|
||||
handshake_reply(user_object, handshake.subsystem);
|
||||
// Handshake
|
||||
let mut handshake_buffer: Vec<u8> = Vec::with_capacity(BUFFER_SIZE);
|
||||
let handshake = loop {
|
||||
let buffer = recv!(rx);
|
||||
handshake_buffer.extend_from_slice(&buffer);
|
||||
if let Ok((_, handshake)) = parse_handshake(&handshake_buffer) {
|
||||
break handshake;
|
||||
}
|
||||
};
|
||||
handshake_reply(user_object, handshake.subsystem);
|
||||
|
||||
// Read and process input
|
||||
loop {
|
||||
let buffer = recv!(rx);
|
||||
if let Err(msg) = process::line(user_object, &buffer) {
|
||||
log::error!("{}", msg);
|
||||
}
|
||||
}
|
||||
// Read and process input
|
||||
loop {
|
||||
let buffer = recv!(rx);
|
||||
if let Err(msg) = process::line(user_object, &buffer) {
|
||||
log::error!("{}", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! handshake_register {
|
||||
($obj: ident, $func: ident, $subsystem: expr, $type: expr, $name: expr) => {
|
||||
if $obj.$func() {
|
||||
println!("register|{}|{}|{}", $type, $subsystem.to_string(), $name);
|
||||
log::trace!(
|
||||
"{} {} for {} registered",
|
||||
$type,
|
||||
$name,
|
||||
$subsystem.to_string()
|
||||
);
|
||||
}
|
||||
};
|
||||
($obj: ident, $func: ident, $subsystem: expr, $type: expr, $name: expr) => {
|
||||
if $obj.$func() {
|
||||
println!("register|{}|{}|{}", $type, $subsystem.to_string(), $name);
|
||||
log::trace!(
|
||||
"{} {} for {} registered",
|
||||
$type,
|
||||
$name,
|
||||
$subsystem.to_string()
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn handshake_reply<T>(obj: &mut T, ss: SubSystem)
|
||||
where
|
||||
T: Filter,
|
||||
T: Filter,
|
||||
{
|
||||
// Filters
|
||||
handshake_register!(obj, has_filter_auth, ss, "filter", "auth");
|
||||
handshake_register!(obj, has_filter_commit, ss, "filter", "commit");
|
||||
handshake_register!(obj, has_filter_connect, ss, "filter", "connect");
|
||||
handshake_register!(obj, has_filter_data, ss, "filter", "data");
|
||||
handshake_register!(obj, has_filter_data_line, ss, "filter", "data-line");
|
||||
handshake_register!(obj, has_filter_ehlo, ss, "filter", "ehlo");
|
||||
handshake_register!(obj, has_filter_helo, ss, "filter", "helo");
|
||||
handshake_register!(obj, has_filter_mail_from, ss, "filter", "mail-from");
|
||||
handshake_register!(obj, has_filter_rcpt_to, ss, "filter", "rcpt-to");
|
||||
handshake_register!(obj, has_filter_starttls, ss, "filter", "starttls");
|
||||
// Filters
|
||||
handshake_register!(obj, has_filter_auth, ss, "filter", "auth");
|
||||
handshake_register!(obj, has_filter_commit, ss, "filter", "commit");
|
||||
handshake_register!(obj, has_filter_connect, ss, "filter", "connect");
|
||||
handshake_register!(obj, has_filter_data, ss, "filter", "data");
|
||||
handshake_register!(obj, has_filter_data_line, ss, "filter", "data-line");
|
||||
handshake_register!(obj, has_filter_ehlo, ss, "filter", "ehlo");
|
||||
handshake_register!(obj, has_filter_helo, ss, "filter", "helo");
|
||||
handshake_register!(obj, has_filter_mail_from, ss, "filter", "mail-from");
|
||||
handshake_register!(obj, has_filter_rcpt_to, ss, "filter", "rcpt-to");
|
||||
handshake_register!(obj, has_filter_starttls, ss, "filter", "starttls");
|
||||
|
||||
// Reports
|
||||
handshake_register!(obj, has_report_link_auth, ss, "report", "link-auth");
|
||||
handshake_register!(obj, has_report_link_connect, ss, "report", "link-connect");
|
||||
handshake_register!(
|
||||
obj,
|
||||
has_report_link_disconnect,
|
||||
ss,
|
||||
"report",
|
||||
"link-disconnect"
|
||||
);
|
||||
handshake_register!(obj, has_report_link_greeting, ss, "report", "link-greeting");
|
||||
handshake_register!(obj, has_report_link_identify, ss, "report", "link-identify");
|
||||
handshake_register!(obj, has_report_link_tls, ss, "report", "link-tls");
|
||||
handshake_register!(obj, has_report_tx_begin, ss, "report", "tx-begin");
|
||||
handshake_register!(obj, has_report_tx_mail, ss, "report", "tx-mail");
|
||||
handshake_register!(obj, has_report_tx_reset, ss, "report", "tx-reset");
|
||||
handshake_register!(obj, has_report_tx_rcpt, ss, "report", "tx-rcpt");
|
||||
handshake_register!(obj, has_report_tx_envelope, ss, "report", "tx-envelope");
|
||||
handshake_register!(obj, has_report_tx_data, ss, "report", "tx-data");
|
||||
handshake_register!(obj, has_report_tx_commit, ss, "report", "tx-commit");
|
||||
handshake_register!(obj, has_report_tx_rollback, ss, "report", "tx-rollback");
|
||||
handshake_register!(
|
||||
obj,
|
||||
has_report_protocol_client,
|
||||
ss,
|
||||
"report",
|
||||
"protocol-client"
|
||||
);
|
||||
handshake_register!(
|
||||
obj,
|
||||
has_report_protocol_server,
|
||||
ss,
|
||||
"report",
|
||||
"protocol-server"
|
||||
);
|
||||
handshake_register!(
|
||||
obj,
|
||||
has_report_filter_response,
|
||||
ss,
|
||||
"report",
|
||||
"filter-response"
|
||||
);
|
||||
handshake_register!(obj, has_report_filter_report, ss, "report", "filter-report");
|
||||
handshake_register!(obj, has_report_timeout, ss, "report", "timeout");
|
||||
// Reports
|
||||
handshake_register!(obj, has_report_link_auth, ss, "report", "link-auth");
|
||||
handshake_register!(obj, has_report_link_connect, ss, "report", "link-connect");
|
||||
handshake_register!(
|
||||
obj,
|
||||
has_report_link_disconnect,
|
||||
ss,
|
||||
"report",
|
||||
"link-disconnect"
|
||||
);
|
||||
handshake_register!(obj, has_report_link_greeting, ss, "report", "link-greeting");
|
||||
handshake_register!(obj, has_report_link_identify, ss, "report", "link-identify");
|
||||
handshake_register!(obj, has_report_link_tls, ss, "report", "link-tls");
|
||||
handshake_register!(obj, has_report_tx_begin, ss, "report", "tx-begin");
|
||||
handshake_register!(obj, has_report_tx_mail, ss, "report", "tx-mail");
|
||||
handshake_register!(obj, has_report_tx_reset, ss, "report", "tx-reset");
|
||||
handshake_register!(obj, has_report_tx_rcpt, ss, "report", "tx-rcpt");
|
||||
handshake_register!(obj, has_report_tx_envelope, ss, "report", "tx-envelope");
|
||||
handshake_register!(obj, has_report_tx_data, ss, "report", "tx-data");
|
||||
handshake_register!(obj, has_report_tx_commit, ss, "report", "tx-commit");
|
||||
handshake_register!(obj, has_report_tx_rollback, ss, "report", "tx-rollback");
|
||||
handshake_register!(
|
||||
obj,
|
||||
has_report_protocol_client,
|
||||
ss,
|
||||
"report",
|
||||
"protocol-client"
|
||||
);
|
||||
handshake_register!(
|
||||
obj,
|
||||
has_report_protocol_server,
|
||||
ss,
|
||||
"report",
|
||||
"protocol-server"
|
||||
);
|
||||
handshake_register!(
|
||||
obj,
|
||||
has_report_filter_response,
|
||||
ss,
|
||||
"report",
|
||||
"filter-response"
|
||||
);
|
||||
handshake_register!(obj, has_report_filter_report, ss, "report", "filter-report");
|
||||
handshake_register!(obj, has_report_timeout, ss, "report", "timeout");
|
||||
|
||||
// Ready
|
||||
println!("register|ready");
|
||||
log::trace!("register ready");
|
||||
// Ready
|
||||
println!("register|ready");
|
||||
log::trace!("register ready");
|
||||
}
|
||||
|
|
|
@ -10,126 +10,126 @@ 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 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 version: String,
|
||||
pub timestamp: TimeVal,
|
||||
pub subsystem: SubSystem,
|
||||
pub phase: FilterPhase,
|
||||
pub session_id: String,
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
pub(crate) enum EntryOption {
|
||||
Report(ReportEntry),
|
||||
Filter(FilterEntry),
|
||||
Report(ReportEntry),
|
||||
Filter(FilterEntry),
|
||||
}
|
||||
|
||||
pub(crate) fn parse_entry(input: &[u8]) -> IResult<&[u8], EntryOption> {
|
||||
let (input, entry) = alt((parse_report_entry_meta, parse_filter_entry_meta))(input)?;
|
||||
Ok((input, entry))
|
||||
let (input, entry) = alt((parse_report_entry_meta, parse_filter_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)))
|
||||
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)))
|
||||
let (input, _) = tag("filter")(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, entry) = parse_filter_entry(input)?;
|
||||
Ok((input, EntryOption::Filter(entry)))
|
||||
}
|
||||
|
||||
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))
|
||||
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))
|
||||
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_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))
|
||||
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::*;
|
||||
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"));
|
||||
}
|
||||
#[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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::{
|
||||
parse_data_structure, parse_delimiter, parse_eol, parse_string_parameter, parse_usize,
|
||||
parse_data_structure, parse_delimiter, parse_eol, parse_string_parameter, parse_usize,
|
||||
};
|
||||
use crate::SubSystem;
|
||||
use nom::bytes::streaming::tag;
|
||||
|
@ -7,116 +7,116 @@ use nom::IResult;
|
|||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Handshake {
|
||||
pub(crate) smtpd_version: String,
|
||||
pub(crate) smtp_session_timeout: usize,
|
||||
pub(crate) subsystem: SubSystem,
|
||||
pub(crate) smtpd_version: String,
|
||||
pub(crate) smtp_session_timeout: usize,
|
||||
pub(crate) subsystem: SubSystem,
|
||||
}
|
||||
|
||||
pub(crate) fn parse_handshake(input: &[u8]) -> IResult<&[u8], Handshake> {
|
||||
let (input, smtpd_version) = parse_smtpd_version(input)?;
|
||||
let (input, smtp_session_timeout) = parse_smtp_session_timeout(input)?;
|
||||
let (input, subsystem) = parse_subsystem(input)?;
|
||||
let (input, _) = parse_ready(input)?;
|
||||
let handshake = Handshake {
|
||||
smtpd_version,
|
||||
smtp_session_timeout,
|
||||
subsystem,
|
||||
};
|
||||
Ok((input, handshake))
|
||||
let (input, smtpd_version) = parse_smtpd_version(input)?;
|
||||
let (input, smtp_session_timeout) = parse_smtp_session_timeout(input)?;
|
||||
let (input, subsystem) = parse_subsystem(input)?;
|
||||
let (input, _) = parse_ready(input)?;
|
||||
let handshake = Handshake {
|
||||
smtpd_version,
|
||||
smtp_session_timeout,
|
||||
subsystem,
|
||||
};
|
||||
Ok((input, handshake))
|
||||
}
|
||||
|
||||
fn parse_smtpd_version(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_config_initial(input)?;
|
||||
let (input, _) = tag("smtpd-version")(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, version) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, version))
|
||||
let (input, _) = parse_config_initial(input)?;
|
||||
let (input, _) = tag("smtpd-version")(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, version) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, version))
|
||||
}
|
||||
|
||||
fn parse_smtp_session_timeout(input: &[u8]) -> IResult<&[u8], usize> {
|
||||
let (input, _) = parse_config_initial(input)?;
|
||||
let (input, _) = tag("smtp-session-timeout")(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, timeout) = parse_usize(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, timeout))
|
||||
let (input, _) = parse_config_initial(input)?;
|
||||
let (input, _) = tag("smtp-session-timeout")(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, timeout) = parse_usize(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, timeout))
|
||||
}
|
||||
|
||||
fn parse_subsystem(input: &[u8]) -> IResult<&[u8], SubSystem> {
|
||||
let (input, _) = parse_config_initial(input)?;
|
||||
let (input, _) = tag("subsystem")(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, subsystem) = parse_data_structure::<SubSystem>(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, subsystem))
|
||||
let (input, _) = parse_config_initial(input)?;
|
||||
let (input, _) = tag("subsystem")(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, subsystem) = parse_data_structure::<SubSystem>(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, subsystem))
|
||||
}
|
||||
|
||||
fn parse_ready(input: &[u8]) -> IResult<&[u8], ()> {
|
||||
let (input, _) = parse_config_initial(input)?;
|
||||
let (input, _) = tag("ready")(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, ()))
|
||||
let (input, _) = parse_config_initial(input)?;
|
||||
let (input, _) = tag("ready")(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, ()))
|
||||
}
|
||||
|
||||
fn parse_config_initial(input: &[u8]) -> IResult<&[u8], ()> {
|
||||
let (input, _) = tag("config")(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
Ok((input, ()))
|
||||
let (input, _) = tag("config")(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
Ok((input, ()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::parse_handshake;
|
||||
use crate::SubSystem;
|
||||
use super::parse_handshake;
|
||||
use crate::SubSystem;
|
||||
|
||||
#[test]
|
||||
fn test_valid_handshake_nl() {
|
||||
let input = b"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready\n";
|
||||
let r = parse_handshake(input);
|
||||
assert!(r.is_ok());
|
||||
let (r, h) = r.unwrap();
|
||||
assert_eq!(r, b"");
|
||||
assert_eq!(h.smtpd_version, "6.6.1");
|
||||
assert_eq!(h.smtp_session_timeout, 300);
|
||||
assert_eq!(h.subsystem, SubSystem::SmtpIn);
|
||||
}
|
||||
#[test]
|
||||
fn test_valid_handshake_nl() {
|
||||
let input = b"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready\n";
|
||||
let r = parse_handshake(input);
|
||||
assert!(r.is_ok());
|
||||
let (r, h) = r.unwrap();
|
||||
assert_eq!(r, b"");
|
||||
assert_eq!(h.smtpd_version, "6.6.1");
|
||||
assert_eq!(h.smtp_session_timeout, 300);
|
||||
assert_eq!(h.subsystem, SubSystem::SmtpIn);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_valid_handshake_crnl() {
|
||||
let input = b"config|smtpd-version|6.6.1\r\nconfig|smtp-session-timeout|300\r\nconfig|subsystem|smtp-in\r\nconfig|ready\r\n";
|
||||
let r = parse_handshake(input);
|
||||
assert!(r.is_ok());
|
||||
let (r, h) = r.unwrap();
|
||||
assert_eq!(r, b"");
|
||||
assert_eq!(h.smtpd_version, "6.6.1");
|
||||
assert_eq!(h.smtp_session_timeout, 300);
|
||||
assert_eq!(h.subsystem, SubSystem::SmtpIn);
|
||||
}
|
||||
#[test]
|
||||
fn test_valid_handshake_crnl() {
|
||||
let input = b"config|smtpd-version|6.6.1\r\nconfig|smtp-session-timeout|300\r\nconfig|subsystem|smtp-in\r\nconfig|ready\r\n";
|
||||
let r = parse_handshake(input);
|
||||
assert!(r.is_ok());
|
||||
let (r, h) = r.unwrap();
|
||||
assert_eq!(r, b"");
|
||||
assert_eq!(h.smtpd_version, "6.6.1");
|
||||
assert_eq!(h.smtp_session_timeout, 300);
|
||||
assert_eq!(h.subsystem, SubSystem::SmtpIn);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_valid_handshake_over() {
|
||||
let input = b"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready\nplop";
|
||||
let r = parse_handshake(input);
|
||||
assert!(r.is_ok());
|
||||
let (r, h) = r.unwrap();
|
||||
assert_eq!(r, b"plop");
|
||||
assert_eq!(h.smtpd_version, "6.6.1");
|
||||
assert_eq!(h.smtp_session_timeout, 300);
|
||||
assert_eq!(h.subsystem, SubSystem::SmtpIn);
|
||||
}
|
||||
#[test]
|
||||
fn test_valid_handshake_over() {
|
||||
let input = b"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready\nplop";
|
||||
let r = parse_handshake(input);
|
||||
assert!(r.is_ok());
|
||||
let (r, h) = r.unwrap();
|
||||
assert_eq!(r, b"plop");
|
||||
assert_eq!(h.smtpd_version, "6.6.1");
|
||||
assert_eq!(h.smtp_session_timeout, 300);
|
||||
assert_eq!(h.subsystem, SubSystem::SmtpIn);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_handshakes() {
|
||||
let test_vectors = vec![
|
||||
"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|\nconfig|subsystem|smtp-in\nconfig|ready\n",
|
||||
"config|smtp-session-timeout|300\nconfig|smtpd-version|6.6.1\nconfig|subsystem|smtp-in\nconfig|ready\n",
|
||||
"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready",
|
||||
"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready\r",
|
||||
];
|
||||
for input in test_vectors {
|
||||
let r = parse_handshake(input.as_bytes());
|
||||
assert!(r.is_err());
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_invalid_handshakes() {
|
||||
let test_vectors = vec![
|
||||
"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|\nconfig|subsystem|smtp-in\nconfig|ready\n",
|
||||
"config|smtp-session-timeout|300\nconfig|smtpd-version|6.6.1\nconfig|subsystem|smtp-in\nconfig|ready\n",
|
||||
"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready",
|
||||
"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready\r",
|
||||
];
|
||||
for input in test_vectors {
|
||||
let r = parse_handshake(input.as_bytes());
|
||||
assert!(r.is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,58 +9,58 @@ use nom::IResult;
|
|||
use std::str::FromStr;
|
||||
|
||||
fn is_body_char(c: u8) -> bool {
|
||||
!(c as char).is_control()
|
||||
!(c as char).is_control()
|
||||
}
|
||||
|
||||
fn is_parameter_char(c: u8) -> bool {
|
||||
is_body_char(c) && (c as char) != '|'
|
||||
is_body_char(c) && (c as char) != '|'
|
||||
}
|
||||
|
||||
fn parse_string_parameter(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, s) = take_while1(is_parameter_char)(input)?;
|
||||
Ok((input, String::from_utf8(s.to_vec()).unwrap()))
|
||||
let (input, s) = take_while1(is_parameter_char)(input)?;
|
||||
Ok((input, String::from_utf8(s.to_vec()).unwrap()))
|
||||
}
|
||||
|
||||
fn parse_data_structure<T>(input: &[u8]) -> IResult<&[u8], T>
|
||||
where
|
||||
T: FromStr,
|
||||
T: FromStr,
|
||||
{
|
||||
map_res(take_while1(is_parameter_char), |s: &[u8]| {
|
||||
T::from_str(&String::from_utf8_lossy(s))
|
||||
})(input)
|
||||
map_res(take_while1(is_parameter_char), |s: &[u8]| {
|
||||
T::from_str(&String::from_utf8_lossy(s))
|
||||
})(input)
|
||||
}
|
||||
|
||||
fn parse_delimiter(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||
tag("|")(input)
|
||||
tag("|")(input)
|
||||
}
|
||||
|
||||
fn parse_eol(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||
alt((tag("\r\n"), tag("\n")))(input)
|
||||
alt((tag("\r\n"), tag("\n")))(input)
|
||||
}
|
||||
|
||||
fn parse_usize(input: &[u8]) -> IResult<&[u8], usize> {
|
||||
map_res(take_while1(|c| (c as char).is_ascii_digit()), |s| {
|
||||
usize::from_str_radix(&String::from_utf8_lossy(s), 10)
|
||||
})(input)
|
||||
map_res(take_while1(|c| (c as char).is_ascii_digit()), |s| {
|
||||
usize::from_str_radix(&String::from_utf8_lossy(s), 10)
|
||||
})(input)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::is_parameter_char;
|
||||
use super::is_parameter_char;
|
||||
|
||||
#[test]
|
||||
fn test_valid_parameter_char() {
|
||||
let char_lst = "a0.:-_/";
|
||||
for c in char_lst.bytes() {
|
||||
assert!(is_parameter_char(c));
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_valid_parameter_char() {
|
||||
let char_lst = "a0.:-_/";
|
||||
for c in char_lst.bytes() {
|
||||
assert!(is_parameter_char(c));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_parameter_char() {
|
||||
let char_lst = "|\n";
|
||||
for c in char_lst.bytes() {
|
||||
assert!(!is_parameter_char(c));
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_invalid_parameter_char() {
|
||||
let char_lst = "|\n";
|
||||
for c in char_lst.bytes() {
|
||||
assert!(!is_parameter_char(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{
|
||||
is_body_char, is_parameter_char, parse_data_structure, parse_delimiter, parse_eol,
|
||||
parse_string_parameter, parse_usize,
|
||||
is_body_char, is_parameter_char, parse_data_structure, parse_delimiter, parse_eol,
|
||||
parse_string_parameter, parse_usize,
|
||||
};
|
||||
use crate::{Address, AuthResult, FilterKind, FilterPhase, MailResult, Method};
|
||||
use nom::branch::alt;
|
||||
|
@ -11,338 +11,338 @@ use std::net::SocketAddr;
|
|||
use std::path::PathBuf;
|
||||
|
||||
pub(crate) fn parse_filter_auth(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_filter_connect(
|
||||
input: &[u8],
|
||||
input: &[u8],
|
||||
) -> IResult<&[u8], (String, String, Address, Address)> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, rdns) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, fcrdns) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, src) = parse_address(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, dest) = parse_address(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (rdns, fcrdns, src, dest)))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, rdns) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, fcrdns) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, src) = parse_address(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, dest) = parse_address(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (rdns, fcrdns, src, dest)))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_filter_data_line(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = take_while(is_body_char)(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = take_while(is_body_char)(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_filter_ehlo(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_filter_helo(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_filter_mail_from(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_filter_rcpt_to(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_filter_starttls(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, s))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_link_auth(input: &[u8]) -> IResult<&[u8], (String, AuthResult)> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, username) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, result) = parse_data_structure::<AuthResult>(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (username, result)))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, username) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, result) = parse_data_structure::<AuthResult>(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (username, result)))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_link_connect(
|
||||
input: &[u8],
|
||||
input: &[u8],
|
||||
) -> IResult<&[u8], (String, String, Address, Address)> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, rdns) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, fcrdns) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, src) = parse_address(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, dest) = parse_address(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (rdns, fcrdns, src, dest)))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, rdns) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, fcrdns) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, src) = parse_address(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, dest) = parse_address(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (rdns, fcrdns, src, dest)))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_link_greeting(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, hostname) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, hostname))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, hostname) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, hostname))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_link_identify(input: &[u8]) -> IResult<&[u8], (Method, String)> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, method) = parse_data_structure::<Method>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, identity) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (method, identity)))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, method) = parse_data_structure::<Method>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, identity) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (method, identity)))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_link_tls(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, tls_string) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, tls_string))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, tls_string) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, tls_string))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_tx_begin(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, id))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, id))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_tx_mail(input: &[u8]) -> IResult<&[u8], (String, MailResult, String)> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, result) = parse_data_structure::<MailResult>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, addr) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (id, result, addr)))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, result) = parse_data_structure::<MailResult>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, addr) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (id, result, addr)))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_tx_reset(input: &[u8]) -> IResult<&[u8], Option<String>> {
|
||||
let (input, id) = opt(parse_tx_reset_opt)(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, id))
|
||||
let (input, id) = opt(parse_tx_reset_opt)(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, id))
|
||||
}
|
||||
|
||||
fn parse_tx_reset_opt(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
Ok((input, id))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
Ok((input, id))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_tx_rcpt(input: &[u8]) -> IResult<&[u8], (String, MailResult, String)> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, result) = parse_data_structure::<MailResult>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, addr) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (id, result, addr)))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, result) = parse_data_structure::<MailResult>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, addr) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (id, result, addr)))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_tx_envelope(input: &[u8]) -> IResult<&[u8], (String, String)> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, msg) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, env) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (msg, env)))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, msg) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, env) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (msg, env)))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_tx_data(input: &[u8]) -> IResult<&[u8], (String, MailResult)> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, result) = parse_data_structure::<MailResult>(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (id, result)))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, result) = parse_data_structure::<MailResult>(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (id, result)))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_tx_commit(input: &[u8]) -> IResult<&[u8], (String, usize)> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_usize(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (id, s)))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, s) = parse_usize(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (id, s)))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_tx_rollback(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, id))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, id) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, id))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_protocol_client(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, cmd) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, cmd))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, cmd) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, cmd))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_protocol_server(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, res) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, res))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, res) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, res))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_filter_response(
|
||||
input: &[u8],
|
||||
input: &[u8],
|
||||
) -> IResult<&[u8], (FilterPhase, String, Option<String>)> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, phase) = parse_data_structure::<FilterPhase>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, res) = parse_string_parameter(input)?;
|
||||
let (input, param) = opt(parse_filter_response_opt)(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (phase, res, param)))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, phase) = parse_data_structure::<FilterPhase>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, res) = parse_string_parameter(input)?;
|
||||
let (input, param) = opt(parse_filter_response_opt)(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (phase, res, param)))
|
||||
}
|
||||
|
||||
fn parse_filter_response_opt(input: &[u8]) -> IResult<&[u8], String> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
parse_string_parameter(input)
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
parse_string_parameter(input)
|
||||
}
|
||||
|
||||
pub(crate) fn parse_report_filter_report(
|
||||
input: &[u8],
|
||||
input: &[u8],
|
||||
) -> IResult<&[u8], (FilterKind, String, String)> {
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, kind) = parse_data_structure::<FilterKind>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, name) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, message) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (kind, name, message)))
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, kind) = parse_data_structure::<FilterKind>(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, name) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_delimiter(input)?;
|
||||
let (input, message) = parse_string_parameter(input)?;
|
||||
let (input, _) = parse_eol(input)?;
|
||||
Ok((input, (kind, name, message)))
|
||||
}
|
||||
|
||||
fn parse_address(input: &[u8]) -> IResult<&[u8], Address> {
|
||||
alt((parse_unix_socket, parse_socketaddr))(input)
|
||||
alt((parse_unix_socket, parse_socketaddr))(input)
|
||||
}
|
||||
|
||||
fn parse_socketaddr(input: &[u8]) -> IResult<&[u8], Address> {
|
||||
map_res(
|
||||
take_while1(is_parameter_char),
|
||||
|s: &[u8]| -> Result<Address, String> {
|
||||
let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?;
|
||||
let addr = s.parse::<SocketAddr>().map_err(|e| e.to_string())?;
|
||||
Ok(Address::Ip(addr))
|
||||
},
|
||||
)(input)
|
||||
map_res(
|
||||
take_while1(is_parameter_char),
|
||||
|s: &[u8]| -> Result<Address, String> {
|
||||
let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?;
|
||||
let addr = s.parse::<SocketAddr>().map_err(|e| e.to_string())?;
|
||||
Ok(Address::Ip(addr))
|
||||
},
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn parse_unix_socket(input: &[u8]) -> IResult<&[u8], Address> {
|
||||
let (input, _) = tag("unix:")(input)?;
|
||||
map_res(
|
||||
take_while1(is_parameter_char),
|
||||
|s: &[u8]| -> Result<Address, String> {
|
||||
let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?;
|
||||
let addr = s.parse::<PathBuf>().map_err(|e| e.to_string())?;
|
||||
Ok(Address::UnixSocket(addr))
|
||||
},
|
||||
)(input)
|
||||
let (input, _) = tag("unix:")(input)?;
|
||||
map_res(
|
||||
take_while1(is_parameter_char),
|
||||
|s: &[u8]| -> Result<Address, String> {
|
||||
let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?;
|
||||
let addr = s.parse::<PathBuf>().map_err(|e| e.to_string())?;
|
||||
Ok(Address::UnixSocket(addr))
|
||||
},
|
||||
)(input)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
use std::path::Path;
|
||||
use super::*;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
fn test_ipv4_port() {
|
||||
let res = parse_address(b"199.185.178.25:33174|");
|
||||
assert!(res.is_ok());
|
||||
let (i, addr) = res.unwrap();
|
||||
assert_eq!(i, b"|");
|
||||
match addr {
|
||||
Address::Ip(addr) => {
|
||||
assert!(addr.is_ipv4());
|
||||
assert_eq!(addr.port(), 33174);
|
||||
assert_eq!(addr.ip(), IpAddr::V4(Ipv4Addr::new(199, 185, 178, 25)));
|
||||
}
|
||||
Address::UnixSocket(_) => assert!(false),
|
||||
};
|
||||
}
|
||||
#[test]
|
||||
fn test_ipv4_port() {
|
||||
let res = parse_address(b"199.185.178.25:33174|");
|
||||
assert!(res.is_ok());
|
||||
let (i, addr) = res.unwrap();
|
||||
assert_eq!(i, b"|");
|
||||
match addr {
|
||||
Address::Ip(addr) => {
|
||||
assert!(addr.is_ipv4());
|
||||
assert_eq!(addr.port(), 33174);
|
||||
assert_eq!(addr.ip(), IpAddr::V4(Ipv4Addr::new(199, 185, 178, 25)));
|
||||
}
|
||||
Address::UnixSocket(_) => assert!(false),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ipv6_port() {
|
||||
let res = parse_address(b"[2001:db8::42]:33174\n");
|
||||
assert!(res.is_ok());
|
||||
let (i, addr) = res.unwrap();
|
||||
assert_eq!(i, b"\n");
|
||||
match addr {
|
||||
Address::Ip(addr) => {
|
||||
assert!(addr.is_ipv6());
|
||||
assert_eq!(addr.port(), 33174);
|
||||
assert_eq!(
|
||||
addr.ip(),
|
||||
IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0x42))
|
||||
);
|
||||
}
|
||||
Address::UnixSocket(_) => assert!(false),
|
||||
};
|
||||
}
|
||||
#[test]
|
||||
fn test_ipv6_port() {
|
||||
let res = parse_address(b"[2001:db8::42]:33174\n");
|
||||
assert!(res.is_ok());
|
||||
let (i, addr) = res.unwrap();
|
||||
assert_eq!(i, b"\n");
|
||||
match addr {
|
||||
Address::Ip(addr) => {
|
||||
assert!(addr.is_ipv6());
|
||||
assert_eq!(addr.port(), 33174);
|
||||
assert_eq!(
|
||||
addr.ip(),
|
||||
IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0x42))
|
||||
);
|
||||
}
|
||||
Address::UnixSocket(_) => assert!(false),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unix_socket() {
|
||||
let res = parse_address(b"unix:/var/something.sock|");
|
||||
assert!(res.is_ok());
|
||||
let (i, addr) = res.unwrap();
|
||||
assert_eq!(i, b"|");
|
||||
match addr {
|
||||
Address::UnixSocket(addr) => {
|
||||
assert_eq!(addr, Path::new("/var/something.sock").to_path_buf());
|
||||
}
|
||||
Address::Ip(_) => assert!(false),
|
||||
};
|
||||
}
|
||||
#[test]
|
||||
fn test_unix_socket() {
|
||||
let res = parse_address(b"unix:/var/something.sock|");
|
||||
assert!(res.is_ok());
|
||||
let (i, addr) = res.unwrap();
|
||||
assert_eq!(i, b"|");
|
||||
match addr {
|
||||
Address::UnixSocket(addr) => {
|
||||
assert_eq!(addr, Path::new("/var/something.sock").to_path_buf());
|
||||
}
|
||||
Address::Ip(_) => assert!(false),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_valid_parse_filter_auth() {
|
||||
let test_vectors = vec![
|
||||
("|derp\n", "derp"),
|
||||
("|derp.derpson@example.com\r\n", "derp.derpson@example.com"),
|
||||
];
|
||||
for (test, ref_auth) in test_vectors {
|
||||
let res = parse_filter_auth(test.as_bytes());
|
||||
assert!(res.is_ok());
|
||||
let (input, auth) = res.unwrap();
|
||||
assert_eq!(input, b"");
|
||||
assert_eq!(auth, ref_auth.to_string());
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_valid_parse_filter_auth() {
|
||||
let test_vectors = vec![
|
||||
("|derp\n", "derp"),
|
||||
("|derp.derpson@example.com\r\n", "derp.derpson@example.com"),
|
||||
];
|
||||
for (test, ref_auth) in test_vectors {
|
||||
let res = parse_filter_auth(test.as_bytes());
|
||||
assert!(res.is_ok());
|
||||
let (input, auth) = res.unwrap();
|
||||
assert_eq!(input, b"");
|
||||
assert_eq!(auth, ref_auth.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_parse_filter_auth() {
|
||||
let test_vectors = vec!["|\n", "|\r\n", "|derp", "|derp|derpson\n"];
|
||||
for test in test_vectors {
|
||||
let res = parse_filter_auth(test.as_bytes());
|
||||
assert!(!res.is_ok());
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_invalid_parse_filter_auth() {
|
||||
let test_vectors = vec!["|\n", "|\r\n", "|derp", "|derp|derpson\n"];
|
||||
for test in test_vectors {
|
||||
let res = parse_filter_auth(test.as_bytes());
|
||||
assert!(!res.is_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,166 +1,166 @@
|
|||
use crate::error::nom_err_to_string;
|
||||
use crate::parsers::entry::{parse_entry, EntryOption};
|
||||
use crate::parsers::parameters::{
|
||||
parse_filter_auth, parse_filter_connect, parse_filter_data_line, parse_filter_ehlo,
|
||||
parse_filter_helo, parse_filter_mail_from, parse_filter_rcpt_to, parse_filter_starttls,
|
||||
parse_report_filter_report, parse_report_filter_response, parse_report_link_auth,
|
||||
parse_report_link_connect, parse_report_link_greeting, parse_report_link_identify,
|
||||
parse_report_link_tls, parse_report_protocol_client, parse_report_protocol_server,
|
||||
parse_report_tx_begin, parse_report_tx_commit, parse_report_tx_data, parse_report_tx_envelope,
|
||||
parse_report_tx_mail, parse_report_tx_rcpt, parse_report_tx_reset, parse_report_tx_rollback,
|
||||
parse_filter_auth, parse_filter_connect, parse_filter_data_line, parse_filter_ehlo,
|
||||
parse_filter_helo, parse_filter_mail_from, parse_filter_rcpt_to, parse_filter_starttls,
|
||||
parse_report_filter_report, parse_report_filter_response, parse_report_link_auth,
|
||||
parse_report_link_connect, parse_report_link_greeting, parse_report_link_identify,
|
||||
parse_report_link_tls, parse_report_protocol_client, parse_report_protocol_server,
|
||||
parse_report_tx_begin, parse_report_tx_commit, parse_report_tx_data, parse_report_tx_envelope,
|
||||
parse_report_tx_mail, parse_report_tx_rcpt, parse_report_tx_reset, parse_report_tx_rollback,
|
||||
};
|
||||
use crate::{Event, Filter, FilterPhase};
|
||||
|
||||
macro_rules! handle_reports {
|
||||
($obj: ident, $r: ident, $input: ident) => {
|
||||
match $r.event {
|
||||
Event::LinkAuth => {
|
||||
let (_, (username, result)) =
|
||||
parse_report_link_auth($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_link_auth(&$r, &username, result);
|
||||
}
|
||||
Event::LinkConnect => {
|
||||
let (_, (rdns, fcrdns, src, dest)) =
|
||||
parse_report_link_connect($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_link_connect(&$r, &rdns, &fcrdns, &src, &dest);
|
||||
}
|
||||
Event::LinkDisconnect => {
|
||||
$obj.on_report_link_disconnect(&$r);
|
||||
}
|
||||
Event::LinkGreeting => {
|
||||
let (_, hostname) =
|
||||
parse_report_link_greeting($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_link_greeting(&$r, &hostname);
|
||||
}
|
||||
Event::LinkIdentify => {
|
||||
let (_, (method, identity)) =
|
||||
parse_report_link_identify($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_link_identify(&$r, method, &identity);
|
||||
}
|
||||
Event::LinkTls => {
|
||||
let (_, s) = parse_report_link_tls($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_link_tls(&$r, &s);
|
||||
}
|
||||
Event::TxBegin => {
|
||||
let (_, id) = parse_report_tx_begin($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_begin(&$r, &id);
|
||||
}
|
||||
Event::TxMail => {
|
||||
let (_, (id, result, addr)) =
|
||||
parse_report_tx_mail($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_mail(&$r, &id, result, &addr);
|
||||
}
|
||||
Event::TxReset => {
|
||||
let (_, id) = parse_report_tx_reset($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_reset(&$r, &id);
|
||||
}
|
||||
Event::TxRcpt => {
|
||||
let (_, (id, result, addr)) =
|
||||
parse_report_tx_rcpt($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_rcpt(&$r, &id, result, &addr);
|
||||
}
|
||||
Event::TxEnvelope => {
|
||||
let (_, (msg, env)) =
|
||||
parse_report_tx_envelope($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_envelope(&$r, &msg, &env);
|
||||
}
|
||||
Event::TxData => {
|
||||
let (_, (id, result)) = parse_report_tx_data($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_data(&$r, &id, result);
|
||||
}
|
||||
Event::TxCommit => {
|
||||
let (_, (id, size)) = parse_report_tx_commit($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_commit(&$r, &id, size);
|
||||
}
|
||||
Event::TxRollback => {
|
||||
let (_, id) = parse_report_tx_rollback($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_rollback(&$r, &id);
|
||||
}
|
||||
Event::ProtocolClient => {
|
||||
let (_, cmd) = parse_report_protocol_client($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_protocol_client(&$r, &cmd);
|
||||
}
|
||||
Event::ProtocolServer => {
|
||||
let (_, res) = parse_report_protocol_server($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_protocol_server(&$r, &res);
|
||||
}
|
||||
Event::FilterResponse => {
|
||||
let (_, (phase, res, param)) =
|
||||
parse_report_filter_response($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_filter_response(&$r, phase, &res, ¶m);
|
||||
}
|
||||
Event::FilterReport => {
|
||||
let (_, (kind, name, message)) =
|
||||
parse_report_filter_report($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_filter_report(&$r, kind, &name, &message);
|
||||
}
|
||||
Event::Timeout => {
|
||||
$obj.on_report_timeout(&$r);
|
||||
}
|
||||
}
|
||||
};
|
||||
($obj: ident, $r: ident, $input: ident) => {
|
||||
match $r.event {
|
||||
Event::LinkAuth => {
|
||||
let (_, (username, result)) =
|
||||
parse_report_link_auth($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_link_auth(&$r, &username, result);
|
||||
}
|
||||
Event::LinkConnect => {
|
||||
let (_, (rdns, fcrdns, src, dest)) =
|
||||
parse_report_link_connect($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_link_connect(&$r, &rdns, &fcrdns, &src, &dest);
|
||||
}
|
||||
Event::LinkDisconnect => {
|
||||
$obj.on_report_link_disconnect(&$r);
|
||||
}
|
||||
Event::LinkGreeting => {
|
||||
let (_, hostname) =
|
||||
parse_report_link_greeting($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_link_greeting(&$r, &hostname);
|
||||
}
|
||||
Event::LinkIdentify => {
|
||||
let (_, (method, identity)) =
|
||||
parse_report_link_identify($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_link_identify(&$r, method, &identity);
|
||||
}
|
||||
Event::LinkTls => {
|
||||
let (_, s) = parse_report_link_tls($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_link_tls(&$r, &s);
|
||||
}
|
||||
Event::TxBegin => {
|
||||
let (_, id) = parse_report_tx_begin($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_begin(&$r, &id);
|
||||
}
|
||||
Event::TxMail => {
|
||||
let (_, (id, result, addr)) =
|
||||
parse_report_tx_mail($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_mail(&$r, &id, result, &addr);
|
||||
}
|
||||
Event::TxReset => {
|
||||
let (_, id) = parse_report_tx_reset($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_reset(&$r, &id);
|
||||
}
|
||||
Event::TxRcpt => {
|
||||
let (_, (id, result, addr)) =
|
||||
parse_report_tx_rcpt($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_rcpt(&$r, &id, result, &addr);
|
||||
}
|
||||
Event::TxEnvelope => {
|
||||
let (_, (msg, env)) =
|
||||
parse_report_tx_envelope($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_envelope(&$r, &msg, &env);
|
||||
}
|
||||
Event::TxData => {
|
||||
let (_, (id, result)) = parse_report_tx_data($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_data(&$r, &id, result);
|
||||
}
|
||||
Event::TxCommit => {
|
||||
let (_, (id, size)) = parse_report_tx_commit($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_commit(&$r, &id, size);
|
||||
}
|
||||
Event::TxRollback => {
|
||||
let (_, id) = parse_report_tx_rollback($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_tx_rollback(&$r, &id);
|
||||
}
|
||||
Event::ProtocolClient => {
|
||||
let (_, cmd) = parse_report_protocol_client($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_protocol_client(&$r, &cmd);
|
||||
}
|
||||
Event::ProtocolServer => {
|
||||
let (_, res) = parse_report_protocol_server($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_protocol_server(&$r, &res);
|
||||
}
|
||||
Event::FilterResponse => {
|
||||
let (_, (phase, res, param)) =
|
||||
parse_report_filter_response($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_filter_response(&$r, phase, &res, ¶m);
|
||||
}
|
||||
Event::FilterReport => {
|
||||
let (_, (kind, name, message)) =
|
||||
parse_report_filter_report($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_report_filter_report(&$r, kind, &name, &message);
|
||||
}
|
||||
Event::Timeout => {
|
||||
$obj.on_report_timeout(&$r);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! handle_filters {
|
||||
($obj: ident, $f: ident, $input: ident) => {
|
||||
match $f.phase {
|
||||
FilterPhase::Auth => {
|
||||
let (_, auth) = parse_filter_auth($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_auth(&$f, &auth))
|
||||
}
|
||||
FilterPhase::Commit => Some($obj.on_filter_commit(&$f)),
|
||||
FilterPhase::Connect => {
|
||||
let (_, (rdns, fcrdns, src, dest)) =
|
||||
parse_filter_connect($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_connect(&$f, &rdns, &fcrdns, &src, &dest))
|
||||
}
|
||||
FilterPhase::Data => Some($obj.on_filter_data(&$f)),
|
||||
FilterPhase::DataLine => {
|
||||
let (_, data_line) = parse_filter_data_line($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_filter_data_line(&$f, &data_line);
|
||||
None
|
||||
}
|
||||
FilterPhase::Ehlo => {
|
||||
let (_, identity) = parse_filter_ehlo($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_ehlo(&$f, &identity))
|
||||
}
|
||||
FilterPhase::Helo => {
|
||||
let (_, identity) = parse_filter_helo($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_helo(&$f, &identity))
|
||||
}
|
||||
FilterPhase::MailFrom => {
|
||||
let (_, address) = parse_filter_mail_from($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_mail_from(&$f, &address))
|
||||
}
|
||||
FilterPhase::RcptTo => {
|
||||
let (_, address) = parse_filter_rcpt_to($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_rcpt_to(&$f, &address))
|
||||
}
|
||||
FilterPhase::StartTls => {
|
||||
let (_, tls_str) = parse_filter_starttls($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_starttls(&$f, &tls_str))
|
||||
}
|
||||
}
|
||||
};
|
||||
($obj: ident, $f: ident, $input: ident) => {
|
||||
match $f.phase {
|
||||
FilterPhase::Auth => {
|
||||
let (_, auth) = parse_filter_auth($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_auth(&$f, &auth))
|
||||
}
|
||||
FilterPhase::Commit => Some($obj.on_filter_commit(&$f)),
|
||||
FilterPhase::Connect => {
|
||||
let (_, (rdns, fcrdns, src, dest)) =
|
||||
parse_filter_connect($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_connect(&$f, &rdns, &fcrdns, &src, &dest))
|
||||
}
|
||||
FilterPhase::Data => Some($obj.on_filter_data(&$f)),
|
||||
FilterPhase::DataLine => {
|
||||
let (_, data_line) = parse_filter_data_line($input).map_err(|e| e.to_string())?;
|
||||
$obj.on_filter_data_line(&$f, &data_line);
|
||||
None
|
||||
}
|
||||
FilterPhase::Ehlo => {
|
||||
let (_, identity) = parse_filter_ehlo($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_ehlo(&$f, &identity))
|
||||
}
|
||||
FilterPhase::Helo => {
|
||||
let (_, identity) = parse_filter_helo($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_helo(&$f, &identity))
|
||||
}
|
||||
FilterPhase::MailFrom => {
|
||||
let (_, address) = parse_filter_mail_from($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_mail_from(&$f, &address))
|
||||
}
|
||||
FilterPhase::RcptTo => {
|
||||
let (_, address) = parse_filter_rcpt_to($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_rcpt_to(&$f, &address))
|
||||
}
|
||||
FilterPhase::StartTls => {
|
||||
let (_, tls_str) = parse_filter_starttls($input).map_err(|e| e.to_string())?;
|
||||
Some($obj.on_filter_starttls(&$f, &tls_str))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn line<T>(user_object: &mut T, input: &[u8]) -> Result<(), String>
|
||||
where
|
||||
T: Filter,
|
||||
T: Filter,
|
||||
{
|
||||
let (input, entry) = parse_entry(input).map_err(nom_err_to_string)?;
|
||||
match entry {
|
||||
EntryOption::Report(r) => handle_reports!(user_object, r, input),
|
||||
EntryOption::Filter(f) => {
|
||||
if let Some(answer) = handle_filters!(user_object, f, input) {
|
||||
println!(
|
||||
"filter-result|{}|{}|{}",
|
||||
f.session_id,
|
||||
f.token,
|
||||
answer.to_string()
|
||||
);
|
||||
};
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
let (input, entry) = parse_entry(input).map_err(nom_err_to_string)?;
|
||||
match entry {
|
||||
EntryOption::Report(r) => handle_reports!(user_object, r, input),
|
||||
EntryOption::Filter(f) => {
|
||||
if let Some(answer) = handle_filters!(user_object, f, input) {
|
||||
println!(
|
||||
"filter-result|{}|{}|{}",
|
||||
f.session_id,
|
||||
f.token,
|
||||
answer.to_string()
|
||||
);
|
||||
};
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
|
Reference in a new issue