whois 4.0.0.pre.beta2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # An intelligent pure Ruby WHOIS client and parser.
5
5
  #
6
- # Copyright (c) 2009-2015 Simone Carletti <weppos@weppos.net>
6
+ # Copyright (c) 2009-2016 Simone Carletti <weppos@weppos.net>
7
7
  #++
8
8
 
9
9
 
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # An intelligent pure Ruby WHOIS client and parser.
5
5
  #
6
- # Copyright (c) 2009-2015 Simone Carletti <weppos@weppos.net>
6
+ # Copyright (c) 2009-2016 Simone Carletti <weppos@weppos.net>
7
7
  #++
8
8
 
9
9
 
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # An intelligent pure Ruby WHOIS client and parser.
5
5
  #
6
- # Copyright (c) 2009-2015 Simone Carletti <weppos@weppos.net>
6
+ # Copyright (c) 2009-2016 Simone Carletti <weppos@weppos.net>
7
7
  #++
8
8
 
9
9
 
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # An intelligent pure Ruby WHOIS client and parser.
5
5
  #
6
- # Copyright (c) 2009-2015 Simone Carletti <weppos@weppos.net>
6
+ # Copyright (c) 2009-2016 Simone Carletti <weppos@weppos.net>
7
7
  #++
8
8
 
9
9
 
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # An intelligent pure Ruby WHOIS client and parser.
5
5
  #
6
- # Copyright (c) 2009-2015 Simone Carletti <weppos@weppos.net>
6
+ # Copyright (c) 2009-2016 Simone Carletti <weppos@weppos.net>
7
7
  #++
8
8
 
9
9
 
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # An intelligent pure Ruby WHOIS client and parser.
5
5
  #
6
- # Copyright (c) 2009-2015 Simone Carletti <weppos@weppos.net>
6
+ # Copyright (c) 2009-2016 Simone Carletti <weppos@weppos.net>
7
7
  #++
8
8
 
9
9
 
@@ -37,294 +37,347 @@ module Whois
37
37
  autoload :Web, "whois/server/adapters/web"
38
38
  end
39
39
 
40
+ # @return [Array<Symbol>] the definition types
41
+ TYPES = [
42
+ TYPE_TLD = :tld,
43
+ TYPE_IPV4 = :ipv4,
44
+ TYPE_IPV6 = :ipv6,
45
+ TYPE_ASN16 = :asn16,
46
+ TYPE_ASN32 = :asn32,
47
+ ].freeze
48
+
49
+ class << self
50
+
51
+ # Clears the definition and reset them to an empty list.
52
+ #
53
+ # @return [void]
54
+ def clear_definitions
55
+ @definitions = {}
56
+ end
40
57
 
41
- # The WHOIS server definitions.
42
- #
43
- # @return [{ Symbol => Array }] The definition Hash.
44
- # @private
45
- @@definitions = {}
58
+ # Searches the +/definitions+ folder for definition files and loads them.
59
+ # This method is automatically invoked when this file is parsed
60
+ # by the Ruby interpreter (scroll down to the bottom of this file).
61
+ #
62
+ # @return [void]
63
+ def load_definitions
64
+ clear_definitions
65
+ Dir[File.expand_path("../../../data/*.json", __FILE__)].each { |f| load_json(f) }
66
+ end
67
+
68
+ # Loads the definitions from a JSON file.
69
+ #
70
+ # @param [String] file The path to the definition file.
71
+ #
72
+ # @return [void]
73
+ def load_json(file)
74
+ type = File.basename(file, File.extname(file)).to_sym
75
+ JSON.load(File.read(file)).each do |allocation, settings|
76
+ next if allocation == "_"
77
+ settings.reject! { |k, _| k.start_with?("_") }
78
+ define(type, allocation, settings.delete("host"), Hash[settings.map { |k,v| [k.to_sym, v] }])
79
+ end
80
+ end
46
81
 
47
- # Searches the +/definitions+ folder for definition files and loads them.
48
- # This method is automatically invoked when this file is parsed
49
- # by the Ruby interpreter (scroll down to the bottom of this file).
50
- #
51
- # @return [void]
52
- def self.load_definitions
53
- Dir[File.expand_path("../../../data/*.json", __FILE__)].each { |f| load_json(f) }
54
- end
55
82
 
56
- # Loads the definitions from a JSON file.
57
- #
58
- # @param [String] file The path to the definition file.
59
- #
60
- # @return [void]
61
- def self.load_json(file)
62
- type = File.basename(file, File.extname(file)).to_sym
63
- JSON.load(File.read(file)).each do |allocation, settings|
64
- define(type, allocation, settings.delete("host"), Hash[settings.map { |k,v| [k.to_sym, v] }])
83
+ # Lookup and returns the definition list for given `type`.
84
+ #
85
+ # @param [Symbol] type The type of WHOIS server to lookup.
86
+ # See Whois::Server::TYPES for valid types.
87
+ #
88
+ # @return [{ Symbol => Array }]
89
+ # The definition Hash if +type+ is +nil+.
90
+ # @return [Array<Hash>]
91
+ # The definitions for given +type+ if +type+ is not +nil+ and +type+ exists.
92
+ #
93
+ # @example Return the definitions for given key.
94
+ #
95
+ # Whois::Server.definitions(:tld)
96
+ # # => [...]
97
+ #
98
+ # Whois::Server.definitions(:invalid)
99
+ # # => nil
100
+ #
101
+ def definitions(type)
102
+ TYPES.include?(type) or
103
+ raise(ArgumentError, "`#{type}` is not a valid definition type")
104
+
105
+ _definitions(type).values
65
106
  end
66
- end
67
107
 
108
+ # Defines a new server for <tt>:type</tt> queries.
109
+ #
110
+ # @param [Symbol] type
111
+ # The type of WHOIS server to define.
112
+ # Known values are :tld, :ipv4, :ipv6.
113
+ # @param [String] allocation
114
+ # The allocation, range or hostname, this server is responsible for.
115
+ # @param [String, nil] host
116
+ # The server hostname. Use nil if unknown or not available.
117
+ # @param [Hash] options Optional definition properties.
118
+ # @option options [Class] :adapter (Whois::Server::Adapters::Standard)
119
+ # This option has a special meaning and determines the adapter Class to use.
120
+ # Defaults to {Whois::Server::Adapters::Standard} unless specified.
121
+ # All the other options are passed directly to the adapter which can decide how to use them.
122
+ #
123
+ # @return [void]
124
+ #
125
+ # @example
126
+ #
127
+ # # Define a server for the .it extension
128
+ # Whois::Server.define :tld, "it", "whois.nic.it"
129
+ #
130
+ # # Define a new server for an range of IPv4 addresses
131
+ # Whois::Server.define :ipv4, "61.192.0.0/12", "whois.nic.ad.jp"
132
+ #
133
+ # # Define a new server for an range of IPv6 addresses
134
+ # Whois::Server.define :ipv6, "2001:2000::/19", "whois.ripe.net"
135
+ #
136
+ # # Define a new server with a custom adapter
137
+ # Whois::Server.define :tld, "test", nil,
138
+ # :adapter => Whois::Server::Adapter::None
139
+ #
140
+ # # Define a new server with a custom adapter and options
141
+ # Whois::Server.define :tld, "ar", nil,
142
+ # :adapter => Whois::Server::Adapters::Web,
143
+ # :url => "http://www.nic.ar/"
144
+ #
145
+ def define(type, allocation, host, options = {})
146
+ TYPES.include?(type) or
147
+ raise(ArgumentError, "`#{type}` is not a valid definition type")
148
+
149
+ _definitions(type)[allocation] = [allocation, host, options]
150
+ end
68
151
 
69
- # Lookup and returns the definition list for given <tt>type</tt>,
70
- # or all definitions if <tt>type</tt> is <tt>nil</tt>.
71
- #
72
- # @param [Symbol] type The type of WHOIS server to lookup.
73
- # Known values are :tld, :ipv4, :ipv6.
74
- #
75
- # @return [{ Symbol => Array }]
76
- # The definition Hash if +type+ is +nil+.
77
- # @return [Array<Hash>]
78
- # The definitions for given +type+ if +type+ is not +nil+ and +type+ exists.
79
- # @return [nil]
80
- # The definitions for given +type+ if +type+ is not +nil+ and +type+ doesn't exist.
81
- #
82
- # @example Return the definition database.
83
- #
84
- # Whois::Server.definitions
85
- # # => { :tld => [...], :ipv4 => [], ... }
86
- #
87
- # @example Return the definitions for given key.
88
- #
89
- # Whois::Server.definitions(:tld)
90
- # # => [...]
91
- #
92
- # Whois::Server.definitions(:invalid)
93
- # # => nil
94
- #
95
- def self.definitions(type = nil)
96
- if type.nil?
97
- @@definitions
98
- else
99
- @@definitions[type]
152
+ # Creates a new server adapter from given arguments
153
+ # and returns the server instance.
154
+ #
155
+ # By default, returns a new {Whois::Server::Adapters::Standard} instance.
156
+ # You can customize the behavior passing a custom adapter class
157
+ # as <tt>:adapter</tt> option.
158
+ #
159
+ # Whois::Server.factory :tld, "it", "whois.nic.it"
160
+ # # => #<Whois::Servers::Adapter::Standard>
161
+ #
162
+ # Whois::Server.factory :tld, "it", "whois.nic.it",
163
+ # :option => Whois::Servers::Adapter::Custom
164
+ # # => #<Whois::Servers::Adapter::Custom>
165
+ #
166
+ # Please note that any adapter is responsible for a limited set
167
+ # of queries, which should be included in the range of the <tt>allocation</tt> parameter.
168
+ # Use {Whois::Server.guess} if you are not sure which adapter
169
+ # is the right one for a specific string.
170
+ #
171
+ # @param [Symbol] type
172
+ # The type of WHOIS server to define.
173
+ # Known values are :tld, :ipv4, :ipv6.
174
+ # @param [String] allocation
175
+ # The allocation, range or hostname, this server is responsible for.
176
+ # @param [String, nil] host
177
+ # The server hostname. Use nil if unknown or not available.
178
+ # @param [Hash] options Optional definition properties.
179
+ # @option options [Class] :adapter (Whois::Server::Adapters::Standard)
180
+ # This option has a special meaning and determines the adapter Class to use.
181
+ # Defaults to {Whois::Server::Adapters::Standard} unless specified.
182
+ # All the other options are passed directly to the adapter which can decide how to use them.
183
+ #
184
+ # @return [Whois::Server::Adapters::Base]
185
+ # a server adapter that can be used to perform queries.
186
+ def factory(type, allocation, host, options = {})
187
+ options = options.dup
188
+ adapter = options.delete(:adapter) || Adapters::Standard
189
+ adapter = Adapters.const_get(camelize(adapter)) unless adapter.respond_to?(:new)
190
+ adapter.new(type, allocation, host, options)
100
191
  end
101
- end
102
192
 
103
- # Defines a new server for <tt>:type</tt> queries.
104
- #
105
- # @param [Symbol] type
106
- # The type of WHOIS server to define.
107
- # Known values are :tld, :ipv4, :ipv6.
108
- # @param [String] allocation
109
- # The allocation, range or hostname, this server is responsible for.
110
- # @param [String, nil] host
111
- # The server hostname. Use nil if unknown or not available.
112
- # @param [Hash] options Optional definition properties.
113
- # @option options [Class] :adapter (Whois::Server::Adapters::Standard)
114
- # This option has a special meaning and determines the adapter Class to use.
115
- # Defaults to {Whois::Server::Adapters::Standard} unless specified.
116
- # All the other options are passed directly to the adapter which can decide how to use them.
117
- #
118
- # @return [void]
119
- #
120
- # @example
121
- #
122
- # # Define a server for the .it extension
123
- # Whois::Server.define :tld, ".it", "whois.nic.it"
124
- #
125
- # # Define a new server for an range of IPv4 addresses
126
- # Whois::Server.define :ipv4, "61.192.0.0/12", "whois.nic.ad.jp"
127
- #
128
- # # Define a new server for an range of IPv6 addresses
129
- # Whois::Server.define :ipv6, "2001:2000::/19", "whois.ripe.net"
130
- #
131
- # # Define a new server with a custom adapter
132
- # Whois::Server.define :tld, ".test", nil,
133
- # :adapter => Whois::Server::Adapter::None
134
- #
135
- # # Define a new server with a custom adapter and options
136
- # Whois::Server.define :tld, ".ar", nil,
137
- # :adapter => Whois::Server::Adapters::Web,
138
- # :url => "http://www.nic.ar/"
139
- #
140
- def self.define(type, allocation, host, options = {})
141
- @@definitions[type] ||= []
142
- @@definitions[type] << [allocation, host, options]
143
- end
144
193
 
145
- # Creates a new server adapter from given arguments
146
- # and returns the server instance.
147
- #
148
- # By default, returns a new {Whois::Server::Adapters::Standard} instance.
149
- # You can customize the behavior passing a custom adapter class
150
- # as <tt>:adapter</tt> option.
151
- #
152
- # Whois::Server.factory :tld, ".it", "whois.nic.it"
153
- # # => #<Whois::Servers::Adapter::Standard>
154
- #
155
- # Whois::Server.factory :tld, ".it", "whois.nic.it",
156
- # :option => Whois::Servers::Adapter::Custom
157
- # # => #<Whois::Servers::Adapter::Custom>
158
- #
159
- # Please note that any adapter is responsible for a limited set
160
- # of queries, which should be included in the range of the <tt>allocation</tt> parameter.
161
- # Use {Whois::Server.guess} if you are not sure which adapter
162
- # is the right one for a specific string.
163
- #
164
- # @param [Symbol] type
165
- # The type of WHOIS server to define.
166
- # Known values are :tld, :ipv4, :ipv6.
167
- # @param [String] allocation
168
- # The allocation, range or hostname, this server is responsible for.
169
- # @param [String, nil] host
170
- # The server hostname. Use nil if unknown or not available.
171
- # @param [Hash] options Optional definition properties.
172
- # @option options [Class] :adapter (Whois::Server::Adapters::Standard)
173
- # This option has a special meaning and determines the adapter Class to use.
174
- # Defaults to {Whois::Server::Adapters::Standard} unless specified.
175
- # All the other options are passed directly to the adapter which can decide how to use them.
176
- #
177
- # @return [Whois::Server::Adapters::Standard]
178
- # An adapter that can be used to perform queries.
179
- #
180
- def self.factory(type, allocation, host, options = {})
181
- options = options.dup
182
- adapter = options.delete(:adapter) || Adapters::Standard
183
- adapter = Adapters.const_get(camelize(adapter)) unless adapter.respond_to?(:new)
184
- adapter.new(type, allocation, host, options)
185
- end
194
+ # Parses <tt>string</tt> and tries to guess the right server.
195
+ #
196
+ # It successfully detects the following query types:
197
+ # * ipv6
198
+ # * ipv4
199
+ # * top level domains (e.g. .com, .net, .it)
200
+ # * domain names (e.g. google.com, google.net, google.it)
201
+ # * emails
202
+ #
203
+ # Note that not all query types actually have a corresponding adapter.
204
+ # For instance, the following request will result in a
205
+ # {Whois::ServerNotSupported} exception.
206
+ #
207
+ # Whois::Server.guess "mail@example.com"
208
+ #
209
+ #
210
+ # @param string [String]
211
+ # @return [Whois::Server::Adapters::Base]
212
+ # a server adapter that can be used to perform queries.
213
+ #
214
+ # @raise [Whois::AllocationUnknown]
215
+ # when the input is an IP, but the IP doesn't have a specific known allocation
216
+ # that matches one of the existing server definitions.
217
+ # @raise [Whois::ServerNotFound]
218
+ # when unable to find an appropriate WHOIS adapter. In most of the cases, the input
219
+ # is not recognised as one of the supported query types.
220
+ # @raise [Whois::ServerNotSupported]
221
+ # when the string type is detected,
222
+ # but the object type doesn't have any supported WHOIS adapter associated.
223
+ def guess(string)
224
+ # Top Level Domain match
225
+ if matches_tld?(string)
226
+ return factory(:tld, ".", "whois.iana.org")
227
+ end
186
228
 
229
+ # IP address (secure match)
230
+ if matches_ip?(string)
231
+ return find_for_ip(string)
232
+ end
187
233
 
188
- # Parses <tt>string</tt> and tries to guess the right server.
189
- #
190
- # It successfully detects the following query types:
191
- # * ipv6
192
- # * ipv4
193
- # * top level domains (e.g. .com, .net, .it)
194
- # * domain names (e.g. google.com, google.net, google.it)
195
- # * emails
196
- #
197
- # Note that not all query types actually have a corresponding adapter.
198
- # For instance, the following request will result in a
199
- # {Whois::ServerNotSupported} exception.
200
- #
201
- # Whois::Server.guess "mail@example.com"
202
- #
203
- #
204
- # @param [String] string
205
- # @return [Whois::Server::Adapters::Base]
206
- # The adapter that can be used to perform
207
- # WHOIS queries for <tt>string</tt>.
208
- #
209
- # @raise [Whois::ServerNotFound]
210
- # When unable to find an appropriate WHOIS adapter
211
- # for <tt>string</tt>. Most of the cases, the <tt>string</tt>
212
- # haven't been recognised as one of the supported query types.
213
- # @raise [Whois::ServerNotSupported]
214
- # When the <tt>string</tt> type is detected,
215
- # but the object type doesn't have any supported WHOIS adapter associated.
216
- #
217
- def self.guess(string)
218
- # Top Level Domain match
219
- if matches_tld?(string)
220
- return factory(:tld, ".", "whois.iana.org")
221
- end
234
+ # Email Address (secure match)
235
+ if matches_email?(string)
236
+ return find_for_email(string)
237
+ end
222
238
 
223
- # IP address (secure match)
224
- if matches_ip?(string)
225
- return find_for_ip(string)
226
- end
239
+ # Domain Name match
240
+ if (server = find_for_domain(string))
241
+ return server
242
+ end
243
+
244
+ # ASN match
245
+ if matches_asn?(string)
246
+ return find_for_asn(string)
247
+ end
227
248
 
228
- # Email Address (secure match)
229
- if matches_email?(string)
230
- return find_for_email(string)
249
+ # Game Over
250
+ raise ServerNotFound, "Unable to find a WHOIS server for `#{string}'"
231
251
  end
232
252
 
233
- # Domain Name match
234
- if server = find_for_domain(string)
235
- return server
253
+
254
+ # Searches for definition that matches given IP.
255
+ #
256
+ # @param string [String]
257
+ # @return [Whois::Server::Adapters::Base, nil]
258
+ # a server adapter that can be used to perform queries.
259
+ # @raise [Whois::AllocationUnknown]
260
+ # when the IP doesn't have a specific known allocation
261
+ # that matches one of the existing server definitions.
262
+ def find_for_ip(string)
263
+ begin
264
+ ip = IPAddr.new(string)
265
+ type = ip.ipv4? ? TYPE_IPV4 : TYPE_IPV6
266
+ _definitions(type).each do |_, definition|
267
+ if IPAddr.new(definition.first).include?(ip)
268
+ return factory(type, *definition)
269
+ end
270
+ end
271
+ rescue ArgumentError
272
+ # continue
273
+ end
274
+ raise AllocationUnknown, "IP Allocation for `#{string}' unknown"
236
275
  end
237
276
 
238
- # ASN match
239
- if matches_asn?(string)
240
- return find_for_asn(string)
277
+ # Searches for definition that matches given email.
278
+ #
279
+ # @param string [String]
280
+ # @raise [Whois::ServerNotSupported]
281
+ # emails are not supported.
282
+ def find_for_email(string)
283
+ raise ServerNotSupported, "No WHOIS server is known for email objects"
241
284
  end
242
285
 
243
- # Game Over
244
- raise ServerNotFound, "Unable to find a WHOIS server for `#{string}'"
245
- end
286
+ # Searches for definition that matches given domain.
287
+ #
288
+ # @param string [String]
289
+ # @return [Whois::Server::Adapters::Base, nil]
290
+ # a server adapter that can be used to perform queries.
291
+ def find_for_domain(string)
292
+ token = string
293
+ defs = _definitions(TYPE_TLD)
294
+
295
+ while token != "" do
296
+ if (found = defs[token])
297
+ return factory(:tld, *found)
298
+ else
299
+ index = token.index(".")
300
+ break if index.nil?
301
+
302
+ token = token[(index + 1)..-1]
303
+ end
304
+ end
246
305
 
306
+ nil
307
+ end
247
308
 
248
- private
309
+ # Searches for definition that matches given ASN string.
310
+ #
311
+ # @param string [String]
312
+ # @return [Whois::Server::Adapters::Base, nil]
313
+ # a server adapter that can be used to perform queries.
314
+ # @raise [Whois::AllocationUnknown]
315
+ # when the IP doesn't have a specific known allocation
316
+ # that matches one of the existing server definitions.
317
+ def find_for_asn(string)
318
+ asn = string[/\d+/].to_i
319
+ asn_type = asn <= 65535 ? TYPE_ASN16 : TYPE_ASN32
320
+ _definitions(asn_type).each do |_, definition|
321
+ if (range = definition.first.split.map(&:to_i)) && asn >= range.first && asn <= range.last
322
+ return factory(asn_type, *definition)
323
+ end
324
+ end
325
+ raise AllocationUnknown, "Unknown AS number - `#{asn}'."
326
+ end
249
327
 
250
- def self.camelize(string)
251
- string.to_s.split("_").collect(&:capitalize).join
252
- end
253
328
 
329
+ private
254
330
 
255
- def self.matches_tld?(string)
256
- string =~ /^\.(xn--)?[a-z0-9]+$/
257
- end
331
+ def _definitions(type = nil)
332
+ if type.nil?
333
+ @definitions
334
+ else
335
+ @definitions[type] ||= {}
336
+ end
337
+ end
258
338
 
259
- def self.matches_ip?(string)
260
- valid_ipv4?(string) || valid_ipv6?(string)
261
- end
262
339
 
263
- def self.matches_email?(string)
264
- string =~ /@/
265
- end
340
+ def camelize(string)
341
+ string.to_s.split("_").collect(&:capitalize).join
342
+ end
266
343
 
267
- def self.matches_asn?(string)
268
- string =~ /^as\d+$/i
269
- end
344
+ def matches_tld?(string)
345
+ string =~ /^\.(xn--)?[a-z0-9]+$/
346
+ end
270
347
 
271
- def self.find_for_ip(string)
272
- begin
273
- ip = IPAddr.new(string)
274
- type = ip.ipv4? ? :ipv4 : :ipv6
275
- definitions(type).each do |definition|
276
- if IPAddr.new(definition.first).include?(ip)
277
- return factory(type, *definition)
278
- end
279
- end
280
- rescue ArgumentError
281
- # continue
348
+ def matches_ip?(string)
349
+ valid_ipv4?(string) || valid_ipv6?(string)
282
350
  end
283
- raise AllocationUnknown, "IP Allocation for `#{string}' unknown. Server definitions might be outdated."
284
- end
285
351
 
286
- def self.find_for_email(string)
287
- raise ServerNotSupported, "No WHOIS server is known for email objects"
288
- end
352
+ def matches_email?(string)
353
+ string =~ /@/
354
+ end
289
355
 
290
- def self.find_for_domain(string)
291
- definitions(:tld).each do |definition|
292
- return factory(:tld, *definition) if /#{Regexp.escape(definition.first)}$/ =~ string
356
+ def matches_asn?(string)
357
+ string =~ /^as\d+$/i
293
358
  end
294
- nil
295
- end
296
359
 
297
- def self.find_for_asn(string)
298
- asn = string[/\d+/].to_i
299
- asn_type = asn <= 65535 ? :asn16 : :asn32
300
- definitions(asn_type).each do |definition|
301
- if (range = definition.first.split.map(&:to_i)) && asn >= range.first && asn <= range.last
302
- return factory(asn_type, *definition)
360
+
361
+ def valid_ipv4?(addr)
362
+ if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
363
+ return $~.captures.all? {|i| i.to_i < 256}
303
364
  end
365
+ false
304
366
  end
305
- raise AllocationUnknown, "Unknown AS number - `#{asn}'."
306
- end
307
367
 
308
-
309
- def self.valid_ipv4?(addr)
310
- if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
311
- return $~.captures.all? {|i| i.to_i < 256}
368
+ def valid_ipv6?(addr)
369
+ # IPv6 (normal)
370
+ return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ addr
371
+ return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
372
+ return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
373
+ # IPv6 (IPv4 compat)
374
+ return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ addr && valid_ipv4?($')
375
+ return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_ipv4?($')
376
+ return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_ipv4?($')
377
+ false
312
378
  end
313
- false
314
- end
315
379
 
316
- def self.valid_ipv6?(addr)
317
- # IPv6 (normal)
318
- return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ addr
319
- return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
320
- return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
321
- # IPv6 (IPv4 compat)
322
- return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ addr && valid_ipv4?($')
323
- return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_ipv4?($')
324
- return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_ipv4?($')
325
- false
326
380
  end
327
-
328
381
  end
329
382
 
330
383
  end