spf-discuss
[Top] [All Lists]

Re: a "never relays" parameter

2004-06-09 00:39:50
On Tue, 2004-06-08 at 10:35, Stuart D. Gathman wrote:
On Mon, 7 Jun 2004, Daniel Quinlan wrote:

Let me run an idea past you all.  How about an SPF parameter to indicate
that only permitted senders may relay messages?  That is, nobody else
would be allowed to relay messages from the sender, period.  (This is
not the same as "-all".)

Relay, no--I don't agree.

But only permitting certain header Senders: for any header From: that's
not from a mailing list--sure.  :-)

Already handled via exists.  

SPF is already completely general with exists.  The only way to make
it more powerful is to define more macros so that more variables are
available to the exists code.

Excellent.  Then my previous ONBEHALFOF suggestion (similar to Daniel's)
can (almost) be done with exists.

But...everything can be done with exists.  Almost.

There is some serious potential here.

In fact...if New-SPF didn't exist, and we were working under old SPF
rules...we could still almost implement new SPF functionality via exists
in addition to the old rules, as well as implementing
somewhat-anti-phishing ONBEHALFOF type functionality, as well as SES.

Almost.

To look at the different things each provides, as I understand it:

   Old SPF:  Checked that the IP address sending the message is
             authorized by the claimed MAIL FROM to receive bounces
             for it.

   New SPF:  Checks that the IP address sending the message is
             authorized by the PRA, (which is the address the
             message headers claim is the address most recently
             responsible for submitting the message into the
             mail stream), to send messages claiming that address
             is the PRA.

ONBEHALFOF/SENDER combination using validsenders= modifier,
             as I suggested in a previous email:

             Checks whether the List-ID or Header-From allows/denies
             SENDER to send on its behalf.

       SES:  Generates unique, time-limited MAIL FROMs to prevent
             forged bounces.  (You have to have a message from this
             person to bounce back a message, and you have to bounce
             before the MAIL FROM becomes invalid.)

             Also allows CBV-testing recipients to validate
             SES-protected MAIL FROMs.

             Can be extended to allow recipients to test for message
             tampering by verifying an included checksum after
             validating MAIL FROM via checksum.

Unfortunately just adding variables to the "exists" mechanism won't
work, as success on an incomplete test would mean a complete SPF PASS.

Here's a notion--what about an additional "exists" *modifier*?

I can hear the groans in the audience at Yet Another Proposal To Extent
The Spec.  Please stay with me though, I think this really does make
sense.

IP blocklists can allow for multiple responses, with 127.0.0.1 meaning
one thing, 127.0.0.2 meaning another, etc.  (Normally, these are
implemented as bit flags.)

However, the exists mechanism only allows old-blocklist style answers,
there's-an-answer or there's-no-answer, and if the query results in an
answer, mechanism processing stops right there.  An exists modifier
needn't be so limited.

If we had an exists modifier, we could do two things:

1.  Have multiple responses that matched up to the normal SPF results.

2.  Combine all exists modifier results together, and overlay their
    cumulative answer with the rest of the SPF result to come to a
    final SPF result.

Imagine any particular SPF "exists" *modifier* resulted in one of the
following results:

127.0.0.1 :  Pass (+)
127.0.0.16:  Softfail (~)
127.0.0.32:  Fail (-)
127.0.0.64:  Error   (Also return this if the DNS query itself fails.)

127.0.1.2 :  Neutral (?)
127.0.1.4 :  None
127.0.1.8 :  Unknown

At the beginning of SPF evaluation of any message, assign an internal
variable, say exists_m and exists_m_error to 0, and do something like
the following psuedocode:

  exists_m = 0
  exists_m_error=0
  for every exists modifier:
    if result in ["127.0.0.1","127.0.0.16","127.0.0.32","127.0.0.64"]:
      exists_m = max ( exists_m, result)
    if result in ["127.0.1.2", "127.0.1.4", "127.0.1.8"]:
      exists_m_err = max ( exists_m_err, result)

  map spf_partial_result to above 7 strings

  if spf_partial_result begins with "127.0.0.":
    spf_final_result = max(spf_partial_result, exists_m)
  if spf_partial_result begins with "127.0.1.":
    spf_final_result = max(spf_partial_result, exists_m_error)

(I'm finding it difficult to succinctly describe this other than in
annoying pseudocode as the above.)

The exists modifier evaluations are uncoupled with the rest of the SPF
string evaluation.  Then when the rest of the SPF evaluation is
available along with the result of all the exists modifiers, return as
the final SPF answer the greater of the two.

(ie, the rest of SPF says "PASS", exists modifier says "Error", then
return "Error".  If the rest of SPF says "Error", and all the exists
modifiers say "PASS", then return "Error".  If the rest of SPF says
"FAIL" and the exist modifiers say "PASS", return "FAIL".)

For this to be of much use in the cases I mentioned at the beginning,
(such as doing new-spf tests in old-spf world), we'd need new variables.

Currently, the exists *mechanism* has the following macro variables
defined.

      l = local-part of responsible-sender
      s = responsible-sender
      o = responsible-domain
      d = current-domain
      i = SMTP client IP (nibble format when an IPv6 address)
      p = SMTP client domain name
      v = client IP version string: "in-addr" for ipv4 or "ip6" for ipv6
      h = HELO/EHLO domain
      r = receiving domain

Imagine additional variables for use with an exists modifier:

o  Three PRA-related variables corresponding to the top three
   MAIL FROM variables, say capital L, S, and O.

o  Three variables for the header-From, its local-part, and its domain.
   
o  Three variables for the OnBehalfOf, its local-part, and its domain.
   (OnBehalfOf==header-list-ID if it exists, header-Sender otherwise,
   and an empty string if there is no header-Sender.)

With an exists modifier and those additional nine variables defined, the
complete new-spf functionality can fit in the old-spf syntax, with the
expense of extra after-DATA checks.

If there were SUBMITTER, SENDER, and ONBEHALFOF esmtp extensions, then
the exists tests that had any of these extra nine variables could be
split in two--a partial result being given before DATA, followed by a
sanity/corruption check that SUBMITTER==PRA, SENDER==Header-Sender,
ONBEHALFOF==max(List-ID, Header-From:)

You get the best of all worlds.

Were we still operating in old-SPF world, then people who didn't want to
do any PRA tests could ignore any exists modifier that includes those
variables.  People who don't want to do any ONBEHALFOF tests can simply
ignore any exists modifier that includes that variable.  In both cases
they'll lose some functionality, but hey, it's their choice, and it
wouldn't affect the old-spf's consecutive mechanism matching result.

As an aside, I think both SES and domainkeys like proposals could also
fit in with an exists modifier, or at the very least use the same macro
variables within their own modifier as previously discussed with SES.

In any event, it looks to me like all the advantages of the new spf
could exist (haha) in old-spf world using an exists modifier and extra
macro variables.

Even in a new-spf world, the permitted-senders concept can work, *if*
there's an exists modifier and extra macro variables.

(But for both cases, exist would have to exist as a modifier in addition
to a mechanism, unless we used *really* complex and error-prone exists
modifier strings.)

-- 
Mark Shewmaker
mark(_at_)primefactor(_dot_)com