[opendmarc-dev] rfc: how to fix wrong spf result if Received-SPF is used?

Juri Haberland juri at sapienti-sat.org
Mon Oct 17 02:39:18 PDT 2016


Hi list,

I found a bug in the code that uses the result from parsing a Received-SPF
header and a general problem in the result codes from the internal SPF
checking.

I see two possible ways to solve these problems and I would like to get some
opinions from you.

Let me start with a description of how it works now:

There are two ways in the code to represent the SPF results:
ARES_RESULT_* and DMARC_POLICY_SPF_OUTCOME_*. They both differ in terms of
integer values and DMARC_POLICY_SPF_OUTCOME_* has not enough different
variants to represent all possible SPF states.
The ARES_RESULT_* is used to represent the result found in
Authentication-Result headers and it is also the format used for the history
file resp. the database.
The DMARC_POLICY_SPF_OUTCOME_* is a flattened representation for the internal
DMARC calculation (everything that is not 'pass' or an error is 'fail').

First, the code looks for Authentication-Result headers and if found, parses
it, stores the ARES_RESULT_* in the history file as well as in an internal
message context. Than the result is flattened to DMARC_POLICY_SPF_OUTCOME_*
and stored into the internal DMARC context with opendmarc_policy_store_spf().
So far so good.

If no Auth-Res header is found, the code looks for a Received-SPF header. If
found, it's parsed with dmarcf_parse_received_spf(), but the result is
returned as a flattened DMARC_POLICY_SPF_OUTCOME_*. This result is used for
the history file and the internal message context. That's where the bug is...

If there is no Received-SPF as well, or if we have told OpenDMARC to ignore
all results, the code calls opendmarc_spf2_test(), which calls libspf2 to get
a SPF result. This is also returned as a flattened DMARC_POLICY_SPF_OUTCOME_*
result, but before it is stored into the history file and the internal message
context it is mapped to (a flattened version of) ARES_RESULT_*. Not a bug per
se, but we lose some information detail and might report different results
than other implementations.

Now to the possible fixes:
1) Change the functions that parses the Received-SPF header
(dmarcf_parse_received_spf()) and the function that calls libspf2
(opendmarc_spf2_test()) to return the real SPF result by using ARES_RESULT_*
and flatten it before storing it into the internal DMARC context.
Disadvantage:
  We have to change the signature (or at least the return values) of a
function in the libopendmarc.

2) We enhance the DMARC_POLICY_SPF_OUTCOME_* macros to be able to represent
all SPF results, let dmarcf_parse_received_spf() and opendmarc_spf2_test()
return these enhanced values, let opendmarc_policy_store_spf() flatten the
result itself and map the result to ARES_RESULT_* before writing it to the
history file and the internal message context.
Advantage:
  The library functions would keep their return values, but might return
additional values.


What solution would you prefer?

Kind regards,
  Juri




More information about the opendmarc-dev mailing list