Class: SPF::Term

Inherits:
Object
  • Object
show all
Defined in:
lib/spf/model.rb

Direct Known Subclasses

Mech, Mod, UnknownTerm

Constant Summary collapse

NAME_PATTERN =
'[[:alpha:]] [[:alnum:]\\-_\\.]*'
MACRO_LITERAL_PATTERN =
"[!-$&-~%]"
MACRO_DELIMITER =
"[\\.\\-+,\\/_=]"
MACRO_TRANSFORMERS_PATTERN =
"\\d*r?"
MACRO_EXPAND_PATTERN =
"
    %
    (?:
        { [[:alpha:]] } #{MACRO_TRANSFORMERS_PATTERN} #{MACRO_DELIMITER}* } |
        [%_-]
    )
"
MACRO_STRING_PATTERN =
"
    (?:
        #{MACRO_EXPAND_PATTERN}  |
        #{MACRO_LITERAL_PATTERN}
    )*
"
TOPLABEL_PATTERN =
"
    [[:alnum:]_-]+ - [[:alnum:]-]* [[:alnum:]] |
    [[:alnum:]]*   [[:alpha:]]   [[:alnum:]]*
"
DOMAIN_END_PATTERN =
"
  (?: \\. #{TOPLABEL_PATTERN} \\.? |
          #{MACRO_EXPAND_PATTERN}
  )
"
DOMAIN_SPEC_PATTERN =
" #{MACRO_STRING_PATTERN} #{DOMAIN_END_PATTERN} "
QNUM_PATTERN =
" (?: 25[0-5] | 2[0-4]\\d | 1\\d\\d | [1-9]\\d | \\d ) "
IPV4_ADDRESS_PATTERN =
" #{QNUM_PATTERN} (?: \\. #{QNUM_PATTERN}){3} "
HEXWORD_PATTERN =
"[[:xdigit:]]{1,4}"
TWO_HEXWORDS_OR_IPV4_ADDRESS_PATTERN =
/
    #{HEXWORD_PATTERN} : #{HEXWORD_PATTERN} | #{IPV4_ADDRESS_PATTERN}
/x
IPV6_ADDRESS_PATTERN =
"
  #                x:x:x:x:x:x:x:x |     x:x:x:x:x:x:n.n.n.n
  (?: #{HEXWORD_PATTERN} : ){6}                                   #{TWO_HEXWORDS_OR_IPV4_ADDRESS_PATTERN} |
  #                 x::x:x:x:x:x:x |      x::x:x:x:x:n.n.n.n
  (?: #{HEXWORD_PATTERN} : ){1}   : (?: #{HEXWORD_PATTERN} : ){4} #{TWO_HEXWORDS_OR_IPV4_ADDRESS_PATTERN} |
  #               x[:x]::x:x:x:x:x |    x[:x]::x:x:x:n.n.n.n
  (?: #{HEXWORD_PATTERN} : ){1,2} : (?: #{HEXWORD_PATTERN} : ){3} #{TWO_HEXWORDS_OR_IPV4_ADDRESS_PATTERN} |
  #               x[:...]::x:x:x:x |    x[:...]::x:x:n.n.n.n
  (?: #{HEXWORD_PATTERN} : ){1,3} : (?: #{HEXWORD_PATTERN} : ){2} #{TWO_HEXWORDS_OR_IPV4_ADDRESS_PATTERN} |
  #                 x[:...]::x:x:x |      x[:...]::x:n.n.n.n
  (?: #{HEXWORD_PATTERN} : ){1,4} : (?: #{HEXWORD_PATTERN} : ){1} #{TWO_HEXWORDS_OR_IPV4_ADDRESS_PATTERN} |
  #                   x[:...]::x:x |        x[:...]::n.n.n.n
  (?: #{HEXWORD_PATTERN} : ){1,5} :                               #{TWO_HEXWORDS_OR_IPV4_ADDRESS_PATTERN} |
  #                     x[:...]::x |                       -
  (?: #{HEXWORD_PATTERN} : ){1,6} :     #{HEXWORD_PATTERN}                                                |
  #                      x[:...]:: |
  (?: #{HEXWORD_PATTERN} : ){1,7} :                                                                       |
  #                      ::[...:]x |                       -
 :: (?: #{HEXWORD_PATTERN} : ){0,6}       #{HEXWORD_PATTERN}                                                |
  #                              - |         ::[...:]n.n.n.n
 :: (?: #{HEXWORD_PATTERN} : ){0,5}                                 #{TWO_HEXWORDS_OR_IPV4_ADDRESS_PATTERN} |
  #                             :: |                       -
 ::
"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Term

Returns a new instance of Term.



91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/spf/model.rb', line 91

def initialize(options = {})
  @ip_address         = nil
  @ip_network         = nil
  @ipv4_prefix_length = nil
  @ipv6_prefix_length = nil
  @raw_params         = nil
  @errors             = []
  @ip_netblocks       = []
  @text               = options[:text]
  @record_domain      = options[:record_domain]
  @raise_exceptions   = options.has_key?(:raise_exceptions) ? options[:raise_exceptions] : true
end

Instance Attribute Details

#domain_specObject (readonly)

Returns the value of attribute domain_spec.



89
90
91
# File 'lib/spf/model.rb', line 89

def domain_spec
  @domain_spec
end

#errorsObject (readonly)

Returns the value of attribute errors.



89
90
91
# File 'lib/spf/model.rb', line 89

def errors
  @errors
end

#ip_addressObject (readonly)

Returns the value of attribute ip_address.



89
90
91
# File 'lib/spf/model.rb', line 89

def ip_address
  @ip_address
end

#ip_netblocksObject (readonly)

Returns the value of attribute ip_netblocks.



89
90
91
# File 'lib/spf/model.rb', line 89

def ip_netblocks
  @ip_netblocks
end

#ip_networkObject (readonly)

Returns the value of attribute ip_network.



89
90
91
# File 'lib/spf/model.rb', line 89

def ip_network
  @ip_network
end

#ipv4_prefix_lengthObject (readonly)

Returns the value of attribute ipv4_prefix_length.



89
90
91
# File 'lib/spf/model.rb', line 89

def ipv4_prefix_length
  @ipv4_prefix_length
end

#ipv6_prefix_lengthObject (readonly)

Returns the value of attribute ipv6_prefix_length.



89
90
91
# File 'lib/spf/model.rb', line 89

def ipv6_prefix_length
  @ipv6_prefix_length
end

#raw_paramsObject (readonly)

Returns the value of attribute raw_params.



89
90
91
# File 'lib/spf/model.rb', line 89

def raw_params
  @raw_params
end

#record_domainObject (readonly)

Returns the value of attribute record_domain.



89
90
91
# File 'lib/spf/model.rb', line 89

def record_domain
  @record_domain
end

Class Method Details

.new_from_string(text, options = {}) ⇒ Object



109
110
111
112
113
114
# File 'lib/spf/model.rb', line 109

def self.new_from_string(text, options = {})
  options[:text] = text
  term = self.new(options)
  term.parse
  return term
end

Instance Method Details

#domain(server, request) ⇒ Object



218
219
220
221
222
223
# File 'lib/spf/model.rb', line 218

def domain(server, request)
  if self.instance_variable_defined?(:@domain_spec) and @domain_spec
    return SPF::MacroString.new({:server => server, :request => request, :text => @domain_spec.text})
  end
  return request.authority_domain
end

#error(exception) ⇒ Object



104
105
106
107
# File 'lib/spf/model.rb', line 104

def error(exception)
  raise exception if @raise_exceptions
  @errors << exception
end

#parse_domain_spec(required = false) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/spf/model.rb', line 116

def parse_domain_spec(required = false)
  if @parse_text.sub!(/^(#{DOMAIN_SPEC_PATTERN})/x, '')
    domain_spec = $1
    domain_spec.sub!(/^(.*?)\.?$/, $1)
    @domain_spec = SPF::MacroString.new({:text => domain_spec})
  elsif record_domain
    @domain_spec = SPF::MacroString.new({:text => record_domain})
  elsif required
    error(SPF::TermDomainSpecExpectedError.new(
      "Missing required domain-spec in '#{@text}'"))
  end
end

#parse_ipv4_address(required = false) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
# File 'lib/spf/model.rb', line 129

def parse_ipv4_address(required = false)
  @raw_params = @parse_text.dup
  if @parse_text.sub!(/^(#{IPV4_ADDRESS_PATTERN})/x, '')
    @ip_address = $1
  elsif required
    error(SPF::TermIPv4AddressExpectedError.new(
      "Missing or invalid required IPv4 address in '#{@text}'"))
  end
  @ip_address = @parse_text.dup unless @ip_address

end

#parse_ipv4_ipv6_prefix_lengthsObject



209
210
211
212
213
214
215
216
# File 'lib/spf/model.rb', line 209

def parse_ipv4_ipv6_prefix_lengths
  self.parse_ipv4_prefix_length
  if self.instance_variable_defined?(:@ipv4_prefix_length) and # An IPv4 prefix length has been parsed, and
    @parse_text.sub!(/^\//, '')                           # another slash is following.
    # Parse an IPv6 prefix length:
    self.parse_ipv6_prefix_length(true)
  end
end

#parse_ipv4_network(required = false) ⇒ Object



159
160
161
162
163
164
165
166
167
168
# File 'lib/spf/model.rb', line 159

def parse_ipv4_network(required = false)
  @raw_params = @parse_text.dup
  self.parse_ipv4_address(required)
  self.parse_ipv4_prefix_length
  begin
    @ip_network = IP.new("#{@ip_address}/#{@ipv4_prefix_length}") if @ip_address and @ipv4_prefix_length
  rescue ArgumentError
    @ip_network = @ip_address
  end
end

#parse_ipv4_prefix_length(required = false) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/spf/model.rb', line 141

def parse_ipv4_prefix_length(required = false)
  if @parse_text.sub!(/^\/(\d+)/, '')
    bits = $1.to_i
    unless bits and bits >= 0 and bits <= 32 and $1 !~ /^0./
      error(SPF::TermIPv4PrefixLengthExpectedError.new(
        "Invalid IPv4 prefix length encountered in '#{@text}'"))
      return
    end
    @ipv4_prefix_length = bits
  elsif required
    error(SPF::TermIPv4PrefixLengthExpectedError.new(
      "Missing required IPv4 prefix length in '#{@text}"))
    return
  else
    @ipv4_prefix_length = self.default_ipv4_prefix_length
  end
end

#parse_ipv6_address(required = false) ⇒ Object



170
171
172
173
174
175
176
177
178
# File 'lib/spf/model.rb', line 170

def parse_ipv6_address(required = false)
  if @parse_text.sub!(/(#{IPV6_ADDRESS_PATTERN})(?=\/|$)/x, '')
    @ip_address = $1
  elsif required
    error(SPF::TermIPv6AddressExpectedError.new(
      "Missing or invalid required IPv6 address in '#{@text}'"))
  end
  @ip_address = @parse_text.dup unless @ip_address
end

#parse_ipv6_network(required = false) ⇒ Object



198
199
200
201
202
203
204
205
206
207
# File 'lib/spf/model.rb', line 198

def parse_ipv6_network(required = false)
  @raw_params = @parse_text.dup
  self.parse_ipv6_address(required)
  self.parse_ipv6_prefix_length
  begin
    @ip_network = IP.new("#{@ip_address}/#{@ipv6_prefix_length}") if @ip_address and @ipv6_prefix_length
  rescue ArgumentError
    @ip_network = @ip_address
  end
end

#parse_ipv6_prefix_length(required = false) ⇒ Object



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/spf/model.rb', line 180

def parse_ipv6_prefix_length(required = false)
  if @parse_text.sub!(/^\/(\d+)/, '')
    bits = $1.to_i
    unless bits and bits >= 0 and bits <= 128 and $1 !~ /^0./
      error(SPF::TermIPv6PrefixLengthExpectedError.new(
        "Invalid IPv6 prefix length encountered in '#{@text}'"))
      return
    end
    @ipv6_prefix_length = bits
  elsif required
    error(SPF::TermIPv6PrefixLengthExpectedError.new(
      "Missing required IPv6 prefix length in '#{@text}'"))
    return
  else
    @ipv6_prefix_length = self.default_ipv6_prefix_length
  end
end

#textObject



225
226
227
228
229
230
231
# File 'lib/spf/model.rb', line 225

def text
  if self.instance_variable_defined?(:@text)
    return @text
  else
    raise SPF::NoUnparsedTextError
  end
end