diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..55bfac2 --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..218e203 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +hard_tabs = true diff --git a/opensmtpd-derive/src/lib.rs b/opensmtpd-derive/src/lib.rs index 24f0c85..c166915 100644 --- a/opensmtpd-derive/src/lib.rs +++ b/opensmtpd-derive/src/lib.rs @@ -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() } diff --git a/opensmtpd/examples/counter.rs b/opensmtpd/examples/counter.rs index 5c1ad95..abe2cf9 100644 --- a/opensmtpd/examples/counter.rs +++ b/opensmtpd/examples/counter.rs @@ -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); } diff --git a/opensmtpd/examples/rm_x-originating-ip.rs b/opensmtpd/examples/rm_x-originating-ip.rs index 9bfd6ae..ac27b67 100644 --- a/opensmtpd/examples/rm_x-originating-ip.rs +++ b/opensmtpd/examples/rm_x-originating-ip.rs @@ -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); } diff --git a/opensmtpd/src/data_line.rs b/opensmtpd/src/data_line.rs index b235452..7a15bdf 100644 --- a/opensmtpd/src/data_line.rs +++ b/opensmtpd/src/data_line.rs @@ -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) + ); } diff --git a/opensmtpd/src/data_structures/address.rs b/opensmtpd/src/data_structures/address.rs index 7023148..83a94a6 100644 --- a/opensmtpd/src/data_structures/address.rs +++ b/opensmtpd/src/data_structures/address.rs @@ -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(), + }, + } + } } diff --git a/opensmtpd/src/data_structures/auth_result.rs b/opensmtpd/src/data_structures/auth_result.rs index 8d09a0a..7385efe 100644 --- a/opensmtpd/src/data_structures/auth_result.rs +++ b/opensmtpd/src/data_structures/auth_result.rs @@ -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 { - match s { - "pass" => Ok(AuthResult::Pass), - "fail" => Ok(AuthResult::Fail), - "error" => Ok(AuthResult::Error), - _ => Err(()), - } - } + fn from_str(s: &str) -> Result { + match s { + "pass" => Ok(AuthResult::Pass), + "fail" => Ok(AuthResult::Fail), + "error" => Ok(AuthResult::Error), + _ => Err(()), + } + } } diff --git a/opensmtpd/src/data_structures/event.rs b/opensmtpd/src/data_structures/event.rs index af9d232..81f29b6 100644 --- a/opensmtpd/src/data_structures/event.rs +++ b/opensmtpd/src/data_structures/event.rs @@ -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 { - 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 { + 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(()), + } + } } diff --git a/opensmtpd/src/data_structures/filter_kind.rs b/opensmtpd/src/data_structures/filter_kind.rs index de65072..d9da856 100644 --- a/opensmtpd/src/data_structures/filter_kind.rs +++ b/opensmtpd/src/data_structures/filter_kind.rs @@ -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 { - match s { - "builtin" => Ok(FilterKind::Builtin), - "proc" => Ok(FilterKind::Proc), - _ => Err(()), - } - } + fn from_str(s: &str) -> Result { + match s { + "builtin" => Ok(FilterKind::Builtin), + "proc" => Ok(FilterKind::Proc), + _ => Err(()), + } + } } diff --git a/opensmtpd/src/data_structures/filter_phase.rs b/opensmtpd/src/data_structures/filter_phase.rs index 4161364..9dabcce 100644 --- a/opensmtpd/src/data_structures/filter_phase.rs +++ b/opensmtpd/src/data_structures/filter_phase.rs @@ -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 { - 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 { + 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(()), + } + } } diff --git a/opensmtpd/src/data_structures/filter_response.rs b/opensmtpd/src/data_structures/filter_response.rs index bf45fb1..585ed8a 100644 --- a/opensmtpd/src/data_structures/filter_response.rs +++ b/opensmtpd/src/data_structures/filter_response.rs @@ -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), + } + } } diff --git a/opensmtpd/src/data_structures/mail_result.rs b/opensmtpd/src/data_structures/mail_result.rs index 9c52c25..86086f1 100644 --- a/opensmtpd/src/data_structures/mail_result.rs +++ b/opensmtpd/src/data_structures/mail_result.rs @@ -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 { - match s { - "ok" => Ok(MailResult::Ok), - "permfail" => Ok(MailResult::PermFail), - "tempfail" => Ok(MailResult::TempFail), - _ => Err(()), - } - } + fn from_str(s: &str) -> Result { + match s { + "ok" => Ok(MailResult::Ok), + "permfail" => Ok(MailResult::PermFail), + "tempfail" => Ok(MailResult::TempFail), + _ => Err(()), + } + } } diff --git a/opensmtpd/src/data_structures/method.rs b/opensmtpd/src/data_structures/method.rs index fb5dbd8..bba7f25 100644 --- a/opensmtpd/src/data_structures/method.rs +++ b/opensmtpd/src/data_structures/method.rs @@ -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 { - match s { - "HELO" => Ok(Method::Helo), - "EHLO" => Ok(Method::Ehlo), - _ => Err(()), - } - } + fn from_str(s: &str) -> Result { + match s { + "HELO" => Ok(Method::Helo), + "EHLO" => Ok(Method::Ehlo), + _ => Err(()), + } + } } diff --git a/opensmtpd/src/data_structures/smtp_status.rs b/opensmtpd/src/data_structures/smtp_status.rs index 879ad63..d7e68f2 100644 --- a/opensmtpd/src/data_structures/smtp_status.rs +++ b/opensmtpd/src/data_structures/smtp_status.rs @@ -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) + } } diff --git a/opensmtpd/src/data_structures/subsystem.rs b/opensmtpd/src/data_structures/subsystem.rs index e7562d8..d5db891 100644 --- a/opensmtpd/src/data_structures/subsystem.rs +++ b/opensmtpd/src/data_structures/subsystem.rs @@ -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 { - match s { - "smtp-in" => Ok(SubSystem::SmtpIn), - _ => Err(()), - } - } + fn from_str(s: &str) -> Result { + match s { + "smtp-in" => Ok(SubSystem::SmtpIn), + _ => Err(()), + } + } } diff --git a/opensmtpd/src/data_structures/timeval.rs b/opensmtpd/src/data_structures/timeval.rs index 440b053..8a6f78a 100644 --- a/opensmtpd/src/data_structures/timeval.rs +++ b/opensmtpd/src/data_structures/timeval.rs @@ -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) + } } diff --git a/opensmtpd/src/error.rs b/opensmtpd/src/error.rs index 0efb99f..fe54431 100644 --- a/opensmtpd/src/error.rs +++ b/opensmtpd/src/error.rs @@ -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>) -> 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), + } } diff --git a/opensmtpd/src/filter.rs b/opensmtpd/src/filter.rs index dd6cb6d..8f3bacf 100644 --- a/opensmtpd/src/filter.rs +++ b/opensmtpd/src/filter.rs @@ -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) {} - #[doc(hidden)] - fn has_report_tx_reset(&self) -> bool { - false - } + fn on_report_tx_reset(&mut self, _entry: &ReportEntry, _message_id: &Option) {} + #[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, - ) { - } - #[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, + ) { + } + #[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 + } } diff --git a/opensmtpd/src/io.rs b/opensmtpd/src/io.rs index 22a2d75..70e5a8f 100644 --- a/opensmtpd/src/io.rs +++ b/opensmtpd/src/io.rs @@ -3,39 +3,39 @@ use std::io::{self, ErrorKind, Read}; use std::sync::mpsc::Sender; pub(crate) fn read_stdin(tx: &Sender>) { - 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>) -> Result<(), String> { - let mut read_buffer: [u8; crate::BUFFER_SIZE] = [0; crate::BUFFER_SIZE]; - let mut line_buffer: Vec = 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 = 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); + } + } } diff --git a/opensmtpd/src/lib.rs b/opensmtpd/src/lib.rs index 8beb09a..6a323f8 100644 --- a/opensmtpd/src/lib.rs +++ b/opensmtpd/src/lib.rs @@ -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(user_object: &mut T) where - T: Filter, + T: Filter, { - // IO init - let (tx, rx) = channel::>(); - thread::spawn(move || { - io::read_stdin(&tx); - }); + // IO init + let (tx, rx) = channel::>(); + thread::spawn(move || { + io::read_stdin(&tx); + }); - // Handshake - let mut handshake_buffer: Vec = 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 = 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(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"); } diff --git a/opensmtpd/src/parsers/entry.rs b/opensmtpd/src/parsers/entry.rs index e0adb26..06e02bf 100644 --- a/opensmtpd/src/parsers/entry.rs +++ b/opensmtpd/src/parsers/entry.rs @@ -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::(input)?; - let (input, _) = parse_delimiter(input)?; - let (input, event) = parse_data_structure::(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::(input)?; + let (input, _) = parse_delimiter(input)?; + let (input, event) = parse_data_structure::(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::(input)?; - let (input, _) = parse_delimiter(input)?; - let (input, phase) = parse_data_structure::(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::(input)?; + let (input, _) = parse_delimiter(input)?; + let (input, phase) = parse_data_structure::(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::())(input)?; - let (input, _) = tag(".")(input)?; - let (input, usec) = map_res(digit1, |s| { - format!("{:0<6}", String::from_utf8_lossy(s)).parse::() - })(input)?; - let timestamp = TimeVal { sec, usec }; - Ok((input, timestamp)) + let (input, sec) = map_res(digit1, |s| String::from_utf8_lossy(s).parse::())(input)?; + let (input, _) = tag(".")(input)?; + let (input, usec) = map_res(digit1, |s| { + format!("{:0<6}", String::from_utf8_lossy(s)).parse::() + })(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")); + } } diff --git a/opensmtpd/src/parsers/handshake.rs b/opensmtpd/src/parsers/handshake.rs index 0bf15e8..938091e 100644 --- a/opensmtpd/src/parsers/handshake.rs +++ b/opensmtpd/src/parsers/handshake.rs @@ -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::(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::(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![ + #[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()); - } - } + for input in test_vectors { + let r = parse_handshake(input.as_bytes()); + assert!(r.is_err()); + } + } } diff --git a/opensmtpd/src/parsers/mod.rs b/opensmtpd/src/parsers/mod.rs index 3b50269..70e0e34 100644 --- a/opensmtpd/src/parsers/mod.rs +++ b/opensmtpd/src/parsers/mod.rs @@ -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(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)); + } + } } diff --git a/opensmtpd/src/parsers/parameters.rs b/opensmtpd/src/parsers/parameters.rs index 128c933..0a2d391 100644 --- a/opensmtpd/src/parsers/parameters.rs +++ b/opensmtpd/src/parsers/parameters.rs @@ -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::(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::(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::(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::(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::(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::(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> { - 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::(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::(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::(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::(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)> { - let (input, _) = parse_delimiter(input)?; - let (input, phase) = parse_data_structure::(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::(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::(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::(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 { - let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?; - let addr = s.parse::().map_err(|e| e.to_string())?; - Ok(Address::Ip(addr)) - }, - )(input) + map_res( + take_while1(is_parameter_char), + |s: &[u8]| -> Result { + let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?; + let addr = s.parse::().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 { - let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?; - let addr = s.parse::().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 { + let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?; + let addr = s.parse::().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()); + } + } } diff --git a/opensmtpd/src/process.rs b/opensmtpd/src/process.rs index d63431c..72f5c5a 100644 --- a/opensmtpd/src/process.rs +++ b/opensmtpd/src/process.rs @@ -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(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(()) }