Commit
Author: Mauro D [mauro@stalw.art]
Hash: 7a8daf8c37db2076211e811468a73f4cb142e172
Timestamp: Wed, 14 Dec 2022 18:05:10 +0000 (1 year ago)

+79 -49 +/-6 browse
Removed SPF parameters from Resolver object.
1diff --git a/README.md b/README.md
2index 4cd2f5b..963779c 100644
3--- a/README.md
4+++ b/README.md
5 @@ -140,13 +140,13 @@ Features:
6
7 // Verify HELO identity
8 let result = resolver
9- .verify_spf_helo("127.0.0.1".parse().unwrap(), "gmail.com")
10+ .verify_spf_helo("127.0.0.1".parse().unwrap(), "gmail.com", "my-local-domain.org")
11 .await;
12 assert_eq!(result.result(), SpfResult::Fail);
13
14 // Verify MAIL-FROM identity
15 let result = resolver
16- .verify_spf_sender("::1".parse().unwrap(), "gmail.com", "sender@gmail.com")
17+ .verify_spf_sender("::1".parse().unwrap(), "gmail.com", "my-local-domain.org", "sender@gmail.com")
18 .await;
19 assert_eq!(result.result(), SpfResult::Fail);
20 ```
21 @@ -163,7 +163,7 @@ Features:
22
23 // Verify SPF MAIL-FROM identity
24 let spf_result = resolver
25- .verify_spf_sender("::1".parse().unwrap(), "example.org", "sender@example.org")
26+ .verify_spf_sender("::1".parse().unwrap(), "example.org", "my-local-domain.org", "sender@example.org")
27 .await;
28
29 // Verify DMARC
30 diff --git a/examples/dmarc_verify.rs b/examples/dmarc_verify.rs
31index b43a7ec..55f5f53 100644
32--- a/examples/dmarc_verify.rs
33+++ b/examples/dmarc_verify.rs
34 @@ -48,7 +48,12 @@ async fn main() {
35
36 // Verify SPF MAIL-FROM identity
37 let spf_result = resolver
38- .verify_spf_sender("::1".parse().unwrap(), "example.org", "sender@example.org")
39+ .verify_spf_sender(
40+ "::1".parse().unwrap(),
41+ "example.org",
42+ "my-host-domain.org",
43+ "sender@example.org",
44+ )
45 .await;
46
47 // Verify DMARC
48 diff --git a/examples/spf_verify.rs b/examples/spf_verify.rs
49index f960b52..7b1b666 100644
50--- a/examples/spf_verify.rs
51+++ b/examples/spf_verify.rs
52 @@ -17,13 +17,22 @@ async fn main() {
53
54 // Verify HELO identity
55 let result = resolver
56- .verify_spf_helo("127.0.0.1".parse().unwrap(), "gmail.com")
57+ .verify_spf_helo(
58+ "127.0.0.1".parse().unwrap(),
59+ "gmail.com",
60+ "my-host-domain.org",
61+ )
62 .await;
63 assert_eq!(result.result(), SpfResult::Fail);
64
65 // Verify MAIL-FROM identity
66 let result = resolver
67- .verify_spf_sender("::1".parse().unwrap(), "gmail.com", "sender@gmail.com")
68+ .verify_spf_sender(
69+ "::1".parse().unwrap(),
70+ "gmail.com",
71+ "my-host-domain.org",
72+ "sender@gmail.com",
73+ )
74 .await;
75 assert_eq!(result.result(), SpfResult::Fail);
76 }
77 diff --git a/src/common/resolver.rs b/src/common/resolver.rs
78index 55c5506..b9e407a 100644
79--- a/src/common/resolver.rs
80+++ b/src/common/resolver.rs
81 @@ -26,7 +26,7 @@ use crate::{
82 dkim::{Atps, DomainKeyReport},
83 dmarc::Dmarc,
84 spf::{Macro, Spf},
85- Error, Policy, Resolver, Txt, MX,
86+ Error, Resolver, Txt, MX,
87 };
88
89 use super::{
90 @@ -37,7 +37,7 @@ use super::{
91
92 impl Resolver {
93 pub fn new_cloudflare_tls() -> Result<Self, ResolveError> {
94- Self::new(
95+ Self::with_capacity(
96 ResolverConfig::cloudflare_tls(),
97 ResolverOpts::default(),
98 128,
99 @@ -45,27 +45,27 @@ impl Resolver {
100 }
101
102 pub fn new_cloudflare() -> Result<Self, ResolveError> {
103- Self::new(ResolverConfig::cloudflare(), ResolverOpts::default(), 128)
104+ Self::with_capacity(ResolverConfig::cloudflare(), ResolverOpts::default(), 128)
105 }
106
107 pub fn new_google() -> Result<Self, ResolveError> {
108- Self::new(ResolverConfig::google(), ResolverOpts::default(), 128)
109+ Self::with_capacity(ResolverConfig::google(), ResolverOpts::default(), 128)
110 }
111
112 pub fn new_quad9() -> Result<Self, ResolveError> {
113- Self::new(ResolverConfig::quad9(), ResolverOpts::default(), 128)
114+ Self::with_capacity(ResolverConfig::quad9(), ResolverOpts::default(), 128)
115 }
116
117 pub fn new_quad9_tls() -> Result<Self, ResolveError> {
118- Self::new(ResolverConfig::quad9_tls(), ResolverOpts::default(), 128)
119+ Self::with_capacity(ResolverConfig::quad9_tls(), ResolverOpts::default(), 128)
120 }
121
122 pub fn new_system_conf() -> Result<Self, ResolveError> {
123 let (config, options) = read_system_conf()?;
124- Self::new(config, options, 128)
125+ Self::with_capacity(config, options, 128)
126 }
127
128- pub fn new(
129+ pub fn with_capacity(
130 config: ResolverConfig,
131 options: ResolverOpts,
132 capacity: usize,
133 @@ -77,19 +77,26 @@ impl Resolver {
134 cache_ipv4: LruCache::with_capacity(capacity),
135 cache_ipv6: LruCache::with_capacity(capacity),
136 cache_ptr: LruCache::with_capacity(capacity),
137- host_domain: String::new(),
138- verify_policy: Policy::VeryStrict,
139 })
140 }
141
142- pub fn with_host_domain(mut self, hostname: &str) -> Self {
143- self.host_domain = hostname.to_lowercase();
144- self
145- }
146-
147- pub fn with_policy(mut self, policy: Policy) -> Self {
148- self.verify_policy = policy;
149- self
150+ pub fn with_capacities(
151+ config: ResolverConfig,
152+ options: ResolverOpts,
153+ txt_capacity: usize,
154+ mx_capacity: usize,
155+ ipv4_capacity: usize,
156+ ipv6_capacity: usize,
157+ ptr_capacity: usize,
158+ ) -> Result<Self, ResolveError> {
159+ Ok(Self {
160+ resolver: AsyncResolver::tokio(config, options)?,
161+ cache_txt: LruCache::with_capacity(txt_capacity),
162+ cache_mx: LruCache::with_capacity(mx_capacity),
163+ cache_ipv4: LruCache::with_capacity(ipv4_capacity),
164+ cache_ipv6: LruCache::with_capacity(ipv6_capacity),
165+ cache_ptr: LruCache::with_capacity(ptr_capacity),
166+ })
167 }
168
169 pub(crate) async fn txt_lookup<'x, T: TxtRecordParser + Into<Txt> + UnwrapTxtRecord>(
170 diff --git a/src/lib.rs b/src/lib.rs
171index 52fc139..791a721 100644
172--- a/src/lib.rs
173+++ b/src/lib.rs
174 @@ -150,13 +150,13 @@
175 //!
176 //! // Verify HELO identity
177 //! let result = resolver
178- //! .verify_spf_helo("127.0.0.1".parse().unwrap(), "gmail.com")
179+ //! .verify_spf_helo("127.0.0.1".parse().unwrap(), "gmail.com", "my-local-domain.org")
180 //! .await;
181 //! assert_eq!(result.result(), SpfResult::Fail);
182 //!
183 //! // Verify MAIL-FROM identity
184 //! let result = resolver
185- //! .verify_spf_sender("::1".parse().unwrap(), "gmail.com", "sender@gmail.com")
186+ //! .verify_spf_sender("::1".parse().unwrap(), "gmail.com", "my-local-domain.org", "sender@gmail.com")
187 //! .await;
188 //! assert_eq!(result.result(), SpfResult::Fail);
189 //! ```
190 @@ -173,7 +173,7 @@
191 //!
192 //! // Verify SPF MAIL-FROM identity
193 //! let spf_result = resolver
194- //! .verify_spf_sender("::1".parse().unwrap(), "example.org", "sender@example.org")
195+ //! .verify_spf_sender("::1".parse().unwrap(), "example.org", "my-local-domain.org", "sender@example.org")
196 //! .await;
197 //!
198 //! // Verify DMARC
199 @@ -275,6 +275,8 @@ pub mod dmarc;
200 pub mod report;
201 pub mod spf;
202
203+ pub use trust_dns_resolver;
204+
205 pub struct Resolver {
206 pub(crate) resolver: TokioAsyncResolver,
207 pub(crate) cache_txt: LruCache<String, Txt>,
208 @@ -282,8 +284,6 @@ pub struct Resolver {
209 pub(crate) cache_ipv4: LruCache<String, Arc<Vec<Ipv4Addr>>>,
210 pub(crate) cache_ipv6: LruCache<String, Arc<Vec<Ipv6Addr>>>,
211 pub(crate) cache_ptr: LruCache<IpAddr, Arc<Vec<String>>>,
212- pub(crate) host_domain: String,
213- pub(crate) verify_policy: Policy,
214 }
215
216 #[derive(Clone)]
217 @@ -303,13 +303,6 @@ pub struct MX {
218 preference: u16,
219 }
220
221- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
222- pub enum Policy {
223- Relaxed,
224- Strict,
225- VeryStrict,
226- }
227-
228 #[derive(Debug, Clone)]
229 pub struct AuthenticatedMessage<'x> {
230 pub(crate) headers: Vec<(&'x [u8], &'x [u8])>,
231 diff --git a/src/spf/verify.rs b/src/spf/verify.rs
232index 7655943..6da76ed 100644
233--- a/src/spf/verify.rs
234+++ b/src/spf/verify.rs
235 @@ -13,18 +13,24 @@ use std::{
236 time::Instant,
237 };
238
239- use crate::{Error, Policy, Resolver, SpfOutput, SpfResult};
240+ use crate::{Error, Resolver, SpfOutput, SpfResult};
241
242 use super::{Macro, Mechanism, Qualifier, Spf, Variables};
243
244 impl Resolver {
245 /// Verifies the SPF EHLO identity
246- pub async fn verify_spf_helo(&self, ip: IpAddr, helo_domain: &str) -> SpfOutput {
247+ pub async fn verify_spf_helo(
248+ &self,
249+ ip: IpAddr,
250+ helo_domain: &str,
251+ host_domain: &str,
252+ ) -> SpfOutput {
253 if helo_domain.has_labels() {
254 self.check_host(
255 ip,
256 helo_domain,
257 helo_domain,
258+ host_domain,
259 &format!("postmaster@{}", helo_domain),
260 )
261 .await
262 @@ -38,29 +44,36 @@ impl Resolver {
263 &self,
264 ip: IpAddr,
265 helo_domain: &str,
266+ host_domain: &str,
267 sender: &str,
268 ) -> SpfOutput {
269 self.check_host(
270 ip,
271 sender.rsplit_once('@').map_or(helo_domain, |(_, d)| d),
272 helo_domain,
273+ host_domain,
274 sender,
275 )
276 .await
277 }
278
279 /// Verifies both the SPF EHLO and MAIL FROM identities
280- pub async fn verify_spf(&self, ip: IpAddr, helo_domain: &str, mail_from: &str) -> SpfOutput {
281+ pub async fn verify_spf(
282+ &self,
283+ ip: IpAddr,
284+ helo_domain: &str,
285+ host_domain: &str,
286+ mail_from: &str,
287+ ) -> SpfOutput {
288 // Verify HELO identity
289- let output = self.verify_spf_helo(ip, helo_domain).await;
290- match output.result() {
291- SpfResult::TempError | SpfResult::Pass => (),
292- SpfResult::None | SpfResult::PermError if self.verify_policy != Policy::VeryStrict => {}
293- _ => return output,
294+ let output = self.verify_spf_helo(ip, helo_domain, host_domain).await;
295+ if matches!(output.result(), SpfResult::Pass) {
296+ // Verify MAIL FROM identity
297+ self.verify_spf_sender(ip, helo_domain, host_domain, mail_from)
298+ .await
299+ } else {
300+ output
301 }
302-
303- // Verify MAIL FROM identity
304- self.verify_spf_sender(ip, helo_domain, mail_from).await
305 }
306
307 #[allow(clippy::while_let_on_iterator)]
308 @@ -69,6 +82,7 @@ impl Resolver {
309 ip: IpAddr,
310 domain: &str,
311 helo_domain: &str,
312+ host_domain: &str,
313 sender: &str,
314 ) -> SpfOutput {
315 let output = SpfOutput::new(domain.to_string());
316 @@ -84,7 +98,7 @@ impl Resolver {
317 vars.set_sender(format!("postmaster@{}", domain).into_bytes());
318 }
319 vars.set_domain(domain.as_bytes());
320- vars.set_host_domain(self.host_domain.as_bytes());
321+ vars.set_host_domain(host_domain.as_bytes());
322 vars.set_helo_domain(helo_domain.as_bytes());
323
324 let mut lookup_limit = LookupLimit::new();
325 @@ -625,7 +639,9 @@ mod test {
326 } else {
327 (value.try_into().unwrap(), "")
328 };
329- let output = resolver.verify_spf(client_ip, helo, mail_from).await;
330+ let output = resolver
331+ .verify_spf(client_ip, helo, "localdomain.org", mail_from)
332+ .await;
333 assert_eq!(
334 output.result(),
335 result,