Compare commits

..

10 commits

Author SHA1 Message Date
Rodolphe Bréard
847fbd6213 put project to sleep 2022-01-12 20:00:53 +01:00
Rodolphe Bréard
d9b89beb3f Merge branch 'main' of github.com:breard-r/rust-opensmtpd 2022-01-12 19:59:30 +01:00
Rodolphe Bréard
28e93f0353 Update the Travis-CI configuration 2021-05-10 18:59:37 +02:00
Rodolphe Bréard
a28b8846a2
Merge pull request #5 from breard-r/dependabot/add-v2-config-file
Upgrade to GitHub-native Dependabot
2021-04-30 19:02:59 +02:00
Rodolphe Bréard
e0ab5ca6fa
Merge pull request #4 from breard-r/dependabot/cargo/simplelog-0.10
Update simplelog requirement from 0.9 to 0.10
2021-04-30 19:02:47 +02:00
dependabot-preview[bot]
20493e9dec
Upgrade to GitHub-native Dependabot 2021-04-29 20:13:35 +00:00
dependabot-preview[bot]
e8f99f957d
Update simplelog requirement from 0.9 to 0.10
Updates the requirements on [simplelog](https://github.com/drakulix/simplelog.rs) to permit the latest version.
- [Release notes](https://github.com/drakulix/simplelog.rs/releases)
- [Changelog](https://github.com/Drakulix/simplelog.rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/drakulix/simplelog.rs/compare/v0.9.0...v0.10.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-03-29 04:26:16 +00:00
Rodolphe Bréard
0fe864e6db Replace the lasts space indents with tabs 2021-02-28 14:10:12 +01:00
Rodolphe Bréard
e83af3d3e5 Switch to tab indentation 2021-02-28 13:56:40 +01:00
Rodolphe Bréard
ecf0ca1191 Rust-OpenSMTPD v0.4.1 2020-12-21 15:43:56 +01:00
31 changed files with 1409 additions and 1390 deletions

9
.editorconfig Normal file
View file

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = tab
indent_size = tab
trim_trailing_whitespace = true

1
.rustfmt.toml Normal file
View file

@ -0,0 +1 @@
hard_tabs = true

View file

@ -10,6 +10,10 @@ rust:
- "1.46.0"
- "1.47.0"
- "1.48.0"
- "1.49.0"
- "1.50.0"
- "1.51.0"
- "1.52.1"
- "stable"
- "beta"
- "nightly"

View file

@ -1,5 +1,5 @@
[workspace]
members = [
"opensmtpd",
"opensmtpd-derive"
"opensmtpd",
"opensmtpd-derive"
]

View file

@ -17,3 +17,8 @@ Read the documentation on [docs.rs](https://docs.rs/opensmtpd/).
# Requirements
Rust 1.43 or newer.
# Status
Abandoned (at least temporarily).

View file

@ -1,6 +1,6 @@
[package]
name = "opensmtpd_derive"
version = "0.4.0"
version = "0.4.1"
authors = ["Rodolphe Bréard <rodolphe@what.tf>"]
edition = "2018"
description = "Interface for OpenSMTPD filters"

View file

@ -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()
}

View file

@ -1,6 +1,6 @@
[package]
name = "opensmtpd"
version = "0.4.0"
version = "0.4.1"
authors = ["Rodolphe Bréard <rodolphe@what.tf>"]
edition = "2018"
description = "Interface for OpenSMTPD filters"
@ -18,7 +18,7 @@ opensmtpd_derive = { version = "0.4", path = "../opensmtpd-derive" }
pretty-hex = "0.2"
[dev-dependencies]
simplelog = "0.9"
simplelog = "0.10"
[[example]]
name = "counter"

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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)
);
}

View file

@ -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(),
},
}
}
}

View file

@ -2,30 +2,30 @@ use std::str::FromStr;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum AuthResult {
Pass,
Fail,
Error,
Pass,
Fail,
Error,
}
impl ToString for AuthResult {
fn to_string(&self) -> String {
match self {
AuthResult::Pass => String::from("pass"),
AuthResult::Fail => String::from("fail"),
AuthResult::Error => String::from("error"),
}
}
fn to_string(&self) -> String {
match self {
AuthResult::Pass => String::from("pass"),
AuthResult::Fail => String::from("fail"),
AuthResult::Error => String::from("error"),
}
}
}
impl FromStr for AuthResult {
type Err = ();
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"pass" => Ok(AuthResult::Pass),
"fail" => Ok(AuthResult::Fail),
"error" => Ok(AuthResult::Error),
_ => Err(()),
}
}
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"pass" => Ok(AuthResult::Pass),
"fail" => Ok(AuthResult::Fail),
"error" => Ok(AuthResult::Error),
_ => Err(()),
}
}
}

View file

@ -2,78 +2,78 @@ use std::str::FromStr;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Event {
LinkAuth,
LinkConnect,
LinkDisconnect,
LinkGreeting,
LinkIdentify,
LinkTls,
TxBegin,
TxMail,
TxReset,
TxRcpt,
TxEnvelope,
TxData,
TxCommit,
TxRollback,
ProtocolClient,
ProtocolServer,
FilterResponse,
FilterReport,
Timeout,
LinkAuth,
LinkConnect,
LinkDisconnect,
LinkGreeting,
LinkIdentify,
LinkTls,
TxBegin,
TxMail,
TxReset,
TxRcpt,
TxEnvelope,
TxData,
TxCommit,
TxRollback,
ProtocolClient,
ProtocolServer,
FilterResponse,
FilterReport,
Timeout,
}
impl ToString for Event {
fn to_string(&self) -> String {
match self {
Event::LinkAuth => String::from("link-auth"),
Event::LinkConnect => String::from("link-connect"),
Event::LinkDisconnect => String::from("link-disconnect"),
Event::LinkGreeting => String::from("link-greeting"),
Event::LinkIdentify => String::from("link-identify"),
Event::LinkTls => String::from("link-tls"),
Event::TxBegin => String::from("tx-begin"),
Event::TxMail => String::from("tx-mail"),
Event::TxReset => String::from("tx-reset"),
Event::TxRcpt => String::from("tx-rcpt"),
Event::TxEnvelope => String::from("tx-envelope"),
Event::TxData => String::from("tx-data"),
Event::TxCommit => String::from("tx-commit"),
Event::TxRollback => String::from("tx-rollback"),
Event::ProtocolClient => String::from("protocol-client"),
Event::ProtocolServer => String::from("protocol-server"),
Event::FilterResponse => String::from("filter-response"),
Event::FilterReport => String::from("filter-report"),
Event::Timeout => String::from("timeout"),
}
}
fn to_string(&self) -> String {
match self {
Event::LinkAuth => String::from("link-auth"),
Event::LinkConnect => String::from("link-connect"),
Event::LinkDisconnect => String::from("link-disconnect"),
Event::LinkGreeting => String::from("link-greeting"),
Event::LinkIdentify => String::from("link-identify"),
Event::LinkTls => String::from("link-tls"),
Event::TxBegin => String::from("tx-begin"),
Event::TxMail => String::from("tx-mail"),
Event::TxReset => String::from("tx-reset"),
Event::TxRcpt => String::from("tx-rcpt"),
Event::TxEnvelope => String::from("tx-envelope"),
Event::TxData => String::from("tx-data"),
Event::TxCommit => String::from("tx-commit"),
Event::TxRollback => String::from("tx-rollback"),
Event::ProtocolClient => String::from("protocol-client"),
Event::ProtocolServer => String::from("protocol-server"),
Event::FilterResponse => String::from("filter-response"),
Event::FilterReport => String::from("filter-report"),
Event::Timeout => String::from("timeout"),
}
}
}
impl FromStr for Event {
type Err = ();
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"link-auth" => Ok(Event::LinkAuth),
"link-connect" => Ok(Event::LinkConnect),
"link-disconnect" => Ok(Event::LinkDisconnect),
"link-greeting" => Ok(Event::LinkGreeting),
"link-identify" => Ok(Event::LinkIdentify),
"link-tls" => Ok(Event::LinkTls),
"tx-begin" => Ok(Event::TxBegin),
"tx-mail" => Ok(Event::TxMail),
"tx-reset" => Ok(Event::TxReset),
"tx-rcpt" => Ok(Event::TxRcpt),
"tx-envelope" => Ok(Event::TxEnvelope),
"tx-data" => Ok(Event::TxData),
"tx-commit" => Ok(Event::TxCommit),
"tx-rollback" => Ok(Event::TxRollback),
"protocol-client" => Ok(Event::ProtocolClient),
"protocol-server" => Ok(Event::ProtocolServer),
"filter-response" => Ok(Event::FilterResponse),
"filter-report" => Ok(Event::FilterReport),
"timeout" => Ok(Event::Timeout),
_ => Err(()),
}
}
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"link-auth" => Ok(Event::LinkAuth),
"link-connect" => Ok(Event::LinkConnect),
"link-disconnect" => Ok(Event::LinkDisconnect),
"link-greeting" => Ok(Event::LinkGreeting),
"link-identify" => Ok(Event::LinkIdentify),
"link-tls" => Ok(Event::LinkTls),
"tx-begin" => Ok(Event::TxBegin),
"tx-mail" => Ok(Event::TxMail),
"tx-reset" => Ok(Event::TxReset),
"tx-rcpt" => Ok(Event::TxRcpt),
"tx-envelope" => Ok(Event::TxEnvelope),
"tx-data" => Ok(Event::TxData),
"tx-commit" => Ok(Event::TxCommit),
"tx-rollback" => Ok(Event::TxRollback),
"protocol-client" => Ok(Event::ProtocolClient),
"protocol-server" => Ok(Event::ProtocolServer),
"filter-response" => Ok(Event::FilterResponse),
"filter-report" => Ok(Event::FilterReport),
"timeout" => Ok(Event::Timeout),
_ => Err(()),
}
}
}

View file

@ -2,27 +2,27 @@ use std::str::FromStr;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FilterKind {
Builtin,
Proc,
Builtin,
Proc,
}
impl ToString for FilterKind {
fn to_string(&self) -> String {
match self {
FilterKind::Builtin => String::from("builtin"),
FilterKind::Proc => String::from("proc"),
}
}
fn to_string(&self) -> String {
match self {
FilterKind::Builtin => String::from("builtin"),
FilterKind::Proc => String::from("proc"),
}
}
}
impl FromStr for FilterKind {
type Err = ();
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"builtin" => Ok(FilterKind::Builtin),
"proc" => Ok(FilterKind::Proc),
_ => Err(()),
}
}
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"builtin" => Ok(FilterKind::Builtin),
"proc" => Ok(FilterKind::Proc),
_ => Err(()),
}
}
}

View file

@ -2,51 +2,51 @@ use std::str::FromStr;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FilterPhase {
Connect,
Helo,
Ehlo,
StartTls,
Auth,
MailFrom,
RcptTo,
Data,
DataLine,
Commit,
Connect,
Helo,
Ehlo,
StartTls,
Auth,
MailFrom,
RcptTo,
Data,
DataLine,
Commit,
}
impl ToString for FilterPhase {
fn to_string(&self) -> String {
match self {
FilterPhase::Connect => String::from("connect"),
FilterPhase::Helo => String::from("helo"),
FilterPhase::Ehlo => String::from("ehlo"),
FilterPhase::StartTls => String::from("starttls"),
FilterPhase::Auth => String::from("auth"),
FilterPhase::MailFrom => String::from("mail-from"),
FilterPhase::RcptTo => String::from("rcpt-to"),
FilterPhase::Data => String::from("data"),
FilterPhase::DataLine => String::from("data-line"),
FilterPhase::Commit => String::from("commit"),
}
}
fn to_string(&self) -> String {
match self {
FilterPhase::Connect => String::from("connect"),
FilterPhase::Helo => String::from("helo"),
FilterPhase::Ehlo => String::from("ehlo"),
FilterPhase::StartTls => String::from("starttls"),
FilterPhase::Auth => String::from("auth"),
FilterPhase::MailFrom => String::from("mail-from"),
FilterPhase::RcptTo => String::from("rcpt-to"),
FilterPhase::Data => String::from("data"),
FilterPhase::DataLine => String::from("data-line"),
FilterPhase::Commit => String::from("commit"),
}
}
}
impl FromStr for FilterPhase {
type Err = ();
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"connect" => Ok(FilterPhase::Connect),
"helo" => Ok(FilterPhase::Helo),
"ehlo" => Ok(FilterPhase::Ehlo),
"starttls" => Ok(FilterPhase::StartTls),
"auth" => Ok(FilterPhase::Auth),
"mail-from" => Ok(FilterPhase::MailFrom),
"rcpt-to" => Ok(FilterPhase::RcptTo),
"data" => Ok(FilterPhase::Data),
"data-line" => Ok(FilterPhase::DataLine),
"commit" => Ok(FilterPhase::Commit),
_ => Err(()),
}
}
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"connect" => Ok(FilterPhase::Connect),
"helo" => Ok(FilterPhase::Helo),
"ehlo" => Ok(FilterPhase::Ehlo),
"starttls" => Ok(FilterPhase::StartTls),
"auth" => Ok(FilterPhase::Auth),
"mail-from" => Ok(FilterPhase::MailFrom),
"rcpt-to" => Ok(FilterPhase::RcptTo),
"data" => Ok(FilterPhase::Data),
"data-line" => Ok(FilterPhase::DataLine),
"commit" => Ok(FilterPhase::Commit),
_ => Err(()),
}
}
}

View file

@ -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),
}
}
}

View file

@ -2,30 +2,30 @@ use std::str::FromStr;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum MailResult {
Ok,
PermFail,
TempFail,
Ok,
PermFail,
TempFail,
}
impl ToString for MailResult {
fn to_string(&self) -> String {
match self {
MailResult::Ok => String::from("ok"),
MailResult::PermFail => String::from("permfail"),
MailResult::TempFail => String::from("tempfail"),
}
}
fn to_string(&self) -> String {
match self {
MailResult::Ok => String::from("ok"),
MailResult::PermFail => String::from("permfail"),
MailResult::TempFail => String::from("tempfail"),
}
}
}
impl FromStr for MailResult {
type Err = ();
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"ok" => Ok(MailResult::Ok),
"permfail" => Ok(MailResult::PermFail),
"tempfail" => Ok(MailResult::TempFail),
_ => Err(()),
}
}
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"ok" => Ok(MailResult::Ok),
"permfail" => Ok(MailResult::PermFail),
"tempfail" => Ok(MailResult::TempFail),
_ => Err(()),
}
}
}

View file

@ -2,27 +2,27 @@ use std::str::FromStr;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Method {
Helo,
Ehlo,
Helo,
Ehlo,
}
impl ToString for Method {
fn to_string(&self) -> String {
match self {
Method::Helo => String::from("HELO"),
Method::Ehlo => String::from("EHLO"),
}
}
fn to_string(&self) -> String {
match self {
Method::Helo => String::from("HELO"),
Method::Ehlo => String::from("EHLO"),
}
}
}
impl FromStr for Method {
type Err = ();
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"HELO" => Ok(Method::Helo),
"EHLO" => Ok(Method::Ehlo),
_ => Err(()),
}
}
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"HELO" => Ok(Method::Helo),
"EHLO" => Ok(Method::Ehlo),
_ => Err(()),
}
}
}

View file

@ -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)
}
}

View file

@ -2,24 +2,24 @@ use std::str::FromStr;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SubSystem {
SmtpIn,
SmtpIn,
}
impl ToString for SubSystem {
fn to_string(&self) -> String {
match self {
SubSystem::SmtpIn => String::from("smtp-in"),
}
}
fn to_string(&self) -> String {
match self {
SubSystem::SmtpIn => String::from("smtp-in"),
}
}
}
impl FromStr for SubSystem {
type Err = ();
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"smtp-in" => Ok(SubSystem::SmtpIn),
_ => Err(()),
}
}
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"smtp-in" => Ok(SubSystem::SmtpIn),
_ => Err(()),
}
}
}

View file

@ -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)
}
}

View file

@ -3,25 +3,25 @@ use nom::Err;
use pretty_hex::pretty_hex;
fn error_to_string(e: Error<&[u8]>) -> String {
format!(
"parsing error: {:?}: input:{}",
e.code,
get_pretty_hex(&e.input)
)
format!(
"parsing error: {:?}: input:{}",
e.code,
get_pretty_hex(&e.input)
)
}
pub(crate) fn get_pretty_hex(input: &[u8]) -> String {
let mut s = String::new();
for l in pretty_hex(&input).split('\n') {
s += &format!("\n{}", l);
}
s
let mut s = String::new();
for l in pretty_hex(&input).split('\n') {
s += &format!("\n{}", l);
}
s
}
pub(crate) fn nom_err_to_string(e: Err<Error<&[u8]>>) -> String {
match e {
Err::Incomplete(_) => e.to_string(),
Err::Error(er) => error_to_string(er),
Err::Failure(er) => error_to_string(er),
}
match e {
Err::Incomplete(_) => e.to_string(),
Err::Error(er) => error_to_string(er),
Err::Failure(er) => error_to_string(er),
}
}

View file

@ -1,253 +1,253 @@
use crate::{
Address, AuthResult, FilterEntry, FilterKind, FilterPhase, FilterResponse, MailResult, Method,
ReportEntry,
Address, AuthResult, FilterEntry, FilterKind, FilterPhase, FilterResponse, MailResult, Method,
ReportEntry,
};
pub trait Filter {
fn on_filter_auth(&mut self, _entry: &FilterEntry, _auth: &str) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_auth(&self) -> bool {
false
}
fn on_filter_auth(&mut self, _entry: &FilterEntry, _auth: &str) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_auth(&self) -> bool {
false
}
fn on_filter_commit(&mut self, _entry: &FilterEntry) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_commit(&self) -> bool {
false
}
fn on_filter_commit(&mut self, _entry: &FilterEntry) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_commit(&self) -> bool {
false
}
fn on_filter_connect(
&mut self,
_entry: &FilterEntry,
_rdns: &str,
_fcrdns: &str,
_src: &Address,
_dest: &Address,
) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_connect(&self) -> bool {
false
}
fn on_filter_connect(
&mut self,
_entry: &FilterEntry,
_rdns: &str,
_fcrdns: &str,
_src: &Address,
_dest: &Address,
) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_connect(&self) -> bool {
false
}
fn on_filter_data(&mut self, _entry: &FilterEntry) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_data(&self) -> bool {
false
}
fn on_filter_data(&mut self, _entry: &FilterEntry) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_data(&self) -> bool {
false
}
fn on_filter_data_line(&mut self, _entry: &FilterEntry, _data_line: &[u8]) {}
#[doc(hidden)]
fn has_filter_data_line(&self) -> bool {
false
}
fn on_filter_data_line(&mut self, _entry: &FilterEntry, _data_line: &[u8]) {}
#[doc(hidden)]
fn has_filter_data_line(&self) -> bool {
false
}
fn on_filter_ehlo(&mut self, _entry: &FilterEntry, _identity: &str) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_ehlo(&self) -> bool {
false
}
fn on_filter_ehlo(&mut self, _entry: &FilterEntry, _identity: &str) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_ehlo(&self) -> bool {
false
}
fn on_filter_helo(&mut self, _entry: &FilterEntry, _identity: &str) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_helo(&self) -> bool {
false
}
fn on_filter_helo(&mut self, _entry: &FilterEntry, _identity: &str) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_helo(&self) -> bool {
false
}
fn on_filter_mail_from(&mut self, _entry: &FilterEntry, _address: &str) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_mail_from(&self) -> bool {
false
}
fn on_filter_mail_from(&mut self, _entry: &FilterEntry, _address: &str) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_mail_from(&self) -> bool {
false
}
fn on_filter_rcpt_to(&mut self, _entry: &FilterEntry, _address: &str) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_rcpt_to(&self) -> bool {
false
}
fn on_filter_rcpt_to(&mut self, _entry: &FilterEntry, _address: &str) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_rcpt_to(&self) -> bool {
false
}
fn on_filter_starttls(&mut self, _entry: &FilterEntry, _tls_string: &str) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_starttls(&self) -> bool {
false
}
fn on_filter_starttls(&mut self, _entry: &FilterEntry, _tls_string: &str) -> FilterResponse {
FilterResponse::Proceed
}
#[doc(hidden)]
fn has_filter_starttls(&self) -> bool {
false
}
fn on_report_link_auth(&mut self, _entry: &ReportEntry, _username: &str, _result: AuthResult) {}
#[doc(hidden)]
fn has_report_link_auth(&self) -> bool {
false
}
fn on_report_link_auth(&mut self, _entry: &ReportEntry, _username: &str, _result: AuthResult) {}
#[doc(hidden)]
fn has_report_link_auth(&self) -> bool {
false
}
fn on_report_link_connect(
&mut self,
_entry: &ReportEntry,
_rdns: &str,
_fcrdns: &str,
_src: &Address,
_dest: &Address,
) {
}
#[doc(hidden)]
fn has_report_link_connect(&self) -> bool {
false
}
fn on_report_link_connect(
&mut self,
_entry: &ReportEntry,
_rdns: &str,
_fcrdns: &str,
_src: &Address,
_dest: &Address,
) {
}
#[doc(hidden)]
fn has_report_link_connect(&self) -> bool {
false
}
fn on_report_link_disconnect(&mut self, _entry: &ReportEntry) {}
#[doc(hidden)]
fn has_report_link_disconnect(&self) -> bool {
false
}
fn on_report_link_disconnect(&mut self, _entry: &ReportEntry) {}
#[doc(hidden)]
fn has_report_link_disconnect(&self) -> bool {
false
}
fn on_report_link_greeting(&mut self, _entry: &ReportEntry, _hostname: &str) {}
#[doc(hidden)]
fn has_report_link_greeting(&self) -> bool {
false
}
fn on_report_link_greeting(&mut self, _entry: &ReportEntry, _hostname: &str) {}
#[doc(hidden)]
fn has_report_link_greeting(&self) -> bool {
false
}
fn on_report_link_identify(&mut self, _entry: &ReportEntry, _method: Method, _identity: &str) {}
#[doc(hidden)]
fn has_report_link_identify(&self) -> bool {
false
}
fn on_report_link_identify(&mut self, _entry: &ReportEntry, _method: Method, _identity: &str) {}
#[doc(hidden)]
fn has_report_link_identify(&self) -> bool {
false
}
fn on_report_link_tls(&mut self, _entry: &ReportEntry, _tls_string: &str) {}
#[doc(hidden)]
fn has_report_link_tls(&self) -> bool {
false
}
fn on_report_link_tls(&mut self, _entry: &ReportEntry, _tls_string: &str) {}
#[doc(hidden)]
fn has_report_link_tls(&self) -> bool {
false
}
fn on_report_tx_begin(&mut self, _entry: &ReportEntry, _message_id: &str) {}
#[doc(hidden)]
fn has_report_tx_begin(&self) -> bool {
false
}
fn on_report_tx_begin(&mut self, _entry: &ReportEntry, _message_id: &str) {}
#[doc(hidden)]
fn has_report_tx_begin(&self) -> bool {
false
}
fn on_report_tx_mail(
&mut self,
_entry: &ReportEntry,
_message_id: &str,
_result: MailResult,
_address: &str,
) {
}
#[doc(hidden)]
fn has_report_tx_mail(&self) -> bool {
false
}
fn on_report_tx_mail(
&mut self,
_entry: &ReportEntry,
_message_id: &str,
_result: MailResult,
_address: &str,
) {
}
#[doc(hidden)]
fn has_report_tx_mail(&self) -> bool {
false
}
fn on_report_tx_reset(&mut self, _entry: &ReportEntry, _message_id: &Option<String>) {}
#[doc(hidden)]
fn has_report_tx_reset(&self) -> bool {
false
}
fn on_report_tx_reset(&mut self, _entry: &ReportEntry, _message_id: &Option<String>) {}
#[doc(hidden)]
fn has_report_tx_reset(&self) -> bool {
false
}
fn on_report_tx_rcpt(
&mut self,
_entry: &ReportEntry,
_message_id: &str,
_result: MailResult,
_address: &str,
) {
}
#[doc(hidden)]
fn has_report_tx_rcpt(&self) -> bool {
false
}
fn on_report_tx_rcpt(
&mut self,
_entry: &ReportEntry,
_message_id: &str,
_result: MailResult,
_address: &str,
) {
}
#[doc(hidden)]
fn has_report_tx_rcpt(&self) -> bool {
false
}
fn on_report_tx_envelope(
&mut self,
_entry: &ReportEntry,
_message_id: &str,
_envelope_id: &str,
) {
}
#[doc(hidden)]
fn has_report_tx_envelope(&self) -> bool {
false
}
fn on_report_tx_envelope(
&mut self,
_entry: &ReportEntry,
_message_id: &str,
_envelope_id: &str,
) {
}
#[doc(hidden)]
fn has_report_tx_envelope(&self) -> bool {
false
}
fn on_report_tx_data(&mut self, _entry: &ReportEntry, _message_id: &str, _result: MailResult) {}
#[doc(hidden)]
fn has_report_tx_data(&self) -> bool {
false
}
fn on_report_tx_data(&mut self, _entry: &ReportEntry, _message_id: &str, _result: MailResult) {}
#[doc(hidden)]
fn has_report_tx_data(&self) -> bool {
false
}
fn on_report_tx_commit(
&mut self,
_entry: &ReportEntry,
_message_id: &str,
_message_size: usize,
) {
}
#[doc(hidden)]
fn has_report_tx_commit(&self) -> bool {
false
}
fn on_report_tx_commit(
&mut self,
_entry: &ReportEntry,
_message_id: &str,
_message_size: usize,
) {
}
#[doc(hidden)]
fn has_report_tx_commit(&self) -> bool {
false
}
fn on_report_tx_rollback(&mut self, _entry: &ReportEntry, _message_id: &str) {}
#[doc(hidden)]
fn has_report_tx_rollback(&self) -> bool {
false
}
fn on_report_tx_rollback(&mut self, _entry: &ReportEntry, _message_id: &str) {}
#[doc(hidden)]
fn has_report_tx_rollback(&self) -> bool {
false
}
fn on_report_protocol_client(&mut self, _entry: &ReportEntry, _command: &str) {}
#[doc(hidden)]
fn has_report_protocol_client(&self) -> bool {
false
}
fn on_report_protocol_client(&mut self, _entry: &ReportEntry, _command: &str) {}
#[doc(hidden)]
fn has_report_protocol_client(&self) -> bool {
false
}
fn on_report_protocol_server(&mut self, _entry: &ReportEntry, _response: &str) {}
#[doc(hidden)]
fn has_report_protocol_server(&self) -> bool {
false
}
fn on_report_protocol_server(&mut self, _entry: &ReportEntry, _response: &str) {}
#[doc(hidden)]
fn has_report_protocol_server(&self) -> bool {
false
}
fn on_report_filter_response(
&mut self,
_entry: &ReportEntry,
_phase: FilterPhase,
_response: &str,
_param: &Option<String>,
) {
}
#[doc(hidden)]
fn has_report_filter_response(&self) -> bool {
false
}
fn on_report_filter_response(
&mut self,
_entry: &ReportEntry,
_phase: FilterPhase,
_response: &str,
_param: &Option<String>,
) {
}
#[doc(hidden)]
fn has_report_filter_response(&self) -> bool {
false
}
fn on_report_filter_report(
&mut self,
_entry: &ReportEntry,
_filter_kind: FilterKind,
_name: &str,
_message: &str,
) {
}
#[doc(hidden)]
fn has_report_filter_report(&self) -> bool {
false
}
fn on_report_filter_report(
&mut self,
_entry: &ReportEntry,
_filter_kind: FilterKind,
_name: &str,
_message: &str,
) {
}
#[doc(hidden)]
fn has_report_filter_report(&self) -> bool {
false
}
fn on_report_timeout(&mut self, _entry: &ReportEntry) {}
#[doc(hidden)]
fn has_report_timeout(&self) -> bool {
false
}
fn on_report_timeout(&mut self, _entry: &ReportEntry) {}
#[doc(hidden)]
fn has_report_timeout(&self) -> bool {
false
}
}

View file

@ -3,39 +3,39 @@ use std::io::{self, ErrorKind, Read};
use std::sync::mpsc::Sender;
pub(crate) fn read_stdin(tx: &Sender<Vec<u8>>) {
if let Err(e) = do_read_stdin(tx) {
log::error!("{}", e);
}
if let Err(e) = do_read_stdin(tx) {
log::error!("{}", e);
}
}
fn do_read_stdin(tx: &Sender<Vec<u8>>) -> Result<(), String> {
let mut read_buffer: [u8; crate::BUFFER_SIZE] = [0; crate::BUFFER_SIZE];
let mut line_buffer: Vec<u8> = Vec::with_capacity(crate::BUFFER_SIZE);
let mut stdin = io::stdin();
loop {
read_buffer.copy_from_slice(&[0; crate::BUFFER_SIZE]);
let len = match stdin.read(&mut read_buffer) {
Ok(n) => n,
Err(e) => match e.kind() {
ErrorKind::Interrupted => {
continue;
}
_ => {
return Err(e.to_string());
}
},
};
if len == 0 {
return Err(String::from("unable to read on stdin"));
}
line_buffer.extend_from_slice(&read_buffer[..len]);
while let Some(id) = line_buffer.iter().position(|i| *i == b'\n') {
let pos = id + 1;
let mut line = Vec::with_capacity(pos);
line.extend_from_slice(&line_buffer[..pos]);
log::trace!("new line:{}", get_pretty_hex(&line));
tx.send(line).unwrap();
line_buffer.drain(..pos);
}
}
let mut read_buffer: [u8; crate::BUFFER_SIZE] = [0; crate::BUFFER_SIZE];
let mut line_buffer: Vec<u8> = Vec::with_capacity(crate::BUFFER_SIZE);
let mut stdin = io::stdin();
loop {
read_buffer.copy_from_slice(&[0; crate::BUFFER_SIZE]);
let len = match stdin.read(&mut read_buffer) {
Ok(n) => n,
Err(e) => match e.kind() {
ErrorKind::Interrupted => {
continue;
}
_ => {
return Err(e.to_string());
}
},
};
if len == 0 {
return Err(String::from("unable to read on stdin"));
}
line_buffer.extend_from_slice(&read_buffer[..len]);
while let Some(id) = line_buffer.iter().position(|i| *i == b'\n') {
let pos = id + 1;
let mut line = Vec::with_capacity(pos);
line.extend_from_slice(&line_buffer[..pos]);
log::trace!("new line:{}", get_pretty_hex(&line));
tx.send(line).unwrap();
line_buffer.drain(..pos);
}
}
}

View file

@ -56,19 +56,19 @@
//! use opensmtpd_derive::register;
//!
//! struct MyCounter {
//! nb: u64,
//! nb: u64,
//! }
//!
//! impl Filter for MyCounter {
//! #[register]
//! fn on_report_link_disconnect(&mut self, _entry: &ReportEntry) {
//! self.nb + 1;
//! }
//! #[register]
//! fn on_report_link_disconnect(&mut self, _entry: &ReportEntry) {
//! self.nb + 1;
//! }
//! }
//!
//! fn main() {
//! let mut my_counter = MyCounter { nb: 0, };
//! run_filter(&mut my_counter);
//! let mut my_counter = MyCounter { nb: 0, };
//! run_filter(&mut my_counter);
//! }
//! ```
//!
@ -88,23 +88,23 @@
//! struct RmXOriginatingIp {}
//!
//! impl Filter for RmXOriginatingIp {
//! #[register]
//! fn on_filter_data_line(&mut self, entry: &FilterEntry, data_line: &[u8]) {
//! if data_line.len() >= HEADER_LEN {
//! let head_start = data_line[..HEADER_LEN].to_vec();
//! if let Ok(s) = String::from_utf8(head_start) {
//! if s.to_lowercase() == HEADER_NAME {
//! return;
//! }
//! }
//! }
//! return_data_line(entry, data_line);
//! }
//! #[register]
//! fn on_filter_data_line(&mut self, entry: &FilterEntry, data_line: &[u8]) {
//! if data_line.len() >= HEADER_LEN {
//! let head_start = data_line[..HEADER_LEN].to_vec();
//! if let Ok(s) = String::from_utf8(head_start) {
//! if s.to_lowercase() == HEADER_NAME {
//! return;
//! }
//! }
//! }
//! return_data_line(entry, data_line);
//! }
//! }
//!
//! fn main() {
//! let mut my_filter = RmXOriginatingIp {};
//! run_filter(&mut my_filter);
//! let mut my_filter = RmXOriginatingIp {};
//! run_filter(&mut my_filter);
//! }
//! ```
//!
@ -162,123 +162,123 @@ use std::thread;
const BUFFER_SIZE: usize = 4096;
macro_rules! recv {
($rx: ident) => {
match $rx.recv() {
Ok(b) => b,
Err(e) => {
log::error!("{}", e);
return;
}
}
};
($rx: ident) => {
match $rx.recv() {
Ok(b) => b,
Err(e) => {
log::error!("{}", e);
return;
}
}
};
}
pub fn run_filter<T>(user_object: &mut T)
where
T: Filter,
T: Filter,
{
// IO init
let (tx, rx) = channel::<Vec<u8>>();
thread::spawn(move || {
io::read_stdin(&tx);
});
// IO init
let (tx, rx) = channel::<Vec<u8>>();
thread::spawn(move || {
io::read_stdin(&tx);
});
// Handshake
let mut handshake_buffer: Vec<u8> = Vec::with_capacity(BUFFER_SIZE);
let handshake = loop {
let buffer = recv!(rx);
handshake_buffer.extend_from_slice(&buffer);
if let Ok((_, handshake)) = parse_handshake(&handshake_buffer) {
break handshake;
}
};
handshake_reply(user_object, handshake.subsystem);
// Handshake
let mut handshake_buffer: Vec<u8> = Vec::with_capacity(BUFFER_SIZE);
let handshake = loop {
let buffer = recv!(rx);
handshake_buffer.extend_from_slice(&buffer);
if let Ok((_, handshake)) = parse_handshake(&handshake_buffer) {
break handshake;
}
};
handshake_reply(user_object, handshake.subsystem);
// Read and process input
loop {
let buffer = recv!(rx);
if let Err(msg) = process::line(user_object, &buffer) {
log::error!("{}", msg);
}
}
// Read and process input
loop {
let buffer = recv!(rx);
if let Err(msg) = process::line(user_object, &buffer) {
log::error!("{}", msg);
}
}
}
macro_rules! handshake_register {
($obj: ident, $func: ident, $subsystem: expr, $type: expr, $name: expr) => {
if $obj.$func() {
println!("register|{}|{}|{}", $type, $subsystem.to_string(), $name);
log::trace!(
"{} {} for {} registered",
$type,
$name,
$subsystem.to_string()
);
}
};
($obj: ident, $func: ident, $subsystem: expr, $type: expr, $name: expr) => {
if $obj.$func() {
println!("register|{}|{}|{}", $type, $subsystem.to_string(), $name);
log::trace!(
"{} {} for {} registered",
$type,
$name,
$subsystem.to_string()
);
}
};
}
fn handshake_reply<T>(obj: &mut T, ss: SubSystem)
where
T: Filter,
T: Filter,
{
// Filters
handshake_register!(obj, has_filter_auth, ss, "filter", "auth");
handshake_register!(obj, has_filter_commit, ss, "filter", "commit");
handshake_register!(obj, has_filter_connect, ss, "filter", "connect");
handshake_register!(obj, has_filter_data, ss, "filter", "data");
handshake_register!(obj, has_filter_data_line, ss, "filter", "data-line");
handshake_register!(obj, has_filter_ehlo, ss, "filter", "ehlo");
handshake_register!(obj, has_filter_helo, ss, "filter", "helo");
handshake_register!(obj, has_filter_mail_from, ss, "filter", "mail-from");
handshake_register!(obj, has_filter_rcpt_to, ss, "filter", "rcpt-to");
handshake_register!(obj, has_filter_starttls, ss, "filter", "starttls");
// Filters
handshake_register!(obj, has_filter_auth, ss, "filter", "auth");
handshake_register!(obj, has_filter_commit, ss, "filter", "commit");
handshake_register!(obj, has_filter_connect, ss, "filter", "connect");
handshake_register!(obj, has_filter_data, ss, "filter", "data");
handshake_register!(obj, has_filter_data_line, ss, "filter", "data-line");
handshake_register!(obj, has_filter_ehlo, ss, "filter", "ehlo");
handshake_register!(obj, has_filter_helo, ss, "filter", "helo");
handshake_register!(obj, has_filter_mail_from, ss, "filter", "mail-from");
handshake_register!(obj, has_filter_rcpt_to, ss, "filter", "rcpt-to");
handshake_register!(obj, has_filter_starttls, ss, "filter", "starttls");
// Reports
handshake_register!(obj, has_report_link_auth, ss, "report", "link-auth");
handshake_register!(obj, has_report_link_connect, ss, "report", "link-connect");
handshake_register!(
obj,
has_report_link_disconnect,
ss,
"report",
"link-disconnect"
);
handshake_register!(obj, has_report_link_greeting, ss, "report", "link-greeting");
handshake_register!(obj, has_report_link_identify, ss, "report", "link-identify");
handshake_register!(obj, has_report_link_tls, ss, "report", "link-tls");
handshake_register!(obj, has_report_tx_begin, ss, "report", "tx-begin");
handshake_register!(obj, has_report_tx_mail, ss, "report", "tx-mail");
handshake_register!(obj, has_report_tx_reset, ss, "report", "tx-reset");
handshake_register!(obj, has_report_tx_rcpt, ss, "report", "tx-rcpt");
handshake_register!(obj, has_report_tx_envelope, ss, "report", "tx-envelope");
handshake_register!(obj, has_report_tx_data, ss, "report", "tx-data");
handshake_register!(obj, has_report_tx_commit, ss, "report", "tx-commit");
handshake_register!(obj, has_report_tx_rollback, ss, "report", "tx-rollback");
handshake_register!(
obj,
has_report_protocol_client,
ss,
"report",
"protocol-client"
);
handshake_register!(
obj,
has_report_protocol_server,
ss,
"report",
"protocol-server"
);
handshake_register!(
obj,
has_report_filter_response,
ss,
"report",
"filter-response"
);
handshake_register!(obj, has_report_filter_report, ss, "report", "filter-report");
handshake_register!(obj, has_report_timeout, ss, "report", "timeout");
// Reports
handshake_register!(obj, has_report_link_auth, ss, "report", "link-auth");
handshake_register!(obj, has_report_link_connect, ss, "report", "link-connect");
handshake_register!(
obj,
has_report_link_disconnect,
ss,
"report",
"link-disconnect"
);
handshake_register!(obj, has_report_link_greeting, ss, "report", "link-greeting");
handshake_register!(obj, has_report_link_identify, ss, "report", "link-identify");
handshake_register!(obj, has_report_link_tls, ss, "report", "link-tls");
handshake_register!(obj, has_report_tx_begin, ss, "report", "tx-begin");
handshake_register!(obj, has_report_tx_mail, ss, "report", "tx-mail");
handshake_register!(obj, has_report_tx_reset, ss, "report", "tx-reset");
handshake_register!(obj, has_report_tx_rcpt, ss, "report", "tx-rcpt");
handshake_register!(obj, has_report_tx_envelope, ss, "report", "tx-envelope");
handshake_register!(obj, has_report_tx_data, ss, "report", "tx-data");
handshake_register!(obj, has_report_tx_commit, ss, "report", "tx-commit");
handshake_register!(obj, has_report_tx_rollback, ss, "report", "tx-rollback");
handshake_register!(
obj,
has_report_protocol_client,
ss,
"report",
"protocol-client"
);
handshake_register!(
obj,
has_report_protocol_server,
ss,
"report",
"protocol-server"
);
handshake_register!(
obj,
has_report_filter_response,
ss,
"report",
"filter-response"
);
handshake_register!(obj, has_report_filter_report, ss, "report", "filter-report");
handshake_register!(obj, has_report_timeout, ss, "report", "timeout");
// Ready
println!("register|ready");
log::trace!("register ready");
// Ready
println!("register|ready");
log::trace!("register ready");
}

View file

@ -10,126 +10,126 @@ use nom::combinator::map_res;
use nom::IResult;
pub struct ReportEntry {
pub version: String,
pub timestamp: TimeVal,
pub subsystem: SubSystem,
pub event: Event,
pub session_id: String,
pub version: String,
pub timestamp: TimeVal,
pub subsystem: SubSystem,
pub event: Event,
pub session_id: String,
}
pub struct FilterEntry {
pub version: String,
pub timestamp: TimeVal,
pub subsystem: SubSystem,
pub phase: FilterPhase,
pub session_id: String,
pub token: String,
pub version: String,
pub timestamp: TimeVal,
pub subsystem: SubSystem,
pub phase: FilterPhase,
pub session_id: String,
pub token: String,
}
pub(crate) enum EntryOption {
Report(ReportEntry),
Filter(FilterEntry),
Report(ReportEntry),
Filter(FilterEntry),
}
pub(crate) fn parse_entry(input: &[u8]) -> IResult<&[u8], EntryOption> {
let (input, entry) = alt((parse_report_entry_meta, parse_filter_entry_meta))(input)?;
Ok((input, entry))
let (input, entry) = alt((parse_report_entry_meta, parse_filter_entry_meta))(input)?;
Ok((input, entry))
}
fn parse_report_entry_meta(input: &[u8]) -> IResult<&[u8], EntryOption> {
let (input, _) = tag("report")(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, entry) = parse_report_entry(input)?;
Ok((input, EntryOption::Report(entry)))
let (input, _) = tag("report")(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, entry) = parse_report_entry(input)?;
Ok((input, EntryOption::Report(entry)))
}
fn parse_filter_entry_meta(input: &[u8]) -> IResult<&[u8], EntryOption> {
let (input, _) = tag("filter")(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, entry) = parse_filter_entry(input)?;
Ok((input, EntryOption::Filter(entry)))
let (input, _) = tag("filter")(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, entry) = parse_filter_entry(input)?;
Ok((input, EntryOption::Filter(entry)))
}
fn parse_report_entry(input: &[u8]) -> IResult<&[u8], ReportEntry> {
let (input, version) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, timestamp) = parse_timestamp(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, subsystem) = parse_data_structure::<SubSystem>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, event) = parse_data_structure::<Event>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, session_id) = parse_string_parameter(input)?;
let entry = ReportEntry {
version,
timestamp,
subsystem,
event,
session_id,
};
Ok((input, entry))
let (input, version) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, timestamp) = parse_timestamp(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, subsystem) = parse_data_structure::<SubSystem>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, event) = parse_data_structure::<Event>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, session_id) = parse_string_parameter(input)?;
let entry = ReportEntry {
version,
timestamp,
subsystem,
event,
session_id,
};
Ok((input, entry))
}
fn parse_filter_entry(input: &[u8]) -> IResult<&[u8], FilterEntry> {
let (input, version) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, timestamp) = parse_timestamp(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, subsystem) = parse_data_structure::<SubSystem>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, phase) = parse_data_structure::<FilterPhase>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, session_id) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, token) = parse_string_parameter(input)?;
let entry = FilterEntry {
version,
timestamp,
subsystem,
phase,
session_id,
token,
};
Ok((input, entry))
let (input, version) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, timestamp) = parse_timestamp(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, subsystem) = parse_data_structure::<SubSystem>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, phase) = parse_data_structure::<FilterPhase>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, session_id) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, token) = parse_string_parameter(input)?;
let entry = FilterEntry {
version,
timestamp,
subsystem,
phase,
session_id,
token,
};
Ok((input, entry))
}
fn parse_timestamp(input: &[u8]) -> IResult<&[u8], TimeVal> {
let (input, sec) = map_res(digit1, |s| String::from_utf8_lossy(s).parse::<i64>())(input)?;
let (input, _) = tag(".")(input)?;
let (input, usec) = map_res(digit1, |s| {
format!("{:0<6}", String::from_utf8_lossy(s)).parse::<i64>()
})(input)?;
let timestamp = TimeVal { sec, usec };
Ok((input, timestamp))
let (input, sec) = map_res(digit1, |s| String::from_utf8_lossy(s).parse::<i64>())(input)?;
let (input, _) = tag(".")(input)?;
let (input, usec) = map_res(digit1, |s| {
format!("{:0<6}", String::from_utf8_lossy(s)).parse::<i64>()
})(input)?;
let timestamp = TimeVal { sec, usec };
Ok((input, timestamp))
}
#[cfg(test)]
mod tests {
use super::*;
use super::*;
#[test]
fn test_report_link_connect() {
let input = b"report|0.5|1576146008.06099|smtp-in|link-connect|7641df9771b4ed00|mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25";
let res = parse_entry(input);
assert!(res.is_ok());
let (_, res) = res.unwrap();
let res = match res {
EntryOption::Report(r) => r,
_ => {
assert!(false);
return;
}
};
assert_eq!(res.version, String::from("0.5"));
assert_eq!(
res.timestamp,
TimeVal {
sec: 1576146008,
usec: 60990
}
);
assert_eq!(res.subsystem, SubSystem::SmtpIn);
assert_eq!(res.event, Event::LinkConnect);
assert_eq!(res.session_id, String::from("7641df9771b4ed00"));
}
#[test]
fn test_report_link_connect() {
let input = b"report|0.5|1576146008.06099|smtp-in|link-connect|7641df9771b4ed00|mail.openbsd.org|pass|199.185.178.25:33174|45.77.67.80:25";
let res = parse_entry(input);
assert!(res.is_ok());
let (_, res) = res.unwrap();
let res = match res {
EntryOption::Report(r) => r,
_ => {
assert!(false);
return;
}
};
assert_eq!(res.version, String::from("0.5"));
assert_eq!(
res.timestamp,
TimeVal {
sec: 1576146008,
usec: 60990
}
);
assert_eq!(res.subsystem, SubSystem::SmtpIn);
assert_eq!(res.event, Event::LinkConnect);
assert_eq!(res.session_id, String::from("7641df9771b4ed00"));
}
}

View file

@ -1,5 +1,5 @@
use super::{
parse_data_structure, parse_delimiter, parse_eol, parse_string_parameter, parse_usize,
parse_data_structure, parse_delimiter, parse_eol, parse_string_parameter, parse_usize,
};
use crate::SubSystem;
use nom::bytes::streaming::tag;
@ -7,116 +7,116 @@ use nom::IResult;
#[derive(Debug)]
pub(crate) struct Handshake {
pub(crate) smtpd_version: String,
pub(crate) smtp_session_timeout: usize,
pub(crate) subsystem: SubSystem,
pub(crate) smtpd_version: String,
pub(crate) smtp_session_timeout: usize,
pub(crate) subsystem: SubSystem,
}
pub(crate) fn parse_handshake(input: &[u8]) -> IResult<&[u8], Handshake> {
let (input, smtpd_version) = parse_smtpd_version(input)?;
let (input, smtp_session_timeout) = parse_smtp_session_timeout(input)?;
let (input, subsystem) = parse_subsystem(input)?;
let (input, _) = parse_ready(input)?;
let handshake = Handshake {
smtpd_version,
smtp_session_timeout,
subsystem,
};
Ok((input, handshake))
let (input, smtpd_version) = parse_smtpd_version(input)?;
let (input, smtp_session_timeout) = parse_smtp_session_timeout(input)?;
let (input, subsystem) = parse_subsystem(input)?;
let (input, _) = parse_ready(input)?;
let handshake = Handshake {
smtpd_version,
smtp_session_timeout,
subsystem,
};
Ok((input, handshake))
}
fn parse_smtpd_version(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_config_initial(input)?;
let (input, _) = tag("smtpd-version")(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, version) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, version))
let (input, _) = parse_config_initial(input)?;
let (input, _) = tag("smtpd-version")(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, version) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, version))
}
fn parse_smtp_session_timeout(input: &[u8]) -> IResult<&[u8], usize> {
let (input, _) = parse_config_initial(input)?;
let (input, _) = tag("smtp-session-timeout")(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, timeout) = parse_usize(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, timeout))
let (input, _) = parse_config_initial(input)?;
let (input, _) = tag("smtp-session-timeout")(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, timeout) = parse_usize(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, timeout))
}
fn parse_subsystem(input: &[u8]) -> IResult<&[u8], SubSystem> {
let (input, _) = parse_config_initial(input)?;
let (input, _) = tag("subsystem")(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, subsystem) = parse_data_structure::<SubSystem>(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, subsystem))
let (input, _) = parse_config_initial(input)?;
let (input, _) = tag("subsystem")(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, subsystem) = parse_data_structure::<SubSystem>(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, subsystem))
}
fn parse_ready(input: &[u8]) -> IResult<&[u8], ()> {
let (input, _) = parse_config_initial(input)?;
let (input, _) = tag("ready")(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, ()))
let (input, _) = parse_config_initial(input)?;
let (input, _) = tag("ready")(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, ()))
}
fn parse_config_initial(input: &[u8]) -> IResult<&[u8], ()> {
let (input, _) = tag("config")(input)?;
let (input, _) = parse_delimiter(input)?;
Ok((input, ()))
let (input, _) = tag("config")(input)?;
let (input, _) = parse_delimiter(input)?;
Ok((input, ()))
}
#[cfg(test)]
mod tests {
use super::parse_handshake;
use crate::SubSystem;
use super::parse_handshake;
use crate::SubSystem;
#[test]
fn test_valid_handshake_nl() {
let input = b"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready\n";
let r = parse_handshake(input);
assert!(r.is_ok());
let (r, h) = r.unwrap();
assert_eq!(r, b"");
assert_eq!(h.smtpd_version, "6.6.1");
assert_eq!(h.smtp_session_timeout, 300);
assert_eq!(h.subsystem, SubSystem::SmtpIn);
}
#[test]
fn test_valid_handshake_nl() {
let input = b"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready\n";
let r = parse_handshake(input);
assert!(r.is_ok());
let (r, h) = r.unwrap();
assert_eq!(r, b"");
assert_eq!(h.smtpd_version, "6.6.1");
assert_eq!(h.smtp_session_timeout, 300);
assert_eq!(h.subsystem, SubSystem::SmtpIn);
}
#[test]
fn test_valid_handshake_crnl() {
let input = b"config|smtpd-version|6.6.1\r\nconfig|smtp-session-timeout|300\r\nconfig|subsystem|smtp-in\r\nconfig|ready\r\n";
let r = parse_handshake(input);
assert!(r.is_ok());
let (r, h) = r.unwrap();
assert_eq!(r, b"");
assert_eq!(h.smtpd_version, "6.6.1");
assert_eq!(h.smtp_session_timeout, 300);
assert_eq!(h.subsystem, SubSystem::SmtpIn);
}
#[test]
fn test_valid_handshake_crnl() {
let input = b"config|smtpd-version|6.6.1\r\nconfig|smtp-session-timeout|300\r\nconfig|subsystem|smtp-in\r\nconfig|ready\r\n";
let r = parse_handshake(input);
assert!(r.is_ok());
let (r, h) = r.unwrap();
assert_eq!(r, b"");
assert_eq!(h.smtpd_version, "6.6.1");
assert_eq!(h.smtp_session_timeout, 300);
assert_eq!(h.subsystem, SubSystem::SmtpIn);
}
#[test]
fn test_valid_handshake_over() {
let input = b"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready\nplop";
let r = parse_handshake(input);
assert!(r.is_ok());
let (r, h) = r.unwrap();
assert_eq!(r, b"plop");
assert_eq!(h.smtpd_version, "6.6.1");
assert_eq!(h.smtp_session_timeout, 300);
assert_eq!(h.subsystem, SubSystem::SmtpIn);
}
#[test]
fn test_valid_handshake_over() {
let input = b"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready\nplop";
let r = parse_handshake(input);
assert!(r.is_ok());
let (r, h) = r.unwrap();
assert_eq!(r, b"plop");
assert_eq!(h.smtpd_version, "6.6.1");
assert_eq!(h.smtp_session_timeout, 300);
assert_eq!(h.subsystem, SubSystem::SmtpIn);
}
#[test]
fn test_invalid_handshakes() {
let test_vectors = vec![
"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|\nconfig|subsystem|smtp-in\nconfig|ready\n",
"config|smtp-session-timeout|300\nconfig|smtpd-version|6.6.1\nconfig|subsystem|smtp-in\nconfig|ready\n",
"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready",
"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready\r",
];
for input in test_vectors {
let r = parse_handshake(input.as_bytes());
assert!(r.is_err());
}
}
#[test]
fn test_invalid_handshakes() {
let test_vectors = vec![
"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|\nconfig|subsystem|smtp-in\nconfig|ready\n",
"config|smtp-session-timeout|300\nconfig|smtpd-version|6.6.1\nconfig|subsystem|smtp-in\nconfig|ready\n",
"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready",
"config|smtpd-version|6.6.1\nconfig|smtp-session-timeout|300\nconfig|subsystem|smtp-in\nconfig|ready\r",
];
for input in test_vectors {
let r = parse_handshake(input.as_bytes());
assert!(r.is_err());
}
}
}

View file

@ -9,58 +9,58 @@ use nom::IResult;
use std::str::FromStr;
fn is_body_char(c: u8) -> bool {
!(c as char).is_control()
!(c as char).is_control()
}
fn is_parameter_char(c: u8) -> bool {
is_body_char(c) && (c as char) != '|'
is_body_char(c) && (c as char) != '|'
}
fn parse_string_parameter(input: &[u8]) -> IResult<&[u8], String> {
let (input, s) = take_while1(is_parameter_char)(input)?;
Ok((input, String::from_utf8(s.to_vec()).unwrap()))
let (input, s) = take_while1(is_parameter_char)(input)?;
Ok((input, String::from_utf8(s.to_vec()).unwrap()))
}
fn parse_data_structure<T>(input: &[u8]) -> IResult<&[u8], T>
where
T: FromStr,
T: FromStr,
{
map_res(take_while1(is_parameter_char), |s: &[u8]| {
T::from_str(&String::from_utf8_lossy(s))
})(input)
map_res(take_while1(is_parameter_char), |s: &[u8]| {
T::from_str(&String::from_utf8_lossy(s))
})(input)
}
fn parse_delimiter(input: &[u8]) -> IResult<&[u8], &[u8]> {
tag("|")(input)
tag("|")(input)
}
fn parse_eol(input: &[u8]) -> IResult<&[u8], &[u8]> {
alt((tag("\r\n"), tag("\n")))(input)
alt((tag("\r\n"), tag("\n")))(input)
}
fn parse_usize(input: &[u8]) -> IResult<&[u8], usize> {
map_res(take_while1(|c| (c as char).is_ascii_digit()), |s| {
usize::from_str_radix(&String::from_utf8_lossy(s), 10)
})(input)
map_res(take_while1(|c| (c as char).is_ascii_digit()), |s| {
usize::from_str_radix(&String::from_utf8_lossy(s), 10)
})(input)
}
#[cfg(test)]
mod tests {
use super::is_parameter_char;
use super::is_parameter_char;
#[test]
fn test_valid_parameter_char() {
let char_lst = "a0.:-_/";
for c in char_lst.bytes() {
assert!(is_parameter_char(c));
}
}
#[test]
fn test_valid_parameter_char() {
let char_lst = "a0.:-_/";
for c in char_lst.bytes() {
assert!(is_parameter_char(c));
}
}
#[test]
fn test_invalid_parameter_char() {
let char_lst = "|\n";
for c in char_lst.bytes() {
assert!(!is_parameter_char(c));
}
}
#[test]
fn test_invalid_parameter_char() {
let char_lst = "|\n";
for c in char_lst.bytes() {
assert!(!is_parameter_char(c));
}
}
}

View file

@ -1,6 +1,6 @@
use super::{
is_body_char, is_parameter_char, parse_data_structure, parse_delimiter, parse_eol,
parse_string_parameter, parse_usize,
is_body_char, is_parameter_char, parse_data_structure, parse_delimiter, parse_eol,
parse_string_parameter, parse_usize,
};
use crate::{Address, AuthResult, FilterKind, FilterPhase, MailResult, Method};
use nom::branch::alt;
@ -11,338 +11,338 @@ use std::net::SocketAddr;
use std::path::PathBuf;
pub(crate) fn parse_filter_auth(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
}
pub(crate) fn parse_filter_connect(
input: &[u8],
input: &[u8],
) -> IResult<&[u8], (String, String, Address, Address)> {
let (input, _) = parse_delimiter(input)?;
let (input, rdns) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, fcrdns) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, src) = parse_address(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, dest) = parse_address(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (rdns, fcrdns, src, dest)))
let (input, _) = parse_delimiter(input)?;
let (input, rdns) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, fcrdns) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, src) = parse_address(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, dest) = parse_address(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (rdns, fcrdns, src, dest)))
}
pub(crate) fn parse_filter_data_line(input: &[u8]) -> IResult<&[u8], &[u8]> {
let (input, _) = parse_delimiter(input)?;
let (input, s) = take_while(is_body_char)(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
let (input, _) = parse_delimiter(input)?;
let (input, s) = take_while(is_body_char)(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
}
pub(crate) fn parse_filter_ehlo(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
}
pub(crate) fn parse_filter_helo(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
}
pub(crate) fn parse_filter_mail_from(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
}
pub(crate) fn parse_filter_rcpt_to(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
}
pub(crate) fn parse_filter_starttls(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, s))
}
pub(crate) fn parse_report_link_auth(input: &[u8]) -> IResult<&[u8], (String, AuthResult)> {
let (input, _) = parse_delimiter(input)?;
let (input, username) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, result) = parse_data_structure::<AuthResult>(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (username, result)))
let (input, _) = parse_delimiter(input)?;
let (input, username) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, result) = parse_data_structure::<AuthResult>(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (username, result)))
}
pub(crate) fn parse_report_link_connect(
input: &[u8],
input: &[u8],
) -> IResult<&[u8], (String, String, Address, Address)> {
let (input, _) = parse_delimiter(input)?;
let (input, rdns) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, fcrdns) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, src) = parse_address(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, dest) = parse_address(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (rdns, fcrdns, src, dest)))
let (input, _) = parse_delimiter(input)?;
let (input, rdns) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, fcrdns) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, src) = parse_address(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, dest) = parse_address(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (rdns, fcrdns, src, dest)))
}
pub(crate) fn parse_report_link_greeting(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, hostname) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, hostname))
let (input, _) = parse_delimiter(input)?;
let (input, hostname) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, hostname))
}
pub(crate) fn parse_report_link_identify(input: &[u8]) -> IResult<&[u8], (Method, String)> {
let (input, _) = parse_delimiter(input)?;
let (input, method) = parse_data_structure::<Method>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, identity) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (method, identity)))
let (input, _) = parse_delimiter(input)?;
let (input, method) = parse_data_structure::<Method>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, identity) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (method, identity)))
}
pub(crate) fn parse_report_link_tls(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, tls_string) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, tls_string))
let (input, _) = parse_delimiter(input)?;
let (input, tls_string) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, tls_string))
}
pub(crate) fn parse_report_tx_begin(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, id))
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, id))
}
pub(crate) fn parse_report_tx_mail(input: &[u8]) -> IResult<&[u8], (String, MailResult, String)> {
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, result) = parse_data_structure::<MailResult>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, addr) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (id, result, addr)))
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, result) = parse_data_structure::<MailResult>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, addr) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (id, result, addr)))
}
pub(crate) fn parse_report_tx_reset(input: &[u8]) -> IResult<&[u8], Option<String>> {
let (input, id) = opt(parse_tx_reset_opt)(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, id))
let (input, id) = opt(parse_tx_reset_opt)(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, id))
}
fn parse_tx_reset_opt(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
Ok((input, id))
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
Ok((input, id))
}
pub(crate) fn parse_report_tx_rcpt(input: &[u8]) -> IResult<&[u8], (String, MailResult, String)> {
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, result) = parse_data_structure::<MailResult>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, addr) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (id, result, addr)))
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, result) = parse_data_structure::<MailResult>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, addr) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (id, result, addr)))
}
pub(crate) fn parse_report_tx_envelope(input: &[u8]) -> IResult<&[u8], (String, String)> {
let (input, _) = parse_delimiter(input)?;
let (input, msg) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, env) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (msg, env)))
let (input, _) = parse_delimiter(input)?;
let (input, msg) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, env) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (msg, env)))
}
pub(crate) fn parse_report_tx_data(input: &[u8]) -> IResult<&[u8], (String, MailResult)> {
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, result) = parse_data_structure::<MailResult>(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (id, result)))
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, result) = parse_data_structure::<MailResult>(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (id, result)))
}
pub(crate) fn parse_report_tx_commit(input: &[u8]) -> IResult<&[u8], (String, usize)> {
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_usize(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (id, s)))
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, s) = parse_usize(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (id, s)))
}
pub(crate) fn parse_report_tx_rollback(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, id))
let (input, _) = parse_delimiter(input)?;
let (input, id) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, id))
}
pub(crate) fn parse_report_protocol_client(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, cmd) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, cmd))
let (input, _) = parse_delimiter(input)?;
let (input, cmd) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, cmd))
}
pub(crate) fn parse_report_protocol_server(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
let (input, res) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, res))
let (input, _) = parse_delimiter(input)?;
let (input, res) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, res))
}
pub(crate) fn parse_report_filter_response(
input: &[u8],
input: &[u8],
) -> IResult<&[u8], (FilterPhase, String, Option<String>)> {
let (input, _) = parse_delimiter(input)?;
let (input, phase) = parse_data_structure::<FilterPhase>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, res) = parse_string_parameter(input)?;
let (input, param) = opt(parse_filter_response_opt)(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (phase, res, param)))
let (input, _) = parse_delimiter(input)?;
let (input, phase) = parse_data_structure::<FilterPhase>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, res) = parse_string_parameter(input)?;
let (input, param) = opt(parse_filter_response_opt)(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (phase, res, param)))
}
fn parse_filter_response_opt(input: &[u8]) -> IResult<&[u8], String> {
let (input, _) = parse_delimiter(input)?;
parse_string_parameter(input)
let (input, _) = parse_delimiter(input)?;
parse_string_parameter(input)
}
pub(crate) fn parse_report_filter_report(
input: &[u8],
input: &[u8],
) -> IResult<&[u8], (FilterKind, String, String)> {
let (input, _) = parse_delimiter(input)?;
let (input, kind) = parse_data_structure::<FilterKind>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, name) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, message) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (kind, name, message)))
let (input, _) = parse_delimiter(input)?;
let (input, kind) = parse_data_structure::<FilterKind>(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, name) = parse_string_parameter(input)?;
let (input, _) = parse_delimiter(input)?;
let (input, message) = parse_string_parameter(input)?;
let (input, _) = parse_eol(input)?;
Ok((input, (kind, name, message)))
}
fn parse_address(input: &[u8]) -> IResult<&[u8], Address> {
alt((parse_unix_socket, parse_socketaddr))(input)
alt((parse_unix_socket, parse_socketaddr))(input)
}
fn parse_socketaddr(input: &[u8]) -> IResult<&[u8], Address> {
map_res(
take_while1(is_parameter_char),
|s: &[u8]| -> Result<Address, String> {
let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?;
let addr = s.parse::<SocketAddr>().map_err(|e| e.to_string())?;
Ok(Address::Ip(addr))
},
)(input)
map_res(
take_while1(is_parameter_char),
|s: &[u8]| -> Result<Address, String> {
let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?;
let addr = s.parse::<SocketAddr>().map_err(|e| e.to_string())?;
Ok(Address::Ip(addr))
},
)(input)
}
fn parse_unix_socket(input: &[u8]) -> IResult<&[u8], Address> {
let (input, _) = tag("unix:")(input)?;
map_res(
take_while1(is_parameter_char),
|s: &[u8]| -> Result<Address, String> {
let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?;
let addr = s.parse::<PathBuf>().map_err(|e| e.to_string())?;
Ok(Address::UnixSocket(addr))
},
)(input)
let (input, _) = tag("unix:")(input)?;
map_res(
take_while1(is_parameter_char),
|s: &[u8]| -> Result<Address, String> {
let s = String::from_utf8(s.to_vec()).map_err(|e| e.to_string())?;
let addr = s.parse::<PathBuf>().map_err(|e| e.to_string())?;
Ok(Address::UnixSocket(addr))
},
)(input)
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::path::Path;
use super::*;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::path::Path;
#[test]
fn test_ipv4_port() {
let res = parse_address(b"199.185.178.25:33174|");
assert!(res.is_ok());
let (i, addr) = res.unwrap();
assert_eq!(i, b"|");
match addr {
Address::Ip(addr) => {
assert!(addr.is_ipv4());
assert_eq!(addr.port(), 33174);
assert_eq!(addr.ip(), IpAddr::V4(Ipv4Addr::new(199, 185, 178, 25)));
}
Address::UnixSocket(_) => assert!(false),
};
}
#[test]
fn test_ipv4_port() {
let res = parse_address(b"199.185.178.25:33174|");
assert!(res.is_ok());
let (i, addr) = res.unwrap();
assert_eq!(i, b"|");
match addr {
Address::Ip(addr) => {
assert!(addr.is_ipv4());
assert_eq!(addr.port(), 33174);
assert_eq!(addr.ip(), IpAddr::V4(Ipv4Addr::new(199, 185, 178, 25)));
}
Address::UnixSocket(_) => assert!(false),
};
}
#[test]
fn test_ipv6_port() {
let res = parse_address(b"[2001:db8::42]:33174\n");
assert!(res.is_ok());
let (i, addr) = res.unwrap();
assert_eq!(i, b"\n");
match addr {
Address::Ip(addr) => {
assert!(addr.is_ipv6());
assert_eq!(addr.port(), 33174);
assert_eq!(
addr.ip(),
IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0x42))
);
}
Address::UnixSocket(_) => assert!(false),
};
}
#[test]
fn test_ipv6_port() {
let res = parse_address(b"[2001:db8::42]:33174\n");
assert!(res.is_ok());
let (i, addr) = res.unwrap();
assert_eq!(i, b"\n");
match addr {
Address::Ip(addr) => {
assert!(addr.is_ipv6());
assert_eq!(addr.port(), 33174);
assert_eq!(
addr.ip(),
IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0x42))
);
}
Address::UnixSocket(_) => assert!(false),
};
}
#[test]
fn test_unix_socket() {
let res = parse_address(b"unix:/var/something.sock|");
assert!(res.is_ok());
let (i, addr) = res.unwrap();
assert_eq!(i, b"|");
match addr {
Address::UnixSocket(addr) => {
assert_eq!(addr, Path::new("/var/something.sock").to_path_buf());
}
Address::Ip(_) => assert!(false),
};
}
#[test]
fn test_unix_socket() {
let res = parse_address(b"unix:/var/something.sock|");
assert!(res.is_ok());
let (i, addr) = res.unwrap();
assert_eq!(i, b"|");
match addr {
Address::UnixSocket(addr) => {
assert_eq!(addr, Path::new("/var/something.sock").to_path_buf());
}
Address::Ip(_) => assert!(false),
};
}
#[test]
fn test_valid_parse_filter_auth() {
let test_vectors = vec![
("|derp\n", "derp"),
("|derp.derpson@example.com\r\n", "derp.derpson@example.com"),
];
for (test, ref_auth) in test_vectors {
let res = parse_filter_auth(test.as_bytes());
assert!(res.is_ok());
let (input, auth) = res.unwrap();
assert_eq!(input, b"");
assert_eq!(auth, ref_auth.to_string());
}
}
#[test]
fn test_valid_parse_filter_auth() {
let test_vectors = vec![
("|derp\n", "derp"),
("|derp.derpson@example.com\r\n", "derp.derpson@example.com"),
];
for (test, ref_auth) in test_vectors {
let res = parse_filter_auth(test.as_bytes());
assert!(res.is_ok());
let (input, auth) = res.unwrap();
assert_eq!(input, b"");
assert_eq!(auth, ref_auth.to_string());
}
}
#[test]
fn test_invalid_parse_filter_auth() {
let test_vectors = vec!["|\n", "|\r\n", "|derp", "|derp|derpson\n"];
for test in test_vectors {
let res = parse_filter_auth(test.as_bytes());
assert!(!res.is_ok());
}
}
#[test]
fn test_invalid_parse_filter_auth() {
let test_vectors = vec!["|\n", "|\r\n", "|derp", "|derp|derpson\n"];
for test in test_vectors {
let res = parse_filter_auth(test.as_bytes());
assert!(!res.is_ok());
}
}
}

View file

@ -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, &param);
}
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, &param);
}
Event::FilterReport => {
let (_, (kind, name, message)) =
parse_report_filter_report($input).map_err(|e| e.to_string())?;
$obj.on_report_filter_report(&$r, kind, &name, &message);
}
Event::Timeout => {
$obj.on_report_timeout(&$r);
}
}
};
}
macro_rules! handle_filters {
($obj: ident, $f: ident, $input: ident) => {
match $f.phase {
FilterPhase::Auth => {
let (_, auth) = parse_filter_auth($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_auth(&$f, &auth))
}
FilterPhase::Commit => Some($obj.on_filter_commit(&$f)),
FilterPhase::Connect => {
let (_, (rdns, fcrdns, src, dest)) =
parse_filter_connect($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_connect(&$f, &rdns, &fcrdns, &src, &dest))
}
FilterPhase::Data => Some($obj.on_filter_data(&$f)),
FilterPhase::DataLine => {
let (_, data_line) = parse_filter_data_line($input).map_err(|e| e.to_string())?;
$obj.on_filter_data_line(&$f, &data_line);
None
}
FilterPhase::Ehlo => {
let (_, identity) = parse_filter_ehlo($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_ehlo(&$f, &identity))
}
FilterPhase::Helo => {
let (_, identity) = parse_filter_helo($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_helo(&$f, &identity))
}
FilterPhase::MailFrom => {
let (_, address) = parse_filter_mail_from($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_mail_from(&$f, &address))
}
FilterPhase::RcptTo => {
let (_, address) = parse_filter_rcpt_to($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_rcpt_to(&$f, &address))
}
FilterPhase::StartTls => {
let (_, tls_str) = parse_filter_starttls($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_starttls(&$f, &tls_str))
}
}
};
($obj: ident, $f: ident, $input: ident) => {
match $f.phase {
FilterPhase::Auth => {
let (_, auth) = parse_filter_auth($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_auth(&$f, &auth))
}
FilterPhase::Commit => Some($obj.on_filter_commit(&$f)),
FilterPhase::Connect => {
let (_, (rdns, fcrdns, src, dest)) =
parse_filter_connect($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_connect(&$f, &rdns, &fcrdns, &src, &dest))
}
FilterPhase::Data => Some($obj.on_filter_data(&$f)),
FilterPhase::DataLine => {
let (_, data_line) = parse_filter_data_line($input).map_err(|e| e.to_string())?;
$obj.on_filter_data_line(&$f, &data_line);
None
}
FilterPhase::Ehlo => {
let (_, identity) = parse_filter_ehlo($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_ehlo(&$f, &identity))
}
FilterPhase::Helo => {
let (_, identity) = parse_filter_helo($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_helo(&$f, &identity))
}
FilterPhase::MailFrom => {
let (_, address) = parse_filter_mail_from($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_mail_from(&$f, &address))
}
FilterPhase::RcptTo => {
let (_, address) = parse_filter_rcpt_to($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_rcpt_to(&$f, &address))
}
FilterPhase::StartTls => {
let (_, tls_str) = parse_filter_starttls($input).map_err(|e| e.to_string())?;
Some($obj.on_filter_starttls(&$f, &tls_str))
}
}
};
}
pub(crate) fn line<T>(user_object: &mut T, input: &[u8]) -> Result<(), String>
where
T: Filter,
T: Filter,
{
let (input, entry) = parse_entry(input).map_err(nom_err_to_string)?;
match entry {
EntryOption::Report(r) => handle_reports!(user_object, r, input),
EntryOption::Filter(f) => {
if let Some(answer) = handle_filters!(user_object, f, input) {
println!(
"filter-result|{}|{}|{}",
f.session_id,
f.token,
answer.to_string()
);
};
}
};
Ok(())
let (input, entry) = parse_entry(input).map_err(nom_err_to_string)?;
match entry {
EntryOption::Report(r) => handle_reports!(user_object, r, input),
EntryOption::Filter(f) => {
if let Some(answer) = handle_filters!(user_object, f, input) {
println!(
"filter-result|{}|{}|{}",
f.session_id,
f.token,
answer.to_string()
);
};
}
};
Ok(())
}