coppertone 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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}"