spf-discuss
[Top] [All Lists]

Re: Should SPF be Frozen or Extensible? (XML insights)

2004-05-31 13:48:21
Back to the main point about extensibility.

Greg Connor wrote:
| 0. Current SPF method:
|  v=spf1 +ptr +mx ?all
|  v=spf2 +ptr +mx +domainkeys -all

I casually wrote "version numbers don't cut it" in a recent message. Let me elaborate a bit. I think version numbers are great for products, but not so great for protocols. First off, it suggests that there will be a central authority determining what goes into the "next" version. (That may not be the intent, but it is a conclusion that many readers will come to on their own, based on how they already understand "version numbers" to work)

It is possible to have a version split off from the numbered sequence (like 1, 1a, 1d). That allows you to add one feature pretty easily, but if there are two or three features people want to add, you would have to have like four or more versions of your record, to support all possible receivers (1, 1a, 1d, 1ad).

I think this puts too much burden on the publisher, to cater to the many possible permutations of receivers... I think it ought to be the other way around: the receivers ought to be flexible enough to cater to the many types of publishers out there, within the limits of their currently loaded feature sets.

Version numbers are OK for "major" version changes (of the type that make the whole language incompatible with older parsers). But I think I would like to have a way to add features incrementally too, that is not as cumbersome as changing the version number.

That is the main reason I am harping on extensibility. The XML issue has just brought it out into the open :)


| 2. Use modifiers to say what to do in case of unknown mechanisms.
|
|  v=spf1 +ptr +mx unsupported=? +domainkeys -all
|

Skipping my table that suggests unsupported=X (X in {? - + abort contine break})


--Meng Weng Wong <mengwong(_at_)dumbo(_dot_)pobox(_dot_)com> wrote:
Of the alternatives you identified,

|  unsupported=?  Stop processing and return "unknown" ("neutral")
this is the standard behaviour now.

|  unsupported=-  Stop processing and return "Fail"
if this were a desired semantic, why wouldn't a domain just
leave out the mechanism knowing that it was not widely supported?


Let's turn that question around: what if we are talking about an old SPF parser that doesn't understand the new feature, while a significant percentage of receivers have already adopted it?

I didn't use the word "unsupported" to mean "unpopular" -- it just means "unsupported by the current receiver". If a new feature becomes popular, implementations will be updated and receivers can upgrade. All I'm asking for here is an intelligent fallback behavior, so that publishers can use the new keyword with accurate knowledge of what the older clients will do.

I think this will be a more graceful way for new features to "bootstrap" themselves. It's a way to say "let the market decide what features are cool"


Why is the issue of new features all bound up with the issue of error handling? The current SPF defines "unknown mechanism" to be the same as "error". If the error handling could be trapped or controlled, I could deal with this... that is why I threw error handling into the discussion. If we had a better way to deal with unknown mechanisms, inflexible error handling wouldn't be such an issue.

On the other hand, if we stick with our assertion that unknown mechanisms are just another error, and improve our error handling to let the publisher specify where to go from there, I would be happy with that approach too (and it could have other advantages as well).


|  unsupported=continue  Ignore the unknown keyword and resume with the
| next step

this would be desirable, and reflects a set-theoretic rather
than procedural approach.  but again, why wouldn't a domain
just leave out the generally unrecognized unknown keyword?

|  unsupported=break  Stop processing the current record, but if we were
|  in  an include: or redirect= then continue with the previous record

this would also be desirable.  adding features like these
would move use closer to being a fuller-featured language.


Right!  That is the direction I was trying to go.

My first thought was that we really need {nesting {in order to fully {express}}} what receivers might want to do. But if I set aside my programmer hat and put on my sysadmin hat, I start to think, as long as I can define the escape vector from an unsupported situation, I can create a reasonable backup/recovery plan, and that might give me 90% of what I could do with a truly structured language. After all, ASM doesn't have nesting :)



| Now, let's say what I *really* want is to return "unknown" (neutral) for
| Comcast,

doesn't this do it?

  v=spf1 +a +ptr ?include:comcast.net include:earthlink.net -all


Yes, you are right; I wasn't thinking of ?include as an option. This does what I want unless Comcast has an error in their stuff, or removes their record.

do you really want a ? from the include to cause a match on
include:comcast.net?


Nope, probably not... but there are cases where I might want a ? from the include to continue on in my first record.


It's possible that include: does most of what I want. include: does allow for a crude type of nesting.

What would people think about a couple of modifiers that specify alternate behavior for some entries here?


either way, i think the possibility for fine-tuning lies
within this table:

      included    include
      query       mechanism      SPF
      result      result         processing
      -------- -- -------------- -------------------------------------
      pass     => match,         return the prefix value for "include"
      fail     => no match,      continue processing
      softfail => no match,      continue processing
      neutral  => no match,      continue processing
      error    => throw error,   abort processing, return error
      unknown  => throw unknown, abort processing, return unknown
      none     => throw unknown, abort processing, return unknown

The last three lines, where you use the word "throw" -- these are reasonable defaults, but there are cases where I would like to "catch" that condition. What about something like,

error=break
Stop processing the current record, but if the error was in an include, continue with the previous record after the include: This allows a crude type of nesting. (In other words, if there is an error with the include record, come back here. This could include unsupported mechanisms.)

unknown=break
If the included record results in unknown, don't return it, instead continue with the previous record. (In other words, if the include record can't say pass for sure, come back here)




--
Greg Connor <gconnor(_at_)nekodojo(_dot_)org>