coppertone 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE +201 -0
  6. data/README.md +58 -0
  7. data/Rakefile +140 -0
  8. data/coppertone.gemspec +27 -0
  9. data/lib/coppertone/class_builder.rb +20 -0
  10. data/lib/coppertone/directive.rb +38 -0
  11. data/lib/coppertone/dns/error.rb +9 -0
  12. data/lib/coppertone/dns/mock_client.rb +106 -0
  13. data/lib/coppertone/dns/resolv_client.rb +110 -0
  14. data/lib/coppertone/dns.rb +3 -0
  15. data/lib/coppertone/domain_spec.rb +45 -0
  16. data/lib/coppertone/error.rb +29 -0
  17. data/lib/coppertone/ip_address_wrapper.rb +75 -0
  18. data/lib/coppertone/macro_context.rb +67 -0
  19. data/lib/coppertone/macro_string/macro_expand.rb +84 -0
  20. data/lib/coppertone/macro_string/macro_literal.rb +24 -0
  21. data/lib/coppertone/macro_string/macro_parser.rb +62 -0
  22. data/lib/coppertone/macro_string/macro_static_expand.rb +52 -0
  23. data/lib/coppertone/macro_string.rb +31 -0
  24. data/lib/coppertone/mechanism/a.rb +16 -0
  25. data/lib/coppertone/mechanism/all.rb +24 -0
  26. data/lib/coppertone/mechanism/cidr_parser.rb +14 -0
  27. data/lib/coppertone/mechanism/domain_spec_mechanism.rb +18 -0
  28. data/lib/coppertone/mechanism/domain_spec_optional.rb +46 -0
  29. data/lib/coppertone/mechanism/domain_spec_required.rb +37 -0
  30. data/lib/coppertone/mechanism/domain_spec_with_dual_cidr.rb +114 -0
  31. data/lib/coppertone/mechanism/exists.rb +14 -0
  32. data/lib/coppertone/mechanism/include.rb +18 -0
  33. data/lib/coppertone/mechanism/include_matcher.rb +34 -0
  34. data/lib/coppertone/mechanism/ip4.rb +13 -0
  35. data/lib/coppertone/mechanism/ip6.rb +13 -0
  36. data/lib/coppertone/mechanism/ip_mechanism.rb +48 -0
  37. data/lib/coppertone/mechanism/mx.rb +40 -0
  38. data/lib/coppertone/mechanism/ptr.rb +17 -0
  39. data/lib/coppertone/mechanism.rb +32 -0
  40. data/lib/coppertone/modifier/base.rb +24 -0
  41. data/lib/coppertone/modifier/exp.rb +34 -0
  42. data/lib/coppertone/modifier/redirect.rb +17 -0
  43. data/lib/coppertone/modifier/unknown.rb +16 -0
  44. data/lib/coppertone/modifier.rb +30 -0
  45. data/lib/coppertone/qualifier.rb +45 -0
  46. data/lib/coppertone/record.rb +86 -0
  47. data/lib/coppertone/record_evaluator.rb +63 -0
  48. data/lib/coppertone/record_finder.rb +34 -0
  49. data/lib/coppertone/request.rb +68 -0
  50. data/lib/coppertone/request_context.rb +67 -0
  51. data/lib/coppertone/request_count_limiter.rb +36 -0
  52. data/lib/coppertone/result.rb +50 -0
  53. data/lib/coppertone/sender_identity.rb +39 -0
  54. data/lib/coppertone/spf_service.rb +9 -0
  55. data/lib/coppertone/term.rb +13 -0
  56. data/lib/coppertone/utils/domain_utils.rb +59 -0
  57. data/lib/coppertone/utils/host_utils.rb +22 -0
  58. data/lib/coppertone/utils/ip_in_domain_checker.rb +53 -0
  59. data/lib/coppertone/utils/validated_domain_finder.rb +40 -0
  60. data/lib/coppertone/utils.rb +4 -0
  61. data/lib/coppertone/version.rb +3 -0
  62. data/lib/coppertone.rb +48 -0
  63. data/lib/resolv/dns/resource/in/spf.rb +15 -0
  64. data/spec/directive_spec.rb +41 -0
  65. data/spec/dns/resolv_client_spec.rb +307 -0
  66. data/spec/domain_spec_spec.rb +35 -0
  67. data/spec/ip_address_wrapper_spec.rb +67 -0
  68. data/spec/macro_context_spec.rb +69 -0
  69. data/spec/macro_string/macro_expand_spec.rb +79 -0
  70. data/spec/macro_string/macro_literal_spec.rb +27 -0
  71. data/spec/macro_string/macro_static_expand_spec.rb +67 -0
  72. data/spec/macro_string_spec.rb +20 -0
  73. data/spec/mechanism/a_spec.rb +198 -0
  74. data/spec/mechanism/all_spec.rb +22 -0
  75. data/spec/mechanism/exists_spec.rb +91 -0
  76. data/spec/mechanism/include_spec.rb +43 -0
  77. data/spec/mechanism/ip4_spec.rb +110 -0
  78. data/spec/mechanism/ip6_spec.rb +104 -0
  79. data/spec/mechanism/mx_spec.rb +51 -0
  80. data/spec/mechanism/ptr_spec.rb +43 -0
  81. data/spec/mechanism_spec.rb +4 -0
  82. data/spec/modifier_spec.rb +4 -0
  83. data/spec/open_spf/ALL_mechanism_syntax_spec.rb +38 -0
  84. data/spec/open_spf/A_mechanism_syntax_spec.rb +159 -0
  85. data/spec/open_spf/EXISTS_mechanism_syntax_spec.rb +46 -0
  86. data/spec/open_spf/IP4_mechanism_syntax_spec.rb +59 -0
  87. data/spec/open_spf/IP6_mechanism_syntax_spec.rb +60 -0
  88. data/spec/open_spf/Include_mechanism_semantics_and_syntax_spec.rb +56 -0
  89. data/spec/open_spf/Initial_processing_spec.rb +77 -0
  90. data/spec/open_spf/MX_mechanism_syntax_spec.rb +119 -0
  91. data/spec/open_spf/Macro_expansion_rules_spec.rb +154 -0
  92. data/spec/open_spf/PTR_mechanism_syntax_spec.rb +42 -0
  93. data/spec/open_spf/Processing_limits_spec.rb +72 -0
  94. data/spec/open_spf/Record_evaluation_spec.rb +75 -0
  95. data/spec/open_spf/Record_lookup_spec.rb +48 -0
  96. data/spec/open_spf/Selecting_records_spec.rb +61 -0
  97. data/spec/open_spf/Semantics_of_exp_and_other_modifiers_spec.rb +167 -0
  98. data/spec/open_spf/Test_cases_from_implementation_bugs_spec.rb +17 -0
  99. data/spec/qualifier_spec.rb +54 -0
  100. data/spec/record_evaluator_spec.rb +4 -0
  101. data/spec/record_finder_spec.rb +4 -0
  102. data/spec/record_spec.rb +100 -0
  103. data/spec/request_context_spec.rb +43 -0
  104. data/spec/request_count_limiter_spec.rb +28 -0
  105. data/spec/result_spec.rb +4 -0
  106. data/spec/rfc7208-tests.yml +2548 -0
  107. data/spec/sender_identity_spec.rb +69 -0
  108. data/spec/spec_helper.rb +8 -0
  109. data/spec/term_spec.rb +38 -0
  110. data/spec/utils/domain_utils_spec.rb +60 -0
  111. data/spec/utils/host_utils_spec.rb +32 -0
  112. data/spec/utils/ip_in_domain_checker_spec.rb +4 -0
  113. data/spec/utils/validated_domain_finder_spec.rb +4 -0
  114. metadata +306 -0
@@ -0,0 +1,2548 @@
1
+ # This is the openspf.org test suite (release 2014.04) based on RFC 7208.
2
+ # http://www.openspf.org/Test_Suite
3
+ #
4
+ # $Id: rfc7208-tests.yml,v 1.1.2.8 2014/08/02 18:35:01 customdesigned Exp $
5
+ # vim:sw=2 sts=2 et
6
+ #
7
+ # See rfc7208-tests.CHANGES for a changelog.
8
+ #
9
+ # Contributors:
10
+ # Stuart D Gathman 90% of the tests
11
+ # Julian Mehnle some tests, proofread YAML syntax, formal schema
12
+ # Frank Ellermann
13
+ # Scott Kitterman
14
+ # Wayne Schlitt
15
+ # Craig Whitmore
16
+ # Norman Maurer
17
+ # Mark Shewmaker
18
+ # Philip Gladstone
19
+ #
20
+ # For RFC 4408, the test suite was designed for use with SPF (type 99) and TXT
21
+ # implementations. In RFC 7208, use of type SPF has been removed.
22
+ #
23
+ # The "Selecting records" test section is the only one concerned with weeding
24
+ # out (incorrect) queries for type SPF of any kind or proper response to
25
+ # duplicate or conflicting records. Other sections rely on auto-magic
26
+ # duplication of SPF to TXT records (by test suite drivers) to test all
27
+ # implementation types with one specification.
28
+ #
29
+ # All new tests should use Documentation IPs for both IP4 and IP6. I was
30
+ # stupid to use 1.2.3.4 - that is a real global IP (although it doesn't ping).
31
+ #
32
+ ---
33
+ description: Initial processing
34
+ tests:
35
+ toolonglabel:
36
+ description: >-
37
+ DNS labels limited to 63 chars.
38
+ comment: >-
39
+ For initial processing, a long label results in None, not TempError
40
+ spec: 4.3/1
41
+ helo: mail.example.net
42
+ host: 1.2.3.5
43
+ mailfrom: lyme.eater@A123456789012345678901234567890123456789012345678901234567890123.example.com
44
+ result: none
45
+ longlabel:
46
+ description: >-
47
+ DNS labels limited to 63 chars.
48
+ spec: 4.3/1
49
+ helo: mail.example.net
50
+ host: 1.2.3.5
51
+ mailfrom: lyme.eater@A12345678901234567890123456789012345678901234567890123456789012.example.com
52
+ result: fail
53
+ emptylabel:
54
+ spec: 4.3/1
55
+ helo: mail.example.net
56
+ host: 1.2.3.5
57
+ mailfrom: lyme.eater@A...example.com
58
+ result: none
59
+ helo-not-fqdn:
60
+ spec: 4.3/1
61
+ helo: A2345678
62
+ host: 1.2.3.5
63
+ mailfrom: ""
64
+ result: none
65
+ helo-domain-literal:
66
+ spec: 4.3/1
67
+ helo: "[1.2.3.5]"
68
+ host: 1.2.3.5
69
+ mailfrom: ""
70
+ result: none
71
+ nolocalpart:
72
+ spec: 4.3/2
73
+ helo: mail.example.net
74
+ host: 1.2.3.4
75
+ mailfrom: '@example.net'
76
+ result: fail
77
+ explanation: postmaster
78
+ domain-literal:
79
+ spec: 4.3/1
80
+ helo: OEMCOMPUTER
81
+ host: 1.2.3.5
82
+ mailfrom: "foo@[1.2.3.5]"
83
+ result: none
84
+ non-ascii-policy:
85
+ description: >-
86
+ SPF policies are restricted to 7-bit ascii.
87
+ spec: 3.1/1
88
+ helo: hosed
89
+ host: 1.2.3.4
90
+ mailfrom: "foobar@hosed.example.com"
91
+ result: permerror
92
+ non-ascii-mech:
93
+ description: >-
94
+ SPF policies are restricted to 7-bit ascii.
95
+ comment: >-
96
+ Checking a possibly different code path for non-ascii chars.
97
+ spec: 3.1/1
98
+ helo: hosed
99
+ host: 1.2.3.4
100
+ mailfrom: "foobar@hosed2.example.com"
101
+ result: permerror
102
+ non-ascii-result:
103
+ description: >-
104
+ SPF policies are restricted to 7-bit ascii.
105
+ comment: >-
106
+ Checking yet another code path for non-ascii chars.
107
+ spec: 3.1/1
108
+ helo: hosed
109
+ host: 1.2.3.4
110
+ mailfrom: "foobar@hosed3.example.com"
111
+ result: permerror
112
+ non-ascii-non-spf:
113
+ description: >-
114
+ Non-ascii content in non-SPF related records.
115
+ comment: >-
116
+ Non-SPF related TXT records are none of our business.
117
+ spec: 4.5/1
118
+ helo: hosed
119
+ host: 1.2.3.4
120
+ mailfrom: "foobar@nothosed.example.com"
121
+ result: fail
122
+ explanation: DEFAULT
123
+ control-char-policy:
124
+ description: >-
125
+ Mechanisms are separated by spaces only, not any control char.
126
+ spec: 4.6.1/2
127
+ helo: hosed
128
+ host: 192.0.2.3
129
+ mailfrom: "foobar@ctrl.example.com"
130
+ result: permerror
131
+ zonedata:
132
+ example.com:
133
+ - TIMEOUT
134
+ example.net:
135
+ - TXT: v=spf1 -all exp=exp.example.net
136
+ a.example.net:
137
+ - TXT: v=spf1 -all exp=exp.example.net
138
+ exp.example.net:
139
+ - TXT: '%{l}'
140
+ a12345678901234567890123456789012345678901234567890123456789012.example.com:
141
+ - TXT: v=spf1 -all
142
+ hosed.example.com:
143
+ - TXT: "v=spf1 a:\xEF\xBB\xBFgarbage.example.net -all"
144
+ hosed2.example.com:
145
+ - TXT: "v=spf1 \x80a:example.net -all"
146
+ hosed3.example.com:
147
+ - TXT: "v=spf1 a:example.net \x96all"
148
+ nothosed.example.com:
149
+ - TXT: "v=spf1 a:example.net -all"
150
+ - TXT: "\x96"
151
+ ctrl.example.com:
152
+ - TXT: "v=spf1 a:ctrl.example.com\x0dptr -all"
153
+ - A: 192.0.2.3
154
+ ---
155
+ description: Record lookup
156
+ tests:
157
+ both:
158
+ spec: 4.4/1
159
+ helo: mail.example.net
160
+ host: 1.2.3.4
161
+ mailfrom: foo@both.example.net
162
+ result: fail
163
+ txtonly:
164
+ description: Result is none if checking SPF records only
165
+ (which you should not be doing).
166
+ spec: 4.4/1
167
+ helo: mail.example.net
168
+ host: 1.2.3.4
169
+ mailfrom: foo@txtonly.example.net
170
+ result: fail
171
+ spfonly:
172
+ description: Result is none if checking TXT records only.
173
+ spec: 4.4/1
174
+ helo: mail.example.net
175
+ host: 1.2.3.4
176
+ mailfrom: foo@spfonly.example.net
177
+ result: none
178
+ spftimeout:
179
+ description: >-
180
+ TXT record present, but SPF lookup times out.
181
+ Result is temperror if checking SPF records only. Fortunately,
182
+ we don't do type SPF anymore.
183
+ comment: >-
184
+ This actually happens for a popular braindead DNS server.
185
+ spec: 4.4/1
186
+ helo: mail.example.net
187
+ host: 1.2.3.4
188
+ mailfrom: foo@spftimeout.example.net
189
+ result: fail
190
+ txttimeout:
191
+ description: >-
192
+ SPF record present, but TXT lookup times out.
193
+ If only TXT records are checked, result is temperror.
194
+ spec: 4.4/1
195
+ helo: mail.example.net
196
+ host: 1.2.3.4
197
+ mailfrom: foo@txttimeout.example.net
198
+ result: temperror
199
+ nospftxttimeout:
200
+ description: >-
201
+ No SPF record present, and TXT lookup times out.
202
+ If only TXT records are checked, result is temperror.
203
+ comment: >-
204
+ Because TXT records is where v=spf1 records will likely be, returning
205
+ temperror will try again later. A timeout due to a braindead server
206
+ is unlikely in the case of TXT, as opposed to the newer SPF RR.
207
+ spec: 4.4/1
208
+ helo: mail.example.net
209
+ host: 1.2.3.4
210
+ mailfrom: foo@nospftxttimeout.example.net
211
+ result: temperror
212
+ alltimeout:
213
+ description: Both TXT and SPF queries time out
214
+ spec: 4.4/2
215
+ helo: mail.example.net
216
+ host: 1.2.3.4
217
+ mailfrom: foo@alltimeout.example.net
218
+ result: temperror
219
+ zonedata:
220
+ both.example.net:
221
+ - TXT: v=spf1 -all
222
+ - SPF: v=spf1 -all
223
+ txtonly.example.net:
224
+ - TXT: v=spf1 -all
225
+ spfonly.example.net:
226
+ - SPF: v=spf1 -all
227
+ - TXT: NONE
228
+ spftimeout.example.net:
229
+ - TXT: v=spf1 -all
230
+ - TIMEOUT
231
+ txttimeout.example.net:
232
+ - SPF: v=spf1 -all
233
+ - TXT: NONE
234
+ - TIMEOUT
235
+ nospftxttimeout.example.net:
236
+ - SPF: "v=spf3 !a:yahoo.com -all"
237
+ - TXT: NONE
238
+ - TIMEOUT
239
+ alltimeout.example.net:
240
+ - TIMEOUT
241
+ ---
242
+ description: Selecting records
243
+ tests:
244
+ nospace1:
245
+ description: >-
246
+ Version must be terminated by space or end of record. TXT pieces
247
+ are joined without intervening spaces.
248
+ spec: 4.5/4
249
+ helo: mail.example1.com
250
+ host: 1.2.3.4
251
+ mailfrom: foo@example2.com
252
+ result: none
253
+ empty:
254
+ description: Empty SPF record.
255
+ spec: 4.5/4
256
+ helo: mail1.example1.com
257
+ host: 1.2.3.4
258
+ mailfrom: foo@example1.com
259
+ result: neutral
260
+ nospace2:
261
+ spec: 4.5/4
262
+ helo: mail.example1.com
263
+ host: 1.2.3.4
264
+ mailfrom: foo@example3.com
265
+ result: pass
266
+ spfoverride:
267
+ description: >-
268
+ SPF records no longer used.
269
+ spec: 4.5/5
270
+ helo: mail.example1.com
271
+ host: 1.2.3.4
272
+ mailfrom: foo@example4.com
273
+ result: fail
274
+ multitxt1:
275
+ description: >-
276
+ Implementations should give permerror/unknown because of
277
+ the conflicting TXT records.
278
+ spec: 4.5/5
279
+ helo: mail.example1.com
280
+ host: 1.2.3.4
281
+ mailfrom: foo@example5.com
282
+ result: permerror
283
+ multitxt2:
284
+ description: >-
285
+ Multiple records is a permerror, v=spf1 is case insensitive
286
+ spec: 4.5/6
287
+ helo: mail.example1.com
288
+ host: 1.2.3.4
289
+ mailfrom: foo@example6.com
290
+ result: permerror
291
+ multispf1:
292
+ description: >-
293
+ Multiple records is a permerror, even when they are identical.
294
+ However, this situation cannot be reliably reproduced with live
295
+ DNS since cache and resolvers are allowed to combine identical
296
+ records.
297
+ spec: 4.5/6
298
+ helo: mail.example1.com
299
+ host: 1.2.3.4
300
+ mailfrom: foo@example7.com
301
+ result: [permerror, fail]
302
+ multispf2:
303
+ description: >-
304
+ Ignoring SPF-type records will give pass because there is a (single)
305
+ TXT record.
306
+ spec: 4.5/6
307
+ helo: mail.example1.com
308
+ host: 1.2.3.4
309
+ mailfrom: foo@example8.com
310
+ result: pass
311
+ nospf:
312
+ spec: 4.5/7
313
+ helo: mail.example1.com
314
+ host: 1.2.3.4
315
+ mailfrom: foo@mail.example1.com
316
+ result: none
317
+ case-insensitive:
318
+ description: >-
319
+ v=spf1 is case insensitive
320
+ spec: 4.5/6
321
+ helo: mail.example1.com
322
+ host: 1.2.3.4
323
+ mailfrom: foo@example9.com
324
+ result: softfail
325
+ zonedata:
326
+ example3.com:
327
+ - TXT: v=spf10
328
+ - TXT: v=spf1 mx
329
+ - MX: [0, mail.example1.com]
330
+ example1.com:
331
+ - TXT: v=spf1
332
+ example2.com:
333
+ - TXT: ['v=spf1', 'mx']
334
+ mail.example1.com:
335
+ - A: 1.2.3.4
336
+ example4.com:
337
+ - SPF: v=spf1 +all
338
+ - TXT: v=spf1 -all
339
+ example5.com:
340
+ - SPF: v=spf1 +all
341
+ - TXT: v=spf1 -all
342
+ - TXT: v=spf1 +all
343
+ example6.com:
344
+ - TXT: v=spf1 -all
345
+ - TXT: V=sPf1 +all
346
+ example7.com:
347
+ - TXT: v=spf1 -all
348
+ - TXT: v=spf1 -all
349
+ example8.com:
350
+ - SPF: V=spf1 -all
351
+ - SPF: v=spf1 -all
352
+ - TXT: v=spf1 +all
353
+ example9.com:
354
+ - TXT: v=SpF1 ~all
355
+ ---
356
+ description: Record evaluation
357
+ tests:
358
+ detect-errors-anywhere:
359
+ description: Any syntax errors anywhere in the record MUST be detected.
360
+ spec: 4.6
361
+ helo: mail.example.com
362
+ host: 1.2.3.4
363
+ mailfrom: foo@t1.example.com
364
+ result: permerror
365
+ modifier-charset-good:
366
+ description: name = ALPHA *( ALPHA / DIGIT / "-" / "_" / "." )
367
+ spec: 4.6.1/2
368
+ helo: mail.example.com
369
+ host: 1.2.3.4
370
+ mailfrom: foo@t2.example.com
371
+ result: pass
372
+ modifier-charset-bad1:
373
+ description: >-
374
+ '=' character immediately after the name and before any ":" or "/"
375
+ spec: 4.6.1/4
376
+ helo: mail.example.com
377
+ host: 1.2.3.4
378
+ mailfrom: foo@t3.example.com
379
+ result: permerror
380
+ modifier-charset-bad2:
381
+ description: >-
382
+ '=' character immediately after the name and before any ":" or "/"
383
+ spec: 4.6.1/4
384
+ helo: mail.example.com
385
+ host: 1.2.3.4
386
+ mailfrom: foo@t4.example.com
387
+ result: permerror
388
+ redirect-after-mechanisms1:
389
+ description: >-
390
+ The "redirect" modifier has an effect after all the mechanisms.
391
+ comment: >-
392
+ The redirect in this example would violate processing limits, except
393
+ that it is never used because of the all mechanism.
394
+ spec: 4.6.3
395
+ helo: mail.example.com
396
+ host: 1.2.3.4
397
+ mailfrom: foo@t5.example.com
398
+ result: softfail
399
+ redirect-after-mechanisms2:
400
+ description: >-
401
+ The "redirect" modifier has an effect after all the mechanisms.
402
+ spec: 4.6.3
403
+ helo: mail.example.com
404
+ host: 1.2.3.5
405
+ mailfrom: foo@t6.example.com
406
+ result: fail
407
+ default-result:
408
+ description: Default result is neutral.
409
+ spec: 4.7/1
410
+ helo: mail.example.com
411
+ host: 1.2.3.5
412
+ mailfrom: foo@t7.example.com
413
+ result: neutral
414
+ redirect-is-modifier:
415
+ description: |-
416
+ Invalid mechanism. Redirect is a modifier.
417
+ spec: 4.6.1/4
418
+ helo: mail.example.com
419
+ host: 1.2.3.4
420
+ mailfrom: foo@t8.example.com
421
+ result: permerror
422
+ invalid-domain:
423
+ description: >-
424
+ Domain-spec must end in macro-expand or valid toplabel.
425
+ spec: 7.1/2
426
+ helo: mail.example.com
427
+ host: 1.2.3.4
428
+ mailfrom: foo@t9.example.com
429
+ result: permerror
430
+ invalid-domain-empty-label:
431
+ description: >-
432
+ target-name that is a valid domain-spec per RFC 4408 and RFC 7208 but an
433
+ invalid domain name per RFC 1035 (empty label) should be treated as
434
+ non-existent.
435
+ comment: >-
436
+ An empty domain label, i.e. two successive dots, in a mechanism
437
+ target-name is valid domain-spec syntax (perhaps formed from a macro
438
+ expansion), even though a DNS query cannot be composed from it. The spec
439
+ being unclear about it, this could either be considered a syntax error,
440
+ or, by analogy to 4.3/1 and 5/10/3, the mechanism could be treated as a
441
+ no-match. RFC 7208 failed to agree on which result to use, and declares
442
+ the situation undefined. The preferred test result is therefore a matter
443
+ of opinion.
444
+ spec: 4.3/1, 4.8/5, 5/10/3
445
+ helo: mail.example.com
446
+ host: 1.2.3.4
447
+ mailfrom: foo@t10.example.com
448
+ result: [fail, permerror]
449
+ invalid-domain-long:
450
+ description: >-
451
+ target-name that is a valid domain-spec per RFC 4408 and RFC 7208 but an
452
+ invalid domain name per RFC 1035 (long label) must be treated as
453
+ non-existent.
454
+ comment: >-
455
+ A domain label longer than 63 characters in a mechanism target-name is
456
+ valid domain-spec syntax (perhaps formed from a macro expansion), even
457
+ though a DNS query cannot be composed from it. The spec being unclear
458
+ about it, this could either be considered a syntax error, or, by analogy
459
+ to 4.3/1 and 5/10/3, the mechanism could be treated as a no-match. RFC
460
+ 7208 failed to agree on which result to use, and declares the situation
461
+ undefined. The preferred test result is therefore a matter of opinion.
462
+ spec: 4.3/1, 4.8/5, 5/10/3
463
+ helo: mail.example.com
464
+ host: 1.2.3.4
465
+ mailfrom: foo@t11.example.com
466
+ result: [fail,permerror]
467
+ invalid-domain-long-via-macro:
468
+ description: >-
469
+ target-name that is a valid domain-spec per RFC 4408 and RFC 7208 but an
470
+ invalid domain name per RFC 1035 (long label) must be treated as
471
+ non-existent.
472
+ comment: >-
473
+ A domain label longer than 63 characters that results from macro
474
+ expansion in a mechanism target-name is valid domain-spec syntax (and is
475
+ not even subject to syntax checking after macro expansion), even though
476
+ a DNS query cannot be composed from it. The spec being unclear about
477
+ it, this could either be considered a syntax error, or, by analogy to
478
+ 4.3/1 and 5/10/3, the mechanism could be treated as a no-match. RFC 7208
479
+ failed to agree on which result to use, and declares the situation
480
+ undefined. The preferred test result is therefore a matter of opinion.
481
+ spec: 4.3/1, 4.8/5, 5/10/3
482
+ helo: "%%%%%%%%%%%%%%%%%%%%%%"
483
+ host: 1.2.3.4
484
+ mailfrom: foo@t12.example.com
485
+ result: [fail,permerror]
486
+ zonedata:
487
+ mail.example.com:
488
+ - A: 1.2.3.4
489
+ t1.example.com:
490
+ - TXT: v=spf1 ip4:1.2.3.4 -all moo
491
+ t2.example.com:
492
+ - TXT: v=spf1 moo.cow-far_out=man:dog/cat ip4:1.2.3.4 -all
493
+ t3.example.com:
494
+ - TXT: v=spf1 moo.cow/far_out=man:dog/cat ip4:1.2.3.4 -all
495
+ t4.example.com:
496
+ - TXT: v=spf1 moo.cow:far_out=man:dog/cat ip4:1.2.3.4 -all
497
+ t5.example.com:
498
+ - TXT: v=spf1 redirect=t5.example.com ~all
499
+ t6.example.com:
500
+ - TXT: v=spf1 ip4:1.2.3.4 redirect=t2.example.com
501
+ t7.example.com:
502
+ - TXT: v=spf1 ip4:1.2.3.4
503
+ t8.example.com:
504
+ - TXT: v=spf1 ip4:1.2.3.4 redirect:t2.example.com
505
+ t9.example.com:
506
+ - TXT: v=spf1 a:foo-bar -all
507
+ t10.example.com:
508
+ - TXT: v=spf1 a:mail.example...com -all
509
+ t11.example.com:
510
+ - TXT: v=spf1 a:a123456789012345678901234567890123456789012345678901234567890123.example.com -all
511
+ t12.example.com:
512
+ - TXT: v=spf1 a:%{H}.bar -all
513
+ ---
514
+ description: ALL mechanism syntax
515
+ tests:
516
+ all-dot:
517
+ description: |
518
+ all = "all"
519
+ comment: |-
520
+ At least one implementation got this wrong
521
+ spec: 5.1/1
522
+ helo: mail.example.com
523
+ host: 1.2.3.4
524
+ mailfrom: foo@e1.example.com
525
+ result: permerror
526
+ all-arg:
527
+ description: |
528
+ all = "all"
529
+ comment: |-
530
+ At least one implementation got this wrong
531
+ spec: 5.1/1
532
+ helo: mail.example.com
533
+ host: 1.2.3.4
534
+ mailfrom: foo@e2.example.com
535
+ result: permerror
536
+ all-cidr:
537
+ description: |
538
+ all = "all"
539
+ spec: 5.1/1
540
+ helo: mail.example.com
541
+ host: 1.2.3.4
542
+ mailfrom: foo@e3.example.com
543
+ result: permerror
544
+ all-neutral:
545
+ description: |
546
+ all = "all"
547
+ spec: 5.1/1
548
+ helo: mail.example.com
549
+ host: 1.2.3.4
550
+ mailfrom: foo@e4.example.com
551
+ result: neutral
552
+ all-double:
553
+ description: |
554
+ all = "all"
555
+ spec: 5.1/1
556
+ helo: mail.example.com
557
+ host: 1.2.3.4
558
+ mailfrom: foo@e5.example.com
559
+ result: pass
560
+ zonedata:
561
+ mail.example.com:
562
+ - A: 1.2.3.4
563
+ e1.example.com:
564
+ - TXT: v=spf1 -all.
565
+ e2.example.com:
566
+ - TXT: v=spf1 -all:foobar
567
+ e3.example.com:
568
+ - TXT: v=spf1 -all/8
569
+ e4.example.com:
570
+ - TXT: v=spf1 ?all
571
+ e5.example.com:
572
+ - TXT: v=spf1 all -all
573
+ ---
574
+ description: PTR mechanism syntax
575
+ tests:
576
+ ptr-cidr:
577
+ description: |-
578
+ PTR = "ptr" [ ":" domain-spec ]
579
+ spec: 5.5/2
580
+ helo: mail.example.com
581
+ host: 1.2.3.4
582
+ mailfrom: foo@e1.example.com
583
+ result: permerror
584
+ ptr-match-target:
585
+ description: >-
586
+ Check all validated domain names to see if they end in the <target-name>
587
+ domain.
588
+ spec: 5.5/5
589
+ helo: mail.example.com
590
+ host: 1.2.3.4
591
+ mailfrom: foo@e2.example.com
592
+ result: pass
593
+ ptr-match-implicit:
594
+ description: >-
595
+ Check all validated domain names to see if they end in the <target-name>
596
+ domain.
597
+ spec: 5.5/5
598
+ helo: mail.example.com
599
+ host: 1.2.3.4
600
+ mailfrom: foo@e3.example.com
601
+ result: pass
602
+ ptr-nomatch-invalid:
603
+ description: >-
604
+ Check all validated domain names to see if they end in the <target-name>
605
+ domain.
606
+ comment: >-
607
+ This PTR record does not validate
608
+ spec: 5.5/5
609
+ helo: mail.example.com
610
+ host: 1.2.3.4
611
+ mailfrom: foo@e4.example.com
612
+ result: fail
613
+ ptr-match-ip6:
614
+ description: >-
615
+ Check all validated domain names to see if they end in the <target-name>
616
+ domain.
617
+ spec: 5.5/5
618
+ helo: mail.example.com
619
+ host: "CAFE:BABE::1"
620
+ mailfrom: foo@e3.example.com
621
+ result: pass
622
+ ptr-empty-domain:
623
+ description: >-
624
+ domain-spec cannot be empty.
625
+ spec: 5.5/2
626
+ helo: mail.example.com
627
+ host: 1.2.3.4
628
+ mailfrom: foo@e5.example.com
629
+ result: permerror
630
+ zonedata:
631
+ mail.example.com:
632
+ - A: 1.2.3.4
633
+ e1.example.com:
634
+ - TXT: v=spf1 ptr/0 -all
635
+ e2.example.com:
636
+ - TXT: v=spf1 ptr:example.com -all
637
+ 4.3.2.1.in-addr.arpa:
638
+ - PTR: e3.example.com
639
+ - PTR: e4.example.com
640
+ - PTR: mail.example.com
641
+ 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.E.B.A.B.E.F.A.C.ip6.arpa:
642
+ - PTR: e3.example.com
643
+ e3.example.com:
644
+ - TXT: v=spf1 ptr -all
645
+ - A: 1.2.3.4
646
+ - AAAA: "CAFE:BABE::1"
647
+ e4.example.com:
648
+ - TXT: v=spf1 ptr -all
649
+ e5.example.com:
650
+ - TXT: "v=spf1 ptr:"
651
+ ---
652
+ description: A mechanism syntax
653
+ tests:
654
+ a-cidr6:
655
+ description: |
656
+ A = "a" [ ":" domain-spec ] [ dual-cidr-length ]
657
+ dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
658
+ spec: 5.3/2
659
+ helo: mail.example.com
660
+ host: 1.2.3.4
661
+ mailfrom: foo@e6.example.com
662
+ result: fail
663
+ a-bad-cidr4:
664
+ description: |
665
+ A = "a" [ ":" domain-spec ] [ dual-cidr-length ]
666
+ dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
667
+ spec: 5.3/2
668
+ helo: mail.example.com
669
+ host: 1.2.3.4
670
+ mailfrom: foo@e6a.example.com
671
+ result: permerror
672
+ a-bad-cidr6:
673
+ description: |
674
+ A = "a" [ ":" domain-spec ] [ dual-cidr-length ]
675
+ dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
676
+ spec: 5.3/2
677
+ helo: mail.example.com
678
+ host: 1.2.3.4
679
+ mailfrom: foo@e7.example.com
680
+ result: permerror
681
+ a-dual-cidr-ip4-match:
682
+ description: |
683
+ A = "a" [ ":" domain-spec ] [ dual-cidr-length ]
684
+ dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
685
+ spec: 5.3/2
686
+ helo: mail.example.com
687
+ host: 1.2.3.4
688
+ mailfrom: foo@e8.example.com
689
+ result: pass
690
+ a-dual-cidr-ip4-err:
691
+ description: |
692
+ A = "a" [ ":" domain-spec ] [ dual-cidr-length ]
693
+ dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
694
+ spec: 5.3/2
695
+ helo: mail.example.com
696
+ host: 1.2.3.4
697
+ mailfrom: foo@e8e.example.com
698
+ result: permerror
699
+ a-dual-cidr-ip6-match:
700
+ description: |
701
+ A = "a" [ ":" domain-spec ] [ dual-cidr-length ]
702
+ dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
703
+ spec: 5.3/2
704
+ helo: mail.example.com
705
+ host: "2001:db8:1234::cafe:babe"
706
+ mailfrom: foo@e8.example.com
707
+ result: pass
708
+ a-dual-cidr-ip4-default:
709
+ description: |
710
+ A = "a" [ ":" domain-spec ] [ dual-cidr-length ]
711
+ dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
712
+ spec: 5.3/2
713
+ helo: mail.example.com
714
+ host: 1.2.3.4
715
+ mailfrom: foo@e8b.example.com
716
+ result: fail
717
+ a-dual-cidr-ip6-default:
718
+ description: |
719
+ A = "a" [ ":" domain-spec ] [ dual-cidr-length ]
720
+ dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
721
+ spec: 5.3/2
722
+ helo: mail.example.com
723
+ host: "2001:db8:1234::cafe:babe"
724
+ mailfrom: foo@e8a.example.com
725
+ result: fail
726
+ a-multi-ip1:
727
+ description: >-
728
+ A matches any returned IP.
729
+ spec: 5.3/3
730
+ helo: mail.example.com
731
+ host: 1.2.3.4
732
+ mailfrom: foo@e10.example.com
733
+ result: pass
734
+ a-multi-ip2:
735
+ description: >-
736
+ A matches any returned IP.
737
+ spec: 5.3/3
738
+ helo: mail.example.com
739
+ host: 1.2.3.4
740
+ mailfrom: foo@e10.example.com
741
+ result: pass
742
+ a-bad-domain:
743
+ description: >-
744
+ domain-spec must pass basic syntax checks;
745
+ a ':' may appear in domain-spec, but not in top-label
746
+ spec: 7.1/2
747
+ helo: mail.example.com
748
+ host: 1.2.3.4
749
+ mailfrom: foo@e9.example.com
750
+ result: permerror
751
+ a-nxdomain:
752
+ description: >-
753
+ If no ips are returned, A mechanism does not match, even with /0.
754
+ spec: 5.3/3
755
+ helo: mail.example.com
756
+ host: 1.2.3.4
757
+ mailfrom: foo@e1.example.com
758
+ result: fail
759
+ a-cidr4-0:
760
+ description: >-
761
+ Matches if any A records are present in DNS.
762
+ spec: 5.3/3
763
+ helo: mail.example.com
764
+ host: 1.2.3.4
765
+ mailfrom: foo@e2.example.com
766
+ result: pass
767
+ a-cidr4-0-ip6:
768
+ description: >-
769
+ Matches if any A records are present in DNS.
770
+ spec: 5.3/3
771
+ helo: mail.example.com
772
+ host: "1234::1"
773
+ mailfrom: foo@e2.example.com
774
+ result: fail
775
+ a-cidr6-0-ip4:
776
+ description: >-
777
+ Would match if any AAAA records are present in DNS,
778
+ but not for an IP4 connection.
779
+ spec: 5.3/3
780
+ helo: mail.example.com
781
+ host: 1.2.3.4
782
+ mailfrom: foo@e2a.example.com
783
+ result: fail
784
+ a-cidr6-0-ip4mapped:
785
+ description: >-
786
+ Would match if any AAAA records are present in DNS,
787
+ but not for an IP4 connection.
788
+ spec: 5.3/3
789
+ helo: mail.example.com
790
+ host: "::FFFF:1.2.3.4"
791
+ mailfrom: foo@e2a.example.com
792
+ result: fail
793
+ a-cidr6-0-ip6:
794
+ description: >-
795
+ Matches if any AAAA records are present in DNS.
796
+ spec: 5.3/3
797
+ helo: mail.example.com
798
+ host: "1234::1"
799
+ mailfrom: foo@e2a.example.com
800
+ result: pass
801
+ a-ip6-dualstack:
802
+ description: >-
803
+ Simple IP6 Address match with dual stack.
804
+ spec: 5.3/3
805
+ helo: mail.example.com
806
+ host: "1234::1"
807
+ mailfrom: foo@ipv6.example.com
808
+ result: pass
809
+ a-cidr6-0-nxdomain:
810
+ description: >-
811
+ No match if no AAAA records are present in DNS.
812
+ spec: 5.3/3
813
+ helo: mail.example.com
814
+ host: "1234::1"
815
+ mailfrom: foo@e2b.example.com
816
+ result: fail
817
+ a-null:
818
+ description: >-
819
+ Null octets not allowed in toplabel
820
+ spec: 7.1/2
821
+ helo: mail.example.com
822
+ host: 1.2.3.5
823
+ mailfrom: foo@e3.example.com
824
+ result: permerror
825
+ a-numeric:
826
+ description: >-
827
+ toplabel may not be all numeric
828
+ comment: >-
829
+ A common publishing mistake is using ip4 addresses with A mechanism.
830
+ This should receive special diagnostic attention in the permerror.
831
+ spec: 7.1/2
832
+ helo: mail.example.com
833
+ host: 1.2.3.4
834
+ mailfrom: foo@e4.example.com
835
+ result: permerror
836
+ a-numeric-toplabel:
837
+ description: >-
838
+ toplabel may not be all numeric
839
+ spec: 7.1/2
840
+ helo: mail.example.com
841
+ host: 1.2.3.4
842
+ mailfrom: foo@e5.example.com
843
+ result: permerror
844
+ a-dash-in-toplabel:
845
+ description: >-
846
+ toplabel may contain dashes
847
+ comment: >-
848
+ Going from the "toplabel" grammar definition, an implementation using
849
+ regular expressions in incrementally parsing SPF records might
850
+ erroneously try to match a TLD such as ".xn--zckzah" (cf. IDN TLDs!) to
851
+ '( *alphanum ALPHA *alphanum )' first before trying the alternative
852
+ '( 1*alphanum "-" *( alphanum / "-" ) alphanum )', essentially causing
853
+ a non-greedy, and thus, incomplete match. Make sure a greedy match is
854
+ performed!
855
+ spec: 7.1/2
856
+ helo: mail.example.com
857
+ host: 1.2.3.4
858
+ mailfrom: foo@e14.example.com
859
+ result: pass
860
+ a-bad-toplabel:
861
+ description: >-
862
+ toplabel may not begin with a dash
863
+ spec: 7.1/2
864
+ helo: mail.example.com
865
+ host: 1.2.3.4
866
+ mailfrom: foo@e12.example.com
867
+ result: permerror
868
+ a-only-toplabel:
869
+ description: >-
870
+ domain-spec may not consist of only a toplabel.
871
+ spec: 7.1/2
872
+ helo: mail.example.com
873
+ host: 1.2.3.4
874
+ mailfrom: foo@e5a.example.com
875
+ result: permerror
876
+ a-only-toplabel-trailing-dot:
877
+ description: >-
878
+ domain-spec may not consist of only a toplabel.
879
+ comment: >-
880
+ "A trailing dot doesn't help."
881
+ spec: 7.1/2
882
+ helo: mail.example.com
883
+ host: 1.2.3.4
884
+ mailfrom: foo@e5b.example.com
885
+ result: permerror
886
+ a-colon-domain:
887
+ description: >-
888
+ domain-spec may contain any visible char except %
889
+ spec: 7.1/2
890
+ helo: mail.example.com
891
+ host: 1.2.3.4
892
+ mailfrom: foo@e11.example.com
893
+ result: pass
894
+ a-colon-domain-ip4mapped:
895
+ description: >-
896
+ domain-spec may contain any visible char except %
897
+ spec: 7.1/2
898
+ helo: mail.example.com
899
+ host: "::FFFF:1.2.3.4"
900
+ mailfrom: foo@e11.example.com
901
+ result: pass
902
+ a-empty-domain:
903
+ description: >-
904
+ domain-spec cannot be empty.
905
+ spec: 5.3/2
906
+ helo: mail.example.com
907
+ host: 1.2.3.4
908
+ mailfrom: foo@e13.example.com
909
+ result: permerror
910
+ zonedata:
911
+ mail.example.com:
912
+ - A: 1.2.3.4
913
+ e1.example.com:
914
+ - TXT: v=spf1 a/0 -all
915
+ e2.example.com:
916
+ - A: 1.1.1.1
917
+ - AAAA: "1234::2"
918
+ - TXT: v=spf1 a/0 -all
919
+ e2a.example.com:
920
+ - AAAA: "1234::1"
921
+ - TXT: v=spf1 a//0 -all
922
+ e2b.example.com:
923
+ - A: 1.1.1.1
924
+ - TXT: v=spf1 a//0 -all
925
+ ipv6.example.com:
926
+ - AAAA: "1234::1"
927
+ - A: 1.1.1.1
928
+ - TXT: v=spf1 a -all
929
+ e3.example.com:
930
+ - TXT: "v=spf1 a:foo.example.com\0"
931
+ e4.example.com:
932
+ - TXT: v=spf1 a:111.222.33.44
933
+ e5.example.com:
934
+ - TXT: v=spf1 a:abc.123
935
+ e5a.example.com:
936
+ - TXT: v=spf1 a:museum
937
+ e5b.example.com:
938
+ - TXT: v=spf1 a:museum.
939
+ e6.example.com:
940
+ - TXT: v=spf1 a//33 -all
941
+ e6a.example.com:
942
+ - TXT: v=spf1 a/33 -all
943
+ e7.example.com:
944
+ - TXT: v=spf1 a//129 -all
945
+ e8.example.com:
946
+ - A: 1.2.3.5
947
+ - AAAA: "2001:db8:1234::dead:beef"
948
+ - TXT: v=spf1 a/24//64 -all
949
+ e8e.example.com:
950
+ - A: 1.2.3.5
951
+ - AAAA: "2001:db8:1234::dead:beef"
952
+ - TXT: v=spf1 a/24/64 -all
953
+ e8a.example.com:
954
+ - A: 1.2.3.5
955
+ - AAAA: "2001:db8:1234::dead:beef"
956
+ - TXT: v=spf1 a/24 -all
957
+ e8b.example.com:
958
+ - A: 1.2.3.5
959
+ - AAAA: "2001:db8:1234::dead:beef"
960
+ - TXT: v=spf1 a//64 -all
961
+ e9.example.com:
962
+ - TXT: v=spf1 a:example.com:8080
963
+ e10.example.com:
964
+ - TXT: v=spf1 a:foo.example.com/24
965
+ foo.example.com:
966
+ - A: 1.1.1.1
967
+ - A: 1.2.3.5
968
+ e11.example.com:
969
+ - TXT: v=spf1 a:foo:bar/baz.example.com
970
+ foo:bar/baz.example.com:
971
+ - A: 1.2.3.4
972
+ e12.example.com:
973
+ - TXT: v=spf1 a:example.-com
974
+ e13.example.com:
975
+ - TXT: "v=spf1 a:"
976
+ e14.example.com:
977
+ - TXT: "v=spf1 a:foo.example.xn--zckzah -all"
978
+ foo.example.xn--zckzah:
979
+ - A: 1.2.3.4
980
+ ---
981
+ description: Include mechanism semantics and syntax
982
+ tests:
983
+ include-fail:
984
+ description: >-
985
+ recursive check_host() result of fail causes include to not match.
986
+ spec: 5.2/9
987
+ helo: mail.example.com
988
+ host: 1.2.3.4
989
+ mailfrom: foo@e1.example.com
990
+ result: softfail
991
+ include-softfail:
992
+ description: >-
993
+ recursive check_host() result of softfail causes include to not match.
994
+ spec: 5.2/9
995
+ helo: mail.example.com
996
+ host: 1.2.3.4
997
+ mailfrom: foo@e2.example.com
998
+ result: pass
999
+ include-neutral:
1000
+ description: >-
1001
+ recursive check_host() result of neutral causes include to not match.
1002
+ spec: 5.2/9
1003
+ helo: mail.example.com
1004
+ host: 1.2.3.4
1005
+ mailfrom: foo@e3.example.com
1006
+ result: fail
1007
+ include-temperror:
1008
+ description: >-
1009
+ recursive check_host() result of temperror causes include to temperror
1010
+ spec: 5.2/9
1011
+ helo: mail.example.com
1012
+ host: 1.2.3.4
1013
+ mailfrom: foo@e4.example.com
1014
+ result: temperror
1015
+ include-permerror:
1016
+ description: >-
1017
+ recursive check_host() result of permerror causes include to permerror
1018
+ spec: 5.2/9
1019
+ helo: mail.example.com
1020
+ host: 1.2.3.4
1021
+ mailfrom: foo@e5.example.com
1022
+ result: permerror
1023
+ include-syntax-error:
1024
+ description: >-
1025
+ include = "include" ":" domain-spec
1026
+ spec: 5.2/1
1027
+ helo: mail.example.com
1028
+ host: 1.2.3.4
1029
+ mailfrom: foo@e6.example.com
1030
+ result: permerror
1031
+ include-cidr:
1032
+ description: >-
1033
+ include = "include" ":" domain-spec
1034
+ spec: 5.2/1
1035
+ helo: mail.example.com
1036
+ host: 1.2.3.4
1037
+ mailfrom: foo@e9.example.com
1038
+ result: permerror
1039
+ include-none:
1040
+ description: >-
1041
+ recursive check_host() result of none causes include to permerror
1042
+ spec: 5.2/9
1043
+ helo: mail.example.com
1044
+ host: 1.2.3.4
1045
+ mailfrom: foo@e7.example.com
1046
+ result: permerror
1047
+ include-empty-domain:
1048
+ description: >-
1049
+ domain-spec cannot be empty.
1050
+ spec: 5.2/1
1051
+ helo: mail.example.com
1052
+ host: 1.2.3.4
1053
+ mailfrom: foo@e8.example.com
1054
+ result: permerror
1055
+ zonedata:
1056
+ mail.example.com:
1057
+ - A: 1.2.3.4
1058
+ ip5.example.com:
1059
+ - TXT: v=spf1 ip4:1.2.3.5 -all
1060
+ ip6.example.com:
1061
+ - TXT: v=spf1 ip4:1.2.3.6 ~all
1062
+ ip7.example.com:
1063
+ - TXT: v=spf1 ip4:1.2.3.7 ?all
1064
+ ip8.example.com:
1065
+ - TIMEOUT
1066
+ erehwon.example.com:
1067
+ - TXT: v=spfl am not an SPF record
1068
+ e1.example.com:
1069
+ - TXT: v=spf1 include:ip5.example.com ~all
1070
+ e2.example.com:
1071
+ - TXT: v=spf1 include:ip6.example.com all
1072
+ e3.example.com:
1073
+ - TXT: v=spf1 include:ip7.example.com -all
1074
+ e4.example.com:
1075
+ - TXT: v=spf1 include:ip8.example.com -all
1076
+ e5.example.com:
1077
+ - TXT: v=spf1 include:e6.example.com -all
1078
+ e6.example.com:
1079
+ - TXT: v=spf1 include +all
1080
+ e7.example.com:
1081
+ - TXT: v=spf1 include:erehwon.example.com -all
1082
+ e8.example.com:
1083
+ - TXT: "v=spf1 include: -all"
1084
+ e9.example.com:
1085
+ - TXT: "v=spf1 include:ip5.example.com/24 -all"
1086
+ ---
1087
+ description: MX mechanism syntax
1088
+ tests:
1089
+ mx-cidr6:
1090
+ description: |
1091
+ MX = "mx" [ ":" domain-spec ] [ dual-cidr-length ]
1092
+ dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
1093
+ spec: 5.4/2
1094
+ helo: mail.example.com
1095
+ host: 1.2.3.4
1096
+ mailfrom: foo@e6.example.com
1097
+ result: fail
1098
+ mx-bad-cidr4:
1099
+ description: |
1100
+ MX = "mx" [ ":" domain-spec ] [ dual-cidr-length ]
1101
+ dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
1102
+ spec: 5.4/2
1103
+ helo: mail.example.com
1104
+ host: 1.2.3.4
1105
+ mailfrom: foo@e6a.example.com
1106
+ result: permerror
1107
+ mx-bad-cidr6:
1108
+ description: |
1109
+ MX = "mx" [ ":" domain-spec ] [ dual-cidr-length ]
1110
+ dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
1111
+ spec: 5.4/2
1112
+ helo: mail.example.com
1113
+ host: 1.2.3.4
1114
+ mailfrom: foo@e7.example.com
1115
+ result: permerror
1116
+ mx-multi-ip1:
1117
+ description: >-
1118
+ MX matches any returned IP.
1119
+ spec: 5.4/3
1120
+ helo: mail.example.com
1121
+ host: 1.2.3.4
1122
+ mailfrom: foo@e10.example.com
1123
+ result: pass
1124
+ mx-multi-ip2:
1125
+ description: >-
1126
+ MX matches any returned IP.
1127
+ spec: 5.4/3
1128
+ helo: mail.example.com
1129
+ host: 1.2.3.4
1130
+ mailfrom: foo@e10.example.com
1131
+ result: pass
1132
+ mx-bad-domain:
1133
+ description: >-
1134
+ domain-spec must pass basic syntax checks
1135
+ comment: >-
1136
+ A ':' may appear in domain-spec, but not in top-label.
1137
+ spec: 7.1/2
1138
+ helo: mail.example.com
1139
+ host: 1.2.3.4
1140
+ mailfrom: foo@e9.example.com
1141
+ result: permerror
1142
+ mx-nxdomain:
1143
+ description: >-
1144
+ If no ips are returned, MX mechanism does not match, even with /0.
1145
+ spec: 5.4/3
1146
+ helo: mail.example.com
1147
+ host: 1.2.3.4
1148
+ mailfrom: foo@e1.example.com
1149
+ result: fail
1150
+ mx-cidr4-0:
1151
+ description: >-
1152
+ Matches if any A records for any MX records are present in DNS.
1153
+ spec: 5.4/3
1154
+ helo: mail.example.com
1155
+ host: 1.2.3.4
1156
+ mailfrom: foo@e2.example.com
1157
+ result: pass
1158
+ mx-cidr4-0-ip6:
1159
+ description: >-
1160
+ cidr4 doesn't apply to IP6 connections.
1161
+ comment: >-
1162
+ The IP6 CIDR starts with a double slash.
1163
+ spec: 5.4/3
1164
+ helo: mail.example.com
1165
+ host: "1234::1"
1166
+ mailfrom: foo@e2.example.com
1167
+ result: fail
1168
+ mx-cidr6-0-ip4:
1169
+ description: >-
1170
+ Would match if any AAAA records for MX records are present in DNS,
1171
+ but not for an IP4 connection.
1172
+ spec: 5.4/3
1173
+ helo: mail.example.com
1174
+ host: 1.2.3.4
1175
+ mailfrom: foo@e2a.example.com
1176
+ result: fail
1177
+ mx-cidr6-0-ip4mapped:
1178
+ description: >-
1179
+ Would match if any AAAA records for MX records are present in DNS,
1180
+ but not for an IP4 connection.
1181
+ spec: 5.4/3
1182
+ helo: mail.example.com
1183
+ host: "::FFFF:1.2.3.4"
1184
+ mailfrom: foo@e2a.example.com
1185
+ result: fail
1186
+ mx-cidr6-0-ip6:
1187
+ description: >-
1188
+ Matches if any AAAA records for any MX records are present in DNS.
1189
+ spec: 5.3/3
1190
+ helo: mail.example.com
1191
+ host: "1234::1"
1192
+ mailfrom: foo@e2a.example.com
1193
+ result: pass
1194
+ mx-cidr6-0-nxdomain:
1195
+ description: >-
1196
+ No match if no AAAA records for any MX records are present in DNS.
1197
+ spec: 5.4/3
1198
+ helo: mail.example.com
1199
+ host: "1234::1"
1200
+ mailfrom: foo@e2b.example.com
1201
+ result: fail
1202
+ mx-null:
1203
+ description: >-
1204
+ Null not allowed in top-label.
1205
+ spec: 7.1/2
1206
+ helo: mail.example.com
1207
+ host: 1.2.3.5
1208
+ mailfrom: foo@e3.example.com
1209
+ result: permerror
1210
+ mx-numeric-top-label:
1211
+ description: >-
1212
+ Top-label may not be all numeric
1213
+ spec: 7.1/2
1214
+ helo: mail.example.com
1215
+ host: 1.2.3.4
1216
+ mailfrom: foo@e5.example.com
1217
+ result: permerror
1218
+ mx-colon-domain:
1219
+ description: >-
1220
+ Domain-spec may contain any visible char except %
1221
+ spec: 7.1/2
1222
+ helo: mail.example.com
1223
+ host: 1.2.3.4
1224
+ mailfrom: foo@e11.example.com
1225
+ result: pass
1226
+ mx-colon-domain-ip4mapped:
1227
+ description: >-
1228
+ Domain-spec may contain any visible char except %
1229
+ spec: 7.1/2
1230
+ helo: mail.example.com
1231
+ host: "::FFFF:1.2.3.4"
1232
+ mailfrom: foo@e11.example.com
1233
+ result: pass
1234
+ mx-bad-toplab:
1235
+ description: >-
1236
+ Toplabel may not begin with -
1237
+ spec: 7.1/2
1238
+ helo: mail.example.com
1239
+ host: 1.2.3.4
1240
+ mailfrom: foo@e12.example.com
1241
+ result: permerror
1242
+ mx-empty:
1243
+ description: >-
1244
+ test null MX
1245
+ comment: >-
1246
+ Some implementations have had trouble with null MX
1247
+ spec: 5.4/3
1248
+ helo: mail.example.com
1249
+ host: 1.2.3.4
1250
+ mailfrom: ""
1251
+ result: neutral
1252
+ mx-implicit:
1253
+ description: >-
1254
+ If the target name has no MX records, check_host() MUST NOT pretend the
1255
+ target is its single MX, and MUST NOT default to an A lookup on the
1256
+ target-name directly.
1257
+ spec: 5.4/4
1258
+ helo: mail.example.com
1259
+ host: 1.2.3.4
1260
+ mailfrom: foo@e4.example.com
1261
+ result: neutral
1262
+ mx-empty-domain:
1263
+ description: >-
1264
+ domain-spec cannot be empty.
1265
+ spec: 5.2/1
1266
+ helo: mail.example.com
1267
+ host: 1.2.3.4
1268
+ mailfrom: foo@e13.example.com
1269
+ result: permerror
1270
+ zonedata:
1271
+ mail.example.com:
1272
+ - A: 1.2.3.4
1273
+ - MX: [0, ""]
1274
+ - TXT: v=spf1 mx
1275
+ e1.example.com:
1276
+ - TXT: v=spf1 mx/0 -all
1277
+ - MX: [0, e1.example.com]
1278
+ e2.example.com:
1279
+ - A: 1.1.1.1
1280
+ - AAAA: "1234::2"
1281
+ - MX: [0, e2.example.com]
1282
+ - TXT: v=spf1 mx/0 -all
1283
+ e2a.example.com:
1284
+ - AAAA: "1234::1"
1285
+ - MX: [0, e2a.example.com]
1286
+ - TXT: v=spf1 mx//0 -all
1287
+ e2b.example.com:
1288
+ - A: 1.1.1.1
1289
+ - MX: [0, e2b.example.com]
1290
+ - TXT: v=spf1 mx//0 -all
1291
+ e3.example.com:
1292
+ - TXT: "v=spf1 mx:foo.example.com\0"
1293
+ e4.example.com:
1294
+ - TXT: v=spf1 mx
1295
+ - A: 1.2.3.4
1296
+ e5.example.com:
1297
+ - TXT: v=spf1 mx:abc.123
1298
+ e6.example.com:
1299
+ - TXT: v=spf1 mx//33 -all
1300
+ e6a.example.com:
1301
+ - TXT: v=spf1 mx/33 -all
1302
+ e7.example.com:
1303
+ - TXT: v=spf1 mx//129 -all
1304
+ e9.example.com:
1305
+ - TXT: v=spf1 mx:example.com:8080
1306
+ e10.example.com:
1307
+ - TXT: v=spf1 mx:foo.example.com/24
1308
+ foo.example.com:
1309
+ - MX: [0, foo1.example.com]
1310
+ foo1.example.com:
1311
+ - A: 1.1.1.1
1312
+ - A: 1.2.3.5
1313
+ e11.example.com:
1314
+ - TXT: v=spf1 mx:foo:bar/baz.example.com
1315
+ foo:bar/baz.example.com:
1316
+ - MX: [0, "foo:bar/baz.example.com"]
1317
+ - A: 1.2.3.4
1318
+ e12.example.com:
1319
+ - TXT: v=spf1 mx:example.-com
1320
+ e13.example.com:
1321
+ - TXT: "v=spf1 mx: -all"
1322
+ ---
1323
+ description: EXISTS mechanism syntax
1324
+ tests:
1325
+ exists-empty-domain:
1326
+ description: >-
1327
+ domain-spec cannot be empty.
1328
+ spec: 5.7/2
1329
+ helo: mail.example.com
1330
+ host: 1.2.3.4
1331
+ mailfrom: foo@e1.example.com
1332
+ result: permerror
1333
+ exists-implicit:
1334
+ description: >-
1335
+ exists = "exists" ":" domain-spec
1336
+ spec: 5.7/2
1337
+ helo: mail.example.com
1338
+ host: 1.2.3.4
1339
+ mailfrom: foo@e2.example.com
1340
+ result: permerror
1341
+ exists-cidr:
1342
+ description: >-
1343
+ exists = "exists" ":" domain-spec
1344
+ spec: 5.7/2
1345
+ helo: mail.example.com
1346
+ host: 1.2.3.4
1347
+ mailfrom: foo@e3.example.com
1348
+ result: permerror
1349
+ exists-ip4:
1350
+ description: >-
1351
+ mechanism matches if any DNS A RR exists
1352
+ spec: 5.7/3
1353
+ helo: mail.example.com
1354
+ host: 1.2.3.4
1355
+ mailfrom: foo@e4.example.com
1356
+ result: pass
1357
+ exists-ip6:
1358
+ description: >-
1359
+ The lookup type is A even when the connection is ip6
1360
+ spec: 5.7/3
1361
+ helo: mail.example.com
1362
+ host: "CAFE:BABE::3"
1363
+ mailfrom: foo@e4.example.com
1364
+ result: pass
1365
+ exists-ip6only:
1366
+ description: >-
1367
+ The lookup type is A even when the connection is ip6
1368
+ spec: 5.7/3
1369
+ helo: mail.example.com
1370
+ host: "CAFE:BABE::3"
1371
+ mailfrom: foo@e5.example.com
1372
+ result: fail
1373
+ exists-dnserr:
1374
+ description: >-
1375
+ Result for DNS error clarified in RFC7208: MTAs or other processors
1376
+ SHOULD impose a limit on the maximum amount of elapsed time to evaluate
1377
+ check_host(). Such a limit SHOULD allow at least 20 seconds. If such
1378
+ a limit is exceeded, the result of authorization SHOULD be "temperror".
1379
+ spec: 5/8
1380
+ helo: mail.example.com
1381
+ host: "CAFE:BABE::3"
1382
+ mailfrom: foo@e6.example.com
1383
+ result: temperror
1384
+ zonedata:
1385
+ mail.example.com:
1386
+ - A: 1.2.3.4
1387
+ mail6.example.com:
1388
+ - AAAA: "CAFE:BABE::4"
1389
+ err.example.com:
1390
+ - TIMEOUT
1391
+ e1.example.com:
1392
+ - TXT: "v=spf1 exists:"
1393
+ e2.example.com:
1394
+ - TXT: "v=spf1 exists"
1395
+ e3.example.com:
1396
+ - TXT: "v=spf1 exists:mail.example.com/24"
1397
+ e4.example.com:
1398
+ - TXT: "v=spf1 exists:mail.example.com"
1399
+ e5.example.com:
1400
+ - TXT: "v=spf1 exists:mail6.example.com -all"
1401
+ e6.example.com:
1402
+ - TXT: "v=spf1 exists:err.example.com -all"
1403
+ ---
1404
+ description: IP4 mechanism syntax
1405
+ tests:
1406
+ cidr4-0:
1407
+ description: >-
1408
+ ip4-cidr-length = "/" 1*DIGIT
1409
+ spec: 5.6/2
1410
+ helo: mail.example.com
1411
+ host: 1.2.3.4
1412
+ mailfrom: foo@e1.example.com
1413
+ result: pass
1414
+ cidr4-32:
1415
+ description: >-
1416
+ ip4-cidr-length = "/" 1*DIGIT
1417
+ spec: 5.6/2
1418
+ helo: mail.example.com
1419
+ host: 1.2.3.4
1420
+ mailfrom: foo@e2.example.com
1421
+ result: pass
1422
+ cidr4-33:
1423
+ description: >-
1424
+ Invalid CIDR should get permerror.
1425
+ comment: >-
1426
+ The RFC4408 was silent on ip4 CIDR > 32 or ip6 CIDR > 128, but RFC7208
1427
+ is explicit. Invalid CIDR is prohibited.
1428
+ spec: 5.6/2
1429
+ helo: mail.example.com
1430
+ host: 1.2.3.4
1431
+ mailfrom: foo@e3.example.com
1432
+ result: permerror
1433
+ cidr4-032:
1434
+ description: >-
1435
+ Invalid CIDR should get permerror.
1436
+ comment: >-
1437
+ Leading zeros are not explicitly prohibited by the RFC. However,
1438
+ since the RFC explicity prohibits leading zeros in ip4-network,
1439
+ our interpretation is that CIDR should be also.
1440
+ spec: 5.6/2
1441
+ helo: mail.example.com
1442
+ host: 1.2.3.4
1443
+ mailfrom: foo@e4.example.com
1444
+ result: permerror
1445
+ bare-ip4:
1446
+ description: >-
1447
+ IP4 = "ip4" ":" ip4-network [ ip4-cidr-length ]
1448
+ spec: 5.6/2
1449
+ helo: mail.example.com
1450
+ host: 1.2.3.4
1451
+ mailfrom: foo@e5.example.com
1452
+ result: permerror
1453
+ bad-ip4-port:
1454
+ description: >-
1455
+ IP4 = "ip4" ":" ip4-network [ ip4-cidr-length ]
1456
+ comment: >-
1457
+ This has actually been published in SPF records.
1458
+ spec: 5.6/2
1459
+ helo: mail.example.com
1460
+ host: 1.2.3.4
1461
+ mailfrom: foo@e8.example.com
1462
+ result: permerror
1463
+ bad-ip4-short:
1464
+ description: >-
1465
+ It is not permitted to omit parts of the IP address instead of
1466
+ using CIDR notations.
1467
+ spec: 5.6/4
1468
+ helo: mail.example.com
1469
+ host: 1.2.3.4
1470
+ mailfrom: foo@e9.example.com
1471
+ result: permerror
1472
+ ip4-dual-cidr:
1473
+ description: >-
1474
+ dual-cidr-length not permitted on ip4
1475
+ spec: 5.6/2
1476
+ helo: mail.example.com
1477
+ host: 1.2.3.4
1478
+ mailfrom: foo@e6.example.com
1479
+ result: permerror
1480
+ ip4-mapped-ip6:
1481
+ description: >-
1482
+ IP4 mapped IP6 connections MUST be treated as IP4
1483
+ spec: 5/9/2
1484
+ helo: mail.example.com
1485
+ host: "::FFFF:1.2.3.4"
1486
+ mailfrom: foo@e7.example.com
1487
+ result: fail
1488
+ zonedata:
1489
+ mail.example.com:
1490
+ - A: 1.2.3.4
1491
+ e1.example.com:
1492
+ - TXT: v=spf1 ip4:1.1.1.1/0 -all
1493
+ e2.example.com:
1494
+ - TXT: v=spf1 ip4:1.2.3.4/32 -all
1495
+ e3.example.com:
1496
+ - TXT: v=spf1 ip4:1.2.3.4/33 -all
1497
+ e4.example.com:
1498
+ - TXT: v=spf1 ip4:1.2.3.4/032 -all
1499
+ e5.example.com:
1500
+ - TXT: v=spf1 ip4
1501
+ e6.example.com:
1502
+ - TXT: v=spf1 ip4:1.2.3.4//32
1503
+ e7.example.com:
1504
+ - TXT: "v=spf1 -ip4:1.2.3.4 ip6:::FFFF:1.2.3.4"
1505
+ e8.example.com:
1506
+ - TXT: v=spf1 ip4:1.2.3.4:8080
1507
+ e9.example.com:
1508
+ - TXT: v=spf1 ip4:1.2.3
1509
+ ---
1510
+ description: IP6 mechanism syntax
1511
+ comment: >-
1512
+ IP4 only implementations may skip tests where host is not IP4
1513
+ tests:
1514
+ bare-ip6:
1515
+ description: >-
1516
+ IP6 = "ip6" ":" ip6-network [ ip6-cidr-length ]
1517
+ spec: 5.6/2
1518
+ helo: mail.example.com
1519
+ host: 1.2.3.4
1520
+ mailfrom: foo@e1.example.com
1521
+ result: permerror
1522
+ cidr6-0-ip4:
1523
+ description: >-
1524
+ IP4 connections do not match ip6.
1525
+ comment: >-
1526
+ There was controversy over IPv4 mapped connections. RFC7208 clearly
1527
+ states IPv4 mapped addresses only match ip4: mechanisms.
1528
+ spec: 5/9/2
1529
+ helo: mail.example.com
1530
+ host: 1.2.3.4
1531
+ mailfrom: foo@e2.example.com
1532
+ result: neutral
1533
+ cidr6-ip4:
1534
+ description: >-
1535
+ Even if the SMTP connection is via IPv6, an IPv4-mapped IPv6 IP address
1536
+ (see RFC 3513, Section 2.5.5) MUST still be considered an IPv4 address.
1537
+ comment: >-
1538
+ There was controversy over ip4 mapped connections. RFC7208 clearly
1539
+ requires such connections to be considered as ip4 only.
1540
+ spec: 5/9/2
1541
+ helo: mail.example.com
1542
+ host: "::FFFF:1.2.3.4"
1543
+ mailfrom: foo@e2.example.com
1544
+ result: neutral
1545
+ cidr6-0:
1546
+ description: >-
1547
+ Match any IP6
1548
+ spec: 5/8
1549
+ helo: mail.example.com
1550
+ host: "DEAF:BABE::CAB:FEE"
1551
+ mailfrom: foo@e2.example.com
1552
+ result: pass
1553
+ cidr6-129:
1554
+ description: >-
1555
+ Invalid CIDR
1556
+ comment: >-
1557
+ IP4 only implementations MUST fully syntax check all mechanisms,
1558
+ even if they otherwise ignore them.
1559
+ spec: 5.6/2
1560
+ helo: mail.example.com
1561
+ host: 1.2.3.4
1562
+ mailfrom: foo@e3.example.com
1563
+ result: permerror
1564
+ cidr6-bad:
1565
+ description: >-
1566
+ dual-cidr syntax not used for ip6
1567
+ comment: >-
1568
+ IP4 only implementations MUST fully syntax check all mechanisms,
1569
+ even if they otherwise ignore them.
1570
+ spec: 5.6/2
1571
+ helo: mail.example.com
1572
+ host: 1.2.3.4
1573
+ mailfrom: foo@e4.example.com
1574
+ result: permerror
1575
+ cidr6-33:
1576
+ description: >-
1577
+ make sure ip4 cidr restriction are not used for ip6
1578
+ spec: 5.6/2
1579
+ helo: mail.example.com
1580
+ host: "CAFE:BABE:8000::"
1581
+ mailfrom: foo@e5.example.com
1582
+ result: pass
1583
+ cidr6-33-ip4:
1584
+ description: >-
1585
+ make sure ip4 cidr restriction are not used for ip6
1586
+ spec: 5.6/2
1587
+ helo: mail.example.com
1588
+ host: 1.2.3.4
1589
+ mailfrom: foo@e5.example.com
1590
+ result: neutral
1591
+ ip6-bad1:
1592
+ description: >-
1593
+ spec: 5.6/2
1594
+ helo: mail.example.com
1595
+ host: 1.2.3.4
1596
+ mailfrom: foo@e6.example.com
1597
+ result: permerror
1598
+ zonedata:
1599
+ mail.example.com:
1600
+ - A: 1.2.3.4
1601
+ e1.example.com:
1602
+ - TXT: v=spf1 -all ip6
1603
+ e2.example.com:
1604
+ - TXT: "v=spf1 ip6:::1.1.1.1/0"
1605
+ e3.example.com:
1606
+ - TXT: "v=spf1 ip6:::1.1.1.1/129"
1607
+ e4.example.com:
1608
+ - TXT: "v=spf1 ip6:::1.1.1.1//33"
1609
+ e5.example.com:
1610
+ - TXT: "v=spf1 ip6:CAFE:BABE:8000::/33"
1611
+ e6.example.com:
1612
+ - TXT: "v=spf1 ip6::CAFE::BABE"
1613
+ ---
1614
+ description: Semantics of exp and other modifiers
1615
+ comment: >-
1616
+ Implementing exp= is optional. If not implemented, the test driver should
1617
+ not check the explanation field.
1618
+ tests:
1619
+ redirect-none:
1620
+ description: >-
1621
+ If no SPF record is found, or if the target-name is malformed, the result
1622
+ is a "PermError" rather than "None".
1623
+ spec: 6.1/4
1624
+ helo: mail.example.com
1625
+ host: 1.2.3.4
1626
+ mailfrom: foo@e10.example.com
1627
+ result: permerror
1628
+ redirect-cancels-exp:
1629
+ description: >-
1630
+ when executing "redirect", exp= from the original domain MUST NOT be used.
1631
+ spec: 6.2/13
1632
+ helo: mail.example.com
1633
+ host: 1.2.3.4
1634
+ mailfrom: foo@e1.example.com
1635
+ result: fail
1636
+ explanation: DEFAULT
1637
+ redirect-syntax-error:
1638
+ description: |
1639
+ redirect = "redirect" "=" domain-spec
1640
+ comment: >-
1641
+ A literal application of the grammar causes modifier syntax
1642
+ errors (except for macro syntax) to become unknown-modifier.
1643
+
1644
+ modifier = explanation | redirect | unknown-modifier
1645
+
1646
+ However, it is generally agreed, with precedent in other RFCs,
1647
+ that unknown-modifier should not be "greedy", and should not
1648
+ match known modifier names. There should have been explicit
1649
+ prose to this effect, and some has been proposed as an erratum.
1650
+ spec: 6.1/2
1651
+ helo: mail.example.com
1652
+ host: 1.2.3.4
1653
+ mailfrom: foo@e17.example.com
1654
+ result: permerror
1655
+ include-ignores-exp:
1656
+ description: >-
1657
+ when executing "include", exp= from the target domain MUST NOT be used.
1658
+ spec: 6.2/13
1659
+ helo: mail.example.com
1660
+ host: 1.2.3.4
1661
+ mailfrom: foo@e7.example.com
1662
+ result: fail
1663
+ explanation: Correct!
1664
+ redirect-cancels-prior-exp:
1665
+ description: >-
1666
+ when executing "redirect", exp= from the original domain MUST NOT be used.
1667
+ spec: 6.2/13
1668
+ helo: mail.example.com
1669
+ host: 1.2.3.4
1670
+ mailfrom: foo@e3.example.com
1671
+ result: fail
1672
+ explanation: See me.
1673
+ invalid-modifier:
1674
+ description: |
1675
+ unknown-modifier = name "=" macro-string
1676
+ name = ALPHA *( ALPHA / DIGIT / "-" / "_" / "." )
1677
+ comment: >-
1678
+ Unknown modifier name must begin with alpha.
1679
+ spec: A/3
1680
+ helo: mail.example.com
1681
+ host: 1.2.3.4
1682
+ mailfrom: foo@e5.example.com
1683
+ result: permerror
1684
+ empty-modifier-name:
1685
+ description: |
1686
+ name = ALPHA *( ALPHA / DIGIT / "-" / "_" / "." )
1687
+ comment: >-
1688
+ Unknown modifier name must not be empty.
1689
+ spec: A/3
1690
+ helo: mail.example.com
1691
+ host: 1.2.3.4
1692
+ mailfrom: foo@e6.example.com
1693
+ result: permerror
1694
+ dorky-sentinel:
1695
+ description: >-
1696
+ An implementation that uses a legal expansion as a sentinel. We
1697
+ cannot check them all, but we can check this one.
1698
+ comment: >-
1699
+ Spaces are allowed in local-part.
1700
+ spec: 7.1/6
1701
+ helo: mail.example.com
1702
+ host: 1.2.3.4
1703
+ mailfrom: "Macro Error@e8.example.com"
1704
+ result: fail
1705
+ explanation: Macro Error in implementation
1706
+ exp-multiple-txt:
1707
+ description: |
1708
+ Ignore exp if multiple TXT records.
1709
+ comment: >-
1710
+ If domain-spec is empty, or there are any DNS processing errors (any
1711
+ RCODE other than 0), or if no records are returned, or if more than one
1712
+ record is returned, or if there are syntax errors in the explanation
1713
+ string, then proceed as if no exp modifier was given.
1714
+ spec: 6.2/4
1715
+ helo: mail.example.com
1716
+ host: 1.2.3.4
1717
+ mailfrom: foo@e11.example.com
1718
+ result: fail
1719
+ explanation: DEFAULT
1720
+ exp-no-txt:
1721
+ description: |
1722
+ Ignore exp if no TXT records.
1723
+ comment: >-
1724
+ If domain-spec is empty, or there are any DNS processing errors (any
1725
+ RCODE other than 0), or if no records are returned, or if more than one
1726
+ record is returned, or if there are syntax errors in the explanation
1727
+ string, then proceed as if no exp modifier was given.
1728
+ spec: 6.2/4
1729
+ helo: mail.example.com
1730
+ host: 1.2.3.4
1731
+ mailfrom: foo@e22.example.com
1732
+ result: fail
1733
+ explanation: DEFAULT
1734
+ exp-dns-error:
1735
+ description: |
1736
+ Ignore exp if DNS error.
1737
+ comment: >-
1738
+ If domain-spec is empty, or there are any DNS processing errors (any
1739
+ RCODE other than 0), or if no records are returned, or if more than one
1740
+ record is returned, or if there are syntax errors in the explanation
1741
+ string, then proceed as if no exp modifier was given.
1742
+ spec: 6.2/4
1743
+ helo: mail.example.com
1744
+ host: 1.2.3.4
1745
+ mailfrom: foo@e21.example.com
1746
+ result: fail
1747
+ explanation: DEFAULT
1748
+ exp-empty-domain:
1749
+ description: |
1750
+ PermError if exp= domain-spec is empty.
1751
+ comment: >-
1752
+ Section 6.2/4 says, "If domain-spec is empty, or there are any DNS
1753
+ processing errors (any RCODE other than 0), or if no records are
1754
+ returned, or if more than one record is returned, or if there are syntax
1755
+ errors in the explanation string, then proceed as if no exp modifier was
1756
+ given." However, "if domain-spec is empty" conflicts with the grammar
1757
+ given for the exp modifier. This was reported as an erratum, and the
1758
+ solution chosen was to report explicit "exp=" as PermError, but ignore
1759
+ problems due to macro expansion, DNS, or invalid explanation string.
1760
+ spec: 6.2/4
1761
+ helo: mail.example.com
1762
+ host: 1.2.3.4
1763
+ mailfrom: foo@e12.example.com
1764
+ result: permerror
1765
+ explanation-syntax-error:
1766
+ description: |
1767
+ Ignore exp if the explanation string has a syntax error.
1768
+ comment: >-
1769
+ If domain-spec is empty, or there are any DNS processing errors (any
1770
+ RCODE other than 0), or if no records are returned, or if more than one
1771
+ record is returned, or if there are syntax errors in the explanation
1772
+ string, then proceed as if no exp modifier was given.
1773
+ spec: 6.2/4
1774
+ helo: mail.example.com
1775
+ host: 1.2.3.4
1776
+ mailfrom: foo@e13.example.com
1777
+ result: fail
1778
+ explanation: DEFAULT
1779
+ exp-syntax-error:
1780
+ description: |
1781
+ explanation = "exp" "=" domain-spec
1782
+ comment: >-
1783
+ A literal application of the grammar causes modifier syntax
1784
+ errors (except for macro syntax) to become unknown-modifier.
1785
+
1786
+ modifier = explanation | redirect | unknown-modifier
1787
+
1788
+ However, it is generally agreed, with precedent in other RFCs,
1789
+ that unknown-modifier should not be "greedy", and should not
1790
+ match known modifier names. There should have been explicit
1791
+ prose to this effect, and some has been proposed as an erratum.
1792
+ spec: 6.2/1
1793
+ helo: mail.example.com
1794
+ host: 1.2.3.4
1795
+ mailfrom: foo@e16.example.com
1796
+ result: permerror
1797
+ exp-twice:
1798
+ description: |
1799
+ exp= appears twice.
1800
+ comment: >-
1801
+ These two modifiers (exp,redirect) MUST NOT appear in a record more than
1802
+ once each. If they do, then check_host() exits with a result of
1803
+ "PermError".
1804
+ spec: 6/2
1805
+ helo: mail.example.com
1806
+ host: 1.2.3.4
1807
+ mailfrom: foo@e14.example.com
1808
+ result: permerror
1809
+ redirect-empty-domain:
1810
+ description: |
1811
+ redirect = "redirect" "=" domain-spec
1812
+ comment: >-
1813
+ Unlike for exp, there is no instruction to override the permerror
1814
+ for an empty domain-spec (which is invalid syntax).
1815
+ spec: 6.2/4
1816
+ helo: mail.example.com
1817
+ host: 1.2.3.4
1818
+ mailfrom: foo@e18.example.com
1819
+ result: permerror
1820
+ redirect-twice:
1821
+ description: |
1822
+ redirect= appears twice.
1823
+ comment: >-
1824
+ These two modifiers (exp,redirect) MUST NOT appear in a record more than
1825
+ once each. If they do, then check_host() exits with a result of
1826
+ "PermError".
1827
+ spec: 6/2
1828
+ helo: mail.example.com
1829
+ host: 1.2.3.4
1830
+ mailfrom: foo@e15.example.com
1831
+ result: permerror
1832
+ unknown-modifier-syntax:
1833
+ description: |
1834
+ unknown-modifier = name "=" macro-string
1835
+ comment: >-
1836
+ Unknown modifiers must have valid macro syntax.
1837
+ spec: A/3
1838
+ helo: mail.example.com
1839
+ host: 1.2.3.4
1840
+ mailfrom: foo@e9.example.com
1841
+ result: permerror
1842
+ default-modifier-obsolete:
1843
+ description: |
1844
+ Unknown modifiers do not modify the RFC SPF result.
1845
+ comment: >-
1846
+ Some implementations may have a leftover default= modifier from
1847
+ earlier drafts.
1848
+ spec: 6/3
1849
+ helo: mail.example.com
1850
+ host: 1.2.3.4
1851
+ mailfrom: foo@e19.example.com
1852
+ result: neutral
1853
+ default-modifier-obsolete2:
1854
+ description: |
1855
+ Unknown modifiers do not modify the RFC SPF result.
1856
+ comment: >-
1857
+ Some implementations may have a leftover default= modifier from
1858
+ earlier drafts.
1859
+ spec: 6/3
1860
+ helo: mail.example.com
1861
+ host: 1.2.3.4
1862
+ mailfrom: foo@e20.example.com
1863
+ result: neutral
1864
+ non-ascii-exp:
1865
+ description: >-
1866
+ SPF explanation text is restricted to 7-bit ascii.
1867
+ comment: >-
1868
+ Checking a possibly different code path for non-ascii chars.
1869
+ spec: 6.2/5
1870
+ helo: hosed
1871
+ host: 1.2.3.4
1872
+ mailfrom: "foobar@nonascii.example.com"
1873
+ result: fail
1874
+ explanation: DEFAULT
1875
+ two-exp-records:
1876
+ description: >-
1877
+ Must ignore exp= if DNS returns more than one TXT record.
1878
+ spec: 6.2/4
1879
+ helo: hosed
1880
+ host: 1.2.3.4
1881
+ mailfrom: "foobar@tworecs.example.com"
1882
+ result: fail
1883
+ explanation: DEFAULT
1884
+ exp-void:
1885
+ description: |
1886
+ exp=nxdomain.tld
1887
+ comment: >-
1888
+ Non-existent exp= domains MUST NOT count against the void lookup limit.
1889
+ Implementations should lookup any exp record at most once after
1890
+ computing the result.
1891
+ spec: 4.6.4/1, 6/2
1892
+ helo: mail.example.com
1893
+ host: 1.2.3.4
1894
+ mailfrom: foo@e23.example.com
1895
+ result: fail
1896
+ redirect-implicit:
1897
+ description: |
1898
+ redirect changes implicit domain
1899
+ spec: 6.1/4
1900
+ helo: e24.example.com
1901
+ host: 192.0.2.2
1902
+ mailfrom: bar@e24.example.com
1903
+ result: pass
1904
+ zonedata:
1905
+ mail.example.com:
1906
+ - A: 1.2.3.4
1907
+ e1.example.com:
1908
+ - TXT: v=spf1 exp=exp1.example.com redirect=e2.example.com
1909
+ e2.example.com:
1910
+ - TXT: v=spf1 -all
1911
+ e3.example.com:
1912
+ - TXT: v=spf1 exp=exp1.example.com redirect=e4.example.com
1913
+ e4.example.com:
1914
+ - TXT: v=spf1 -all exp=exp2.example.com
1915
+ exp1.example.com:
1916
+ - TXT: No-see-um
1917
+ exp2.example.com:
1918
+ - TXT: See me.
1919
+ exp3.example.com:
1920
+ - TXT: Correct!
1921
+ exp4.example.com:
1922
+ - TXT: "%{l} in implementation"
1923
+ e5.example.com:
1924
+ - TXT: v=spf1 1up=foo
1925
+ e6.example.com:
1926
+ - TXT: v=spf1 =all
1927
+ e7.example.com:
1928
+ - TXT: v=spf1 include:e3.example.com -all exp=exp3.example.com
1929
+ e8.example.com:
1930
+ - TXT: v=spf1 -all exp=exp4.example.com
1931
+ e9.example.com:
1932
+ - TXT: v=spf1 -all foo=%abc
1933
+ e10.example.com:
1934
+ - TXT: v=spf1 redirect=erehwon.example.com
1935
+ e11.example.com:
1936
+ - TXT: v=spf1 -all exp=e11msg.example.com
1937
+ e11msg.example.com:
1938
+ - TXT: Answer a fool according to his folly.
1939
+ - TXT: Do not answer a fool according to his folly.
1940
+ e12.example.com:
1941
+ - TXT: v=spf1 exp= -all
1942
+ e13.example.com:
1943
+ - TXT: v=spf1 exp=e13msg.example.com -all
1944
+ e13msg.example.com:
1945
+ - TXT: The %{x}-files.
1946
+ e14.example.com:
1947
+ - TXT: v=spf1 exp=e13msg.example.com -all exp=e11msg.example.com
1948
+ e15.example.com:
1949
+ - TXT: v=spf1 redirect=e12.example.com -all redirect=e12.example.com
1950
+ e16.example.com:
1951
+ - TXT: v=spf1 exp=-all
1952
+ e17.example.com:
1953
+ - TXT: v=spf1 redirect=-all ?all
1954
+ e18.example.com:
1955
+ - TXT: v=spf1 ?all redirect=
1956
+ e19.example.com:
1957
+ - TXT: v=spf1 default=pass
1958
+ e20.example.com:
1959
+ - TXT: "v=spf1 default=+"
1960
+ e21.example.com:
1961
+ - TXT: v=spf1 exp=e21msg.example.com -all
1962
+ e21msg.example.com:
1963
+ - TIMEOUT
1964
+ e22.example.com:
1965
+ - TXT: v=spf1 exp=mail.example.com -all
1966
+ nonascii.example.com:
1967
+ - TXT: v=spf1 exp=badexp.example.com -all
1968
+ badexp.example.com:
1969
+ - TXT: "\xEF\xBB\xBFExplanation"
1970
+ tworecs.example.com:
1971
+ - TXT: v=spf1 exp=twoexp.example.com -all
1972
+ twoexp.example.com:
1973
+ - TXT: "one"
1974
+ - TXT: "two"
1975
+ e23.example.com:
1976
+ - TXT: v=spf1 a:erehwon.example.com a:foobar.com exp=nxdomain.com -all
1977
+ e24.example.com:
1978
+ - TXT: v=spf1 redirect=testimplicit.example.com
1979
+ - A: 192.0.2.1
1980
+ testimplicit.example.com:
1981
+ - TXT: v=spf1 a -all
1982
+ - A: 192.0.2.2
1983
+ ---
1984
+ description: Macro expansion rules
1985
+ tests:
1986
+ trailing-dot-domain:
1987
+ spec: 7.1/16
1988
+ description: >-
1989
+ trailing dot is ignored for domains
1990
+ helo: msgbas2x.cos.example.com
1991
+ host: 192.168.218.40
1992
+ mailfrom: test@example.com
1993
+ result: pass
1994
+ trailing-dot-exp:
1995
+ spec: 7.1
1996
+ description: >-
1997
+ trailing dot is not removed from explanation
1998
+ comment: >-
1999
+ A simple way for an implementation to ignore trailing dots on
2000
+ domains is to remove it when present. But be careful not to
2001
+ remove it for explanation text.
2002
+ helo: msgbas2x.cos.example.com
2003
+ host: 192.168.218.40
2004
+ mailfrom: test@exp.example.com
2005
+ result: fail
2006
+ explanation: This is a test.
2007
+ exp-only-macro-char:
2008
+ spec: 7.1/8
2009
+ description: >-
2010
+ The following macro letters are allowed only in "exp" text: c, r, t
2011
+ helo: msgbas2x.cos.example.com
2012
+ host: 192.168.218.40
2013
+ mailfrom: test@e2.example.com
2014
+ result: permerror
2015
+ invalid-macro-char:
2016
+ spec: 7.1/9
2017
+ description: >-
2018
+ A '%' character not followed by a '{', '%', '-', or '_' character
2019
+ is a syntax error.
2020
+ helo: msgbas2x.cos.example.com
2021
+ host: 192.168.218.40
2022
+ mailfrom: test@e1.example.com
2023
+ result: permerror
2024
+ invalid-embedded-macro-char:
2025
+ spec: 7.1/9
2026
+ description: >-
2027
+ A '%' character not followed by a '{', '%', '-', or '_' character
2028
+ is a syntax error.
2029
+ helo: msgbas2x.cos.example.com
2030
+ host: 192.168.218.40
2031
+ mailfrom: test@e1e.example.com
2032
+ result: permerror
2033
+ invalid-trailing-macro-char:
2034
+ spec: 7.1/9
2035
+ description: >-
2036
+ A '%' character not followed by a '{', '%', '-', or '_' character
2037
+ is a syntax error.
2038
+ helo: msgbas2x.cos.example.com
2039
+ host: 192.168.218.40
2040
+ mailfrom: test@e1t.example.com
2041
+ result: permerror
2042
+ macro-mania-in-domain:
2043
+ description: >-
2044
+ macro-encoded percents (%%), spaces (%_), and URL-percent-encoded
2045
+ spaces (%-)
2046
+ spec: 7.1/3, 7.1/4
2047
+ helo: mail.example.com
2048
+ host: 1.2.3.4
2049
+ mailfrom: test@e1a.example.com
2050
+ result: pass
2051
+ exp-txt-macro-char:
2052
+ spec: 7.1/20
2053
+ description: >-
2054
+ For IPv4 addresses, both the "i" and "c" macros expand
2055
+ to the standard dotted-quad format.
2056
+ helo: msgbas2x.cos.example.com
2057
+ host: 192.168.218.40
2058
+ mailfrom: test@e3.example.com
2059
+ result: fail
2060
+ explanation: Connections from 192.168.218.40 not authorized.
2061
+ domain-name-truncation:
2062
+ spec: 7.1/25
2063
+ description: >-
2064
+ When the result of macro expansion is used in a domain name query, if the
2065
+ expanded domain name exceeds 253 characters, the left side is truncated
2066
+ to fit, by removing successive domain labels until the total length does
2067
+ not exceed 253 characters.
2068
+ helo: msgbas2x.cos.example.com
2069
+ host: 192.168.218.40
2070
+ mailfrom: test@somewhat.long.exp.example.com
2071
+ result: fail
2072
+ explanation: Congratulations! That was tricky.
2073
+ v-macro-ip4:
2074
+ spec: 7.1/6
2075
+ description: |-
2076
+ v = the string "in-addr" if <ip> is ipv4, or "ip6" if <ip> is ipv6
2077
+ helo: msgbas2x.cos.example.com
2078
+ host: 192.168.218.40
2079
+ mailfrom: test@e4.example.com
2080
+ result: fail
2081
+ explanation: 192.168.218.40 is queried as 40.218.168.192.in-addr.arpa
2082
+ v-macro-ip6:
2083
+ spec: 7.1/6
2084
+ description: |-
2085
+ v = the string "in-addr" if <ip> is ipv4, or "ip6" if <ip> is ipv6
2086
+ helo: msgbas2x.cos.example.com
2087
+ host: "CAFE:BABE::1"
2088
+ mailfrom: test@e4.example.com
2089
+ result: fail
2090
+ explanation: "cafe:babe::1 is queried as 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.E.B.A.B.E.F.A.C.ip6.arpa"
2091
+ undef-macro:
2092
+ spec: 7.1/6
2093
+ description: >-
2094
+ Allowed macros chars are 'slodipvh' plus 'crt' in explanation.
2095
+ helo: msgbas2x.cos.example.com
2096
+ host: "CAFE:BABE::192.168.218.40"
2097
+ mailfrom: test@e5.example.com
2098
+ result: permerror
2099
+ p-macro-ip4-novalid:
2100
+ spec: 7.1/22
2101
+ description: |-
2102
+ p = the validated domain name of <ip>
2103
+ comment: >-
2104
+ The PTR in this example does not validate.
2105
+ helo: msgbas2x.cos.example.com
2106
+ host: 192.168.218.40
2107
+ mailfrom: test@e6.example.com
2108
+ result: fail
2109
+ explanation: connect from unknown
2110
+ p-macro-ip4-valid:
2111
+ spec: 7.1/22
2112
+ description: |-
2113
+ p = the validated domain name of <ip>
2114
+ comment: >-
2115
+ If a subdomain of the <domain> is present, it SHOULD be used.
2116
+ helo: msgbas2x.cos.example.com
2117
+ host: 192.168.218.41
2118
+ mailfrom: test@e6.example.com
2119
+ result: fail
2120
+ explanation: connect from mx.example.com
2121
+ p-macro-ip6-novalid:
2122
+ spec: 7.1/22
2123
+ description: |-
2124
+ p = the validated domain name of <ip>
2125
+ comment: >-
2126
+ The PTR in this example does not validate.
2127
+ helo: msgbas2x.cos.example.com
2128
+ host: "CAFE:BABE::1"
2129
+ mailfrom: test@e6.example.com
2130
+ result: fail
2131
+ explanation: connect from unknown
2132
+ p-macro-ip6-valid:
2133
+ spec: 7.1/22
2134
+ description: |-
2135
+ p = the validated domain name of <ip>
2136
+ comment: >-
2137
+ If a subdomain of the <domain> is present, it SHOULD be used.
2138
+ helo: msgbas2x.cos.example.com
2139
+ host: "CAFE:BABE::3"
2140
+ mailfrom: test@e6.example.com
2141
+ result: fail
2142
+ explanation: connect from mx.example.com
2143
+ p-macro-multiple:
2144
+ spec: 7.1/22
2145
+ description: |-
2146
+ p = the validated domain name of <ip>
2147
+ comment: >-
2148
+ If a subdomain of the <domain> is present, it SHOULD be used.
2149
+ helo: msgbas2x.cos.example.com
2150
+ host: 192.168.218.42
2151
+ mailfrom: test@e7.example.com
2152
+ result: [pass, softfail]
2153
+ upper-macro:
2154
+ spec: 7.1/26
2155
+ description: >-
2156
+ Uppercased macros expand exactly as their lowercased equivalents,
2157
+ and are then URL escaped. All chars not in the unreserved set
2158
+ MUST be escaped.
2159
+ comment: |
2160
+ unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
2161
+ helo: msgbas2x.cos.example.com
2162
+ host: 192.168.218.42
2163
+ mailfrom: ~jack&jill=up-a_b3.c@e8.example.com
2164
+ result: fail
2165
+ explanation: http://example.com/why.html?l=~jack%26jill%3Dup-a_b3.c
2166
+ hello-macro:
2167
+ spec: 7.1/6
2168
+ description: |-
2169
+ h = HELO/EHLO domain
2170
+ helo: msgbas2x.cos.example.com
2171
+ host: 192.168.218.40
2172
+ mailfrom: test@e9.example.com
2173
+ result: pass
2174
+ invalid-hello-macro:
2175
+ spec: 7.1/2
2176
+ description: |-
2177
+ h = HELO/EHLO domain, but HELO is invalid
2178
+ comment: >-
2179
+ Domain-spec must end in either a macro, or a valid toplabel.
2180
+ It is not correct to check syntax after macro expansion.
2181
+ helo: "JUMPIN' JUPITER"
2182
+ host: 192.168.218.40
2183
+ mailfrom: test@e9.example.com
2184
+ result: fail
2185
+ hello-domain-literal:
2186
+ spec: 7.1/2
2187
+ description: |-
2188
+ h = HELO/EHLO domain, but HELO is a domain literal
2189
+ comment: >-
2190
+ Domain-spec must end in either a macro, or a valid toplabel.
2191
+ It is not correct to check syntax after macro expansion.
2192
+ helo: "[192.168.218.40]"
2193
+ host: 192.168.218.40
2194
+ mailfrom: test@e9.example.com
2195
+ result: fail
2196
+ require-valid-helo:
2197
+ spec: 7.1/6
2198
+ description: >-
2199
+ Example of requiring valid helo in sender policy. This is a complex
2200
+ policy testing several points at once.
2201
+ helo: OEMCOMPUTER
2202
+ host: 1.2.3.4
2203
+ mailfrom: test@e10.example.com
2204
+ result: fail
2205
+ macro-reverse-split-on-dash:
2206
+ spec: 7.1/15, 7.1/16, 7.1/17, 7.1/18
2207
+ description: >-
2208
+ Macro value transformation (splitting on arbitrary characters, reversal,
2209
+ number of right-hand parts to use)
2210
+ helo: mail.example.com
2211
+ host: 1.2.3.4
2212
+ mailfrom: philip-gladstone-test@e11.example.com
2213
+ result: pass
2214
+ macro-multiple-delimiters:
2215
+ spec: 7.1/15, 7.1/16
2216
+ description: |-
2217
+ Multiple delimiters may be specified in a macro expression.
2218
+ macro-expand = ( "%{" macro-letter transformers *delimiter "}" )
2219
+ / "%%" / "%_" / "%-"
2220
+ helo: mail.example.com
2221
+ host: 1.2.3.4
2222
+ mailfrom: foo-bar+zip+quux@e12.example.com
2223
+ result: pass
2224
+ zonedata:
2225
+ example.com.d.spf.example.com:
2226
+ - TXT: v=spf1 redirect=a.spf.example.com
2227
+ a.spf.example.com:
2228
+ - TXT: v=spf1 include:o.spf.example.com. ~all
2229
+ o.spf.example.com:
2230
+ - TXT: v=spf1 ip4:192.168.218.40
2231
+ msgbas2x.cos.example.com:
2232
+ - A: 192.168.218.40
2233
+ example.com:
2234
+ - A: 192.168.90.76
2235
+ - TXT: v=spf1 redirect=%{d}.d.spf.example.com.
2236
+ exp.example.com:
2237
+ - TXT: v=spf1 exp=msg.example.com. -all
2238
+ msg.example.com:
2239
+ - TXT: This is a test.
2240
+ e1.example.com:
2241
+ - TXT: v=spf1 -exists:%(ir).sbl.example.com ?all
2242
+ e1e.example.com:
2243
+ - TXT: v=spf1 exists:foo%(ir).sbl.example.com ?all
2244
+ e1t.example.com:
2245
+ - TXT: v=spf1 exists:foo%.sbl.example.com ?all
2246
+ e1a.example.com:
2247
+ - TXT: "v=spf1 a:macro%%percent%_%_space%-url-space.example.com -all"
2248
+ "macro%percent space%20url-space.example.com":
2249
+ - A: 1.2.3.4
2250
+ e2.example.com:
2251
+ - TXT: v=spf1 -all exp=%{r}.example.com
2252
+ e3.example.com:
2253
+ - TXT: v=spf1 -all exp=%{ir}.example.com
2254
+ 40.218.168.192.example.com:
2255
+ - TXT: Connections from %{c} not authorized.
2256
+ somewhat.long.exp.example.com:
2257
+ - TXT: v=spf1 -all exp=foobar.%{o}.%{o}.%{o}.%{o}.%{o}.%{o}.%{o}.%{o}.example.com
2258
+ somewhat.long.exp.example.com.somewhat.long.exp.example.com.somewhat.long.exp.example.com.somewhat.long.exp.example.com.somewhat.long.exp.example.com.somewhat.long.exp.example.com.somewhat.long.exp.example.com.somewhat.long.exp.example.com.example.com:
2259
+ - TXT: Congratulations! That was tricky.
2260
+ e4.example.com:
2261
+ - TXT: v=spf1 -all exp=e4msg.example.com
2262
+ e4msg.example.com:
2263
+ - TXT: "%{c} is queried as %{ir}.%{v}.arpa"
2264
+ e5.example.com:
2265
+ - TXT: v=spf1 a:%{a}.example.com -all
2266
+ e6.example.com:
2267
+ - TXT: v=spf1 -all exp=e6msg.example.com
2268
+ e6msg.example.com:
2269
+ - TXT: "connect from %{p}"
2270
+ mx.example.com:
2271
+ - A: 192.168.218.41
2272
+ - A: 192.168.218.42
2273
+ - AAAA: "CAFE:BABE::2"
2274
+ - AAAA: "CAFE:BABE::3"
2275
+ 40.218.168.192.in-addr.arpa:
2276
+ - PTR: mx.example.com
2277
+ 41.218.168.192.in-addr.arpa:
2278
+ - PTR: mx.example.com
2279
+ 42.218.168.192.in-addr.arpa:
2280
+ - PTR: mx.example.com
2281
+ - PTR: mx.e7.example.com
2282
+ 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.E.B.A.B.E.F.A.C.ip6.arpa:
2283
+ - PTR: mx.example.com
2284
+ 3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.E.B.A.B.E.F.A.C.ip6.arpa:
2285
+ - PTR: mx.example.com
2286
+ mx.e7.example.com:
2287
+ - A: 192.168.218.42
2288
+ mx.e7.example.com.should.example.com:
2289
+ - A: 127.0.0.2
2290
+ mx.example.com.ok.example.com:
2291
+ - A: 127.0.0.2
2292
+ e7.example.com:
2293
+ - TXT: v=spf1 exists:%{p}.should.example.com ~exists:%{p}.ok.example.com
2294
+ e8.example.com:
2295
+ - TXT: v=spf1 -all exp=msg8.%{D2}
2296
+ msg8.example.com:
2297
+ - TXT: "http://example.com/why.html?l=%{L}"
2298
+ e9.example.com:
2299
+ - TXT: v=spf1 a:%{H} -all
2300
+ e10.example.com:
2301
+ - TXT: v=spf1 -include:_spfh.%{d2} ip4:1.2.3.0/24 -all
2302
+ _spfh.example.com:
2303
+ - TXT: v=spf1 -a:%{h} +all
2304
+ e11.example.com:
2305
+ - TXT: v=spf1 exists:%{i}.%{l2r-}.user.%{d2}
2306
+ 1.2.3.4.gladstone.philip.user.example.com:
2307
+ - A: 127.0.0.2
2308
+ e12.example.com:
2309
+ - TXT: v=spf1 exists:%{l2r+-}.user.%{d2}
2310
+ bar.foo.user.example.com:
2311
+ - A: 127.0.0.2
2312
+ ---
2313
+ description: Processing limits
2314
+ tests:
2315
+ redirect-loop:
2316
+ description: >-
2317
+ SPF implementations MUST limit the number of mechanisms and modifiers
2318
+ that do DNS lookups to at most 10 per SPF check.
2319
+ spec: 4.6.4/1
2320
+ helo: mail.example.com
2321
+ host: 1.2.3.4
2322
+ mailfrom: foo@e1.example.com
2323
+ result: permerror
2324
+ include-loop:
2325
+ description: >-
2326
+ SPF implementations MUST limit the number of mechanisms and modifiers
2327
+ that do DNS lookups to at most 10 per SPF check.
2328
+ spec: 4.6.4/1
2329
+ helo: mail.example.com
2330
+ host: 1.2.3.4
2331
+ mailfrom: foo@e2.example.com
2332
+ result: permerror
2333
+ mx-limit:
2334
+ description: >-
2335
+ there MUST be a limit of no more than 10 MX looked up and checked.
2336
+ comment: >-
2337
+ The required result for this test was the subject of much controversy
2338
+ with RFC4408. For RFC7208 the ambiguity was resolved in favor of
2339
+ producing a permerror result.
2340
+ spec: 4.6.4/2
2341
+ helo: mail.example.com
2342
+ host: 1.2.3.5
2343
+ mailfrom: foo@e4.example.com
2344
+ result: permerror
2345
+ ptr-limit:
2346
+ description: >-
2347
+ there MUST be a limit of no more than 10 PTR looked up and checked.
2348
+ comment: >-
2349
+ The result of this test cannot be permerror not only because the
2350
+ RFC does not specify it, but because the sender has no control over
2351
+ the PTR records of spammers.
2352
+ The preferred result reflects evaluating the 10 allowed PTR records in
2353
+ the order returned by the test data.
2354
+ If testing with live DNS, the PTR order may be random, and a pass
2355
+ result would still be compliant. The SPF result is effectively
2356
+ randomized.
2357
+ spec: 4.6.4/3
2358
+ helo: mail.example.com
2359
+ host: 1.2.3.5
2360
+ mailfrom: foo@e5.example.com
2361
+ result: [neutral, pass]
2362
+ false-a-limit:
2363
+ description: >-
2364
+ unlike MX, PTR, there is no RR limit for A
2365
+ comment: >-
2366
+ There seems to be a tendency for developers to want to limit
2367
+ A RRs in addition to MX and PTR. These are IPs, not usable for
2368
+ 3rd party DoS attacks, and hence need no low limit.
2369
+ spec: 4.6.4
2370
+ helo: mail.example.com
2371
+ host: 1.2.3.12
2372
+ mailfrom: foo@e10.example.com
2373
+ result: pass
2374
+ mech-at-limit:
2375
+ description: >-
2376
+ SPF implementations MUST limit the number of mechanisms and modifiers
2377
+ that do DNS lookups to at most 10 per SPF check.
2378
+ spec: 4.6.4/1
2379
+ helo: mail.example.com
2380
+ host: 1.2.3.4
2381
+ mailfrom: foo@e6.example.com
2382
+ result: pass
2383
+ mech-over-limit:
2384
+ description: >-
2385
+ SPF implementations MUST limit the number of mechanisms and modifiers
2386
+ that do DNS lookups to at most 10 per SPF check.
2387
+ comment: >-
2388
+ We do not check whether an implementation counts mechanisms before
2389
+ or after evaluation. The RFC is not clear on this.
2390
+ spec: 4.6.4/1
2391
+ helo: mail.example.com
2392
+ host: 1.2.3.4
2393
+ mailfrom: foo@e7.example.com
2394
+ result: permerror
2395
+ include-at-limit:
2396
+ description: >-
2397
+ SPF implementations MUST limit the number of mechanisms and modifiers
2398
+ that do DNS lookups to at most 10 per SPF check.
2399
+ comment: >-
2400
+ The part of the RFC that talks about MAY parse the entire record first
2401
+ (4.6) is specific to syntax errors. In RFC7208, processing limits are
2402
+ part of syntax checking (4.6).
2403
+ spec: 4.6.4/1
2404
+ helo: mail.example.com
2405
+ host: 1.2.3.4
2406
+ mailfrom: foo@e8.example.com
2407
+ result: pass
2408
+ include-over-limit:
2409
+ description: >-
2410
+ SPF implementations MUST limit the number of mechanisms and modifiers
2411
+ that do DNS lookups to at most 10 per SPF check.
2412
+ spec: 4.6.4/1
2413
+ helo: mail.example.com
2414
+ host: 1.2.3.4
2415
+ mailfrom: foo@e9.example.com
2416
+ result: permerror
2417
+ void-at-limit:
2418
+ description: >-
2419
+ SPF implementations SHOULD limit "void lookups" to two. An
2420
+ implementation MAY choose to make such a limit configurable.
2421
+ In this case, a default of two is RECOMMENDED.
2422
+ comment: >-
2423
+ This is a new check in RFC7208, but it's been implemented in Mail::SPF
2424
+ for years with no issues.
2425
+ spec: 4.6.4/7
2426
+ helo: mail.example.com
2427
+ host: 1.2.3.4
2428
+ mailfrom: foo@e12.example.com
2429
+ result: neutral
2430
+ void-over-limit:
2431
+ description: >-
2432
+ SPF implementations SHOULD limit "void lookups" to two. An
2433
+ implementation MAY choose to make such a limit configurable.
2434
+ In this case, a default of two is RECOMMENDED.
2435
+ spec: 4.6.4/7
2436
+ helo: mail.example.com
2437
+ host: 1.2.3.4
2438
+ mailfrom: foo@e11.example.com
2439
+ result: permerror
2440
+ zonedata:
2441
+ mail.example.com:
2442
+ - A: 1.2.3.4
2443
+ e1.example.com:
2444
+ - TXT: v=spf1 ip4:1.1.1.1 redirect=e1.example.com
2445
+ - A: 1.2.3.6
2446
+ e2.example.com:
2447
+ - TXT: v=spf1 include:e3.example.com
2448
+ - A: 1.2.3.7
2449
+ e3.example.com:
2450
+ - TXT: v=spf1 include:e2.example.com
2451
+ - A: 1.2.3.8
2452
+ e4.example.com:
2453
+ - TXT: v=spf1 mx
2454
+ - MX: [0, mail.example.com]
2455
+ - MX: [1, mail.example.com]
2456
+ - MX: [2, mail.example.com]
2457
+ - MX: [3, mail.example.com]
2458
+ - MX: [4, mail.example.com]
2459
+ - MX: [5, mail.example.com]
2460
+ - MX: [6, mail.example.com]
2461
+ - MX: [7, mail.example.com]
2462
+ - MX: [8, mail.example.com]
2463
+ - MX: [9, mail.example.com]
2464
+ - MX: [10, e4.example.com]
2465
+ - A: 1.2.3.5
2466
+ e5.example.com:
2467
+ - TXT: v=spf1 ptr
2468
+ - A: 1.2.3.5
2469
+ 5.3.2.1.in-addr.arpa:
2470
+ - PTR: e1.example.com.
2471
+ - PTR: e2.example.com.
2472
+ - PTR: e3.example.com.
2473
+ - PTR: e4.example.com.
2474
+ - PTR: example.com.
2475
+ - PTR: e6.example.com.
2476
+ - PTR: e7.example.com.
2477
+ - PTR: e8.example.com.
2478
+ - PTR: e9.example.com.
2479
+ - PTR: e10.example.com.
2480
+ - PTR: e5.example.com.
2481
+ e6.example.com:
2482
+ - TXT: v=spf1 a mx a mx a mx a mx a ptr ip4:1.2.3.4 -all
2483
+ - A: 1.2.3.8
2484
+ - MX: [10, e6.example.com]
2485
+ e7.example.com:
2486
+ - TXT: v=spf1 a mx a mx a mx a mx a ptr a ip4:1.2.3.4 -all
2487
+ - A: 1.2.3.20
2488
+ e8.example.com:
2489
+ - TXT: v=spf1 a include:inc.example.com ip4:1.2.3.4 mx -all
2490
+ - A: 1.2.3.4
2491
+ inc.example.com:
2492
+ - TXT: v=spf1 a a a a a a a a
2493
+ - A: 1.2.3.10
2494
+ e9.example.com:
2495
+ - TXT: v=spf1 a include:inc.example.com a ip4:1.2.3.4 -all
2496
+ - A: 1.2.3.21
2497
+ e10.example.com:
2498
+ - TXT: v=spf1 a -all
2499
+ - A: 1.2.3.1
2500
+ - A: 1.2.3.2
2501
+ - A: 1.2.3.3
2502
+ - A: 1.2.3.4
2503
+ - A: 1.2.3.5
2504
+ - A: 1.2.3.6
2505
+ - A: 1.2.3.7
2506
+ - A: 1.2.3.8
2507
+ - A: 1.2.3.9
2508
+ - A: 1.2.3.10
2509
+ - A: 1.2.3.11
2510
+ - A: 1.2.3.12
2511
+ e11.example.com:
2512
+ - TXT: v=spf1 a:err.example.com a:err1.example.com a:err2.example.com ?all
2513
+ e12.example.com:
2514
+ - TXT: v=spf1 a:err.example.com a:err1.example.com ?all
2515
+ ---
2516
+ description: Test cases from implementation bugs
2517
+ tests:
2518
+ bytes-bug:
2519
+ description: >-
2520
+ Bytes vs str bug from pyspf.
2521
+ comment: >-
2522
+ Pyspf failed with strict=2 only. Other implementations may ignore
2523
+ the strict parameter.
2524
+ spec: 5.4/4
2525
+ helo: example.org
2526
+ host: "2001:db8:ff0:100::2"
2527
+ mailfrom: test@example.org
2528
+ result: pass
2529
+ strict: 2
2530
+ zonedata:
2531
+ example.org:
2532
+ - TXT: "v=spf1 mx redirect=_spf.example.com"
2533
+ - MX: [10,smtp.example.org]
2534
+ - MX: [10,smtp1.example.com]
2535
+ smtp.example.org:
2536
+ - A: 198.51.100.2
2537
+ - AAAA: "2001:db8:ff0:100::3"
2538
+ smtp1.example.com:
2539
+ - A: 192.0.2.26
2540
+ - AAAA: "2001:db8:ff0:200::2"
2541
+ 2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.F.F.0.8.B.D.0.1.0.0.2.ip6.arpa:
2542
+ - PTR: smtp6-v.fe.example.org
2543
+ smtp6-v.fe.example.org:
2544
+ - AAAA: "2001:db8:ff0:100::2"
2545
+ _spf.example.com:
2546
+ - TXT: "v=spf1 ptr:fe.example.org ptr:sgp.example.com exp=_expspf.example.org -all"
2547
+ _expspf.example.org:
2548
+ - TXT: "Sender domain not allowed from this host. Please see http://www.openspf.org/Why?s=mfrom&id=%{S}&ip=%{C}&r=%{R}"