spftrace 0.3.0

Utility for tracing SPF queries
// spftrace – utility for tracing SPF queries
// Copyright © 2022–2023 David Bürgin <dbuergin@gluet.ch>
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/>.

use std::{error::Error, net::IpAddr, time::Duration};
use viaspf::{
    lookup::Name,
    record::{
        Exists, ExplainString, Explanation, Include, Ip4, Ip6, Mx, Ptr, Redirect, SpfRecord, A,
    },
    EvalError, ExplanationString, SpfResult,
};

pub struct TimedLookup {
    pub lookup: LookupTarget,
    pub duration: Duration,
}

pub enum LookupTarget {
    A(Name),
    Aaaa(Name),
    Mx(Name),
    Txt(Name),
    Ptr(IpAddr),
}

pub struct TimedEvaluatedQuery {
    pub query: EvaluatedQuery,
    pub duration: Duration,
    pub lookup_times: Vec<TimedLookup>,
}

pub struct EvaluatedQuery {
    pub domain: Name,
    pub result: EvaluatedQueryResult,
    pub query_result: SpfResult,
}

pub enum EvaluatedQueryResult {
    NoRecord,
    Error(String),
    Record(EvaluatedRecord),
}

pub struct EvaluatedRecord {
    pub spf_record: SpfRecord,
    pub terms: Vec<EvaluatedTerm>,
}

pub enum EvaluatedTerm {
    All(AllDirective),
    Ip4(Ip4Directive),
    Ip6(Ip6Directive),
    A(ADirective),
    Mx(MxDirective),
    Ptr(PtrDirective),
    Exists(ExistsDirective),
    Include(IncludeDirective),
    Redirect(RedirectModifier),
    Exp(ExpModifier),
    NeutralDefault,
}

pub struct AllDirective {
    pub result: DirectiveResult,
}

pub struct Ip4Directive {
    pub mechanism: Ip4,
    pub result: DirectiveResult,
}

pub struct Ip6Directive {
    pub mechanism: Ip6,
    pub result: DirectiveResult,
}

pub struct ADirective {
    pub mechanism: A,
    pub lookup_counts: LookupCounts,
    pub target_domain: Option<Name>,
    pub ips: Vec<IpAddr>,
    pub result: DirectiveResult,
}

pub struct MxDirective {
    pub mechanism: Mx,
    pub lookup_counts: LookupCounts,
    pub target_domain: Option<Name>,
    pub mxs: Vec<MxName>,
    pub result: DirectiveResult,
}

pub struct MxName {
    pub target_domain: Name,
    pub ips: Vec<IpAddr>,
}

pub struct PtrDirective {
    pub mechanism: Ptr,
    pub lookup_counts: LookupCounts,
    pub target_domain: Option<Name>,
    pub ip: Option<IpAddr>,
    pub lookup_error: Option<EvalError>,
    pub ptrs: Vec<PtrName>,
    pub result: DirectiveResult,
}

pub struct PtrName {
    pub target_domain: Name,
    pub error: Option<Box<dyn Error>>,
    pub ips: Vec<IpAddr>,
    pub validated: bool,
}

pub struct ExistsDirective {
    pub mechanism: Exists,
    pub lookup_counts: LookupCounts,
    pub target_domain: Option<Name>,
    pub result: DirectiveResult,
}

pub struct IncludeDirective {
    pub mechanism: Include,
    pub lookup_counts: LookupCounts,
    pub target_domain: Option<Name>,
    pub query: Option<EvaluatedQuery>,
    pub result: DirectiveResult,
}

pub struct RedirectModifier {
    pub modifier: Redirect,
    pub lookup_counts: LookupCounts,
    pub error: Option<Box<dyn Error>>,
    pub target_domain: Option<Name>,
    pub query: Option<EvaluatedQuery>,
    pub result: SpfResult,
}

pub struct ExpModifier {
    pub modifier: Explanation,
    pub target_domain: Option<Name>,
    pub error: Option<Box<dyn Error>>,
    pub explain_string: Option<ExplainString>,
    pub explanation: ExplanationString,
}

#[derive(Default)]
pub struct LookupCounts {
    pub lookups: usize,
    pub nested: usize,
    pub void: usize,
}

pub enum DirectiveResult {
    Match(SpfResult),
    NotMatch,
    Error(EvalError, SpfResult),
}