spf 0.0.26 → 0.0.27
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.
- 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