whois 0.5.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +55 -0
- data/Manifest +43 -8
- data/README.rdoc +53 -20
- data/lib/whois.rb +69 -1
- data/lib/whois/answer.rb +126 -0
- data/lib/whois/answer/contact.rb +55 -0
- data/lib/whois/answer/parser.rb +110 -0
- data/lib/whois/answer/parser/README.rdoc +21 -0
- data/lib/whois/answer/parser/base.rb +144 -0
- data/lib/whois/answer/parser/blank.rb +45 -0
- data/lib/whois/answer/parser/whois.crsnic.net.rb +209 -0
- data/lib/whois/answer/parser/whois.denic.de.rb +202 -0
- data/lib/whois/answer/parser/whois.nic.it.rb +330 -0
- data/lib/whois/answer/parser/whois.publicinterestregistry.net.rb +232 -0
- data/lib/whois/answer/part.rb +35 -0
- data/lib/whois/answer/registrar.rb +42 -0
- data/lib/whois/answer/super_struct.rb +57 -0
- data/lib/whois/client.rb +6 -0
- data/lib/whois/definitions/tlds.rb +2 -2
- data/lib/whois/errors.rb +25 -8
- data/lib/whois/server.rb +0 -1
- data/lib/whois/server/adapters/afilias.rb +5 -5
- data/lib/whois/server/adapters/base.rb +31 -4
- data/lib/whois/server/adapters/formatted.rb +3 -1
- data/lib/whois/server/adapters/none.rb +20 -1
- data/lib/whois/server/adapters/pir.rb +5 -5
- data/lib/whois/server/adapters/standard.rb +13 -2
- data/lib/whois/server/adapters/verisign.rb +5 -5
- data/lib/whois/server/adapters/web.rb +15 -0
- data/lib/whois/version.rb +2 -2
- data/lib/whois/whois.rb +2 -2
- data/test/answer/parser/base_test.rb +27 -0
- data/test/answer/parser/blank_test.rb +19 -0
- data/test/answer/parser/whois_crsnic_net_test.rb +175 -0
- data/test/answer/parser/whois_denic_de_test.rb +209 -0
- data/test/answer/parser/whois_nic_it_test.rb +255 -0
- data/test/answer/parser/whois_publicinterestregistry_net_test.rb +210 -0
- data/test/answer/parser_test.rb +77 -0
- data/test/answer_test.rb +99 -0
- data/test/client_test.rb +3 -3
- data/test/integration_test.rb +31 -0
- data/test/{adapters → server/adapters}/afilias_test.rb +10 -5
- data/test/server/adapters/base_test.rb +15 -0
- data/test/server/adapters/formatted_test.rb +26 -0
- data/test/{adapters → server/adapters}/none_test.rb +0 -0
- data/test/{adapters → server/adapters}/not_implemented_test.rb +0 -0
- data/test/{adapters → server/adapters}/pir_test.rb +10 -5
- data/test/server/adapters/standard_test.rb +29 -0
- data/test/{adapters → server/adapters}/verisign_test.rb +10 -5
- data/test/{adapters → server/adapters}/web_test.rb +0 -0
- data/test/server_test.rb +5 -1
- data/test/testcases/responses/super_struct_test.rb +25 -0
- data/test/testcases/responses/whois.crsnic.net/available.txt +43 -0
- data/test/testcases/responses/whois.crsnic.net/registered.txt +57 -0
- data/test/testcases/responses/whois.denic.de/available.txt +30 -0
- data/test/testcases/responses/whois.denic.de/registered.txt +77 -0
- data/test/testcases/responses/whois.nic.it/available.txt +2 -0
- data/test/testcases/responses/{it.txt → whois.nic.it/registered.txt} +1 -0
- data/test/testcases/responses/whois.nic.it/status_active.txt +53 -0
- data/test/testcases/responses/whois.nic.it/status_available.txt +2 -0
- data/test/testcases/responses/whois.publicinterestregistry.net/available.txt +1 -0
- data/test/testcases/responses/whois.publicinterestregistry.net/registered.txt +85 -0
- data/test/whois_test.rb +23 -1
- data/utils/bm_delegation_vs_inheritance.rb +150 -0
- data/whois.gemspec +6 -6
- metadata +78 -18
- data/test/adapters/standard_test.rb +0 -23
@@ -0,0 +1,232 @@
|
|
1
|
+
#
|
2
|
+
# = Ruby Whois
|
3
|
+
#
|
4
|
+
# An intelligent pure Ruby WHOIS client.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# Category:: Net
|
8
|
+
# Package:: Whois
|
9
|
+
# Author:: Simone Carletti <weppos@weppos.net>
|
10
|
+
# License:: MIT License
|
11
|
+
#
|
12
|
+
#--
|
13
|
+
#
|
14
|
+
#++
|
15
|
+
|
16
|
+
|
17
|
+
require 'whois/answer/parser/base'
|
18
|
+
|
19
|
+
|
20
|
+
module Whois
|
21
|
+
class Answer
|
22
|
+
class Parser
|
23
|
+
|
24
|
+
#
|
25
|
+
# = whois.publicinterestregistry.net parser
|
26
|
+
#
|
27
|
+
# Parser for the whois.publicinterestregistry.net server.
|
28
|
+
#
|
29
|
+
class WhoisPublicinterestregistryNet < Base
|
30
|
+
|
31
|
+
register_method :disclaimer do
|
32
|
+
node("Disclaimer")
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
register_method :domain do
|
37
|
+
node("Domain Name") { |value| value.downcase }
|
38
|
+
end
|
39
|
+
|
40
|
+
register_method :domain_id do
|
41
|
+
node("Domain ID")
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
register_method :status do
|
46
|
+
node("Status")
|
47
|
+
end
|
48
|
+
|
49
|
+
register_method :available? do
|
50
|
+
node("Domain ID").nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
register_method :registered? do
|
54
|
+
!available?
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
register_method :created_on do
|
59
|
+
node("Created On") { |value| Time.parse(value) }
|
60
|
+
end
|
61
|
+
|
62
|
+
register_method :updated_on do
|
63
|
+
node("Last Updated On") { |value| Time.parse(value) }
|
64
|
+
end
|
65
|
+
|
66
|
+
register_method :expires_on do
|
67
|
+
node("Expiration Date") { |value| Time.parse(value) }
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
register_method :registrar do
|
72
|
+
node("Sponsoring Registrar") do |registrar|
|
73
|
+
id, name = if registrar =~ /(.*?)\((.*?)\)/
|
74
|
+
[$2.strip, $1.strip]
|
75
|
+
else
|
76
|
+
[nil, registrar]
|
77
|
+
end
|
78
|
+
Answer::Registrar.new(
|
79
|
+
:id => id,
|
80
|
+
:name => name
|
81
|
+
)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
register_method :registrant do
|
86
|
+
contact("Registrant")
|
87
|
+
end
|
88
|
+
|
89
|
+
register_method :admin do
|
90
|
+
contact("Admin")
|
91
|
+
end
|
92
|
+
|
93
|
+
register_method :technical do
|
94
|
+
contact("Tech")
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
register_method :nameservers do
|
99
|
+
node("Name Server") { |server| server.reject { |value| value.empty? }.map { |value| value.downcase }}
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
register_method :changed? do |other|
|
104
|
+
!unchanged?(other)
|
105
|
+
end
|
106
|
+
|
107
|
+
register_method :unchanged? do |other|
|
108
|
+
self == other ||
|
109
|
+
self.content.to_s == other.content.to_s
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
protected
|
114
|
+
|
115
|
+
def contact(element)
|
116
|
+
node("#{element} ID") do |registrant_id|
|
117
|
+
Answer::Contact.new(
|
118
|
+
:id => registrant_id,
|
119
|
+
:name => node("#{element} Name"),
|
120
|
+
:organization => node("#{element} Organization"),
|
121
|
+
:address => [node("#{element} Street1"),
|
122
|
+
node("#{element} Street2"),
|
123
|
+
node("#{element} Street3")].reject { |value| value.to_s.empty? }.join(" "),
|
124
|
+
:city => node("#{element} City"),
|
125
|
+
:zip => node("#{element} Postal Code"),
|
126
|
+
:state => node("#{element} State/Province"),
|
127
|
+
:country_code => node("#{element} Country"),
|
128
|
+
:phone => node("#{element} Phone"),
|
129
|
+
:fax => node("#{element} FAX"),
|
130
|
+
:email => node("#{element} Email")
|
131
|
+
)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
def ast
|
137
|
+
@ast ||= parse
|
138
|
+
end
|
139
|
+
|
140
|
+
def node(key, &block)
|
141
|
+
if block_given?
|
142
|
+
value = ast[key]
|
143
|
+
value = yield(value) unless value.nil?
|
144
|
+
value
|
145
|
+
else
|
146
|
+
ast[key]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def node?(key)
|
151
|
+
!ast[key].nil?
|
152
|
+
end
|
153
|
+
|
154
|
+
def parse
|
155
|
+
Scanner.new(content.to_s).parse
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
class Scanner
|
160
|
+
|
161
|
+
def initialize(content)
|
162
|
+
@input = StringScanner.new(content.to_s)
|
163
|
+
end
|
164
|
+
|
165
|
+
def parse
|
166
|
+
@ast = {}
|
167
|
+
while !@input.eos?
|
168
|
+
parse_content
|
169
|
+
end
|
170
|
+
@ast
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
def parse_content
|
176
|
+
trim_newline ||
|
177
|
+
parse_not_found ||
|
178
|
+
parse_disclaimer ||
|
179
|
+
parse_pair ||
|
180
|
+
error("Unexpected token")
|
181
|
+
end
|
182
|
+
|
183
|
+
def trim_newline
|
184
|
+
# The last line is \r\n\n
|
185
|
+
@input.scan(/\r\n+/)
|
186
|
+
end
|
187
|
+
|
188
|
+
def parse_not_found
|
189
|
+
@input.scan(/NOT FOUND\n/)
|
190
|
+
end
|
191
|
+
|
192
|
+
def parse_disclaimer
|
193
|
+
if @input.match?(/NOTICE:/)
|
194
|
+
lines = []
|
195
|
+
while !@input.match?(/\r\n/) && @input.scan(/(.*)\r\n/)
|
196
|
+
lines << @input[1].strip
|
197
|
+
end
|
198
|
+
@ast["Disclaimer"] = lines.join(" ")
|
199
|
+
else
|
200
|
+
false
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def parse_pair
|
205
|
+
if @input.scan(/(.*?):(.*?)\r\n/)
|
206
|
+
key, value = @input[1].strip, @input[2].strip
|
207
|
+
if @ast[key].nil?
|
208
|
+
@ast[key] = value
|
209
|
+
else
|
210
|
+
@ast[key].is_a?(Array) || @ast[key] = [@ast[key]]
|
211
|
+
@ast[key] << value
|
212
|
+
end
|
213
|
+
else
|
214
|
+
false
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def error(message)
|
219
|
+
if @input.eos?
|
220
|
+
raise "Unexpected end of input."
|
221
|
+
else
|
222
|
+
raise "#{message}: #{@input.peek(@input.string.length)}"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#
|
2
|
+
# = Ruby Whois
|
3
|
+
#
|
4
|
+
# An intelligent pure Ruby WHOIS client.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# Category:: Net
|
8
|
+
# Package:: Whois
|
9
|
+
# Author:: Simone Carletti <weppos@weppos.net>
|
10
|
+
# License:: MIT License
|
11
|
+
#
|
12
|
+
#--
|
13
|
+
#
|
14
|
+
#++
|
15
|
+
|
16
|
+
|
17
|
+
require 'whois/answer/super_struct'
|
18
|
+
|
19
|
+
|
20
|
+
module Whois
|
21
|
+
class Answer
|
22
|
+
|
23
|
+
#
|
24
|
+
# = Part
|
25
|
+
#
|
26
|
+
# A single <tt>Whois::Answer</tt> fragment. For instance,
|
27
|
+
# in case of thin server, an <tt>Whois::Answer</tt> may be composed by
|
28
|
+
# one or more parts corresponding to all responses
|
29
|
+
# returned by the WHOIS servers.
|
30
|
+
#
|
31
|
+
class Part < SuperStruct.new(:response, :host)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#
|
2
|
+
# = Ruby Whois
|
3
|
+
#
|
4
|
+
# An intelligent pure Ruby WHOIS client.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# Category:: Net
|
8
|
+
# Package:: Whois
|
9
|
+
# Author:: Simone Carletti <weppos@weppos.net>
|
10
|
+
# License:: MIT License
|
11
|
+
#
|
12
|
+
#--
|
13
|
+
#
|
14
|
+
#++
|
15
|
+
|
16
|
+
|
17
|
+
require 'whois/answer/super_struct'
|
18
|
+
|
19
|
+
|
20
|
+
module Whois
|
21
|
+
class Answer
|
22
|
+
|
23
|
+
#
|
24
|
+
# = Registrar
|
25
|
+
#
|
26
|
+
# Holds the details of the Registrar extracted from the WHOIS answer.
|
27
|
+
#
|
28
|
+
# A Registrar is composed by the following attributes:
|
29
|
+
#
|
30
|
+
# <tt>:id</tt>::
|
31
|
+
# <tt>:name</tt>::
|
32
|
+
# <tt>:organization</tt>::
|
33
|
+
# <tt>:url</tt>::
|
34
|
+
#
|
35
|
+
# Be aware that every WHOIS server can return a different number of details
|
36
|
+
# or no details at all.
|
37
|
+
#
|
38
|
+
class Registrar < SuperStruct.new(:id, :name, :organization, :url)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#
|
2
|
+
# = Ruby Whois
|
3
|
+
#
|
4
|
+
# An intelligent pure Ruby WHOIS client.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# Category:: Net
|
8
|
+
# Package:: Whois
|
9
|
+
# Author:: Simone Carletti <weppos@weppos.net>
|
10
|
+
# License:: MIT License
|
11
|
+
#
|
12
|
+
#--
|
13
|
+
#
|
14
|
+
#++
|
15
|
+
|
16
|
+
|
17
|
+
require 'ostruct'
|
18
|
+
|
19
|
+
|
20
|
+
#
|
21
|
+
# = SuperStruct
|
22
|
+
#
|
23
|
+
# SuperStruct is an enhanced version of the Ruby Standar library <tt>Struct</tt>.
|
24
|
+
#
|
25
|
+
# Compared with the original version, it provides the following additional features:
|
26
|
+
# * ability to initialize an instance from Hash
|
27
|
+
# * ability to pass a block on creation
|
28
|
+
#
|
29
|
+
class SuperStruct < Struct
|
30
|
+
|
31
|
+
# Overwrites the standard Struct initializer
|
32
|
+
# to add the ability to create an instance from a Hash of parameters.
|
33
|
+
#
|
34
|
+
# attributes = { :foo => 1, :bar => "baz" }
|
35
|
+
# Struct.new(attributes)
|
36
|
+
# # => #<Struct foo=1, bar="baz">
|
37
|
+
#
|
38
|
+
# If block is given, the block is called on self.
|
39
|
+
#
|
40
|
+
def initialize(*args, &block)
|
41
|
+
if args.first.is_a? Hash
|
42
|
+
initialize_with_hash(args.first)
|
43
|
+
else
|
44
|
+
super
|
45
|
+
end
|
46
|
+
yield(self) if block_given?
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def initialize_with_hash(attributes = {})
|
52
|
+
attributes.each do |key, value|
|
53
|
+
self[key] = value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/lib/whois/client.rb
CHANGED
@@ -60,6 +60,12 @@ module Whois
|
|
60
60
|
end
|
61
61
|
|
62
62
|
|
63
|
+
# Queries the right whois server for <tt>qstring</tt> and returns
|
64
|
+
# a <tt>Whois::Answer</tt> instance containing the response from the server.
|
65
|
+
#
|
66
|
+
# client.query("google.com")
|
67
|
+
# # => #<Whois::Answer>
|
68
|
+
#
|
63
69
|
def query(qstring)
|
64
70
|
Timeout::timeout(timeout) do
|
65
71
|
@server = Server.guess(qstring)
|
@@ -34,7 +34,7 @@ Whois::Server.define :tld, ".arpa", "whois.iana.org"
|
|
34
34
|
Whois::Server.define :tld, ".aero", "whois.aero"
|
35
35
|
Whois::Server.define :tld, ".asia", "whois.nic.asia"
|
36
36
|
Whois::Server.define :tld, ".biz", "whois.nic.biz"
|
37
|
-
Whois::Server.define :tld, ".cat", "whois.cat", {:format => "-C US-ASCII ace %s"}
|
37
|
+
Whois::Server.define :tld, ".cat", "whois.cat", {:adapter=>Whois::Server::Adapters::Formatted, :format => "-C US-ASCII ace %s"}
|
38
38
|
Whois::Server.define :tld, ".coop", "whois.nic.coop"
|
39
39
|
Whois::Server.define :tld, ".info", "whois.afilias.info"
|
40
40
|
Whois::Server.define :tld, ".jobs", "jobswhois.verisign-grs.com", {:adapter=>Whois::Server::Adapters::Verisign}
|
@@ -102,7 +102,7 @@ Whois::Server.define :tld, ".cv", nil, {:adapter=>Whois::Server::Adapters::None}
|
|
102
102
|
Whois::Server.define :tld, ".cx", "whois.nic.cx"
|
103
103
|
Whois::Server.define :tld, ".cy", nil, {:web=>"http://www.nic.cy/nslookup/online_database.php", :adapter=>Whois::Server::Adapters::Web}
|
104
104
|
Whois::Server.define :tld, ".cz", "whois.nic.cz"
|
105
|
-
Whois::Server.define :tld, ".de", "whois.denic.de", {:format => "-T dn,ace -C US-ASCII %s"}
|
105
|
+
Whois::Server.define :tld, ".de", "whois.denic.de", {:adapter=>Whois::Server::Adapters::Formatted, :format => "-T dn,ace -C US-ASCII %s"}
|
106
106
|
Whois::Server.define :tld, ".dj", "whois.domain.dj"
|
107
107
|
Whois::Server.define :tld, ".dk", "whois.dk-hostmaster.dk"
|
108
108
|
Whois::Server.define :tld, ".dm", "whois.nic.dm"
|
data/lib/whois/errors.rb
CHANGED
@@ -25,33 +25,30 @@ module Whois
|
|
25
25
|
class ServerError < Error
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
# Definition not found
|
28
|
+
# Server Definition not found
|
30
29
|
|
31
30
|
# Raised when the class hasn't been able to select a valid server
|
32
31
|
# probably because definitions are outdated.
|
33
32
|
class ServerNotFound < ServerError
|
34
33
|
end
|
35
34
|
|
36
|
-
|
37
|
-
# Definition found
|
35
|
+
# Server Definition found
|
38
36
|
|
39
37
|
class InterfaceNotSupported < ServerError
|
40
38
|
end
|
41
39
|
|
42
40
|
# Raised when a server is known to not be available for this kind of object
|
43
|
-
# or because this specific object doesn't support
|
41
|
+
# or because this specific object doesn't support WHOIS. (\x03)
|
44
42
|
class NoInterfaceError < InterfaceNotSupported
|
45
43
|
end
|
46
44
|
|
47
45
|
# Raised when the class has found a server but it doesn't support the
|
48
46
|
# standard whois interface via port 43. This is the case of some
|
49
|
-
# specific domains that only provide a web–based
|
47
|
+
# specific domains that only provide a web–based WHOIS interface. (\x01)
|
50
48
|
class WebInterfaceError < InterfaceNotSupported
|
51
49
|
end
|
52
50
|
|
53
|
-
|
54
|
-
# Known object, Definition unavailable
|
51
|
+
# Server Known object, Definition unavailable
|
55
52
|
|
56
53
|
# Raised when we know about a specific functionality
|
57
54
|
# but this functionality has not been implemented yet.
|
@@ -66,5 +63,25 @@ module Whois
|
|
66
63
|
# Raised when unknown AS numer of IP network. (\x06)
|
67
64
|
class AllocationUnknown < ServerError
|
68
65
|
end
|
66
|
+
|
67
|
+
|
68
|
+
# Generic Parser exception class.
|
69
|
+
class ParserError < Error
|
70
|
+
end
|
71
|
+
|
72
|
+
# Raised when the class hasn't been able to load a valid parser
|
73
|
+
# according to current settings.
|
74
|
+
class ParserNotFound < ParserError
|
75
|
+
end
|
76
|
+
|
77
|
+
# Raised when the property method has not been overwritten (implemented)
|
78
|
+
# in a child parser class.
|
79
|
+
class PropertyNotImplemented < ParserError
|
80
|
+
end
|
81
|
+
|
82
|
+
# Raised when you are trying to access a property that is not supported
|
83
|
+
# by any of the parsers available for current WHOIS answer.
|
84
|
+
class PropertyNotSupported < ParserError
|
85
|
+
end
|
69
86
|
|
70
87
|
end
|