spf-discuss
[Top] [All Lists]

Mask Syntax

2005-04-01 08:55:10
At 10:57 PM 3/31/2005 -0500, Radu wrote:
David MacQuigg wrote:

Records that are already compiled to a simple one-query list will be processed normally. Records that require multiple queries will not be evaluated at all and will result in a temporary reject. Adding the m= syntax allows us to reach a conclusion in *most* of those multi-query cases, even without the additional queries. In a DoS storm, this could be *almost all* cases.

Actually... 99.98% of records that require multiple queries will be correctly after only 1 query, since in a DNS storm the email comes from everywhere but the few places that the mask specifies. So the incoming MTAs don't need to change behaviour, as they will only do the 2nd query for those 0.02% of emails that actually come from the neighbourhood of the mask.

0.02% may be a bit optimistic. :>) I think attackers will search the planet for domains that have their authorized senders scattered widely among a bunch of dynamic IP blocks they can hijack. We may still need an ability to block even the initial SYN floods from those blocks. This is outside the scope of SPF, however.

For most reputable domains, however, I think you are right. The vast majority will do like rr.com and cluster their servers in small, well-protected IP blocks.

This makes a mask-enabled SPF record extremely resilient to DoS attacks, while maintaining full function of the SPF record.

So don't worry, if you have the mask, your email will not be bounced even at the high of a DoS storm. (unless the storm is coming from you ... LOL).


              --- Mask Syntax ---

Here is an example of what we could do with a huge domain like rr.com:
m=~24(181ecb,181cc8,181ccc,181eda,185d2f,181909,
411805,185ea6,181d6d,424ba2,181802,412005) ... -all
Existing checkers ignore the m= and process the ... with all the usual redirects and includes. Upgraded checkers will be able to take advantage of the new syntax. The ~ means the mask result is ANDed with the remaining ... result. If it fails to match, you are done.

Not quite so. the -all and m=~ are in conflict. The mask result will be the same as the "all" prefix.

Also, the mask is evaluated before the first redirect=, no sooner. So the IP4:'s in the first record are checked against the sender's IP *WITHOUT LOOKING AT THE MASK*. This is because the mask refers *ONLY* to IP4: mechanisms which are not in the current record. It would be a waste of space for the mask to also cover the mechanisms which are clearly visible in the first record.

Also, I would prefer to sticking to a mask representation that is easily human readable, so you can look at a record *set* and be able to easily tell if the mask is right or wrong, just by visual inspection and some simple arithmetic. If you can't easily tell, the trust in the mask is undermined (by humans). So when there are problems with the record, the first thing they do is disable mask generation.

Here are some suggestions on mask syntax. I think we should separate the goals of readability and versatility in the source record from compactness and efficiency in the compiled record. This will allow better optimization on both ends. If we really don't want users messing with the compiled record, we should not tempt them by making it easily editable. If you need to see what's in a compiled record, view it in the wizard.

Another goal should be to facilitate later migration to a syntax that needs nothing but a mask. Currently, we must make masks ignorable, but when I think of the final standard authentication method that may emerge from a Grand Unification by the IETF, I think of everything needed for authentication in one DNS packet. This would most likely include an IP mask for quick screening at the earliest opportunity, a public key for final validation at the destination, and links to any other authentication records that may be necessary. Compactness of the mask will be an issue, unless they upgrade DNS to use larger UDP packets.

Here is a sequence of compactions for the SPF record of a typical large domain, starting with the source record. The ... is the current SPF syntax, and is necessary as long as there are legacy SPF checkers that ignore masks. The operator after the m= could be any visible character. In my hypothetical syntax, ~ means this is a supplemental mask, the original syntax is in ...
+ means this mask is the whole enchilada, you don't even need a -all.

v=spf1 ip4:24.30.203.0/24 ip4:24.28.200.0/24 ip4:24.28.204.0/24
ip4:24.30.218.0/24 ip4:24.93.47.0/24 ip4:24.25.9.0/24
ip4:65.24.5.0/24 ip4:24.94.166.0/24 ip4:24.29.109.0/24
ip4:66.75.162.0/24 ip4:24.24.2.0/24 ip4:65.32.5.0/24 ... -all

v=spf1 m=~24.30.203/24,24.28.200/24,24.28.204/24,24.30.218/24,
24.93.47/24,24.25.9/24,65.24.5/24,24.94.166/24,24.29.109/24,
66.75.162/24,24.24.2/24,65.32.5/24 ... -all

v=spf1 m=~24(24.30.203,24.28.200,24.28.204,24.30.218,24.93.47,
24.25.9,65.24.5,24.94.166,24.29.109,66.75.162,24.24.2,65.32.5)
 ... -all

v=spf1 m=+24(181ecb,181cc8,181ccc,181eda,185d2f,181909,411805,
185ea6,181d6d,424ba2,181802,412005)

v=spf1 m=+24(Kapi2RPMcR1CxEJdXOkLCFECMQDTO0fzuShRvL8q0m5sitIH)

v=spf1 m=+24,12,a2       |<       ---  36 bytes ---        >|

This last record indicates there are 12 masks, 24 bits each, and the binary data for those masks starts at offset a2 within the 512 byte record. The binary data occupies 36 bytes ( 12 masks, 3 bytes each).

We don't need to specify all this now. Just make sure there is plenty of flexibility in whatever we deploy early, so we don't have to deprecate stuff later. I think the m=<operator>... general pattern should work for anything I can anticipate.

-- Dave
************************************************************     *
* David MacQuigg, PhD      email:  dmquigg-spf at yahoo.com      *  *
* IC Design Engineer            phone:  USA 520-721-4583      *  *  *
* Analog Design Methodologies                                 *  *  *
*                                   9320 East Mikelyn Lane     * * *
* VRS Consulting, P.C.              Tucson, Arizona 85710        *
************************************************************ *


<Prev in Thread] Current Thread [Next in Thread>