universal_ruby_whois 1.2.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +19 -0
- data/LICENSE +22 -0
- data/README.rdoc +91 -0
- data/lib/support/extended_regexp.rb +94 -0
- data/lib/support/string.rb +22 -0
- data/lib/universal_ruby_whois/domain.rb +145 -0
- data/lib/universal_ruby_whois/server.rb +245 -0
- data/lib/universal_ruby_whois/server_list.rb +327 -0
- data/lib/universal_ruby_whois.rb +30 -0
- data/test/regexp.rb +22 -0
- data/test/string.rb +13 -0
- data/test/whois.rb +72 -0
- data/universal_ruby_whois.gemspec +40 -0
- metadata +77 -0
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
== 1/17/13
|
2
|
+
* Update TLD output parsing rules by Vasily Shmelev
|
3
|
+
* Know issue: creation date won't return for some TLDs
|
4
|
+
|
5
|
+
== 7/24/09
|
6
|
+
* Added support for .br domain names by Ruy Rocha
|
7
|
+
|
8
|
+
== 2/17/09
|
9
|
+
* Included enhancements for .co.nz domains as provided by Matt Thompson
|
10
|
+
|
11
|
+
== 12/1/08
|
12
|
+
* Included atourino's fix for .mobi domains.
|
13
|
+
* Updated Rakefile to publish to RubyForge.
|
14
|
+
|
15
|
+
== 11/10/08
|
16
|
+
* Support for expiration date parsing added as requested by Jorge Yau.
|
17
|
+
* Renamed "created_date" to "creation_date" for consistency.
|
18
|
+
* Moved supporting libraries into a support folder.
|
19
|
+
* Added support for .jp and .co.jp etc. domain names.
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2008 Matt Lightner
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
22
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
|
2
|
+
=== Rest In Peace Matt Lightner
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
= Universal Whois Server
|
7
|
+
|
8
|
+
*Author*: Matt Lightner <mailto:mlightner@gmail.com>
|
9
|
+
|
10
|
+
*License*: MIT[link:files/LICENSE.html]
|
11
|
+
|
12
|
+
*RDoc*: http://universalwhois.rubyforge.org
|
13
|
+
|
14
|
+
*RubyForge URL*: http://rubyforge.org/projects/universalwhois
|
15
|
+
|
16
|
+
*GitHub URL*: http://github.com/mlightner/universal_ruby_whois/tree/master
|
17
|
+
|
18
|
+
|
19
|
+
This library attempts to interpret WHOIS output from a variety of different registrars.
|
20
|
+
The ultimate goal is to have a complete "dictionary" of all of the TLD registrars (including
|
21
|
+
double domain TLDs such as .co.uk) on the Internet, and corresponding regular expressions
|
22
|
+
to parse the unique output format for each one.
|
23
|
+
|
24
|
+
This package requires a command line whois utility to retrieve output. It will then attempt
|
25
|
+
to interpret that output based on a series of regular expressions.
|
26
|
+
|
27
|
+
|
28
|
+
=== DEFINING WHOIS SERVERS
|
29
|
+
|
30
|
+
Whois servers can be defined on a per-TLD basis, so each registrar can have a unique set
|
31
|
+
of regular expressions to match its particular output format. Whois servers are defined in the
|
32
|
+
file server_list.rb.
|
33
|
+
|
34
|
+
If you're using this module and come across a TLD that isn't yet supported or isn't working
|
35
|
+
quite right, I highly encourage you to fork the project and commit your updates. The more
|
36
|
+
people we have working on the list, the more comprehensive and effective it becomes!
|
37
|
+
|
38
|
+
|
39
|
+
=== TLD SEARCH PRIORITY
|
40
|
+
|
41
|
+
When deciding which whois server to use, the script will always choose the most specific
|
42
|
+
server entry it can find. For instance, if you have defined a server for .uk domains,
|
43
|
+
but also a server for .co.uk domains, the domain name "test.co.uk" will always use the
|
44
|
+
latter whois server.
|
45
|
+
|
46
|
+
|
47
|
+
=== EXAMPLE USAGE
|
48
|
+
|
49
|
+
Here is the output from a sample IRB session using this library:
|
50
|
+
|
51
|
+
require 'universal_ruby_whois'
|
52
|
+
=> true
|
53
|
+
domain = Whois.find("mattlightner.com")
|
54
|
+
=> #<Whois::Domain:0xb7a3b014 @domain="mattlightner.com", @server_tld_key="com">
|
55
|
+
domain.status
|
56
|
+
=> :registered
|
57
|
+
domain.available?
|
58
|
+
=> false
|
59
|
+
domain.registered?
|
60
|
+
=> true
|
61
|
+
domain.creation_date
|
62
|
+
=> Mon Aug 28 00:00:00 EDT 2006
|
63
|
+
domain.expiration_date
|
64
|
+
=> Fri Aug 28 00:00:00 EDT 2009
|
65
|
+
domain = Whois.find("9384jf398ejf9832ej.com")
|
66
|
+
=> #<Whois::Domain:0xb7a1ab34 @domain="9384jf398ejf9832ej.com", @server_tld_key="com">
|
67
|
+
domain.status
|
68
|
+
=> :free
|
69
|
+
|
70
|
+
|
71
|
+
=== NOTES
|
72
|
+
|
73
|
+
Some registrars are relatively unreliable or may add a server to a blacklist after a certain number of
|
74
|
+
queries. In particular, the registrars for these domains:
|
75
|
+
|
76
|
+
- es and related TLDs: They only provide an HTTP whois access interface, which is unreliable at
|
77
|
+
best (although this module supports HTTP lookups quite well).
|
78
|
+
- asn.au com.au id.au net.au org.au: 'whois.aunic.net', seems as though they will blacklist a server
|
79
|
+
making too many queries. Not sure about their blacklist removal policy.
|
80
|
+
|
81
|
+
|
82
|
+
=== TODO
|
83
|
+
|
84
|
+
- Add better support for creation date parsing for major registrars.
|
85
|
+
- Find a more reliable way to look up domains from registrars not providing a whois server.
|
86
|
+
|
87
|
+
|
88
|
+
=== CONTRIBUTIONS
|
89
|
+
|
90
|
+
Contribution is encouraged! Grab the source from: git://github.com/mlightner/universal_ruby_whois.git
|
91
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Whois
|
2
|
+
|
3
|
+
module ExtendedRegexp #:nodoc:
|
4
|
+
|
5
|
+
def self.included(base) #:nodoc:
|
6
|
+
base.send(:include, Whois::ExtendedRegexp::InstanceMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Extensions for Ruby's core Regexp class.
|
10
|
+
module InstanceMethods
|
11
|
+
|
12
|
+
# Find and replace literal values in a regular expression source string. You pass it a Hash
|
13
|
+
# where the keys are either strings or regular expressions to search for, and their values are
|
14
|
+
# the replacement values. A completely new Regexp object is returned and options are preserved.
|
15
|
+
#
|
16
|
+
# /a __REPLACE___ day/i.interpolate("__REPLACE__" => "fun") => /a fun day/i
|
17
|
+
#
|
18
|
+
def interpolate(*args)
|
19
|
+
if args.length > 1
|
20
|
+
replacements = Hash[*args]
|
21
|
+
elsif args.first.kind_of?(Hash)
|
22
|
+
replacements = args.first
|
23
|
+
else
|
24
|
+
raise ArgumentError, "Must pass hash to interpolate."
|
25
|
+
end
|
26
|
+
|
27
|
+
string = self.source
|
28
|
+
|
29
|
+
replacements.each do |key, value|
|
30
|
+
if key.kind_of?(Regexp)
|
31
|
+
string.gsub!(key, value.to_s)
|
32
|
+
else
|
33
|
+
string.gsub!(/#{self.class.escape(key)}/im, value.to_s)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
string = (self.source.to_s).interpolate(*args)
|
38
|
+
self.class.new(string, self.options)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Make a copy of the current regular expression object but with new options. Options are given
|
42
|
+
# as a string, like so:
|
43
|
+
#
|
44
|
+
# /testing/i.new_options('im') => /testing/im
|
45
|
+
def new_options(option_string)
|
46
|
+
options_list = []
|
47
|
+
{ :i => Regexp::IGNORECASE,
|
48
|
+
:x => Regexp::EXTENDED,
|
49
|
+
:m => Regexp::MULTILINE }.each_pair do |charcode, constant|
|
50
|
+
options_list.push(constant) if option_string =~ /#{charcode.to_s}/i
|
51
|
+
end
|
52
|
+
|
53
|
+
self.class.new(self.source, options_list)
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# === Inverted Regular Expressions
|
58
|
+
#
|
59
|
+
# Gives the ability to invert a regular expression so that running a match against it
|
60
|
+
# will yield a true result when it does NOT match the target string.
|
61
|
+
#
|
62
|
+
# Invert this regular expression.
|
63
|
+
def invert!
|
64
|
+
@inverted = true
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
# Uninvert this regular expression.
|
69
|
+
def uninvert!
|
70
|
+
@inverted = false
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
def set_inverted(value = true)
|
75
|
+
@inverted = (value) ? true : false
|
76
|
+
end
|
77
|
+
|
78
|
+
# Is this an inverted regular expression?
|
79
|
+
def inverted?
|
80
|
+
@inverted rescue false
|
81
|
+
end
|
82
|
+
|
83
|
+
# Run an inversion-aware match using this Regexp.
|
84
|
+
def match_with_inversion(*args, &block)
|
85
|
+
result = self.match(*args, &block)
|
86
|
+
if @inverted
|
87
|
+
result.nil? ? true : false
|
88
|
+
else
|
89
|
+
result
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class String #:nodoc:
|
2
|
+
def interpolate(*args)
|
3
|
+
if args.length > 1
|
4
|
+
replacements = Hash[*args]
|
5
|
+
elsif args.first.kind_of?(Hash)
|
6
|
+
replacements = args.first
|
7
|
+
else
|
8
|
+
raise ArgumentError, "Must pass hash to interpolate."
|
9
|
+
end
|
10
|
+
|
11
|
+
string = self.dup
|
12
|
+
replacements.each do |key, value|
|
13
|
+
if key.kind_of?(Regexp)
|
14
|
+
string.gsub!(key, value.to_s)
|
15
|
+
else
|
16
|
+
string.gsub!(/#{key}/i, value.to_s)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
string
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/server'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
module Whois
|
5
|
+
|
6
|
+
class Domain
|
7
|
+
|
8
|
+
# The domain name, lower case, no spaces.
|
9
|
+
attr_reader :domain
|
10
|
+
|
11
|
+
# The TLD server being used for this domain.
|
12
|
+
attr_reader :server_tld_key
|
13
|
+
|
14
|
+
# The cached output from a whois request for this domain.
|
15
|
+
attr_reader :whois_output
|
16
|
+
|
17
|
+
# Look up a domain name. If a proper whois server can not be found for this domain name's extension,
|
18
|
+
# it will return nil. Otherwise it returns a Whois::Domain object.
|
19
|
+
#
|
20
|
+
# Note: the preferred way to call this method is through the wrapper:
|
21
|
+
#
|
22
|
+
# Whois.find(domain)
|
23
|
+
def self.find(domain)
|
24
|
+
::Whois::Server.find(domain)
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(domain, server_tld_key = nil) #:nodoc:
|
28
|
+
@domain, @server_tld_key = domain.to_s.strip.downcase, server_tld_key
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the Whois::Server object for this domain name.
|
32
|
+
def server
|
33
|
+
Whois::Server.list[@server_tld_key] rescue nil
|
34
|
+
end
|
35
|
+
|
36
|
+
# The set of regular expressions that will be used in matching this domain's whois output.
|
37
|
+
def regexes
|
38
|
+
server.regexes rescue {}
|
39
|
+
end
|
40
|
+
|
41
|
+
# Does this object have a domain name set?
|
42
|
+
def has_domain?
|
43
|
+
return false if domain.nil?
|
44
|
+
(domain.to_s =~ /\w/) ? true : false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Does this domain have a server which is available?
|
48
|
+
def has_available_server?
|
49
|
+
server && !(server.unavailable? rescue true)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Does this domain have sufficient info to perform a lookup?
|
53
|
+
def has_domain_and_server?
|
54
|
+
has_domain? && has_available_server?
|
55
|
+
end
|
56
|
+
alias_method :valid?, :has_domain_and_server?
|
57
|
+
|
58
|
+
# The raw whois server output obtained when looking up this domain.
|
59
|
+
def whois_output
|
60
|
+
return @whois_output if !@whois_output.blank?
|
61
|
+
@whois_output = has_domain_and_server? ? server.raw_response!(domain) : ''
|
62
|
+
end
|
63
|
+
|
64
|
+
# The domain name's current registration status:
|
65
|
+
# <tt>:registered</tt> The domain name is registered.
|
66
|
+
# <tt>:free</tt> The domain name is not registered (available).
|
67
|
+
# <tt>:error</tt> There was an error looking up the domain name.
|
68
|
+
# <tt>:unknown</tt> The domain name status could not be determined.
|
69
|
+
def status
|
70
|
+
return :unknown unless has_domain_and_server?
|
71
|
+
return @status unless @status.blank?
|
72
|
+
[ :registered, :free, :error ].each do |status|
|
73
|
+
#return status if Regexp.new(regexes[status].source, 5).match(res)
|
74
|
+
return(@status = status) if regexes[status].match_with_inversion(whois_output)
|
75
|
+
end
|
76
|
+
return @status = :unknown
|
77
|
+
end
|
78
|
+
|
79
|
+
# Is this domain available? Returns true/false.
|
80
|
+
def available?
|
81
|
+
return nil unless has_domain_and_server?
|
82
|
+
status == :free
|
83
|
+
end
|
84
|
+
|
85
|
+
# Is this domain name registered? Returns true/false.
|
86
|
+
def registered?
|
87
|
+
return nil unless has_domain_and_server?
|
88
|
+
status == :registered
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns a Time object representing the date this domain name was created.
|
92
|
+
def creation_date
|
93
|
+
return nil unless has_domain_and_server?
|
94
|
+
return @creation_date unless @creation_date.blank?
|
95
|
+
if regexes[:creation_date] && (regexes[:creation_date] =~ whois_output)
|
96
|
+
@creation_date = (Time.local(*ParseDate.parsedate($2)) rescue nil)
|
97
|
+
end
|
98
|
+
@creation_date
|
99
|
+
end
|
100
|
+
|
101
|
+
# Depreciated. Use creation_date instead.
|
102
|
+
alias_method :created_date, :creation_date
|
103
|
+
|
104
|
+
# Do we know the creation date for this domain?
|
105
|
+
def creation_date_known?
|
106
|
+
creation_date.kind_of?(Time)
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
# Returns a Time object representing the date this domain name is set to expire.
|
111
|
+
def expiration_date
|
112
|
+
return nil unless has_domain_and_server?
|
113
|
+
return @expiration_date unless @expiration_date.blank?
|
114
|
+
if regexes[:expiration_date] && (regexes[:expiration_date] =~ whois_output)
|
115
|
+
@expiration_date = (Time.local(*ParseDate.parsedate($2)) rescue nil)
|
116
|
+
end
|
117
|
+
@expiration_date
|
118
|
+
end
|
119
|
+
|
120
|
+
# Do we know the expiration date for this domain?
|
121
|
+
def expiration_date_known?
|
122
|
+
expiration_date.kind_of?(Time)
|
123
|
+
end
|
124
|
+
|
125
|
+
def to_s
|
126
|
+
domain.to_s rescue nil
|
127
|
+
end
|
128
|
+
def to_hash
|
129
|
+
{
|
130
|
+
:status => self.status,
|
131
|
+
:creation_date => self.creation_date,
|
132
|
+
:expiration_date => self.expiration_date,
|
133
|
+
:output => self.whois_output
|
134
|
+
}
|
135
|
+
end
|
136
|
+
def to_json
|
137
|
+
self.to_hash.to_json
|
138
|
+
end
|
139
|
+
def to_xml
|
140
|
+
self.to_hash.to_xml
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
@@ -0,0 +1,245 @@
|
|
1
|
+
module Whois
|
2
|
+
|
3
|
+
# = Whois::Server
|
4
|
+
#
|
5
|
+
# A Whois server object represents a single TLD mapped to a whois server hostname, and a set of regular expressions
|
6
|
+
# that are used to match against the raw whois output and determine various information about the domain name (currently
|
7
|
+
# registration status is supported on most domain TLDs, and creation date on a good number).
|
8
|
+
class Server
|
9
|
+
|
10
|
+
# Exception class thrown when a WHOIS server is down or unavailable.
|
11
|
+
class Unavailable < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
# The default regular expressions used when defining a new server if none are supplied.
|
15
|
+
DEFAULT_WHOIS_REGULAR_EXPRESSIONS = {
|
16
|
+
:free => /(avail|free|no match|no entr|not taken|Available|Status\:\sNot\sRegistered|not registered|not found|No match for domain)/im,
|
17
|
+
:registered => /(registered|Domain ID|domain name\s*\:|is active|Status\:\sActive|Not available|is not available|exists|\bregistrant\b|Created on|created\:)/im,
|
18
|
+
:creation_date => /(Creation date|created on|created at|Commencement Date|Registration Date|domain_dateregistered|created\:)\s*[\:\.\]]*\s*([\w\-\:\ \/]+)[^\n\r]*[\n\r]/im,
|
19
|
+
:expiration_date => /(expiration date|expires on|registered through|Renewal date|domain_datebilleduntil|expires\:)\s*[\:\.\]]*\s*([\w\-\:\ \/]+)[^\n\r]*[\n\r]/im,
|
20
|
+
:error => /(error)/im,
|
21
|
+
:server_unavailable => /(Sorry\. Server busy\.|too many requests|been blocked)/im
|
22
|
+
}
|
23
|
+
|
24
|
+
# The location of the 'whois' binary utility.
|
25
|
+
WHOIS_BIN = '/usr/bin/env whois'
|
26
|
+
|
27
|
+
attr_reader :tld, :nic_server, :regexes, :port, :server_unavailable, :unavailable_response
|
28
|
+
|
29
|
+
# === Whois Server Definition
|
30
|
+
#
|
31
|
+
# Define a whois server for one or more TLDs. TLDs can be given as a single string or an array of strings representing
|
32
|
+
# TLDs that are handled by this server. The second argument should be a whois server hostname. If none is given,
|
33
|
+
# the generic output from the command line whois program is used (with any available redirection). An optional third
|
34
|
+
# argument is an array of regular expressions used to parse output from this particular server. A set of relatively
|
35
|
+
# liberal defaults is used if none (or only some) are given. Supported regex keys are :free, :registered, :creation_date
|
36
|
+
# and :error.
|
37
|
+
#
|
38
|
+
# ==== Regex Options
|
39
|
+
# * <tt>:registered</tt> -- If this regular expression matches the whois output, this domain is considered registered.
|
40
|
+
# * <tt>:free</tt> -- If this regular expression matches the whois output, the domain is considered available.
|
41
|
+
# * <tt>:error</tt> -- If this regular expression matches, an error is said to have occurred.
|
42
|
+
# * <tt>:creation_date</tt> -- If this regular expression matches, the value of the second set of parentheses is parsed
|
43
|
+
# using ParseDate and used as the creation date for this domain.
|
44
|
+
#
|
45
|
+
# Note, the preferred location for Whois::Server definitions is the server_list.rb file. Definitions should go from
|
46
|
+
# least specific to most specific, as subsequent definitions for a TLD will override previous ones.
|
47
|
+
def self.define(tlds, server = nil, regexes = nil, &block)
|
48
|
+
tlds = tlds.kind_of?(Array) ? tlds : [tlds]
|
49
|
+
tlds.each do |tld|
|
50
|
+
define_single(tld, server, regexes, &block)
|
51
|
+
end
|
52
|
+
tlds
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize(tld, nic_server = nil, options = nil) #:nodoc:
|
56
|
+
@tld = tld.gsub(/^\.+/, '')
|
57
|
+
options ||= Hash.new
|
58
|
+
@response_cache = Hash.new("")
|
59
|
+
@nic_server = nic_server
|
60
|
+
@port = options.delete(:port)
|
61
|
+
@regexes = options.reverse_merge(DEFAULT_WHOIS_REGULAR_EXPRESSIONS)
|
62
|
+
@regexes.each do |key, rx|
|
63
|
+
next unless rx.kind_of?(Array)
|
64
|
+
rx2 = Regexp.new(Regexp.escape(rx.first).gsub(/\s+/, '\s*'))
|
65
|
+
rx2 = rx2.new_options(rx[1])
|
66
|
+
rx2 = rx2.interpolate(/\s+/, '\s+')
|
67
|
+
rx2.invert! if ((rx[2] == true) rescue false)
|
68
|
+
@regexes[key] = rx2
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# A hash of all of the known whois servers indexed by TLD
|
73
|
+
def self.list
|
74
|
+
@@list ||= Hash.new
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.list=(value)
|
78
|
+
@@list = value
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.domain_object_cache #:nodoc:
|
82
|
+
@@domain_object_cache ||= Hash.new
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.domain_object_cache=(value) #:nodoc:
|
86
|
+
@@domain_object_cache = value
|
87
|
+
end
|
88
|
+
|
89
|
+
# A list of strings representing all supported TLDs.
|
90
|
+
def self.defined_tlds
|
91
|
+
self.list.collect {|tld,server| tld.gsub(/^\./, '') }
|
92
|
+
end
|
93
|
+
|
94
|
+
# Find a TLD from a full domain name. There is special care to check for two part TLDs
|
95
|
+
# (such as .co.uk, .kids.us, etc) first and then to look for the last part alone.
|
96
|
+
def self.find_server_from_domain(domain)
|
97
|
+
# valid domain?
|
98
|
+
return nil unless domain =~ /^((?:[-a-zA-Z0-9]+\.)+[a-zA-Z]{2,})$/
|
99
|
+
|
100
|
+
# start the searching.
|
101
|
+
tld = nil
|
102
|
+
parts = domain.split('.')
|
103
|
+
|
104
|
+
# if the passed domain is more than two parts (. separated strings)
|
105
|
+
# try to find the TLD from the last two parts (ie, .co.uk)
|
106
|
+
if parts.size > 2
|
107
|
+
tld_string = parts[-2,2].join('.')
|
108
|
+
tld = self.list[tld_string]
|
109
|
+
end
|
110
|
+
|
111
|
+
# if nothing was found, check for a match on the last part only.
|
112
|
+
if tld.blank?
|
113
|
+
tld_string = parts.last
|
114
|
+
tld = self.list[tld_string]
|
115
|
+
end
|
116
|
+
|
117
|
+
return nil if !tld.kind_of?(Whois::Server)
|
118
|
+
return tld
|
119
|
+
end
|
120
|
+
|
121
|
+
# Look up a domain name. If a proper whois server can not be found for this domain name's extension,
|
122
|
+
# it will return nil. Otherwise it returns a Whois::Domain object.
|
123
|
+
#
|
124
|
+
# Note: the preferred way to call this method is through the wrapper:
|
125
|
+
#
|
126
|
+
# Whois.find(domain)
|
127
|
+
def self.find(domain)
|
128
|
+
domain = domain.to_s.strip.downcase
|
129
|
+
return domain_object_cache[domain] unless domain_object_cache[domain].blank?
|
130
|
+
return nil unless server = server_for_domain(domain)
|
131
|
+
domain_object_cache[domain] = Whois::Domain.new(domain, server.tld)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Determine the appropriate whois server object for a domain name.
|
135
|
+
def self.server_for_domain(domain)
|
136
|
+
server = self.find_server_from_domain(domain)
|
137
|
+
# This will only work on single extension domains
|
138
|
+
if server.blank? # && domain.scan(/(\.)/).length == 1
|
139
|
+
domain =~ /\.([\w\-]+)$/
|
140
|
+
tld = $1
|
141
|
+
self.define_from_iana(tld)
|
142
|
+
return false unless server = self.find_server_from_domain(domain)
|
143
|
+
end
|
144
|
+
server
|
145
|
+
end
|
146
|
+
|
147
|
+
def unavailable?
|
148
|
+
@server_unavailable ? true : false
|
149
|
+
end
|
150
|
+
|
151
|
+
# Retrieve the raw WHOIS server output for a domain.
|
152
|
+
def raw_response(domain)
|
153
|
+
return nil if unavailable?
|
154
|
+
return @response_cache[domain] if !@response_cache[domain].blank?
|
155
|
+
@response_cache[domain] = ""
|
156
|
+
if nic_server.kind_of?(Array)
|
157
|
+
interpolate_vars = {
|
158
|
+
'%DOMAIN%' => domain,
|
159
|
+
'%DOMAIN_NO_TLD%' => domain.gsub(/\.#{tld.to_s}$/i, ''),
|
160
|
+
'%TLD%' => tld
|
161
|
+
}
|
162
|
+
|
163
|
+
url = URI.parse(nic_server.first.dup.interpolate(interpolate_vars))
|
164
|
+
method = nic_server[1] || :post
|
165
|
+
req = "Net::HTTP::#{method.to_s.capitalize}".constantize.new(url.path)
|
166
|
+
form_data = nic_server[2].dup || {}
|
167
|
+
form_data.each { |k,v| form_data[k] = v.interpolate(interpolate_vars) }
|
168
|
+
req.set_form_data(form_data)
|
169
|
+
res = begin
|
170
|
+
Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
|
171
|
+
rescue Net::HTTPBadResponse
|
172
|
+
nil # Ignore these for now...
|
173
|
+
end
|
174
|
+
@response_cache[domain] = case res
|
175
|
+
when Net::HTTPSuccess, Net::HTTPRedirection
|
176
|
+
res.body
|
177
|
+
else
|
178
|
+
''
|
179
|
+
end
|
180
|
+
elsif nic_server.to_s =~ /^http/
|
181
|
+
url = nic_server.gsub(/\%DOMAIN\%/, domain)
|
182
|
+
@response_cache[domain] = Net::HTTP.get_response(URI.parse(url)).body
|
183
|
+
else
|
184
|
+
command = "#{WHOIS_BIN} #{('-h ' + @nic_server) unless @nic_server.blank?} #{self.class.shell_escape(domain)} 2>&1"
|
185
|
+
@response_cache[domain] = Whois::Server.run_command_with_timeout(command, 10, true)
|
186
|
+
end
|
187
|
+
if match = regexes[:server_unavailable].match_with_inversion(@response_cache[domain])
|
188
|
+
@server_unavailable = true
|
189
|
+
@unavailable_response = match[1]
|
190
|
+
nil
|
191
|
+
else
|
192
|
+
@response_cache[domain]
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def raw_response!(domain)
|
197
|
+
res = raw_response(domain)
|
198
|
+
if !res || !res.respond_to?(:to_s) || res.blank?
|
199
|
+
raise Whois::Server::Unavailable, "The WHOIS server for TLD #{tld.to_s} is currently unavailable. (response: #{unavailable_response})"
|
200
|
+
end
|
201
|
+
res
|
202
|
+
end
|
203
|
+
|
204
|
+
# Used as a fallback in case no specific WHOIS server is defined for a given TLD. An attempt will be made to search
|
205
|
+
# the IANA global registrar database to find a suitable whois server.
|
206
|
+
def self.define_from_iana(tld)
|
207
|
+
iana_out = run_command_with_timeout("#{WHOIS_BIN} -h whois.iana.org #{shell_escape(tld.to_s)} 2>&1", 10, false)
|
208
|
+
return false if iana_out.blank?
|
209
|
+
return false unless iana_out =~ /Whois\s+Server\s+\(port ([\d]+)\)\: ([\w\-\.\_]+)/im
|
210
|
+
port = $1
|
211
|
+
server = $2
|
212
|
+
define_single(tld.to_s, server, :port => port)
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.define_single(*args, &block) #:nodoc:
|
216
|
+
new_server = allocate
|
217
|
+
new_server.send(:initialize, *args, &block)
|
218
|
+
list[args.first.to_s] = new_server
|
219
|
+
new_server
|
220
|
+
end
|
221
|
+
|
222
|
+
def self.run_command_with_timeout(command, timeout = 10, do_raise = false) #:nodoc:
|
223
|
+
@output = ""
|
224
|
+
begin
|
225
|
+
status = Timeout::timeout(10) do
|
226
|
+
IO.popen(command, "r") do |io|
|
227
|
+
@output << "#{io.read.to_s}"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
rescue Exception => e
|
231
|
+
if do_raise
|
232
|
+
raise "Running command \"#{command}\" timed out."
|
233
|
+
end
|
234
|
+
end
|
235
|
+
@output.strip!
|
236
|
+
@output
|
237
|
+
end
|
238
|
+
|
239
|
+
def self.shell_escape(word) #:nodoc:
|
240
|
+
word.to_s.gsub(/[^\w\-\_\.]+/, '') rescue ''
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
@@ -0,0 +1,327 @@
|
|
1
|
+
# Define whois servers and their corresponding output format in this file.
|
2
|
+
# If no regular expressions are given to match states, some reasonable
|
3
|
+
# defaults will be used, but more specific is always better :)
|
4
|
+
|
5
|
+
# More generic definitions should appear first, as the more specific definitions
|
6
|
+
# will overwrite them in the extension dictionary if they appear later in the file.
|
7
|
+
|
8
|
+
Whois::Server.define('ae', 'whois.uaenic.ae')
|
9
|
+
Whois::Server.define('ai', 'whois.ainic.ai')
|
10
|
+
Whois::Server.define('as', 'whois.nic.as')
|
11
|
+
Whois::Server.define('at', 'whois.nic.at')
|
12
|
+
Whois::Server.define('bg', 'whois.digsys.bg')
|
13
|
+
Whois::Server.define('bi', 'whois.nic.bi')
|
14
|
+
Whois::Server.define('bj', 'www.nic.bj')
|
15
|
+
Whois::Server.define('br', 'whois.nic.br')
|
16
|
+
Whois::Server.define('bz', 'whois.belizenic.bz')
|
17
|
+
Whois::Server.define('cc', 'whois.nic.cc')
|
18
|
+
Whois::Server.define('cd', 'whois.nic.cd')
|
19
|
+
Whois::Server.define('ck', 'whois.nic.ckcn')
|
20
|
+
Whois::Server.define('de', 'whois.denic.de')
|
21
|
+
Whois::Server.define('fo', 'whois.ripe.net')
|
22
|
+
Whois::Server.define('gg', 'whois.isles.net')
|
23
|
+
Whois::Server.define('gl', 'whois.ripe.net')
|
24
|
+
Whois::Server.define('gm', 'whois.ripe.net')
|
25
|
+
Whois::Server.define('gr', 'whois.grnet.gr')
|
26
|
+
Whois::Server.define('gs', 'whois.gs')
|
27
|
+
Whois::Server.define('hm', 'webhst1.capital.hm')
|
28
|
+
Whois::Server.define('hu', 'whois.nic.hu')
|
29
|
+
Whois::Server.define('id', 'whois.idnic.net.id')
|
30
|
+
Whois::Server.define('in', 'whois.inregistry.net')
|
31
|
+
Whois::Server.define('io', 'whois.nic.io')
|
32
|
+
Whois::Server.define('ir', 'whois.nic.ir')
|
33
|
+
Whois::Server.define('kz', 'whois.nic.kz')
|
34
|
+
Whois::Server.define('la', 'whois2.afilias-grs.net')
|
35
|
+
Whois::Server.define('ly', 'whois.lydomains.com')
|
36
|
+
Whois::Server.define('mc', 'whois.ripe.net')
|
37
|
+
Whois::Server.define('ms', 'whois.nic.ms')
|
38
|
+
Whois::Server.define('mx', 'whois.nic.mx')
|
39
|
+
Whois::Server.define('my', 'whois.mynic.net.my')
|
40
|
+
Whois::Server.define('pl', 'whois.dns.pl')
|
41
|
+
Whois::Server.define('pm', 'whois.nic.pm')
|
42
|
+
Whois::Server.define('pro', 'whois.registrypro.pro')
|
43
|
+
Whois::Server.define('pt', 'whois.nic.pt')
|
44
|
+
Whois::Server.define('sa', 'saudinic.net.sa')
|
45
|
+
Whois::Server.define('sb', 'whois.nic.net.sb')
|
46
|
+
Whois::Server.define('sh', 'whois.nic.sh')
|
47
|
+
Whois::Server.define('si', 'whois.arnes.si')
|
48
|
+
Whois::Server.define('sk', 'whois.sk-nic.sk')
|
49
|
+
Whois::Server.define('sm', 'whois.ripe.net')
|
50
|
+
Whois::Server.define('st', 'whois.nic.st')
|
51
|
+
Whois::Server.define('su', 'whois.ripn.net')
|
52
|
+
Whois::Server.define('th', 'whois.thnic.net')
|
53
|
+
Whois::Server.define('to', 'whois.tonic.to')
|
54
|
+
Whois::Server.define('uy', 'www.nic.org.uy')
|
55
|
+
Whois::Server.define('uz', 'whois.cctld.uz')
|
56
|
+
Whois::Server.define('va', 'whois.ripe.net')
|
57
|
+
Whois::Server.define('ve', 'whois.nic.ve')
|
58
|
+
Whois::Server.define('vg', 'whois.vg')
|
59
|
+
Whois::Server.define('wf', 'whois.nic.wf')
|
60
|
+
Whois::Server.define('ws', 'whois.tld.ws')
|
61
|
+
Whois::Server.define('yt', 'whois.nic.yt')
|
62
|
+
Whois::Server.define('us', 'whois.nic.us')
|
63
|
+
Whois::Server.define('at', 'whois.nic.at')
|
64
|
+
Whois::Server.define('ca', 'whois.cira.ca')
|
65
|
+
Whois::Server.define('cc', 'whois.nic.cc')
|
66
|
+
Whois::Server.define('ch', 'whois.nic.ch')
|
67
|
+
Whois::Server.define('cn', 'whois.cnnic.net.cn')
|
68
|
+
Whois::Server.define('cz', 'whois.nic.cz')
|
69
|
+
Whois::Server.define('ee', 'whois.eenet.ee')
|
70
|
+
Whois::Server.define('gr', 'https://grweb.ics.forth.gr/')
|
71
|
+
Whois::Server.define('it', 'whois.nic.it')
|
72
|
+
Whois::Server.define('li', 'whois.nic.li')
|
73
|
+
Whois::Server.define('lt', 'whois.domreg.lt')
|
74
|
+
Whois::Server.define('lu', 'whois.dns.lu')
|
75
|
+
Whois::Server.define('lv', 'whois.ripe.net')
|
76
|
+
Whois::Server.define('co.nz', 'whois.domainz.net.nz')
|
77
|
+
Whois::Server.define('nu', 'whois.nic.nu')
|
78
|
+
Whois::Server.define('pl', 'whois.dns.pl')
|
79
|
+
Whois::Server.define('ro', 'whois.rotld.ro')
|
80
|
+
Whois::Server.define('ru', 'whois.ripn.net')
|
81
|
+
Whois::Server.define('se', 'whois.iis.se')
|
82
|
+
Whois::Server.define('sk', 'whois.ripe.net')
|
83
|
+
Whois::Server.define('ws', 'whois.worldsite.ws')
|
84
|
+
|
85
|
+
#Whois::Server.define('es',"https://www.nic.es/esnic/servlet/BuscarDomSolAlta?dominio=%DOMAIN%")
|
86
|
+
#Whois::Server.define('com.es',"https://www.nic.es/esnic/servlet/BuscarDomSolAlta?dominio=%DOMAIN%")
|
87
|
+
|
88
|
+
Whois::Server.define(
|
89
|
+
'tv',
|
90
|
+
'tvwhois.verisign-grs.com',
|
91
|
+
:registered => /Domain ID/im,
|
92
|
+
:free => /No match for/im,
|
93
|
+
:creation_date => /Creation Date/im,
|
94
|
+
:expiration_date => /Expiration Date/im
|
95
|
+
)
|
96
|
+
|
97
|
+
|
98
|
+
Whois::Server.define(
|
99
|
+
%w(gd tc vg ms),
|
100
|
+
'whois.adamsnames.tc',
|
101
|
+
:registered => /domain name\:/im,
|
102
|
+
:free => /not found/im
|
103
|
+
)
|
104
|
+
|
105
|
+
Whois::Server.define(
|
106
|
+
%w(jp co.jp or.jp ne.jp ac.jp ad.jp ed.jp go.jp gr.jp lg.jp),
|
107
|
+
'whois.jprs.jp',
|
108
|
+
# ['http://whois.jprs.jp/en/', :post, { :submit => 'query', :key => '%DOMAIN%', :type => 'DOM'}],
|
109
|
+
:registered => /Domain Information\:/im,
|
110
|
+
:free => /No match\!\!/im
|
111
|
+
)
|
112
|
+
|
113
|
+
Whois::Server.define(
|
114
|
+
%w(es com.es nom.es org.es gob.es edu.es),
|
115
|
+
['https://www.nic.es/esnic/servlet/BuscarDomSolAlta', :post, { :Submit => 'Buscar', :domino => '%DOMAIN_NO_TLD%',
|
116
|
+
:sufijo => '%TLD%', :tipo => 'dominio'}],
|
117
|
+
:registered => [%q{%DOMAIN% </a> </th> <td class="disp"> <img src="../images/icon_disp_no.gif" alt="no" />}, 'im'],
|
118
|
+
:free => [%q{%DOMAIN% </a> </th> <td class="disp"> <img src="../images/icon_disp_yes.gif" alt="si" />}, 'im']
|
119
|
+
)
|
120
|
+
|
121
|
+
# By leaving out the whois server, we force it to follow the internic redirection.
|
122
|
+
Whois::Server.define(
|
123
|
+
%w(com net edu),
|
124
|
+
'whois.verisign-grs.com',
|
125
|
+
:registered => /No match for/im.invert!,
|
126
|
+
:free => /No match for/im
|
127
|
+
)
|
128
|
+
|
129
|
+
Whois::Server.define(
|
130
|
+
'gov', 'whois.nic.gov',
|
131
|
+
:registered => /Status:\s*Active/im,
|
132
|
+
:free => /Status:\s*Active/im.invert!
|
133
|
+
)
|
134
|
+
|
135
|
+
Whois::Server.define(
|
136
|
+
%w(asn.au com.au id.au net.au org.au),
|
137
|
+
'whois.ausregistry.net.au',
|
138
|
+
:free => /No Data Found/im,
|
139
|
+
:registered => /Last Modified/im,
|
140
|
+
:error => /BLACKLISTED/m
|
141
|
+
)
|
142
|
+
|
143
|
+
Whois::Server.define(
|
144
|
+
%w(hk com.hk net.hk edu.hk org.hk gov.hk idv.hk),
|
145
|
+
'whois.hkdnr.net.hk',
|
146
|
+
:free => /Domain Not Found/,
|
147
|
+
:registered => /Domain Name\:/im
|
148
|
+
)
|
149
|
+
Whois::Server.define(
|
150
|
+
%w(co.nz net.nz org.nz geek.nz school.nz gen.nz govt.nz maori.nz ac.nz iwi.nz cri.nz mil.nz parliament.nz),
|
151
|
+
'whois.srs.net.nz',
|
152
|
+
:free => /220 available/im,
|
153
|
+
:registered => /220 available/im.invert!
|
154
|
+
)
|
155
|
+
|
156
|
+
Whois::Server.define(
|
157
|
+
'eu.com',
|
158
|
+
'whois.centralnic.net',
|
159
|
+
:free => /DOMAIN NOT FOUND/im,
|
160
|
+
:registered => /Domain Name\:/im
|
161
|
+
)
|
162
|
+
|
163
|
+
Whois::Server.define(
|
164
|
+
%w(uk.com uk.net us.com la cn.com de.com jpn.com kr.com no.com za.com br.com ar.com ru.com sa.com se.com
|
165
|
+
se.net hu.com gb.com gb.net qc.com uy.com ae.org no.com se.com),
|
166
|
+
'whois.centralnic.net',
|
167
|
+
:free => /available for registration/im,
|
168
|
+
:registered => /Domain Name\:/im
|
169
|
+
)
|
170
|
+
|
171
|
+
Whois::Server.define(
|
172
|
+
'be',
|
173
|
+
'whois.dns.be',
|
174
|
+
:free => /Status:\s+FREE/im,
|
175
|
+
:registered => /Status:\s+REGISTERED/im
|
176
|
+
)
|
177
|
+
Whois::Server.define(
|
178
|
+
'biz',
|
179
|
+
'whois.neulevel.biz',
|
180
|
+
:free => /Not found:/im,
|
181
|
+
:registered => /Domain Name:/im
|
182
|
+
)
|
183
|
+
Whois::Server.define(
|
184
|
+
%w(co.uk org.uk me.uk ltd.uk plc.uk net.uk sch.uk),
|
185
|
+
'whois.nic.uk',
|
186
|
+
:registered => /Domain name:/im,
|
187
|
+
:free => /No match for/im,
|
188
|
+
:error => /Error for/im
|
189
|
+
)
|
190
|
+
Whois::Server.define(
|
191
|
+
'de',
|
192
|
+
'whois.denic.de',
|
193
|
+
:error => /Status:\s+invalid/im,
|
194
|
+
:registered => /Status:\s+connect/im,
|
195
|
+
:free => /Status:\s+free/im
|
196
|
+
)
|
197
|
+
Whois::Server.define(
|
198
|
+
'dk',
|
199
|
+
'whois.dk-hostmaster.dk',
|
200
|
+
:registered => /Registered:/im,
|
201
|
+
:error => /Your request is not valid./im,
|
202
|
+
:free => /No entries found for the selected source./im
|
203
|
+
)
|
204
|
+
Whois::Server.define(
|
205
|
+
'eu',
|
206
|
+
'whois.eu',
|
207
|
+
:free => /AVAILABLE/im,
|
208
|
+
:registered => /Name servers\:/im,
|
209
|
+
:pending => /APPLICATION PENDING/im,
|
210
|
+
:error => /NOT ALLOWED/im
|
211
|
+
)
|
212
|
+
Whois::Server.define(
|
213
|
+
'info',
|
214
|
+
'whois.afilias.info',
|
215
|
+
:error => /Not a valid domain search pattern/im,
|
216
|
+
:registered => /Domain Name:/im,
|
217
|
+
:free => /NOT FOUND/im
|
218
|
+
)
|
219
|
+
Whois::Server.define(
|
220
|
+
'name',
|
221
|
+
'whois.nic.name',
|
222
|
+
:registered => /Not available for second level registration./im,
|
223
|
+
:preserved => /Not available for second level registration./im,
|
224
|
+
:free => /No match./im
|
225
|
+
)
|
226
|
+
|
227
|
+
# Whois::Server.define(
|
228
|
+
# 'net',
|
229
|
+
# 'whois.verisign-grs.com',
|
230
|
+
# :registered => /Domain Name:/im,
|
231
|
+
# :free => /No match for/im
|
232
|
+
# )
|
233
|
+
Whois::Server.define(
|
234
|
+
'nl',
|
235
|
+
'whois.domain-registry.nl',
|
236
|
+
:registered => /active/im,
|
237
|
+
:free => /free/im,
|
238
|
+
:error => /invalid domain/im,
|
239
|
+
:preserved => /excluded/im
|
240
|
+
)
|
241
|
+
Whois::Server.define(
|
242
|
+
'org',
|
243
|
+
'whois.publicinterestregistry.net',
|
244
|
+
:registered => /Domain Name:/im,
|
245
|
+
:free => /NOT FOUND/im,
|
246
|
+
:error => /Not a valid domain search pattern/im
|
247
|
+
)
|
248
|
+
Whois::Server.define(
|
249
|
+
'cc',
|
250
|
+
'whois.nic.cc',
|
251
|
+
:registered => /Domain Name:/im,
|
252
|
+
:free => /No match for/im
|
253
|
+
|
254
|
+
)
|
255
|
+
Whois::Server.define(
|
256
|
+
'ru',
|
257
|
+
'whois.ripn.net',
|
258
|
+
:registered => /domain:/im,
|
259
|
+
:free => /No entries found/im
|
260
|
+
|
261
|
+
)
|
262
|
+
Whois::Server.define(
|
263
|
+
'cat',
|
264
|
+
'whois.cat',
|
265
|
+
:registered => /Domain Name: /im,
|
266
|
+
:free => /NOT FOUND/im
|
267
|
+
|
268
|
+
)
|
269
|
+
Whois::Server.define(
|
270
|
+
%w(travel jobs aero pw tw),
|
271
|
+
'whois.encirca.com',
|
272
|
+
:registered => /Domain Registrar Status:/im,
|
273
|
+
:free => /Not found:/im
|
274
|
+
)
|
275
|
+
Whois::Server.define(
|
276
|
+
'mobi',
|
277
|
+
# 'whois.corenic.net',
|
278
|
+
'whois.dotmobiregistry.net',
|
279
|
+
:registered => /is not registered/im.invert!,
|
280
|
+
:free => /is not registered/im
|
281
|
+
)
|
282
|
+
Whois::Server.define(
|
283
|
+
'ca',
|
284
|
+
'whois.cira.ca',
|
285
|
+
:registered => /EXIST/im,
|
286
|
+
:free => /AVAIL/im
|
287
|
+
)
|
288
|
+
Whois::Server.define(
|
289
|
+
'asia',
|
290
|
+
'whois.nic.asia',
|
291
|
+
:registered => /Domain ID/im,
|
292
|
+
:free => /NOT FOUND/im
|
293
|
+
)
|
294
|
+
Whois::Server.define(
|
295
|
+
'co.il',
|
296
|
+
'whois.isoc.org.il',
|
297
|
+
:registered => /validity:/im,
|
298
|
+
:free => /No data was found to match the request criteria./im
|
299
|
+
)
|
300
|
+
Whois::Server.define(
|
301
|
+
'ac.uk',
|
302
|
+
'whois.ja.net',
|
303
|
+
:registered => /Domain:/im,
|
304
|
+
:free => /No such domain/im
|
305
|
+
)
|
306
|
+
Whois::Server.define(
|
307
|
+
%w(cx cm ht ki mu nf sb tl),
|
308
|
+
'whois.nic.cx',
|
309
|
+
:registered => /Expires:/im,
|
310
|
+
:free => /(Not Registered|No Applications Pending)/im
|
311
|
+
)
|
312
|
+
|
313
|
+
Whois::Server.define(
|
314
|
+
'nu',
|
315
|
+
'whois.nic.nu',
|
316
|
+
:free => /NO MATCH.*/,
|
317
|
+
:registered => /Domain Name/
|
318
|
+
)
|
319
|
+
|
320
|
+
Whois::Server.define(
|
321
|
+
'no',
|
322
|
+
'whois.norid.no',
|
323
|
+
:registered => /Domain Information/im,
|
324
|
+
:free => /% No match/im,
|
325
|
+
:creation_date => /(Created:)\s*([\w\-]+)[^\n\r]*[\n\r]/im
|
326
|
+
)
|
327
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'activesupport'
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'time'
|
6
|
+
require 'timeout'
|
7
|
+
|
8
|
+
require File.dirname(__FILE__) + '/support/string'
|
9
|
+
require File.dirname(__FILE__) + '/support/extended_regexp'
|
10
|
+
Regexp.class_eval do
|
11
|
+
include Whois::ExtendedRegexp
|
12
|
+
end
|
13
|
+
|
14
|
+
require File.dirname(__FILE__) + '/universal_ruby_whois/domain'
|
15
|
+
require File.dirname(__FILE__) + '/universal_ruby_whois/server'
|
16
|
+
require File.dirname(__FILE__) + '/universal_ruby_whois/server_list'
|
17
|
+
|
18
|
+
module Whois
|
19
|
+
|
20
|
+
# This is a wrapper around the main domain lookup function. It allows you to simply call:
|
21
|
+
# Whois.find("somedomain.com")
|
22
|
+
#
|
23
|
+
# It returns a Whois::Domain object if found, or nil if an appropriate whois server can't be found.
|
24
|
+
def find(domain)
|
25
|
+
::Whois::Domain.find(domain)
|
26
|
+
end
|
27
|
+
|
28
|
+
module_function :find #:nodoc:
|
29
|
+
|
30
|
+
end
|
data/test/regexp.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/universal_ruby_whois'
|
3
|
+
|
4
|
+
class RegexpTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_inversion
|
7
|
+
r = /hi there/.invert!
|
8
|
+
assert !r.match_with_inversion("hi there")
|
9
|
+
r.uninvert!
|
10
|
+
assert r.match_with_inversion("hi there")
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_interpolation
|
14
|
+
r = /hello __REPLACEME__ end/
|
15
|
+
assert_equal "hello __REPLACEME__ end", r.source
|
16
|
+
old_options = r.options
|
17
|
+
r2 = r.interpolate("__REPLACEME__" => "a value")
|
18
|
+
assert_equal old_options, r2.options
|
19
|
+
assert_equal "hello a value end", r2.source
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/test/string.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/universal_ruby_whois'
|
3
|
+
|
4
|
+
class StringTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_interpolation
|
7
|
+
s = "hello __REPLACEME__ end"
|
8
|
+
assert_equal "hello __REPLACEME__ end", s
|
9
|
+
s2 = s.interpolate("__REPLACEME__" => "a value")
|
10
|
+
assert_equal "hello a value end", s2
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/test/whois.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/universal_ruby_whois'
|
3
|
+
|
4
|
+
class WhoisTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
TEST_TLDS = %w(com org co.uk eu.com ru info jp eu tc nu co.nz no)
|
7
|
+
REGISTERED_DOMAIN = "google"
|
8
|
+
AVAILABLE_DOMAIN = "asdfasdfasdfcvr3rwsdc2e"
|
9
|
+
|
10
|
+
def test_invalid_tld
|
11
|
+
domain = Whois.find("hello.blahblah")
|
12
|
+
assert_nil domain
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_unavailable
|
16
|
+
TEST_TLDS.each do |tld|
|
17
|
+
domain = find_and_assert_domain("#{REGISTERED_DOMAIN}.#{tld}")
|
18
|
+
assert !domain.available?, "The domain name #{domain} shows as available but should not."
|
19
|
+
assert domain.registered?, "The domain name #{domain} does not show as registered but should."
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_available
|
24
|
+
TEST_TLDS.each do |tld|
|
25
|
+
domain = find_and_assert_domain("#{AVAILABLE_DOMAIN}.#{tld}")
|
26
|
+
assert domain.available?, "The domain name #{domain} does not show as available but should."
|
27
|
+
assert !domain.registered?, "The domain name #{domain} shows as registered but should not."
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_creation_date
|
32
|
+
domain = find_and_assert_domain("google.com")
|
33
|
+
assert_equal Time.local(*ParseDate.parsedate("1997-09-15")), domain.creation_date
|
34
|
+
|
35
|
+
TEST_TLDS.each do |tld|
|
36
|
+
domain = find_and_assert_domain("#{REGISTERED_DOMAIN}.#{tld}")
|
37
|
+
next unless domain.creation_date_known?
|
38
|
+
assert_kind_of Time, domain.creation_date, "Can't find creation date for domain: #{domain}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_expiration_date
|
43
|
+
domain = find_and_assert_domain("google.com")
|
44
|
+
assert_equal Time.local(*ParseDate.parsedate("2011-09-14")), domain.expiration_date
|
45
|
+
|
46
|
+
TEST_TLDS.each do |tld|
|
47
|
+
domain = find_and_assert_domain("#{REGISTERED_DOMAIN}.#{tld}")
|
48
|
+
next unless domain.expiration_date_known?
|
49
|
+
assert_kind_of Time, domain.expiration_date, "Can't find expiration date for domain: #{domain}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_mobi_domain
|
54
|
+
domain = find_and_assert_domain("google.mobi")
|
55
|
+
assert domain.expiration_date_known?
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_no_domain
|
59
|
+
domain = find_and_assert_domain("norge.no")
|
60
|
+
assert_equal Time.local(*ParseDate.parsedate("1999-11-15")), domain.creation_date
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
def find_and_assert_domain(domain)
|
66
|
+
domain_object = ::Whois.find(domain)
|
67
|
+
assert_kind_of Whois::Domain, domain_object, "Unable to look up info for domain name: #{domain}"
|
68
|
+
assert domain_object.valid?, "The domain name object for #{domain} is not valid (perhaps the whois server is down or busy?)"
|
69
|
+
domain_object
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
PKG_NAME = 'universal_ruby_whois'
|
2
|
+
PKG_VERSION = '1.2.9'
|
3
|
+
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
4
|
+
# RUBY_FORGE_PROJECT = 'universalwhois'
|
5
|
+
# RUBY_FORGE_USER = 'mlightner'
|
6
|
+
|
7
|
+
GEM_SPEC = spec = Gem::Specification.new do |s|
|
8
|
+
s.name = PKG_NAME
|
9
|
+
s.version = PKG_VERSION
|
10
|
+
s.author = "Vasily Shmelev"
|
11
|
+
s.email = "sleephunter@gmail.com"
|
12
|
+
s.homepage = "https://github.com/vs-adm/universal_ruby_whois/tree/master"
|
13
|
+
s.platform = Gem::Platform::RUBY
|
14
|
+
s.summary = "A module that attempts to act as a universal WHOIS output interpreter allowing you to get information about most domain name extensions."
|
15
|
+
s.files = %w(
|
16
|
+
README.rdoc
|
17
|
+
CHANGELOG.rdoc
|
18
|
+
LICENSE
|
19
|
+
universal_ruby_whois.gemspec
|
20
|
+
lib/universal_ruby_whois.rb
|
21
|
+
lib/universal_ruby_whois/server.rb
|
22
|
+
lib/universal_ruby_whois/server_list.rb
|
23
|
+
lib/universal_ruby_whois/domain.rb
|
24
|
+
lib/support/extended_regexp.rb
|
25
|
+
lib/support/string.rb
|
26
|
+
test/whois.rb
|
27
|
+
test/string.rb
|
28
|
+
test/regexp.rb
|
29
|
+
)
|
30
|
+
s.require_path = "lib"
|
31
|
+
s.autorequire = "name"
|
32
|
+
s.add_dependency('activesupport', '>= 1.4.4')
|
33
|
+
s.test_files = %w(
|
34
|
+
test/whois.rb
|
35
|
+
test/string.rb
|
36
|
+
test/regexp.rb
|
37
|
+
)
|
38
|
+
s.has_rdoc = true
|
39
|
+
#s.extra_rdoc_files = ["README", "LICENSE"]
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: universal_ruby_whois
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.9
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Vasily Shmelev
|
9
|
+
autorequire: name
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.4.4
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.4.4
|
30
|
+
description:
|
31
|
+
email: sleephunter@gmail.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- README.rdoc
|
37
|
+
- CHANGELOG.rdoc
|
38
|
+
- LICENSE
|
39
|
+
- universal_ruby_whois.gemspec
|
40
|
+
- lib/universal_ruby_whois.rb
|
41
|
+
- lib/universal_ruby_whois/server.rb
|
42
|
+
- lib/universal_ruby_whois/server_list.rb
|
43
|
+
- lib/universal_ruby_whois/domain.rb
|
44
|
+
- lib/support/extended_regexp.rb
|
45
|
+
- lib/support/string.rb
|
46
|
+
- test/whois.rb
|
47
|
+
- test/string.rb
|
48
|
+
- test/regexp.rb
|
49
|
+
homepage: https://github.com/vs-adm/universal_ruby_whois/tree/master
|
50
|
+
licenses: []
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.8.24
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: A module that attempts to act as a universal WHOIS output interpreter allowing
|
73
|
+
you to get information about most domain name extensions.
|
74
|
+
test_files:
|
75
|
+
- test/whois.rb
|
76
|
+
- test/string.rb
|
77
|
+
- test/regexp.rb
|