universal_ruby_whois 1.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|