spf 0.0.13 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/spf/eval.rb +3 -3
- data/lib/spf/model.rb +61 -41
- data/lib/spf/version.rb +1 -1
- data/spf.gemspec +1 -1
- metadata +1 -4
data/lib/spf/eval.rb
CHANGED
@@ -99,9 +99,9 @@ class SPF::Server
|
|
99
99
|
rescue SPF::Result => r
|
100
100
|
result = r
|
101
101
|
rescue SPF::DNSError => e
|
102
|
-
result = self.result_class(:temperror).new(self, request, e.message)
|
102
|
+
result = self.result_class(:temperror).new([self, request, e.message])
|
103
103
|
rescue SPF::NoAcceptableRecordError => e
|
104
|
-
result = self.result_class(:none ).new(self, request, e.message)
|
104
|
+
result = self.result_class(:none ).new([self, request, e.message])
|
105
105
|
rescue SPF::RedundantAcceptableRecordsError, SPF::SyntaxError, SPF::ProcessingLimitExceededError => e
|
106
106
|
result = self.result_class(:permerror).new([self, request, e.message])
|
107
107
|
end
|
@@ -253,7 +253,7 @@ class SPF::Server
|
|
253
253
|
klass = RECORD_CLASSES_BY_VERSION[version]
|
254
254
|
begin
|
255
255
|
record = klass.new_from_string(text, {:raise_exceptions => @raise_exceptions})
|
256
|
-
rescue SPF::InvalidRecordVersionError
|
256
|
+
rescue SPF::InvalidRecordVersionError => error
|
257
257
|
# Ignore non-SPF and unknown-version records.
|
258
258
|
# Propagate other errors (including syntax errors), though.
|
259
259
|
end
|
data/lib/spf/model.rb
CHANGED
@@ -94,11 +94,12 @@ class SPF::Term
|
|
94
94
|
@ipv6_prefix_length = nil
|
95
95
|
@errors = []
|
96
96
|
@ip_netblocks = []
|
97
|
+
@raise_exceptions = options.has_key?(:raise_exceptions) ? options[:raise_exceptions] : true
|
97
98
|
end
|
98
99
|
|
99
100
|
def error(exception)
|
101
|
+
raise exception if @raise_exceptions
|
100
102
|
@errors << exception
|
101
|
-
raise exception
|
102
103
|
end
|
103
104
|
|
104
105
|
def self.new_from_string(text, options = {})
|
@@ -115,8 +116,8 @@ class SPF::Term
|
|
115
116
|
domain_spec.sub!(/^(.*?)\.?$/, $1)
|
116
117
|
@domain_spec = SPF::MacroString.new({:text => domain_spec})
|
117
118
|
elsif required
|
118
|
-
|
119
|
-
"Missing required domain-spec in '#{@text}'")
|
119
|
+
error(SPF::TermDomainSpecExpectedError.new(
|
120
|
+
"Missing required domain-spec in '#{@text}'"))
|
120
121
|
end
|
121
122
|
end
|
122
123
|
|
@@ -124,8 +125,8 @@ class SPF::Term
|
|
124
125
|
if @parse_text.sub!(/^(#{IPV4_ADDRESS_PATTERN})/x, '')
|
125
126
|
@ip_address = $1
|
126
127
|
elsif required
|
127
|
-
|
128
|
-
"Missing required IPv4 address in '#{@text}'")
|
128
|
+
error(SPF::TermIPv4AddressExpectedError.new(
|
129
|
+
"Missing or invalid required IPv4 address in '#{@text}'"))
|
129
130
|
end
|
130
131
|
end
|
131
132
|
|
@@ -133,13 +134,15 @@ class SPF::Term
|
|
133
134
|
if @parse_text.sub!(/^\/(\d+)/, '')
|
134
135
|
bits = $1.to_i
|
135
136
|
unless bits and bits >= 0 and bits <= 32 and $1 !~ /^0./
|
136
|
-
|
137
|
-
"Invalid IPv4 prefix length encountered in '#{@text}'")
|
137
|
+
error(SPF::TermIPv4PrefixLengthExpected.new(
|
138
|
+
"Invalid IPv4 prefix length encountered in '#{@text}'"))
|
139
|
+
return
|
138
140
|
end
|
139
141
|
@ipv4_prefix_length = bits
|
140
142
|
elsif required
|
141
|
-
|
142
|
-
"Missing required IPv4 prefix length in '#{@text}")
|
143
|
+
error(SPF::TermIPv4PrefixLengthExpected.new(
|
144
|
+
"Missing required IPv4 prefix length in '#{@text}"))
|
145
|
+
return
|
143
146
|
else
|
144
147
|
@ipv4_prefix_length = self.default_ipv4_prefix_length
|
145
148
|
end
|
@@ -148,15 +151,15 @@ class SPF::Term
|
|
148
151
|
def parse_ipv4_network(required = false)
|
149
152
|
self.parse_ipv4_address(required)
|
150
153
|
self.parse_ipv4_prefix_length
|
151
|
-
@ip_network = IP.new("#{@ip_address}/#{@ipv4_prefix_length}")
|
154
|
+
@ip_network = IP.new("#{@ip_address}/#{@ipv4_prefix_length}") if @ip_address and @ipv4_prefix_length
|
152
155
|
end
|
153
156
|
|
154
157
|
def parse_ipv6_address(required = false)
|
155
158
|
if @parse_text.sub!(/(#{IPV6_ADDRESS_PATTERN})(?=\/|$)/x, '')
|
156
159
|
@ip_address = $1
|
157
160
|
elsif required
|
158
|
-
|
159
|
-
"Missing required IPv6 address in '#{@text}'")
|
161
|
+
error(SPF::TermIPv6AddressExpected.new(
|
162
|
+
"Missing required IPv6 address in '#{@text}'"))
|
160
163
|
end
|
161
164
|
end
|
162
165
|
|
@@ -164,13 +167,15 @@ class SPF::Term
|
|
164
167
|
if @parse_text.sub!(/^\/(\d+)/, '')
|
165
168
|
bits = $1.to_i
|
166
169
|
unless bits and bits >= 0 and bits <= 128 and $1 !~ /^0./
|
167
|
-
|
168
|
-
"Invalid IPv6 prefix length encountered in '#{@text}'")
|
170
|
+
error(SPF::TermIPv6PrefixLengthExpectedError.new(
|
171
|
+
"Invalid IPv6 prefix length encountered in '#{@text}'"))
|
172
|
+
return
|
169
173
|
end
|
170
174
|
@ipv6_prefix_length = bits
|
171
175
|
elsif required
|
172
|
-
|
173
|
-
"Missing required IPv6 prefix length in '#{@text}'")
|
176
|
+
error(SPF::TermIPvPrefixLengthExpected.new(
|
177
|
+
"Missing required IPv6 prefix length in '#{@text}'"))
|
178
|
+
return
|
174
179
|
else
|
175
180
|
@ipv6_prefix_length = self.default_ipv6_prefix_length
|
176
181
|
end
|
@@ -179,7 +184,7 @@ class SPF::Term
|
|
179
184
|
def parse_ipv6_network(required = false)
|
180
185
|
self.parse_ipv6_address(required)
|
181
186
|
self.parse_ipv6_prefix_length
|
182
|
-
@ip_network = IP.new("#{@ip_address}/#{@ipv6_prefix_length}")
|
187
|
+
@ip_network = IP.new("#{@ip_address}/#{@ipv6_prefix_length}") if @ip_address and @ipv6_prefix_length
|
183
188
|
end
|
184
189
|
|
185
190
|
def parse_ipv4_ipv6_prefix_lengths
|
@@ -205,7 +210,9 @@ class SPF::Term
|
|
205
210
|
raise SPF::NoUnparsedTextError
|
206
211
|
end
|
207
212
|
end
|
213
|
+
end
|
208
214
|
|
215
|
+
class SPF::UnknownTerm < SPF::Term
|
209
216
|
end
|
210
217
|
|
211
218
|
class SPF::Mech < SPF::Term
|
@@ -242,17 +249,17 @@ class SPF::Mech < SPF::Term
|
|
242
249
|
raise SPF::NothingToParseError.new('Nothing to parse for mechanism')
|
243
250
|
end
|
244
251
|
parse_qualifier
|
245
|
-
parse_name
|
246
|
-
parse_params
|
247
|
-
parse_end
|
252
|
+
parse_name if @errors.empty?
|
253
|
+
parse_params if @errors.empty?
|
254
|
+
parse_end if @errors.empty?
|
248
255
|
end
|
249
256
|
|
250
257
|
def parse_qualifier
|
251
258
|
if @parse_text.sub!(/(#{QUALIFIER_PATTERN})?/x, '')
|
252
259
|
@qualifier = $1 or DEFAULT_QUALIFIER
|
253
260
|
else
|
254
|
-
|
255
|
-
"Invalid qualifier encountered in '#{@text}'")
|
261
|
+
error(SPF::InvalidMechQualifierError.new(
|
262
|
+
"Invalid qualifier encountered in '#{@text}'"))
|
256
263
|
end
|
257
264
|
end
|
258
265
|
|
@@ -260,7 +267,7 @@ class SPF::Mech < SPF::Term
|
|
260
267
|
if @parse_text.sub!(/^ (#{NAME_PATTERN}) (?: : (?=.) )? /x, '')
|
261
268
|
@name = $1
|
262
269
|
else
|
263
|
-
|
270
|
+
error(SPF::InvalidMechError.new("Unexpected mechanism encountered in '#{@text}'"))
|
264
271
|
end
|
265
272
|
end
|
266
273
|
|
@@ -273,7 +280,7 @@ class SPF::Mech < SPF::Term
|
|
273
280
|
|
274
281
|
def parse_end
|
275
282
|
unless @parse_text == ''
|
276
|
-
|
283
|
+
error(SPF::JunkInTermError.new("Junk encountered in mechanism '#{@text}'"))
|
277
284
|
end
|
278
285
|
@parse_text = nil
|
279
286
|
end
|
@@ -432,6 +439,7 @@ class SPF::Mech < SPF::Term
|
|
432
439
|
end
|
433
440
|
|
434
441
|
def match(server, request, want_result = true)
|
442
|
+
return false unless @ip_network
|
435
443
|
ip_network_v6 = IP::V4 === @ip_network ?
|
436
444
|
SPF::Util.ipv4_address_to_ipv6(@ip_network) :
|
437
445
|
@ip_network
|
@@ -607,10 +615,10 @@ class SPF::Mod < SPF::Term
|
|
607
615
|
end
|
608
616
|
|
609
617
|
def parse
|
610
|
-
|
611
|
-
self.parse_name
|
612
|
-
self.parse_params(true)
|
613
|
-
self.parse_end
|
618
|
+
error(SPF::NothingToParseError('Nothing to parse for modifier')) unless @parse_text
|
619
|
+
self.parse_name if @errors.empty?
|
620
|
+
self.parse_params(true) if @errors.empty?
|
621
|
+
self.parse_end if @errors.empty?
|
614
622
|
end
|
615
623
|
|
616
624
|
def parse_name
|
@@ -618,8 +626,8 @@ class SPF::Mod < SPF::Term
|
|
618
626
|
if $1
|
619
627
|
@name = $1
|
620
628
|
else
|
621
|
-
|
622
|
-
"Unexpected modifier name encoutered in #{@text}")
|
629
|
+
error(SPF::InvalidModError.new(
|
630
|
+
"Unexpected modifier name encoutered in #{@text}"))
|
623
631
|
end
|
624
632
|
end
|
625
633
|
|
@@ -629,14 +637,14 @@ class SPF::Mod < SPF::Term
|
|
629
637
|
if $1
|
630
638
|
@params_text = $1
|
631
639
|
elsif required
|
632
|
-
|
633
|
-
"Invalid macro string encountered in #{@text}")
|
640
|
+
error(SPF::InvalidMacroStringError.new(
|
641
|
+
"Invalid macro string encountered in #{@text}"))
|
634
642
|
end
|
635
643
|
end
|
636
644
|
|
637
645
|
def parse_end
|
638
646
|
unless @parse_text == ''
|
639
|
-
|
647
|
+
error(SPF::JunkInTermError.new("Junk encountered in modifier #{@text}"))
|
640
648
|
end
|
641
649
|
@parse_text = nil
|
642
650
|
end
|
@@ -784,6 +792,11 @@ class SPF::Record
|
|
784
792
|
return record
|
785
793
|
end
|
786
794
|
|
795
|
+
def error(exception)
|
796
|
+
raise exception if @raise_exceptions
|
797
|
+
@errors << exception
|
798
|
+
end
|
799
|
+
|
787
800
|
def ip_netblocks
|
788
801
|
@ip_netblocks.flatten!
|
789
802
|
return @ip_netblocks
|
@@ -791,7 +804,8 @@ class SPF::Record
|
|
791
804
|
|
792
805
|
def parse
|
793
806
|
unless self.instance_variable_defined?(:@parse_text) and @parse_text
|
794
|
-
|
807
|
+
error(SPF::NothingToParseError.new('Nothing to parse for record'))
|
808
|
+
return
|
795
809
|
end
|
796
810
|
self.parse_version_tag
|
797
811
|
while @parse_text.length > 0
|
@@ -805,11 +819,9 @@ class SPF::Record
|
|
805
819
|
return if SPF::JunkInRecordError === e
|
806
820
|
end
|
807
821
|
end
|
808
|
-
#self.parse_end
|
809
822
|
end
|
810
823
|
|
811
824
|
def parse_version_tag
|
812
|
-
#@parse_text.sub!(self.version_tag_pattern, '')
|
813
825
|
@parse_text.sub!(/^#{self.version_tag_pattern}\s+/ix, '')
|
814
826
|
unless $1
|
815
827
|
raise SPF::InvalidRecordVersionError.new(
|
@@ -833,9 +845,16 @@ class SPF::Record
|
|
833
845
|
# Looks like a mechanism:
|
834
846
|
mech_text = $1
|
835
847
|
mech_name = $2.downcase
|
836
|
-
mech_class = self.mech_classes[mech_name.to_sym]
|
837
|
-
|
838
|
-
|
848
|
+
mech_class = self.mech_classes[mech_name.to_sym]
|
849
|
+
exception = nil
|
850
|
+
unless mech_class
|
851
|
+
exception = SPF::InvalidMech.new("Unknown mechanism type '#{mech_name}' in '#{@version_tag}' record")
|
852
|
+
error(exception)
|
853
|
+
mech_class = SPF::Mech
|
854
|
+
end
|
855
|
+
term = mech = mech_class.new_from_string(mech_text, {:raise_exceptions => @raise_exceptions})
|
856
|
+
term.errors << exception if exception
|
857
|
+
@ip_netblocks << mech.ip_netblocks if mech.ip_netblocks
|
839
858
|
@terms << mech
|
840
859
|
if mech_class == SPF::Mech
|
841
860
|
raise SPF::InvalidMechError.new("Unknown mechanism type '#{mech_name}' in '#{@version_tag}' record")
|
@@ -856,7 +875,7 @@ class SPF::Record
|
|
856
875
|
mod_class = self.class::MOD_CLASSES[mod_name.to_sym] || SPF::Mod
|
857
876
|
if mod_class
|
858
877
|
# Known modifier.
|
859
|
-
term = mod = mod_class.new_from_string(mod_text)
|
878
|
+
term = mod = mod_class.new_from_string(mod_text, {:raise_exceptions => @raise_exceptions})
|
860
879
|
if SPF::GlobalMod === mod
|
861
880
|
# Global modifier.
|
862
881
|
if @global_mods[mod_name]
|
@@ -872,6 +891,7 @@ class SPF::Record
|
|
872
891
|
else
|
873
892
|
raise SPF::JunkInRecordError.new("Junk encountered in record '#{@text}'")
|
874
893
|
end
|
894
|
+
@errors.concat(term.errors)
|
875
895
|
return term
|
876
896
|
end
|
877
897
|
|
@@ -910,7 +930,7 @@ class SPF::Record
|
|
910
930
|
# Term is an unknown modifier. Ignore it (RFC 4408, 6/3).
|
911
931
|
else
|
912
932
|
# Invalid term object encountered:
|
913
|
-
|
933
|
+
error(SPF::UnexpectedTermObjectError.new("Unexpected term object '#{term}' encountered."))
|
914
934
|
end
|
915
935
|
end
|
916
936
|
rescue SPF::Result => result
|
data/lib/spf/version.rb
CHANGED
data/spf.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.14
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -119,9 +119,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
119
119
|
- - ! '>='
|
120
120
|
- !ruby/object:Gem::Version
|
121
121
|
version: '0'
|
122
|
-
segments:
|
123
|
-
- 0
|
124
|
-
hash: -4387479351355747049
|
125
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
123
|
none: false
|
127
124
|
requirements:
|