1 /*****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one *
3 * or more contributor license agreements. See the NOTICE file *
4 * distributed with this work for additional information *
5 * regarding copyright ownership. The ASF licenses this file *
6 * to you under the Apache License, Version 2.0 (the *
7 * "License"); you may not use this file except in compliance *
8 * with the License. You may obtain a copy of the License at *
9 * *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, *
13 * software distributed under the License is distributed on an *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15 * KIND, either express or implied. See the License for the *
16 * specific language governing permissions and limitations *
17 * under the License. *
18 ****************************************************************/
19
20
21 package org.apache.james.jspf.terms;
22
23 import org.apache.james.jspf.core.DNSService;
24 import org.apache.james.jspf.core.SPF1Constants;
25 import org.apache.james.jspf.core.SPF1Data;
26 import org.apache.james.jspf.exceptions.PermErrorException;
27 import org.apache.james.jspf.exceptions.TempErrorException;
28 import org.apache.james.jspf.macro.MacroExpand;
29 import org.apache.james.jspf.util.SPFTermsRegexps;
30 import org.apache.james.jspf.wiring.DNSServiceEnabled;
31 import org.apache.james.jspf.wiring.MacroExpandEnabled;
32
33 import java.util.List;
34
35 /***
36 * This class represent the exp modifier
37 *
38 */
39 public class ExpModifier extends GenericModifier implements DNSServiceEnabled, MacroExpandEnabled {
40
41 /***
42 * ABNF: explanation = "exp" "=" domain-spec
43 *
44 * NOTE: the last +"?" has been added to support RFC4408 ERRATA for the EXP modifier.
45 * An "exp=" should not result in a perm error but should be ignored.
46 * Errata: http://www.openspf.org/RFC_4408/Errata#empty-exp
47 */
48 public static final String REGEX = "[eE][xX][pP]" + "//="
49 + SPFTermsRegexps.DOMAIN_SPEC_REGEX+"?";
50
51 private DNSService dnsService;
52
53 private MacroExpand macroExpand;
54
55 /***
56 * Generate the explanation and set it in SPF1Data so it can be accessed
57 * easy later if needed
58 *
59 * @param spfData
60 * The SPF1Data which should used
61 * @throws PermErrorException
62 */
63 protected void checkSPFLogged(SPF1Data spfData) throws PermErrorException {
64 String exp = null;
65 String host = getHost();
66
67
68 if (host == null) {
69 return;
70 }
71
72
73 if (spfData.ignoreExplanation() == true)
74 return;
75
76
77
78 if (spfData.getCurrentResult()== null || !spfData.getCurrentResult().equals(SPF1Constants.FAIL))
79 return;
80
81 host = macroExpand.expand(host, spfData, MacroExpand.DOMAIN);
82
83 try {
84 try {
85 exp = getTxtType(dnsService, host);
86 } catch (TempErrorException e) {
87
88 return;
89 }
90
91 if ((exp != null) && (!exp.equals(""))) {
92 String expandedExplanation = macroExpand.expand(exp, spfData, MacroExpand.EXPLANATION);
93 spfData.setExplanation(expandedExplanation);
94 }
95 } catch (PermErrorException e) {
96
97
98 return;
99 }
100 return;
101 }
102
103
104 /***
105 * Get TXT records as a string
106 *
107 * @param dns The DNSService to query
108 * @param strServer
109 * The hostname for which we want to retrieve the TXT-Record
110 * @return String which reflect the TXT-Record
111 * @throws PermErrorException
112 * if more then one TXT-Record for explanation was found
113 * @throws TempErrorException
114 * if the lookup result was "TRY_AGAIN"
115 */
116 public String getTxtType(DNSService dns, String strServer) throws TempErrorException, PermErrorException {
117 try {
118 List records = dns.getRecords(strServer, DNSService.TXT);
119
120 if (records == null) {
121 return null;
122 }
123
124
125
126
127
128
129 if (records.size() > 1) {
130 log.debug("More then one TXT-Record found for explanation");
131 throw new PermErrorException("More then one TXT-Record for explanation");
132 } else {
133 return (String) records.get(0);
134 }
135 } catch (DNSService.TimeoutException e) {
136 throw new TempErrorException("Timeout querying dns server");
137 }
138 }
139
140 /***
141 * @see java.lang.Object#toString()
142 */
143 public String toString() {
144 return "exp="+getHost();
145 }
146
147 /***
148 * @see org.apache.james.jspf.wiring.DNSServiceEnabled#enableDNSService(org.apache.james.jspf.core.DNSService)
149 */
150 public void enableDNSService(DNSService service) {
151 this.dnsService = service;
152 }
153
154
155 /***
156 * @see org.apache.james.jspf.wiring.MacroExpandEnabled#enableMacroExpand(org.apache.james.jspf.macro.MacroExpand)
157 */
158 public void enableMacroExpand(MacroExpand macroExpand) {
159 this.macroExpand = macroExpand;
160 }
161
162 }