Courier's SPF implementation is not strictly rfc4408-compliant. nevareth wrote on Wed, 04 Feb 2009 21:10:44 -0500: > [... the case of SPF string having mx:name.without.mx.example ...] > http://www.gossamer-threads.com/lists/engine?do=post_view_flat;post=30414;page=1;sb=post_latest_reply;so=ASC;mh=25;list=spf > [...] > > courier-mta errors out when this happens and the mail gets a 417 > SPF error message.
In this case Courier issues an error, where it could possibly have issued a fail. IMHO sensible configurations should only reject mail when a clear and loud *fail* results from SPF checking. Therefore I classify this case as a MISS. It corresponds to to test 7/21 of scenario 9 in OpenSPF's Test Suite http://www.openspf.org/Test_Suite Yaml is a readable format, so please refer to that text for details about specific tests. In the following, WRONG is the converse case, where Courier issues a fail when it shouldn't, and DIFF are differences involving equivalent result codes. I paste the result of running the whole suite, so that we know where we are. More comments below. scenario 1 : Initial processing, 7 test(s), 5 zone(s) 1/7 toolonglabel: DIFF result=error instead of none 2/7 longlabel: OK 3/7 emptylabel: DIFF result=unknown instead of none 4/7 helo-not-fqdn: DIFF result=unknown instead of none 5/7 helo-domain-literal: DIFF result=unknown instead of none 6/7 nolocalpart: OK, but explanation differs 7/7 domain-literal: DIFF result=unknown instead of none scenario 2 : Record lookup, 7 test(s), 7 zone(s) 1/7 both: OK 2/7 txtonly: OK 3/7 spfonly: MISS result=unknown instead of fail, or none 4/7 spftimeout: OK 5/7 txttimeout: OK, but not first choice 6/7 nospftxttimeout: OK 7/7 alltimeout: OK scenario 3 : Selecting records, 10 test(s), 10 zone(s) 1/10 nospace1: DIFF result=neutral instead of none 2/10 empty: OK 3/10 nospace2: DIFF result=unknown instead of pass 4/10 spfoverride: OK, but not first choice 5/10 multitxt1: WRONG result=fail instead of pass, or error 6/10 multitxt2: WRONG result=fail instead of error 7/10 multispf1: OK, but not first choice 8/10 multispf2: OK, but not first choice 9/10 nospf: DIFF result=unknown instead of none 10/10 case-insensitive: OK scenario 4 : Record evaluation, 12 test(s), 13 zone(s) 1/12 detect-errors-anywhere: DIFF result=pass instead of error 2/12 modifier-charset-good: OK 3/12 modifier-charset-bad1: DIFF result=pass instead of error 4/12 modifier-charset-bad2: DIFF result=pass instead of error 5/12 redirect-after-mechanisms1: OK 6/12 redirect-after-mechanisms2: OK 7/12 default-result: OK 8/12 redirect-is-modifier: DIFF result=pass instead of error 9/12 invalid-domain: DIFF result=unknown instead of error 10/12 invalid-domain-empty-label: DIFF result=unknown instead of error, or fail 11/12 invalid-domain-long: DIFF result=unknown instead of error, or fail 12/12 invalid-domain-long-via-macro: DIFF result=unknown instead of error, or fail scenario 5 : ALL mechanism syntax, 5 test(s), 6 zone(s) 1/5 all-dot: DIFF result=neutral instead of error 2/5 all-arg: DIFF result=neutral instead of error 3/5 all-cidr: DIFF result=neutral instead of error 4/5 all-neutral: OK 5/5 all-double: OK scenario 6 : PTR mechanism syntax, 6 test(s), 8 zone(s) 1/6 ptr-cidr: WRONG result=fail instead of error 2/6 ptr-match-target: WRONG result=fail instead of pass 3/6 ptr-match-implicit: WRONG result=fail instead of pass 4/6 ptr-nomatch-invalid: OK 5/6 ptr-match-ip6: requires IPv6 6/6 ptr-empty-domain: DIFF result=neutral instead of error scenario 7 : A mechanism syntax, 23 test(s), 22 zone(s) 1/23 a-cidr6: MISS result=unknown instead of fail 2/23 a-bad-cidr4: DIFF result=unknown instead of error 3/23 a-bad-cidr6: DIFF result=unknown instead of error 4/23 a-multi-ip1: DIFF result=neutral instead of pass 5/23 a-multi-ip2: DIFF result=neutral instead of pass 6/23 a-bad-domain: DIFF result=unknown instead of error 7/23 a-nxdomain: MISS result=unknown instead of fail 8/23 a-cidr4-0: OK 9/23 a-cidr4-0-ip6: requires IPv6 10/23 a-cidr6-0-ip4: MISS result=unknown instead of fail 11/23 a-cidr6-0-ip4mapped: requires IPv6 12/23 a-cidr6-0-ip6: requires IPv6 13/23 a-cidr6-0-nxdomain: requires IPv6 14/23 a-null: DIFF result=neutral instead of error 15/23 a-numeric: DIFF result=unknown instead of error 16/23 a-numeric-toplabel: DIFF result=unknown instead of error 17/23 a-dash-in-toplabel: OK 18/23 a-bad-toplabel: DIFF result=unknown instead of error 19/23 a-only-toplabel: DIFF result=unknown instead of error 20/23 a-only-toplabel-trailing-dot: DIFF result=unknown instead of error 21/23 a-colon-domain: DIFF result=unknown instead of pass 22/23 a-colon-domain-ip4mapped: requires IPv6 23/23 a-empty-domain: DIFF result=unknown instead of error scenario 8 : Include mechanism semantics and syntax, 9 test(s), 15 zone(s) 1/9 include-fail: DIFF result=unknown instead of softfail 2/9 include-softfail: DIFF result=unknown instead of pass 3/9 include-neutral: MISS result=unknown instead of fail 4/9 include-temperror: OK 5/9 include-permerror: DIFF result=pass instead of error 6/9 include-syntax-error: DIFF result=pass instead of error 7/9 include-cidr: DIFF result=unknown instead of error 8/9 include-none: DIFF result=unknown instead of error 9/9 include-empty-domain: DIFF result=unknown instead of error scenario 9 : MX mechanism syntax, 21 test(s), 19 zone(s) 1/21 mx-cidr6: MISS result=error instead of fail 2/21 mx-bad-cidr4: OK 3/21 mx-bad-cidr6: OK 4/21 mx-multi-ip1: DIFF result=error instead of pass 5/21 mx-multi-ip2: DIFF result=error instead of pass 6/21 mx-bad-domain: OK 7/21 mx-nxdomain: MISS result=error instead of fail 8/21 mx-cidr4-0: DIFF result=error instead of pass 9/21 mx-cidr4-0-ip6: requires IPv6 10/21 mx-cidr6-0-ip4: MISS result=unknown instead of fail 11/21 mx-cidr6-0-ip4mapped: requires IPv6 12/21 mx-cidr6-0-ip6: requires IPv6 13/21 mx-cidr6-0-nxdomain: requires IPv6 14/21 mx-null: OK 15/21 mx-numeric-top-label: OK 16/21 mx-colon-domain: DIFF result=error instead of pass 17/21 mx-colon-domain-ip4mapped: requires IPv6 18/21 mx-bad-toplab: DIFF result=unknown instead of error 19/21 mx-empty: DIFF result=unknown instead of neutral 20/21 mx-implicit: DIFF result=error instead of neutral 21/21 mx-empty-domain: OK scenario 10 : EXISTS mechanism syntax, 3 test(s), 4 zone(s) 1/3 exists-empty-domain: DIFF result=neutral instead of error 2/3 exists-implicit: DIFF result=neutral instead of error 3/3 exists-cidr: DIFF result=neutral instead of error scenario 11 : IP4 mechanism syntax, 9 test(s), 10 zone(s) 1/9 cidr4-0: OK 2/9 cidr4-32: OK 3/9 cidr4-33: DIFF result=pass instead of error 4/9 cidr4-032: DIFF result=pass instead of error 5/9 bare-ip4: DIFF result=neutral instead of error 6/9 bad-ip4-port: DIFF result=neutral instead of error 7/9 bad-ip4-short: DIFF result=neutral instead of error 8/9 ip4-dual-cidr: DIFF result=neutral instead of error 9/9 ip4-mapped-ip6: requires IPv6 scenario 12 : IP6 mechanism syntax, 9 test(s), 7 zone(s) 1/9 bare-ip6: WRONG result=fail instead of error 2/9 cidr6-0-ip4: OK 3/9 cidr6-ip4: requires IPv6 4/9 cidr6-0: requires IPv6 5/9 cidr6-129: DIFF result=neutral instead of error 6/9 cidr6-bad: DIFF result=neutral instead of error 7/9 cidr6-33: requires IPv6 8/9 cidr6-33-ip4: OK 9/9 ip6-bad1: DIFF result=neutral instead of error scenario 13 : Semantics of exp and other modifiers, 20 test(s), 30 zone(s) 1/20 redirect-none: DIFF result=unknown instead of error 2/20 redirect-cancels-exp: OK 3/20 redirect-syntax-error: DIFF result=unknown instead of error 4/20 include-ignores-exp: OK, but explanation differs 5/20 redirect-cancels-prior-exp: OK 6/20 invalid-modifier: DIFF result=neutral instead of error 7/20 empty-modifier-name: DIFF result=neutral instead of error 8/20 dorky-sentinel: OK 9/20 exp-multiple-txt: OK 10/20 exp-no-txt: MISS result=unknown instead of fail 11/20 exp-dns-error: OK 12/20 exp-empty-domain: WRONG result=fail instead of error 13/20 explanation-syntax-error: MISS result=unknown instead of fail 14/20 exp-syntax-error: DIFF result=unknown instead of error 15/20 exp-twice: DIFF result=unknown instead of error 16/20 redirect-empty-domain: DIFF result=neutral instead of error 17/20 redirect-twice: WRONG result=fail instead of error 18/20 unknown-modifier-syntax: WRONG result=fail instead of error 19/20 default-modifier-obsolete: OK 20/20 default-modifier-obsolete2: OK scenario 14 : Macro expansion rules, 21 test(s), 37 zone(s) 1/21 trailing-dot-domain: DIFF result=unknown instead of pass 2/21 trailing-dot-exp: MISS result=unknown instead of fail 3/21 exp-only-macro-char: WRONG result=fail instead of error 4/21 invalid-macro-char: DIFF result=neutral instead of error 5/21 macro-mania-in-domain: DIFF result=unknown instead of pass 6/21 exp-txt-macro-char: OK, but explanation differs 7/21 domain-name-truncation: OK, but explanation differs 8/21 v-macro-ip4: OK, but explanation differs 9/21 v-macro-ip6: requires IPv6 10/21 undef-macro: requires IPv6 11/21 p-macro-ip4-novalid: OK, but explanation differs 12/21 p-macro-ip4-valid: OK, but explanation differs 13/21 p-macro-ip6-novalid: requires IPv6 14/21 p-macro-ip6-valid: requires IPv6 15/21 p-macro-multiple: DIFF result=neutral instead of pass, or softfail 16/21 upper-macro: OK, but explanation differs 17/21 hello-macro: DIFF result=unknown instead of pass 18/21 invalid-hello-macro: MISS result=unknown instead of fail 19/21 hello-domain-literal: MISS result=unknown instead of fail 20/21 require-valid-helo: MISS result=unknown instead of fail 21/21 macro-reverse-split-on-dash: DIFF result=unknown instead of pass scenario 15 : Processing limits, 9 test(s), 13 zone(s) 1/9 redirect-loop: DIFF result=unknown instead of error 2/9 include-loop: DIFF result=unknown instead of error 3/9 mx-limit: DIFF result=error instead of neutral, or pass 4/9 ptr-limit: OK 5/9 false-a-limit: DIFF result=unknown instead of pass 6/9 mech-at-limit: DIFF result=unknown instead of pass 7/9 mech-over-limit: DIFF result=unknown instead of error 8/9 include-at-limit: DIFF result=unknown instead of pass 9/9 include-over-limit: DIFF result=unknown instead of error 152 total tests in 15 scenarios 10 wrongly issued fail 14 miss to issue fail 80 different result code 19 skipped 48 ok I think the 10 wrongly issued fail are the most urgent fix. I will look into them as soon as I have time. To get a fully compliant implementation will require using the SPF RR type. I'd propose to have a BOFH variable to enable such queries. It should stay disabled until there is a wide diffusion of DNSs that support it (I've heard SPF RR type queries may cause delays.) SPF may undergo some slight amendment when a new protocol spec aiming at standard track will be issued. I hope we'll have a compliant version by that time. I've soft-linked the source file of the driver for running the test suite to http://www.ext.tana.it/courier-spf-test-suite.c, in case someone wants to run it on an IPv6-enabled version of Courier. It compiles and runs on a debian system with locally compiled yaml library _and_ courier-mta packages. I'll have to make it portable if it will go in Courier tarball (should it?) ------------------------------------------------------------------------------ Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA -OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise -Strategies to boost innovation and cut costs with open source participation -Receive a $600 discount off the registration fee with the source code: SFAD http://p.sf.net/sfu/XcvMzF8H _______________________________________________ courier-users mailing list [email protected] Unsubscribe: https://lists.sourceforge.net/lists/listinfo/courier-users
