2023-04-09 15:13:18 +02:00
|
|
|
mod action;
|
2023-03-26 17:15:41 +02:00
|
|
|
mod algorithm;
|
2023-03-25 19:10:06 +01:00
|
|
|
mod canonicalization;
|
2023-03-26 16:07:49 +02:00
|
|
|
mod config;
|
2023-04-09 17:21:17 +02:00
|
|
|
mod db;
|
2023-03-19 19:06:29 +01:00
|
|
|
mod entry;
|
2023-03-19 17:13:49 +01:00
|
|
|
mod handshake;
|
2023-04-09 17:21:17 +02:00
|
|
|
mod key;
|
2023-03-21 13:00:44 +01:00
|
|
|
mod logs;
|
2023-03-19 20:32:11 +01:00
|
|
|
mod message;
|
2023-03-27 22:46:17 +02:00
|
|
|
mod parsed_message;
|
2023-04-15 19:24:04 +02:00
|
|
|
mod signature;
|
2023-03-19 19:29:02 +01:00
|
|
|
mod stdin_reader;
|
2023-03-19 17:13:49 +01:00
|
|
|
|
2023-04-09 17:44:17 +02:00
|
|
|
use action::{new_action, Action, ActionResult};
|
2023-03-26 23:08:44 +02:00
|
|
|
use algorithm::Algorithm;
|
|
|
|
use canonicalization::CanonicalizationType;
|
2023-04-09 15:13:18 +02:00
|
|
|
use futures::stream::FuturesUnordered;
|
|
|
|
use futures::StreamExt;
|
2023-04-09 19:28:25 +02:00
|
|
|
use key::key_rotation;
|
2023-03-19 20:32:11 +01:00
|
|
|
use message::Message;
|
2023-04-09 17:21:17 +02:00
|
|
|
use sqlx::SqlitePool;
|
2023-03-19 20:32:11 +01:00
|
|
|
use std::collections::HashMap;
|
2023-04-09 15:13:18 +02:00
|
|
|
use std::sync::Arc;
|
2023-03-19 19:29:02 +01:00
|
|
|
use stdin_reader::StdinReader;
|
2023-04-09 15:13:18 +02:00
|
|
|
use tokio::sync::RwLock;
|
2023-03-19 19:06:29 +01:00
|
|
|
|
|
|
|
const DEFAULT_BUFF_SIZE: usize = 1024;
|
2023-03-26 23:08:44 +02:00
|
|
|
const DEFAULT_CNF_ALGORITHM: Algorithm = Algorithm::Rsa2048Sha256;
|
|
|
|
const DEFAULT_CNF_CANONICALIZATION_BODY: CanonicalizationType = CanonicalizationType::Relaxed;
|
|
|
|
const DEFAULT_CNF_CANONICALIZATION_HEADER: CanonicalizationType = CanonicalizationType::Relaxed;
|
|
|
|
const DEFAULT_CNF_CRYPTOPERIOD: u64 = 15552000;
|
|
|
|
const DEFAULT_CNF_EXPIRATION: u64 = 1296000;
|
|
|
|
const DEFAULT_CNF_HEADERS: &str = "from:reply-to:subject:date:to:cc";
|
|
|
|
const DEFAULT_CNF_HEADERS_OPT: &str = "resent-date:resent-from:resent-to:resent-cc:in-reply-to:references:list-id:list-help:list-unsubscribe:list-subscribe:list-post:list-owner:list-archive";
|
|
|
|
const DEFAULT_CNF_KEY_DB: &str = "key-db.sqlite3";
|
|
|
|
const DEFAULT_CNF_REVOCATION: u64 = 1728000;
|
2023-03-26 23:42:16 +02:00
|
|
|
const DEFAULT_LIB_DIR: &str = env!("VARLIBDIR");
|
2023-03-23 20:54:20 +01:00
|
|
|
const DEFAULT_MSG_SIZE: usize = 1024 * 1024;
|
2023-04-10 11:18:11 +02:00
|
|
|
const KEY_CHECK_MIN_DELAY: u64 = 60 * 60 * 3;
|
2023-03-21 13:00:44 +01:00
|
|
|
const LOG_LEVEL_ENV_VAR: &str = "OPENSMTPD_FILTER_DKIMOUT_LOG_LEVEL";
|
2023-04-15 19:24:04 +02:00
|
|
|
const SIG_RETRY_NB_RETRY: usize = 10;
|
|
|
|
const SIG_RETRY_SLEEP_TIME: u64 = 10;
|
2023-03-21 13:00:44 +01:00
|
|
|
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! display_bytes {
|
|
|
|
($bytes: expr) => {
|
|
|
|
$bytes
|
|
|
|
.iter()
|
|
|
|
.map(|b| {
|
|
|
|
let v: Vec<u8> = std::ascii::escape_default(*b).collect();
|
|
|
|
String::from_utf8_lossy(&v).to_string()
|
|
|
|
})
|
|
|
|
.collect::<String>()
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! log_messages {
|
|
|
|
($list: ident) => {
|
|
|
|
log::trace!(
|
|
|
|
"message list has {} elements: {}",
|
|
|
|
$list.len(),
|
|
|
|
$list
|
|
|
|
.iter()
|
|
|
|
.map(|(k, v)| { format!("{k} ({} lines)", v.nb_lines()) })
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
.join(", ")
|
|
|
|
)
|
|
|
|
};
|
|
|
|
}
|
2023-03-19 19:06:29 +01:00
|
|
|
|
2023-04-09 11:07:16 +02:00
|
|
|
#[tokio::main]
|
|
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
2023-03-26 16:07:49 +02:00
|
|
|
match config::Config::init() {
|
|
|
|
Ok(cnf) => {
|
2023-03-26 21:49:34 +02:00
|
|
|
logs::init_log_system(&cnf);
|
2023-03-26 16:07:49 +02:00
|
|
|
log::debug!("{cnf:?}");
|
2023-04-09 17:21:17 +02:00
|
|
|
match db::init(&cnf).await {
|
|
|
|
Ok(pool) => main_loop(&cnf, &pool).await,
|
|
|
|
Err(e) => eprintln!("{e}"),
|
|
|
|
}
|
2023-03-26 16:07:49 +02:00
|
|
|
}
|
2023-03-26 21:49:34 +02:00
|
|
|
Err(e) => eprintln!("{e}"),
|
2023-03-26 16:07:49 +02:00
|
|
|
}
|
2023-04-09 11:07:16 +02:00
|
|
|
Ok(())
|
2023-03-26 16:07:49 +02:00
|
|
|
}
|
|
|
|
|
2023-04-09 17:21:17 +02:00
|
|
|
async fn main_loop(cnf: &config::Config, db: &SqlitePool) {
|
2023-04-09 15:13:18 +02:00
|
|
|
let mut actions = FuturesUnordered::new();
|
2023-03-19 19:29:02 +01:00
|
|
|
let mut reader = StdinReader::new();
|
2023-03-19 20:32:11 +01:00
|
|
|
let mut messages: HashMap<String, Message> = HashMap::new();
|
2023-04-09 23:31:32 +02:00
|
|
|
tokio::join!(handshake::read_config(&mut reader), key_rotation(db, cnf));
|
2023-03-19 17:13:49 +01:00
|
|
|
handshake::register_filter();
|
2023-03-21 13:00:44 +01:00
|
|
|
log_messages!(messages);
|
2023-04-09 15:13:18 +02:00
|
|
|
let reader_lock = Arc::new(RwLock::new(reader));
|
2023-04-09 17:44:17 +02:00
|
|
|
actions.push(new_action(Action::ReadLine(reader_lock.clone())));
|
|
|
|
actions.push(new_action(Action::RotateKeys((db, cnf))));
|
2023-03-19 19:06:29 +01:00
|
|
|
loop {
|
2023-04-09 17:21:17 +02:00
|
|
|
if actions.len() <= 1 {
|
2023-04-09 15:13:18 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if let Some(action_res) = actions.next().await {
|
|
|
|
match action_res {
|
|
|
|
ActionResult::EndOfStream => {
|
|
|
|
log::debug!("end of input stream");
|
|
|
|
}
|
2023-04-09 17:21:17 +02:00
|
|
|
ActionResult::KeyRotation => {
|
2023-04-09 17:44:17 +02:00
|
|
|
actions.push(new_action(Action::RotateKeys((db, cnf))));
|
2023-04-09 17:21:17 +02:00
|
|
|
}
|
2023-04-09 15:13:18 +02:00
|
|
|
ActionResult::MessageSent(msg_id) => {
|
|
|
|
log::debug!("message removed: {msg_id}");
|
|
|
|
}
|
|
|
|
ActionResult::NewEntry(entry) => {
|
|
|
|
let msg_id = entry.get_msg_id();
|
|
|
|
match messages.get_mut(&msg_id) {
|
|
|
|
Some(msg) => {
|
|
|
|
if !entry.is_end_of_message() {
|
|
|
|
log::debug!("new line in message: {msg_id}");
|
|
|
|
msg.append_line(entry.get_data());
|
|
|
|
} else {
|
|
|
|
log::debug!("message ready: {msg_id}");
|
|
|
|
if let Some(m) = messages.remove(&msg_id) {
|
2023-04-15 19:24:04 +02:00
|
|
|
actions.push(new_action(Action::SendMessage((db, cnf, m))));
|
2023-04-09 15:13:18 +02:00
|
|
|
}
|
|
|
|
}
|
2023-03-19 20:32:11 +01:00
|
|
|
}
|
2023-04-09 15:13:18 +02:00
|
|
|
None => {
|
|
|
|
let msg = Message::from_entry(&entry);
|
2023-03-21 13:00:44 +01:00
|
|
|
log::debug!("new message: {msg_id}");
|
2023-04-09 15:13:18 +02:00
|
|
|
if !entry.is_end_of_message() {
|
|
|
|
messages.insert(msg_id.clone(), msg);
|
|
|
|
} else {
|
2023-04-15 19:24:04 +02:00
|
|
|
actions.push(new_action(Action::SendMessage((db, cnf, msg))));
|
2023-04-09 15:13:18 +02:00
|
|
|
}
|
2023-03-19 20:32:11 +01:00
|
|
|
}
|
|
|
|
}
|
2023-04-09 15:13:18 +02:00
|
|
|
log_messages!(messages);
|
2023-04-09 17:44:17 +02:00
|
|
|
actions.push(new_action(Action::ReadLine(reader_lock.clone())));
|
2023-04-09 15:13:18 +02:00
|
|
|
}
|
|
|
|
ActionResult::NewEntryError(err) => {
|
|
|
|
log::error!("invalid filter line: {err}");
|
2023-04-09 17:44:17 +02:00
|
|
|
actions.push(new_action(Action::ReadLine(reader_lock.clone())));
|
2023-03-19 19:06:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|