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

Reply via email to