Support for referencing context variables from dynamic values.
This commit is contained in:
@@ -24,7 +24,7 @@ test = [
|
||||
{if = "rcpt-domain", starts-with = "foo", then = "${0}${{0}}"},
|
||||
{else = false}
|
||||
]
|
||||
expect = "foo.example.org${{0}}"
|
||||
expect = "foo.example.org${0}"
|
||||
|
||||
[eval."regex"]
|
||||
test = [
|
||||
@@ -40,6 +40,13 @@ test = [
|
||||
]
|
||||
expect = "user@foo.example.org"
|
||||
|
||||
[eval."envelope-match"]
|
||||
test = [
|
||||
{if = "authenticated-as", matches = "^([^.]+)@(.+)$", then = "rcpt ${rcpt} listener ${listener} ip ${local-ip} priority ${priority}"},
|
||||
{else = false}
|
||||
]
|
||||
expect = "rcpt user@foo.example.org listener 123 ip 192.168.9.3 priority -4"
|
||||
|
||||
[eval."static-match"]
|
||||
test = [
|
||||
{if = "authenticated-as", matches = "^([^.]+)@(.+)$", then = "hello world"},
|
||||
@@ -64,6 +71,11 @@ type = "memory"
|
||||
[directory."list_foo".lookup]
|
||||
domains = ["foo"]
|
||||
|
||||
[directory."list_123"]
|
||||
type = "memory"
|
||||
[directory."list_123".lookup]
|
||||
domains = ["123"]
|
||||
|
||||
[maybe-eval."dyn_mx"]
|
||||
test = [
|
||||
{if = "mx", matches = "([^.]+)\.(.+)$", then = "list_${1}"},
|
||||
@@ -86,3 +98,7 @@ expect = "mx"
|
||||
test = "list_foo"
|
||||
expect = "foo"
|
||||
|
||||
[maybe-eval."dyn_123"]
|
||||
test = "list_${listener}"
|
||||
expect = "123"
|
||||
|
||||
|
||||
@@ -21,22 +21,26 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
use std::{borrow::Cow, fs, net::IpAddr, path::PathBuf, sync::Arc, time::Duration};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fs,
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use tokio::net::TcpSocket;
|
||||
|
||||
use utils::config::{Config, DynValue, Listener, Rate, Server, ServerProtocol};
|
||||
use utils::config::{Config, DynValue, KeyLookup, Listener, Rate, Server, ServerProtocol};
|
||||
|
||||
use ahash::{AHashMap, AHashSet};
|
||||
use directory::{config::ConfigDirectory, Lookup};
|
||||
|
||||
use smtp::{
|
||||
config::{
|
||||
condition::ConfigCondition, if_block::ConfigIf, throttle::ConfigThrottle, Condition,
|
||||
ConditionMatch, Conditions, ConfigContext, EnvelopeKey, IfBlock, IfThen, IpAddrMask,
|
||||
StringMatch, Throttle, THROTTLE_AUTH_AS, THROTTLE_REMOTE_IP, THROTTLE_SENDER_DOMAIN,
|
||||
},
|
||||
core::Envelope,
|
||||
use smtp::config::{
|
||||
condition::ConfigCondition, if_block::ConfigIf, throttle::ConfigThrottle, Condition,
|
||||
ConditionMatch, Conditions, ConfigContext, EnvelopeKey, IfBlock, IfThen, IpAddrMask,
|
||||
StringMatch, Throttle, THROTTLE_AUTH_AS, THROTTLE_REMOTE_IP, THROTTLE_SENDER_DOMAIN,
|
||||
};
|
||||
|
||||
use super::add_test_certs;
|
||||
@@ -597,7 +601,7 @@ async fn eval_dynvalue() {
|
||||
for test_name in config.sub_keys("eval") {
|
||||
//println!("============= Testing {:?} ==================", key);
|
||||
let if_block = config
|
||||
.parse_if_block::<Option<DynValue>>(
|
||||
.parse_if_block::<Option<DynValue<EnvelopeKey>>>(
|
||||
("eval", test_name, "test"),
|
||||
&context,
|
||||
&[
|
||||
@@ -621,7 +625,10 @@ async fn eval_dynvalue() {
|
||||
.map(Cow::Owned);
|
||||
|
||||
assert_eq!(
|
||||
if_block.eval_and_capture(&envelope).await.into_value(),
|
||||
if_block
|
||||
.eval_and_capture(&envelope)
|
||||
.await
|
||||
.into_value(&envelope),
|
||||
expected,
|
||||
"failed for test {test_name:?}"
|
||||
);
|
||||
@@ -630,7 +637,7 @@ async fn eval_dynvalue() {
|
||||
for test_name in config.sub_keys("maybe-eval") {
|
||||
//println!("============= Testing {:?} ==================", key);
|
||||
let if_block = config
|
||||
.parse_if_block::<Option<DynValue>>(
|
||||
.parse_if_block::<Option<DynValue<EnvelopeKey>>>(
|
||||
("maybe-eval", test_name, "test"),
|
||||
&context,
|
||||
&[
|
||||
@@ -661,7 +668,7 @@ async fn eval_dynvalue() {
|
||||
assert!(if_block
|
||||
.eval_and_capture(&envelope)
|
||||
.await
|
||||
.into_value()
|
||||
.into_value(&envelope)
|
||||
.unwrap()
|
||||
.is_local_domain(expected)
|
||||
.await
|
||||
@@ -669,49 +676,39 @@ async fn eval_dynvalue() {
|
||||
}
|
||||
}
|
||||
|
||||
impl Envelope for TestEnvelope {
|
||||
fn local_ip(&self) -> IpAddr {
|
||||
self.local_ip
|
||||
impl KeyLookup for TestEnvelope {
|
||||
type Key = EnvelopeKey;
|
||||
|
||||
fn key(&self, key: &Self::Key) -> std::borrow::Cow<'_, str> {
|
||||
match key {
|
||||
EnvelopeKey::Recipient => self.rcpt.as_str().into(),
|
||||
EnvelopeKey::RecipientDomain => self.rcpt_domain.as_str().into(),
|
||||
EnvelopeKey::Sender => self.sender.as_str().into(),
|
||||
EnvelopeKey::SenderDomain => self.sender_domain.as_str().into(),
|
||||
EnvelopeKey::AuthenticatedAs => self.authenticated_as.as_str().into(),
|
||||
EnvelopeKey::Listener => self.listener_id.to_string().into(),
|
||||
EnvelopeKey::RemoteIp => self.remote_ip.to_string().into(),
|
||||
EnvelopeKey::LocalIp => self.local_ip.to_string().into(),
|
||||
EnvelopeKey::Priority => self.priority.to_string().into(),
|
||||
EnvelopeKey::Mx => self.mx.as_str().into(),
|
||||
EnvelopeKey::HeloDomain => self.helo_domain.as_str().into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn remote_ip(&self) -> IpAddr {
|
||||
self.remote_ip
|
||||
fn key_as_int(&self, key: &Self::Key) -> i32 {
|
||||
match key {
|
||||
EnvelopeKey::Priority => self.priority as i32,
|
||||
EnvelopeKey::Listener => self.listener_id as i32,
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn sender_domain(&self) -> &str {
|
||||
self.sender_domain.as_str()
|
||||
}
|
||||
|
||||
fn sender(&self) -> &str {
|
||||
self.sender.as_str()
|
||||
}
|
||||
|
||||
fn rcpt_domain(&self) -> &str {
|
||||
self.rcpt_domain.as_str()
|
||||
}
|
||||
|
||||
fn rcpt(&self) -> &str {
|
||||
self.rcpt.as_str()
|
||||
}
|
||||
|
||||
fn helo_domain(&self) -> &str {
|
||||
self.helo_domain.as_str()
|
||||
}
|
||||
|
||||
fn authenticated_as(&self) -> &str {
|
||||
self.authenticated_as.as_str()
|
||||
}
|
||||
|
||||
fn mx(&self) -> &str {
|
||||
self.mx.as_str()
|
||||
}
|
||||
|
||||
fn listener_id(&self) -> u16 {
|
||||
self.listener_id
|
||||
}
|
||||
|
||||
fn priority(&self) -> i16 {
|
||||
self.priority
|
||||
fn key_as_ip(&self, key: &Self::Key) -> IpAddr {
|
||||
match key {
|
||||
EnvelopeKey::RemoteIp => self.remote_ip,
|
||||
EnvelopeKey::LocalIp => self.local_ip,
|
||||
_ => IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ use crate::smtp::{
|
||||
ParseTestConfig, TestConfig,
|
||||
};
|
||||
use smtp::{
|
||||
config::ConfigContext,
|
||||
config::{ConfigContext, EnvelopeKey},
|
||||
core::{Session, State, SMTP},
|
||||
};
|
||||
|
||||
@@ -68,7 +68,7 @@ async fn auth() {
|
||||
.parse_if(&ctx);
|
||||
config.directory = r"[{if = 'remote-ip', eq = '10.0.0.1', then = 'local'},
|
||||
{else = false}]"
|
||||
.parse_if::<Option<DynValue>>(&ctx)
|
||||
.parse_if::<Option<DynValue<EnvelopeKey>>>(&ctx)
|
||||
.map_if_block(&ctx.directory.directories, "", "")
|
||||
.unwrap();
|
||||
config.errors_max = r"[{if = 'remote-ip', eq = '10.0.0.1', then = 2},
|
||||
|
||||
@@ -42,7 +42,9 @@ use crate::smtp::{
|
||||
ParseTestConfig, TestConfig, TestSMTP,
|
||||
};
|
||||
use smtp::{
|
||||
config::{AggregateFrequency, ConfigContext, IfBlock, MaybeDynValue, VerifyStrategy},
|
||||
config::{
|
||||
AggregateFrequency, ConfigContext, EnvelopeKey, IfBlock, MaybeDynValue, VerifyStrategy,
|
||||
},
|
||||
core::{Session, SMTP},
|
||||
};
|
||||
|
||||
@@ -168,15 +170,15 @@ async fn dmarc() {
|
||||
|
||||
let mut config = &mut core.report.config;
|
||||
config.spf.sign = "['rsa']"
|
||||
.parse_if::<Vec<DynValue>>(&ctx)
|
||||
.parse_if::<Vec<DynValue<EnvelopeKey>>>(&ctx)
|
||||
.map_if_block(&ctx.signers, "", "")
|
||||
.unwrap();
|
||||
config.dmarc.sign = "['rsa']"
|
||||
.parse_if::<Vec<DynValue>>(&ctx)
|
||||
.parse_if::<Vec<DynValue<EnvelopeKey>>>(&ctx)
|
||||
.map_if_block(&ctx.signers, "", "")
|
||||
.unwrap();
|
||||
config.dkim.sign = "['rsa']"
|
||||
.parse_if::<Vec<DynValue>>(&ctx)
|
||||
.parse_if::<Vec<DynValue<EnvelopeKey>>>(&ctx)
|
||||
.map_if_block(&ctx.signers, "", "")
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -113,7 +113,11 @@ async fn address_rewrite() {
|
||||
.map_if_block(&ctx.scripts, "session.mail.script", "script")
|
||||
.unwrap();
|
||||
config.mail.rewrite = settings
|
||||
.parse_if_block::<Option<DynValue>>("session.mail.rewrite", &ctx, &available_keys)
|
||||
.parse_if_block::<Option<DynValue<EnvelopeKey>>>(
|
||||
"session.mail.rewrite",
|
||||
&ctx,
|
||||
&available_keys,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap_or_default();
|
||||
config.rcpt.script = settings
|
||||
@@ -123,7 +127,11 @@ async fn address_rewrite() {
|
||||
.map_if_block(&ctx.scripts, "session.rcpt.script", "script")
|
||||
.unwrap();
|
||||
config.rcpt.rewrite = settings
|
||||
.parse_if_block::<Option<DynValue>>("session.rcpt.rewrite", &ctx, &available_keys)
|
||||
.parse_if_block::<Option<DynValue<EnvelopeKey>>>(
|
||||
"session.rcpt.rewrite",
|
||||
&ctx,
|
||||
&available_keys,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap_or_default();
|
||||
config.rcpt.relay = IfBlock::new(true);
|
||||
|
||||
@@ -36,7 +36,9 @@ use crate::smtp::{
|
||||
ParseTestConfig, TestConfig, TestSMTP,
|
||||
};
|
||||
use smtp::{
|
||||
config::{auth::ConfigAuth, ConfigContext, IfBlock, MaybeDynValue, VerifyStrategy},
|
||||
config::{
|
||||
auth::ConfigAuth, ConfigContext, EnvelopeKey, IfBlock, MaybeDynValue, VerifyStrategy,
|
||||
},
|
||||
core::{Session, SMTP},
|
||||
};
|
||||
|
||||
@@ -174,11 +176,11 @@ async fn sign_and_seal() {
|
||||
config.arc.verify = config.spf.verify_ehlo.clone();
|
||||
config.dmarc.verify = config.spf.verify_ehlo.clone();
|
||||
config.dkim.sign = "['rsa']"
|
||||
.parse_if::<Vec<DynValue>>(&ctx)
|
||||
.parse_if::<Vec<DynValue<EnvelopeKey>>>(&ctx)
|
||||
.map_if_block(&ctx.signers, "", "")
|
||||
.unwrap();
|
||||
config.arc.seal = "'ed'"
|
||||
.parse_if::<Option<DynValue>>(&ctx)
|
||||
.parse_if::<Option<DynValue<EnvelopeKey>>>(&ctx)
|
||||
.map_if_block(&ctx.sealers, "", "")
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use smtp::{
|
||||
config::{ConfigContext, IfBlock},
|
||||
config::{ConfigContext, EnvelopeKey, IfBlock},
|
||||
core::{Session, SMTP},
|
||||
};
|
||||
|
||||
@@ -115,7 +115,7 @@ async fn lookup_sql() {
|
||||
// Enable AUTH
|
||||
let mut config = &mut core.session.config.auth;
|
||||
config.directory = r"'sql'"
|
||||
.parse_if::<Option<DynValue>>(&ctx)
|
||||
.parse_if::<Option<DynValue<EnvelopeKey>>>(&ctx)
|
||||
.map_if_block(&ctx.directory.directories, "", "")
|
||||
.unwrap();
|
||||
config.mechanisms = IfBlock::new(AUTH_PLAIN | AUTH_LOGIN);
|
||||
@@ -124,7 +124,7 @@ async fn lookup_sql() {
|
||||
// Enable VRFY/EXPN/RCPT
|
||||
let mut config = &mut core.session.config.rcpt;
|
||||
config.directory = r"'sql'"
|
||||
.parse_if::<Option<DynValue>>(&ctx)
|
||||
.parse_if::<Option<DynValue<EnvelopeKey>>>(&ctx)
|
||||
.map_if_block(&ctx.directory.directories, "", "")
|
||||
.unwrap();
|
||||
config.relay = IfBlock::new(false);
|
||||
|
||||
@@ -37,6 +37,7 @@ use smtp::{
|
||||
lookup::ToNextHop,
|
||||
mta_sts::{Mode, MxPattern, Policy},
|
||||
},
|
||||
queue::RecipientDomain,
|
||||
};
|
||||
|
||||
use crate::smtp::TestConfig;
|
||||
@@ -75,7 +76,11 @@ async fn lookup_ip() {
|
||||
// Ipv4 strategy
|
||||
core.queue.config.ip_strategy = IfBlock::new(IpLookupStrategy::Ipv4thenIpv6);
|
||||
let (source_ips, remote_ips) = core
|
||||
.resolve_host(&NextHop::MX("mx.foobar.org"), &"envelope", 2)
|
||||
.resolve_host(
|
||||
&NextHop::MX("mx.foobar.org"),
|
||||
&RecipientDomain::new("envelope"),
|
||||
2,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(ipv4.contains(&match source_ips.unwrap() {
|
||||
@@ -87,7 +92,11 @@ async fn lookup_ip() {
|
||||
// Ipv6 strategy
|
||||
core.queue.config.ip_strategy = IfBlock::new(IpLookupStrategy::Ipv6thenIpv4);
|
||||
let (source_ips, remote_ips) = core
|
||||
.resolve_host(&NextHop::MX("mx.foobar.org"), &"envelope", 2)
|
||||
.resolve_host(
|
||||
&NextHop::MX("mx.foobar.org"),
|
||||
&RecipientDomain::new("envelope"),
|
||||
2,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(ipv6.contains(&match source_ips.unwrap() {
|
||||
|
||||
@@ -36,7 +36,7 @@ use crate::smtp::{
|
||||
ParseTestConfig, TestConfig, TestSMTP,
|
||||
};
|
||||
use smtp::{
|
||||
config::ConfigContext,
|
||||
config::{ConfigContext, EnvelopeKey},
|
||||
core::SMTP,
|
||||
queue::{
|
||||
DeliveryAttempt, Domain, Error, ErrorDetails, HostResponse, Message, Recipient, Schedule,
|
||||
@@ -110,7 +110,7 @@ async fn generate_dsn() {
|
||||
let ctx = ConfigContext::new(&[]).parse_signatures();
|
||||
let mut config = &mut core.queue.config.dsn;
|
||||
config.sign = "['rsa']"
|
||||
.parse_if::<Vec<DynValue>>(&ctx)
|
||||
.parse_if::<Vec<DynValue<EnvelopeKey>>>(&ctx)
|
||||
.map_if_block(&ctx.signers, "", "")
|
||||
.unwrap();
|
||||
|
||||
@@ -193,7 +193,7 @@ async fn compare_dsn(message: Box<Message>, test: &str) {
|
||||
failed.set_extension("failed");
|
||||
fs::write(&failed, dsn.as_bytes()).unwrap();
|
||||
panic!(
|
||||
"Failed for {}, ouput saved to {}",
|
||||
"Failed for {}, output saved to {}",
|
||||
path.display(),
|
||||
failed.display()
|
||||
);
|
||||
|
||||
@@ -41,7 +41,7 @@ use crate::smtp::{
|
||||
ParseTestConfig, TestConfig, TestSMTP,
|
||||
};
|
||||
use smtp::{
|
||||
config::{AggregateFrequency, ConfigContext, IfBlock},
|
||||
config::{AggregateFrequency, ConfigContext, EnvelopeKey, IfBlock},
|
||||
core::SMTP,
|
||||
reporting::{
|
||||
dmarc::GenerateDmarcReport,
|
||||
@@ -67,7 +67,7 @@ async fn report_dmarc() {
|
||||
config.path = IfBlock::new(temp_dir.temp_dir.clone());
|
||||
config.hash = IfBlock::new(16);
|
||||
config.dmarc_aggregate.sign = "['rsa']"
|
||||
.parse_if::<Vec<DynValue>>(&ctx)
|
||||
.parse_if::<Vec<DynValue<EnvelopeKey>>>(&ctx)
|
||||
.map_if_block(&ctx.signers, "", "")
|
||||
.unwrap();
|
||||
config.dmarc_aggregate.max_size = IfBlock::new(4096);
|
||||
|
||||
@@ -38,7 +38,7 @@ use crate::smtp::{
|
||||
ParseTestConfig, TestConfig, TestSMTP,
|
||||
};
|
||||
use smtp::{
|
||||
config::{AggregateFrequency, ConfigContext, IfBlock},
|
||||
config::{AggregateFrequency, ConfigContext, EnvelopeKey, IfBlock},
|
||||
core::SMTP,
|
||||
reporting::{
|
||||
scheduler::{ReportType, Scheduler},
|
||||
@@ -64,7 +64,7 @@ async fn report_tls() {
|
||||
config.path = IfBlock::new(temp_dir.temp_dir.clone());
|
||||
config.hash = IfBlock::new(16);
|
||||
config.tls.sign = "['rsa']"
|
||||
.parse_if::<Vec<DynValue>>(&ctx)
|
||||
.parse_if::<Vec<DynValue<EnvelopeKey>>>(&ctx)
|
||||
.map_if_block(&ctx.signers, "", "")
|
||||
.unwrap();
|
||||
config.tls.max_size = IfBlock::new(4096);
|
||||
|
||||
Reference in New Issue
Block a user