spf 0.0.26 → 0.0.27
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/spf/error.rb +9 -9
- data/lib/spf/eval.rb +24 -11
- data/lib/spf/model.rb +2 -2
- data/lib/spf/version.rb +1 -1
- data/spf.gemspec +1 -1
- metadata +1 -1
data/lib/spf/error.rb
CHANGED
@@ -14,15 +14,15 @@ module SPF
|
|
14
14
|
|
15
15
|
class DNSError < Error; end # DNS error
|
16
16
|
class DNSTimeoutError < DNSError; end # DNS timeout
|
17
|
-
class RecordSelectionError < Error
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
@records = records
|
23
|
-
super(message)
|
24
|
-
end
|
17
|
+
class RecordSelectionError < Error # Record selection error
|
18
|
+
attr_accessor :records
|
19
|
+
def initialize(message, records=[])
|
20
|
+
@records = records
|
21
|
+
super(message)
|
25
22
|
end
|
23
|
+
end
|
24
|
+
class NoAcceptableRecordError < RecordSelectionError; end # No acceptable record found
|
25
|
+
class RedundantAcceptableRecordsError < RecordSelectionError; end # Redundant acceptable records found
|
26
26
|
class NoUnparsedTextError < Error; end # No unparsed text available
|
27
27
|
class UnexpectedTermObjectError < Error; end # Unexpected term object encountered
|
28
28
|
class ProcessingLimitExceededError < Error; end # Processing limit exceeded
|
@@ -33,7 +33,7 @@ module SPF
|
|
33
33
|
|
34
34
|
class NothingToParseError < Error; end # Nothing to parse
|
35
35
|
class SyntaxError < Error # Generic syntax error
|
36
|
-
attr_accessor :text, :parse_text
|
36
|
+
attr_accessor :text, :parse_text, :domain
|
37
37
|
def initialize(message, text=nil, parse_text=nil)
|
38
38
|
@text = text
|
39
39
|
@parse_text = parse_text
|
data/lib/spf/eval.rb
CHANGED
@@ -44,6 +44,8 @@ class SPF::Server
|
|
44
44
|
DEFAULT_MAX_NAME_LOOKUPS_PER_PTR_MECH = DEFAULT_MAX_NAME_LOOKUPS_PER_TERM
|
45
45
|
DEFAULT_MAX_VOID_DNS_LOOKUPS = 2
|
46
46
|
|
47
|
+
LOOSE_SPF_MATCH_PATTERN = 'v=spf'
|
48
|
+
|
47
49
|
def initialize(options = {})
|
48
50
|
@default_authority_explanation = options[:default_authority_explanation] ||
|
49
51
|
DEFAULT_DEFAULT_AUTHORITY_EXPLANATION
|
@@ -159,7 +161,7 @@ class SPF::Server
|
|
159
161
|
return packet
|
160
162
|
end
|
161
163
|
|
162
|
-
def select_record(request)
|
164
|
+
def select_record(request, loose_match = false)
|
163
165
|
domain = request.authority_domain
|
164
166
|
versions = request.versions
|
165
167
|
scope = request.scope
|
@@ -169,9 +171,10 @@ class SPF::Server
|
|
169
171
|
# in future revisions of SPF):
|
170
172
|
# Query for SPF type records first, then fall back to TXT type records.
|
171
173
|
|
172
|
-
records
|
173
|
-
|
174
|
-
|
174
|
+
records = []
|
175
|
+
loose_records = []
|
176
|
+
query_count = 0
|
177
|
+
dns_errors = []
|
175
178
|
|
176
179
|
# Query for SPF-type RRs first:
|
177
180
|
if (@query_rr_types == QUERY_RR_TYPE_ALL or
|
@@ -179,8 +182,10 @@ class SPF::Server
|
|
179
182
|
begin
|
180
183
|
query_count += 1
|
181
184
|
packet = self.dns_lookup(domain, 'SPF')
|
182
|
-
|
183
|
-
packet, 'SPF', versions, scope, domain)
|
185
|
+
matches = self.get_acceptable_records_from_packet(
|
186
|
+
packet, 'SPF', versions, scope, domain, loose_match)
|
187
|
+
records << matches[0]
|
188
|
+
loose_records << matches[1]
|
184
189
|
rescue SPF::DNSError => e
|
185
190
|
dns_errors << e
|
186
191
|
#rescue SPF::DNSTimeout => e
|
@@ -205,8 +210,10 @@ class SPF::Server
|
|
205
210
|
begin
|
206
211
|
query_count += 1
|
207
212
|
packet = self.dns_lookup(domain, 'TXT')
|
208
|
-
|
209
|
-
packet, 'TXT', versions, scope, domain)
|
213
|
+
matches = self.get_acceptable_records_from_packet(
|
214
|
+
packet, 'TXT', versions, scope, domain, loose_match)
|
215
|
+
records << matches[0]
|
216
|
+
loose_records << matches[1]
|
210
217
|
rescue SPF::DNSError => e
|
211
218
|
dns_errors << e
|
212
219
|
end
|
@@ -215,10 +222,12 @@ class SPF::Server
|
|
215
222
|
raise dns_errors[0] unless dns_errors.length < query_count
|
216
223
|
|
217
224
|
records.flatten!
|
225
|
+
loose_records.flatten!
|
218
226
|
|
219
227
|
if records.empty?
|
220
228
|
# RFC 4408, 4.5/7
|
221
|
-
raise SPF::NoAcceptableRecordError.new('No applicable sender policy available'
|
229
|
+
raise SPF::NoAcceptableRecordError.new('No applicable sender policy available',
|
230
|
+
loose_records)
|
222
231
|
end
|
223
232
|
|
224
233
|
# Discard all records but the highest acceptable version:
|
@@ -238,7 +247,7 @@ class SPF::Server
|
|
238
247
|
end
|
239
248
|
end
|
240
249
|
|
241
|
-
def get_acceptable_records_from_packet(packet, rr_type, versions, scope, domain)
|
250
|
+
def get_acceptable_records_from_packet(packet, rr_type, versions, scope, domain, loose_match)
|
242
251
|
|
243
252
|
# Try higher record versions first.
|
244
253
|
# (This may be too simplistic for future revisions of SPF.)
|
@@ -246,6 +255,7 @@ class SPF::Server
|
|
246
255
|
|
247
256
|
rr_type = resource_typeclass_for_rr_type(rr_type)
|
248
257
|
records = []
|
258
|
+
possible_matches = []
|
249
259
|
packet.each do |rr|
|
250
260
|
next unless rr_type === rr
|
251
261
|
text = rr.strings.join('')
|
@@ -255,6 +265,9 @@ class SPF::Server
|
|
255
265
|
begin
|
256
266
|
record = klass.new_from_string(text, {:raise_exceptions => @raise_exceptions})
|
257
267
|
rescue SPF::InvalidRecordVersionError => error
|
268
|
+
if text =~ /#{LOOSE_SPF_MATCH_PATTERN}/
|
269
|
+
possible_matches << text
|
270
|
+
end
|
258
271
|
# Ignore non-SPF and unknown-version records.
|
259
272
|
# Propagate other errors (including syntax errors), though.
|
260
273
|
end
|
@@ -266,7 +279,7 @@ class SPF::Server
|
|
266
279
|
end
|
267
280
|
end
|
268
281
|
end
|
269
|
-
return records
|
282
|
+
return records, possible_matches
|
270
283
|
end
|
271
284
|
|
272
285
|
def count_dns_interactive_term(request)
|
data/lib/spf/model.rb
CHANGED
@@ -551,12 +551,12 @@ class SPF::Mech < SPF::Term
|
|
551
551
|
raise result
|
552
552
|
end
|
553
553
|
|
554
|
-
def nested_record(server=nil, request=nil)
|
554
|
+
def nested_record(server=nil, request=nil, loose_match = false)
|
555
555
|
return @nested_record if @nested_record
|
556
556
|
authority_domain = self.domain(server, request)
|
557
557
|
return nil unless request
|
558
558
|
sub_request = request.new_sub_request({:authority_domain => authority_domain})
|
559
|
-
return @nested_record = server.select_record(sub_request)
|
559
|
+
return @nested_record = server.select_record(sub_request, loose_match)
|
560
560
|
end
|
561
561
|
|
562
562
|
end
|
data/lib/spf/version.rb
CHANGED
data/spf.gemspec
CHANGED