1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.james.jspf.impl;
22
23 import org.apache.james.jspf.core.DNSLookupContinuation;
24 import org.apache.james.jspf.core.DNSService;
25 import org.apache.james.jspf.core.DNSServiceEnabled;
26 import org.apache.james.jspf.core.LogEnabled;
27 import org.apache.james.jspf.core.Logger;
28 import org.apache.james.jspf.core.MacroExpand;
29 import org.apache.james.jspf.core.MacroExpandEnabled;
30 import org.apache.james.jspf.core.SPF1Record;
31 import org.apache.james.jspf.core.SPF1Utils;
32 import org.apache.james.jspf.core.SPFCheckEnabled;
33 import org.apache.james.jspf.core.SPFChecker;
34 import org.apache.james.jspf.core.SPFCheckerExceptionCatcher;
35 import org.apache.james.jspf.core.SPFRecordParser;
36 import org.apache.james.jspf.core.SPFSession;
37 import org.apache.james.jspf.core.exceptions.NeutralException;
38 import org.apache.james.jspf.core.exceptions.NoneException;
39 import org.apache.james.jspf.core.exceptions.PermErrorException;
40 import org.apache.james.jspf.core.exceptions.SPFErrorConstants;
41 import org.apache.james.jspf.core.exceptions.SPFResultException;
42 import org.apache.james.jspf.core.exceptions.TempErrorException;
43 import org.apache.james.jspf.executor.FutureSPFResult;
44 import org.apache.james.jspf.executor.SPFExecutor;
45 import org.apache.james.jspf.executor.SPFResult;
46 import org.apache.james.jspf.executor.SynchronousSPFExecutor;
47 import org.apache.james.jspf.parser.RFC4408SPF1Parser;
48 import org.apache.james.jspf.policies.InitialChecksPolicy;
49 import org.apache.james.jspf.policies.NeutralIfNotMatchPolicy;
50 import org.apache.james.jspf.policies.NoSPFRecordFoundPolicy;
51 import org.apache.james.jspf.policies.ParseRecordPolicy;
52 import org.apache.james.jspf.policies.Policy;
53 import org.apache.james.jspf.policies.PolicyPostFilter;
54 import org.apache.james.jspf.policies.SPFRetriever;
55 import org.apache.james.jspf.policies.SPFStrictCheckerRetriever;
56 import org.apache.james.jspf.policies.local.BestGuessPolicy;
57 import org.apache.james.jspf.policies.local.DefaultExplanationPolicy;
58 import org.apache.james.jspf.policies.local.FallbackPolicy;
59 import org.apache.james.jspf.policies.local.OverridePolicy;
60 import org.apache.james.jspf.policies.local.TrustedForwarderPolicy;
61 import org.apache.james.jspf.wiring.WiringServiceTable;
62
63 import java.util.Iterator;
64 import java.util.LinkedList;
65
66
67
68
69 public class SPF implements SPFChecker {
70
71 private static final class SPFRecordChecker implements SPFChecker {
72
73
74
75
76 public DNSLookupContinuation checkSPF(SPFSession spfData)
77 throws PermErrorException, TempErrorException,
78 NeutralException, NoneException {
79
80 SPF1Record spfRecord = (SPF1Record) spfData.getAttribute(SPF1Utils.ATTRIBUTE_SPF1_RECORD);
81
82 spfData.removeAttribute(SPF1Utils.ATTRIBUTE_SPF1_RECORD);
83
84 LinkedList policyCheckers = new LinkedList();
85
86 Iterator i = spfRecord.iterator();
87 while (i.hasNext()) {
88 SPFChecker checker = (SPFChecker) i.next();
89 policyCheckers.add(checker);
90 }
91
92 while (policyCheckers.size() > 0) {
93 SPFChecker removeLast = (SPFChecker) policyCheckers.removeLast();
94 spfData.pushChecker(removeLast);
95 }
96
97 return null;
98 }
99 }
100
101 private static final class PolicyChecker implements SPFChecker {
102
103 private LinkedList policies;
104
105 public PolicyChecker(LinkedList policies) {
106 this.policies = policies;
107 }
108
109
110
111
112 public DNSLookupContinuation checkSPF(SPFSession spfData)
113 throws PermErrorException, TempErrorException,
114 NeutralException, NoneException {
115
116 while (policies.size() > 0) {
117 SPFChecker removeLast = (SPFChecker) policies.removeLast();
118 spfData.pushChecker(removeLast);
119 }
120
121 return null;
122 }
123 }
124
125 private static final class SPFPolicyChecker implements SPFChecker {
126 private Policy policy;
127
128
129
130
131 public SPFPolicyChecker(Policy policy) {
132 this.policy = policy;
133 }
134
135
136
137
138 public DNSLookupContinuation checkSPF(SPFSession spfData)
139 throws PermErrorException, TempErrorException,
140 NeutralException, NoneException {
141 SPF1Record res = (SPF1Record) spfData.getAttribute(SPF1Utils.ATTRIBUTE_SPF1_RECORD);
142 if (res == null) {
143 res = policy.getSPFRecord(spfData.getCurrentDomain());
144 spfData.setAttribute(SPF1Utils.ATTRIBUTE_SPF1_RECORD, res);
145 }
146 return null;
147 }
148
149 public String toString() {
150 return "PC:"+policy.toString();
151 }
152 }
153
154 private static final class SPFPolicyPostFilterChecker implements SPFChecker {
155 private PolicyPostFilter policy;
156
157
158
159
160 public SPFPolicyPostFilterChecker(PolicyPostFilter policy) {
161 this.policy = policy;
162 }
163
164
165
166
167 public DNSLookupContinuation checkSPF(SPFSession spfData)
168 throws PermErrorException, TempErrorException,
169 NeutralException, NoneException {
170 SPF1Record res = (SPF1Record) spfData.getAttribute(SPF1Utils.ATTRIBUTE_SPF1_RECORD);
171 res = policy.getSPFRecord(spfData.getCurrentDomain(), res);
172 spfData.setAttribute(SPF1Utils.ATTRIBUTE_SPF1_RECORD, res);
173 return null;
174 }
175
176 public String toString() {
177 return "PFC:"+policy.toString();
178 }
179
180 }
181
182 private DNSService dnsProbe;
183
184 private SPFRecordParser parser;
185
186 private Logger log;
187
188 private String defaultExplanation = null;
189
190 private boolean useBestGuess = false;
191
192 private FallbackPolicy fallBack;
193
194 private OverridePolicy override;
195
196 private boolean useTrustedForwarder = false;
197
198 private boolean mustEquals = false;
199
200 private MacroExpand macroExpand;
201
202 private SPFExecutor executor;
203
204
205
206
207
208
209
210 public SPF(DNSService dnsProbe, Logger logger) {
211 super();
212 this.dnsProbe = dnsProbe;
213 this.log = logger;
214 WiringServiceTable wiringService = new WiringServiceTable();
215 wiringService.put(LogEnabled.class, this.log);
216 wiringService.put(DNSServiceEnabled.class, this.dnsProbe);
217 this.macroExpand = new MacroExpand(logger.getChildLogger("macroExpand"), this.dnsProbe);
218 wiringService.put(MacroExpandEnabled.class, this.macroExpand);
219 this.parser = new RFC4408SPF1Parser(logger.getChildLogger("parser"), new DefaultTermsFactory(logger.getChildLogger("termsfactory"), wiringService));
220
221 wiringService.put(SPFCheckEnabled.class, this);
222 this.executor = new SynchronousSPFExecutor(log, dnsProbe);
223 }
224
225
226
227
228
229
230
231
232
233 public SPF(DNSService dnsProbe, SPFRecordParser parser, Logger logger, MacroExpand macroExpand, SPFExecutor executor) {
234 super();
235 this.dnsProbe = dnsProbe;
236 this.parser = parser;
237 this.log = logger;
238 this.macroExpand = macroExpand;
239 this.executor = executor;
240 }
241
242
243 private static final class DefaultSPFChecker implements SPFChecker, SPFCheckerExceptionCatcher {
244
245 private Logger log;
246
247 public DefaultSPFChecker(Logger log) {
248 this.log = log;
249 }
250
251
252
253
254 public DNSLookupContinuation checkSPF(SPFSession spfData)
255 throws PermErrorException, TempErrorException,
256 NeutralException, NoneException {
257 if (spfData.getCurrentResultExpanded() == null) {
258 String resultChar = spfData.getCurrentResult() != null ? spfData.getCurrentResult() : "";
259 String result = SPF1Utils.resultToName(resultChar);
260 spfData.setCurrentResultExpanded(result);
261 }
262 return null;
263 }
264
265
266
267
268
269 public void onException(Exception exception, SPFSession session)
270 throws PermErrorException, NoneException, TempErrorException,
271 NeutralException {
272
273 String result;
274 if (exception instanceof SPFResultException) {
275 result = ((SPFResultException) exception).getResult();
276 if (!SPFErrorConstants.NEUTRAL_CONV.equals(result)) {
277 log.warn(exception.getMessage(),exception);
278 }
279 } else {
280
281
282 log.error(exception.getMessage(),exception);
283 result = SPFErrorConstants.NEUTRAL_CONV;
284 }
285 session.setCurrentResultExpanded(result);
286 }
287
288 }
289
290
291
292
293
294
295
296
297
298
299
300
301 public SPFResult checkSPF(String ipAddress, String mailFrom, String hostName) {
302 SPFSession spfData = null;
303
304
305 spfData = new SPFSession(mailFrom, hostName, ipAddress);
306
307
308 SPFChecker resultHandler = new DefaultSPFChecker(log);
309
310 spfData.pushChecker(resultHandler);
311 spfData.pushChecker(this);
312
313 FutureSPFResult ret = new FutureSPFResult();
314
315 executor.execute(spfData, ret);
316
317
318
319
320
321 return ret;
322
323 }
324
325
326
327
328
329 public DNSLookupContinuation checkSPF(SPFSession spfData) throws PermErrorException,
330 NoneException, TempErrorException, NeutralException {
331
332
333 if (spfData.getCurrentResultExpanded() == null && spfData.getCurrentResult() == null) {
334 SPFChecker policyChecker = new PolicyChecker(getPolicies());
335 SPFChecker recordChecker = new SPFRecordChecker();
336
337 spfData.pushChecker(recordChecker);
338 spfData.pushChecker(policyChecker);
339 }
340
341 return null;
342 }
343
344
345
346
347 public LinkedList getPolicies() {
348
349 LinkedList policies = new LinkedList();
350
351 if (override != null) {
352 policies.add(new SPFPolicyChecker(override));
353 }
354
355 policies.add(new InitialChecksPolicy());
356
357 if (mustEquals) {
358 policies.add(new SPFStrictCheckerRetriever());
359 } else {
360 policies.add(new SPFRetriever());
361 }
362
363 if (useBestGuess) {
364 policies.add(new SPFPolicyPostFilterChecker(new BestGuessPolicy()));
365 }
366
367 policies.add(new SPFPolicyPostFilterChecker(new ParseRecordPolicy(parser)));
368
369 if (fallBack != null) {
370 policies.add(new SPFPolicyPostFilterChecker(fallBack));
371 }
372
373 policies.add(new SPFPolicyPostFilterChecker(new NoSPFRecordFoundPolicy()));
374
375
376 if (useTrustedForwarder) {
377 policies.add(new SPFPolicyPostFilterChecker(new TrustedForwarderPolicy(log)));
378 }
379
380 policies.add(new SPFPolicyPostFilterChecker(new NeutralIfNotMatchPolicy()));
381
382 policies.add(new SPFPolicyPostFilterChecker(new DefaultExplanationPolicy(log, defaultExplanation, macroExpand)));
383
384 return policies;
385 }
386
387
388
389
390
391
392
393 public synchronized void setTimeOut(int timeOut) {
394 log.debug("TimeOut was set to: " + timeOut);
395 dnsProbe.setTimeOut(timeOut);
396 }
397
398
399
400
401
402
403 public synchronized void setDefaultExplanation(String defaultExplanation) {
404 this.defaultExplanation = defaultExplanation;
405 }
406
407
408
409
410
411
412
413
414 public synchronized void setUseBestGuess(boolean useBestGuess) {
415 this.useBestGuess = useBestGuess;
416 }
417
418
419
420
421
422
423
424
425 public synchronized FallbackPolicy getFallbackPolicy() {
426
427 if (fallBack == null) {
428 this.fallBack = new FallbackPolicy(log.getChildLogger("fallbackpolicy"), parser);
429 }
430 return fallBack;
431 }
432
433
434
435
436
437
438
439
440
441 public synchronized void setUseTrustedForwarder(boolean useTrustedForwarder) {
442 this.useTrustedForwarder = useTrustedForwarder;
443 }
444
445
446
447
448
449
450
451 public synchronized OverridePolicy getOverridePolicy() {
452 if (override == null) {
453 override = new OverridePolicy(log.getChildLogger("overridepolicy"), parser);
454 }
455 return override;
456 }
457
458
459
460
461
462
463
464 public synchronized void setSPFMustEqualsTXT(boolean mustEquals) {
465 this.mustEquals = mustEquals;
466 }
467
468
469 }