|
Ideas for semantic (feature) extensibility
2004-05-22 15:30:30
I will take a stab at identifying some requirements and methods for
semantic extensibility. Please comment... I would like to collect comments
from SPF users and then include MS folks in a second round of comments if
we all feel like we're going in the right direction.
Here are the goals I want to get to:
1. Let's assume that new keywords and new features will crop up.
2. Assume that any client might see some keyword or language element for
which it doesn't have the feature, and in most cases doesn't understand the
new feature.
3. Allow the publisher of the record to define the "fallback position"
(i.e. the logic for dealing with an unknown feature.) There are a wide
range of different situations... we can't really solve the problem by
mandating one and only one fallback position.
4. The publisher needs to know predictably and reliably what will happen on
the receiving end, both with the new feature present and without.
With these in mind, rolling out a new feature should be possible, but we
would need to add a little bit to the language.
(I am sidestepping XML vs SPF TXT for now. Here is how. :) Based on some
conversations at the meeting, we think that XML allows for "syntax
extensibility", meaning you can add new keywords to the language pretty
easily. It's also fairly easy to add to SPF TXT using the same concepts...
in either case, the hard part is that you must agree on what to do when you
come to an unknown mechanism. The examples I'm using here look like SPF,
but please don't take that to be an endorsement of one or the other. For
the record I support the proposed compromise of "SPF and XML running
concurrently for now" and it seems likely that we will need to solve both
problems anyway.)
The essence of the question is, "Here is this unknown/unimplemented
feature, and I can't use it like you want me to, so I need to skip over it
intelligently while still honoring your intentions."
Here is an example of one possible fallback situation
mydomain.com. v=spf1 +ptr +mx +domainkeys -all
"If the message is not from my servers (by ptr or mx) it may also be
allowed if it has the new feature "domainkeys". Otherwise, no exceptions
are allowed."
Here are a couple of ways to state what this publisher probably wants:
0. The current SPF strategy is:
v=spf1 +ptr +mx ?all
v=spf2 +ptr +mx +domainkeys -all
This allows you to do exactly what you want, but the version numbers of the
record mean that you have to repeat yourself. Also, some folks have given
feedback that the version number would limit SPF to only those features
recognized by a centralized version numbering authority. We can sort of
get around this by pointing out that version numbers could be like 1a or 1+
or similar. But, if there is more than one optional feature released
later, you may get an even worse situation: 1, 1d, 1j, 1dj. Also, the
backward compatible records will be slow to go away... and since they are
all TXT as far as DNS is concerned, you have to return all of them, hence
there is less space for each iteration.
So, what follows are three additional methods/mechanisms that would add
by-feature extensibility with a predictable fallback.
1. Structured logic:
+ptr +mx IF domainkeys { +domainkeys -all } ELSE { ?all }
The structured logic provides a very specific "fork" in the road... if the
feature is available, take one track, if not, take another track. Either
track can have multiple follow-on steps. This is a somewhat heavy
solution syntax-wise, I think, because we are adding delimiters and
nesting, as well as conditional tests. (I am pretty sure we don't want 1.
-- it's just here for comparison with what other higher-level languages
might do.)
2. Choose one and only one failure action.
+ptr +mx unsupported=? +domainkeys -all
The modifier "unsupported" tells what action to be taken when an unknown
feature is encountered. That action will probably be one of:
unsupported=? Stop processing and return "unknown" ("neutral")
unsupported=- Stop processing and return "Fail"
unsupported=+ Stop processing and return "Pass" (pretty unlikely ;)
unsupported=abort Stop processing and return error result (current
behavior)
unsupported=continue Ignore the unknown keyword and resume with the
next step
This provides a predictable action if the feature is not supported, though
it will only do one action, not a new sequence. However, the record could
include another unsupported flag later in the record, so that one feature
fails using "unknown" and another feature fails using "Fail".
3. Trap style
+ptr +mx trap(unsupported=break){ +domainkeys -all } ?all
There is no "test" as there would be with if/then/else, but there is
nesting, which allows you to do pretty much the same things. The trap
could be any one of the actions from #2, in addition to "break" which means
"skip to the end of the trap section, then continue".
Brief discussion comparing 1, 2, 3...
My thought is that 1 is the hardest to do and 2 is the easiest (and closest
to the current SPF spec). 3. introduces nesting, but not conditional
tests, so it should be relatively easy to implement, but because it is
"structured" it will give people the "illusion of complexity".
I feel that 3. is the direction that gives us the greatest number of
options later down the line. With a Trap{} mechanism you would be 100%
sure of what will happen if your features are missing, and it also gives
some more clever options that linear processing doesn't give you. BUT,
there are probably very few cases that would need 3. that are not solved
adequately by 2.
If we were talking only about SPF alone, I would probably lean toward 2. to
keep the nesting out of it and keep everything linear. However, if we are
thinking about XML, it already has this type of nesting built in. Consider
the following xml-like snippet.
<ptr/>
<mx/>
<trap unsupported=break>
<domainkeys/>
<all action=FAIL />
</trap>
<all action=UNKNOWN />
So, I guess given the courtship period we are entering with MS CID, I would
want to take a second look at option 3. (Trap mechanism) and not dismiss it
out of hand. However, I would love to hear feedback from others on this.
(Here is where I digress a bit from "adding features" - this example is
about more things a Trap mechanism would allow us to do, other than feature
extensibility)
The "trap style" could also be extended to protect you from other errors,
or even to include/reference someone else's record in a way that you
control. For example, here is another scenario altogether that might
benefit from a trap mechanism.
mydomain.com: +a +ptr include:comcast.net include:earthlink.net -all
comcast.net: +a +ptr -all
earthlink.net: +a +ptr -all
In this case, you are saying that your mail may come from your servers,
Comcast, or Earthlink (perhaps you have users on those two networks). If I
understand include: correctly, if the result for comcast.net is PASS, then
the result is also PASS for mydomain.com.
Here is what happens with include:comcast.net..
comcast.net results: mydomain.com results:
PASS PASS
NEUTRAL, FAIL CONTINUE
ERROR ERROR
No SPF record exists FAIL
I believe the redirect=comcast.net would return either Pass, Fail, or
Unknown, depending on whatever the straight comcast.net test would have
been, but since their record ends in -all (or any "all") then my processing
would never continue on to Earthlink. (Comcast could assist me by
publishing a redirect.comcast.net that has +a +ptr +mx but no -all, I think
if the redirect doesn't contain an "all" it is possible to come back to the
main line. But, still no way to change a + for them into a ? for me)
Now, let's say what I *really* want is to return "unknown" (neutral) for
Comcast, since I have some users, but there are also a lot of forgeries
coming from there. If Comcast says it is a PASS, maybe I really want to
interpret that as an unknown. In other words, I am going to (include,
redirect, whatever) to comcast, and I'm fishing for a + or ? which I will
treat as a ?, and if I get a - or error I will move to the next fork.
So, what I would like in this case is something like this...
mydomain.com: +a +ptr
trap(+=?,?=?,-=break,error=break){ redirect=comcast.net }
trap(+=?,?=?,-=break,error=break){ redirect=earthlink.net }
-all
Anyway, that's a quick example of how a trap might help in other ways not
having to do with adding features... Kind of a "nice to have" but not a
hard/fast requirement, I think...
--
Greg Connor <gconnor(_at_)nekodojo(_dot_)org>
| <Prev in Thread] |
Current Thread |
[Next in Thread> |
- Ideas for semantic (feature) extensibility,
Greg Connor <=
|
|
|