Spf.Context (Spfcheck v0.2.0) View Source

Functions to create, access and update an SPF evaluation context.

Many functions take and return an evaluation context whose purpose is to store information gathered during the evaluation. This includes a dns cache, an ip lookup table that maps prefixes to SPF terms that named them, a stack for recursive evaluations, as well as some statistics around DNS mechanisms seen and void DNS responses seen.

Link to this section Summary

Types

A {qualifier, nth, term} tuple, where nth is the nth SPF record where term was found.

t()

An SPF evaluation context.

An SPF evaluation result.

Functions

Updates context.ipt with one or more {prefix/0, iptval/0}-pairs.

Updates context with given error, reason and verdict.

Returns a previous SPF string given either its domain of nth-tracking number.

Updates context's message queue and, if available, calls the user supplied log function.

Returns true if new_domain constitues a loop for given context, false otherwise.

Returns a new Spf.Context.t/0 for given sender.

Pop the previous state of given context from its stack.

Push the current state of given context onto its stack and re-init the context.

Reinitializes current context for given domain of a redirect modifier.

Given a current context and a range, return the SPF term in that range.

Split an email address into a local and a domain part.

If test is true, logs the given msg with its facility and severity.

Adds delta to counter and returns updated context.

Link to this section Types

Specs

iptval() :: {Spf.Tokens.q(), non_neg_integer(), binary()}

A {qualifier, nth, term} tuple, where nth is the nth SPF record where term was found.

The context's ip lookup table stores these tuples thus tracking which term in which SPF record provided a qualifier for a prefix. Since an evaluation may involve multiple SPF records, each prefix actually stores a list of these tuples.

Once the sender's ip has a longest prefix match, the qualifier will tell how the mechanism at hand matches.

Specs

prefix() :: Pfx.prefix()

A Pfx.prefix/0.

Specs

t() :: %{
  ast: list(),
  atype: :a | :aaaa,
  contact: binary(),
  depth: non_neg_integer(),
  dns: map(),
  dns_timeout: non_neg_integer(),
  domain: binary(),
  duration: non_neg_integer(),
  error: nil | atom(),
  explain: nil | tuple(),
  explain_string: binary(),
  explanation: binary(),
  helo: binary(),
  ip: binary(),
  ipt: Iptrie.t(),
  local: binary(),
  log: function(),
  map: map(),
  max_dnsm: non_neg_integer(),
  max_dnsv: non_neg_integer(),
  msg: list(),
  nth: non_neg_integer(),
  num_checks: non_neg_integer(),
  num_dnsm: non_neg_integer(),
  num_dnsq: non_neg_integer(),
  num_dnsv: non_neg_integer(),
  num_error: non_neg_integer(),
  num_spf: non_neg_integer(),
  num_warn: non_neg_integer(),
  owner: binary(),
  reason: binary(),
  sender: binary(),
  spf: binary(),
  spf_rest: binary(),
  spf_tokens: list(),
  stack: list(),
  t0: non_neg_integer(),
  traces: map(),
  verbosity: non_neg_integer(),
  verdict: verdict()
}

An SPF evaluation context.

Specs

token() :: Spf.Tokens.token()

A Spf.Tokens.token/0.

Specs

verdict() ::
  :fail | :neutral | :none | :pass | :permerror | :softfail | :temperror

An SPF evaluation result.

Link to this section Functions

Link to this function

addip(context, ips, dual, value)

View Source

Specs

addip(t(), list(), list(), iptval()) :: t()
addip(t(), binary(), list(), iptval()) :: t()

Updates context.ipt with one or more {prefix/0, iptval/0}-pairs.

When given a list op ip's, they all will be be updated with given iptval/0 which records the SPF record and term (including the qualifier) that attributed the ip or ip's.

The dual parameter contains the dual-cidr lengths to apply to the given ip addresses.

Link to this function

error(context, error, reason, verdict \\ nil)

View Source

Specs

error(t(), atom(), binary(), nil | atom()) :: t()

Updates context with given error, reason and verdict.

When verdict is nil, context.verdict is not updated. This allows for setting error conditions whose impact is to be evaluated at a later stage.

Specs

get_spf(t(), integer() | binary()) :: binary()

Returns a previous SPF string given either its domain of nth-tracking number.

Used for reporting rather than evalutation an SPF record.

Link to this function

log(context, facility, severity, msg)

View Source

Specs

log(t(), atom(), atom(), binary()) :: t()

Updates context's message queue and, if available, calls the user supplied log function.

The log/4 is called with:

  • context the current context/state of the evalution
  • facility an atom denoting which part of the program emitted the event
  • severity an atom describing the severity
  • msg a binary with event details
Link to this function

loop?(context, new_domain)

View Source

Specs

loop?(t(), binary()) :: boolean()

Returns true if new_domain constitues a loop for given context, false otherwise.

Loops may occur when two SPF records (eventually) include or redirect to each other and is considered a permanent error.

Specs

new(binary(), Keyword.t()) :: t()

Returns a new Spf.Context.t/0 for given sender.

Options include:

  • dns:, filepath or binary with zonedata (defaults to nil)
  • helo:, sender's helo string to use (defaults to sender)
  • ip:, sender ip to use (defaults to 127.0.0.1)
  • log:, user supplied log function (defaults to nil)
  • verbosity:, log level 0..5 to use (defaults to 4)

The initial domain is derived from given sender. The default for ip is likely to traverse all SPF mechanisms during evaluation, gathering as much information as possible. Set ip: to a real IPv4 or IPv6 address to check a policy for that specific address.

The context is used for the entire SPF evaluation, including during any recursive calls. When evaluating an include mechanism, the current state (a few selected context properties) is pushed onto an internal stack and a new domain is set. After evaluating the include mechanism, the state if popped and the results are processed according to the include-mechanism's qualifier.

When evaluating a redirect modifier, the current state is altered for the new domain specified by the modifier.

Specs

pop(t()) :: t()

Pop the previous state of given context from its stack.

Before evaluating an include mechanism, the current SPF's record state is pushed onto the stack. This function restores that state from the stack.

Specs

push(t(), binary()) :: t()

Push the current state of given context onto its stack and re-init the context.

The details of the current SPF record are pushed onto a stack and the context is re-initialized for retrieving, parsing and evaluate a new included record.

Link to this function

redirect(context, domain)

View Source

Specs

redirect(t(), binary()) :: t()

Reinitializes current context for given domain of a redirect modifier.

When a redirect modifier is encountered it basically replaces the current SPF record and the context is modified accordingly..

Link to this function

spf_term(context, range)

View Source

Specs

spf_term(t(), Range.t()) :: binary()

Given a current context and a range, return the SPF term in that range.

Retrieves a slice of the context.spf current record being evaluated. Used for logging events.

Specs

split(binary()) :: {binary(), binary()}

Split an email address into a local and a domain part.

The local part is left to the left-most @, if there is no local part it defaults to "postmaster". Note that splitting an empty string yields {"postmaster", ""}.

Link to this function

test(context, facility, severity, test, msg)

View Source

Specs

test(t(), atom(), atom(), boolean(), binary()) :: t()

If test is true, logs the given msg with its facility and severity.

A convencience function to quickly perform some test (in the call) and, if true, log it as well.

Link to this function

tick(context, counter, delta \\ 1)

View Source

Specs

tick(t(), atom(), integer()) :: t()

Adds delta to counter and returns updated context.

Valid counters include:

  • :num_spf, the number of SPF records seen
  • :num_dnsm the number of DNS mechanisms seen
  • :num_dnsq the number of DNS queries performed
  • :num_dnsv the number of void DNS queries seen
  • :num_checks the number of checks performed
  • :num_warn the number of warnings seen
  • :num_error the number of errors see (may not be fatal)
  • :depth the current recursion depth