viaspf

This library is experimental/in development. The API is not stable yet. Please try out the master branch, feedback on API and implementation is welcome!

The viaspf library is a complete implementation of the Sender Policy Framework (SPF) protocol, version 1, as specified in [RFC 7208]. It is written in the Rust programming language.

This library implements the core SPF protocol, but it does not itself do DNS queries and it does not depend on a DNS library. Users of this library must provide an implementation of a DNS lookup trait in order to perform SPF queries. That way, we hope to enable users to choose themselves which DNS resolver they want to use to implement their SPF verifier applications.

This library was first created in a ‘clean room’ setting. That is, it was written from scratch, referring only to the RFC, and following it to the letter. It can therefore be considered an independent alternative to existing SPF protocol implementations.

The minimum supported Rust version is 1.42.0.

Usage

This is a [Rust] library, for consumption through Cargo as usual.

The main pattern of use of this library is to implement a required DNS lookup trait and then let the library do the SPF protocol handling.

Note, however, that it is also possible to forgo the SPF evaluation functionality and only use the data model: The module [viaspf::model] is a self-contained model of the SPF protocol data structures. It is, essentially, an encoding of the grammar in [section 12] of RFC 7208. This model could be used to construct SPF software that does not use the evaluation logic in this library.

In order to let this library do the actual SPF protocol handling, that is, not only obtain and parse SPF records, but also fully evaluate them to an authorisation result, it is necessary to implement the trait [viaspf::Lookup] first.

rust trait Lookup { fn lookup_a(&self, name: &Name) -> LookupResult<Vec<Ipv4Addr>>; fn lookup_aaaa(&self, name: &Name) -> LookupResult<Vec<Ipv6Addr>>; fn lookup_mx(&self, name: &Name) -> LookupResult<Vec<Name>>; fn lookup_txt(&self, name: &Name) -> LookupResult<Vec<String>>; fn lookup_ptr(&self, ip: IpAddr) -> LookupResult<Vec<Name>>; }

The implementation of this trait serves as a DNS resolver. All DNS queries are performed through that resolver.

The example application included with this library contains an implementation of the Lookup trait.

Once instantiated, a Lookup trait implementation can be passed to viaspf::evaluate_spf. This function is the main API entry point. It corresponds roughly to the check_host() function in the RFC.

rust fn evaluate_spf( lookup: &impl Lookup, config: &Config, ip: IpAddr, sender: &str, helo_domain: &str, ) -> QueryResult;

Refer to the API documentation for a description of the inputs and output, and common usage patterns.

In addition to evaluating the inputs to an authorisation result, this API allows capturing a trace of the query execution. The trace provides programmatic access to the protocol processing steps after the fact.

Examples

A simple SPF verifier is included as an executable example: the command-line tool spfquery. This program uses the [Trust-DNS] DNS resolver to perform DNS lookups.

Pass an IP address and a domain as arguments to spfquery. The query is then evaluated and the result and a trace is printed out.

cargo run --example spfquery 83.166.150.145 gluet.ch

IP: 83.166.150.145 Domain: gluet.ch SPF result: pass Mechanism: mx Trace: executing SPF query for domain "gluet.ch" evaluating SPF record "v=spf1 mx -all" evaluating directive "mx" evaluating mechanism "mx" incrementing global lookup count using target name "gluet.ch" trying MX name "mail.gluet.ch" ... evaluated directive to result "pass"

Licence

Copyright © 2020 David Bürgin

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.