nicinfo 0.2.0
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.
- checksums.yaml +7 -0
- data/bin/nicinfo +22 -0
- data/lib/autnum.rb +90 -0
- data/lib/bootstrap.rb +198 -0
- data/lib/bsfiles/asn.json +2326 -0
- data/lib/bsfiles/dns.json +25 -0
- data/lib/bsfiles/entity.json +52 -0
- data/lib/bsfiles/ipv4.json +244 -0
- data/lib/bsfiles/ipv6.json +97 -0
- data/lib/cache.rb +141 -0
- data/lib/common_json.rb +263 -0
- data/lib/common_names.rb +49 -0
- data/lib/config.rb +260 -0
- data/lib/constants.rb +113 -0
- data/lib/data_tree.rb +205 -0
- data/lib/demo/autnum.json +228 -0
- data/lib/demo/domain-dnr.json +695 -0
- data/lib/demo/domain-rir.json +569 -0
- data/lib/demo/domains.json +625 -0
- data/lib/demo/entities.json +545 -0
- data/lib/demo/entity-dnr.json +143 -0
- data/lib/demo/entity-rir.json +394 -0
- data/lib/demo/error-code.json +31 -0
- data/lib/demo/help.json +58 -0
- data/lib/demo/ip.json +306 -0
- data/lib/demo/nameservers.json +434 -0
- data/lib/demo/ns-simple.json +210 -0
- data/lib/demo/ns-very-simple.json +41 -0
- data/lib/demo/ns.json +63 -0
- data/lib/demo/simple-ip.json +41 -0
- data/lib/demo/simple.json +13 -0
- data/lib/domain.rb +203 -0
- data/lib/ds_data.rb +70 -0
- data/lib/entity.rb +372 -0
- data/lib/enum.rb +47 -0
- data/lib/error_code.rb +56 -0
- data/lib/female-first-names.txt +4275 -0
- data/lib/ip.rb +86 -0
- data/lib/key_data.rb +70 -0
- data/lib/last-names.txt +88799 -0
- data/lib/male-first-names.txt +1219 -0
- data/lib/nicinfo_logger.rb +370 -0
- data/lib/nicinfo_main.rb +1013 -0
- data/lib/notices.rb +110 -0
- data/lib/ns.rb +108 -0
- data/lib/utils.rb +189 -0
- metadata +90 -0
data/lib/nicinfo_main.rb
ADDED
@@ -0,0 +1,1013 @@
|
|
1
|
+
# Copyright (C) 2011,2012,2013,2014 American Registry for Internet Numbers
|
2
|
+
#
|
3
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
4
|
+
# purpose with or without fee is hereby granted, provided that the above
|
5
|
+
# copyright notice and this permission notice appear in all copies.
|
6
|
+
#
|
7
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
13
|
+
# IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
14
|
+
|
15
|
+
|
16
|
+
require 'optparse'
|
17
|
+
require 'net/http'
|
18
|
+
require 'net/https'
|
19
|
+
require 'uri'
|
20
|
+
require 'config'
|
21
|
+
require 'constants'
|
22
|
+
require 'cache'
|
23
|
+
require 'enum'
|
24
|
+
require 'common_names'
|
25
|
+
require 'bootstrap'
|
26
|
+
require 'notices'
|
27
|
+
require 'entity'
|
28
|
+
require 'ip'
|
29
|
+
require 'ns'
|
30
|
+
require 'domain'
|
31
|
+
require 'autnum'
|
32
|
+
require 'error_code'
|
33
|
+
require 'ipaddr'
|
34
|
+
require 'data_tree'
|
35
|
+
begin
|
36
|
+
require 'json'
|
37
|
+
rescue LoadError
|
38
|
+
require 'rubygems'
|
39
|
+
require 'json'
|
40
|
+
end
|
41
|
+
|
42
|
+
module NicInfo
|
43
|
+
|
44
|
+
class QueryType < NicInfo::Enum
|
45
|
+
|
46
|
+
QueryType.add_item :BY_IP4_ADDR, "IP4ADDR"
|
47
|
+
QueryType.add_item :BY_IP6_ADDR, "IP6ADDR"
|
48
|
+
QueryType.add_item :BY_IP4_CIDR, "IP4CIDR"
|
49
|
+
QueryType.add_item :BY_IP6_CIDR, "IP6CIDR"
|
50
|
+
QueryType.add_item :BY_IP, "IP"
|
51
|
+
QueryType.add_item :BY_AS_NUMBER, "ASNUMBER"
|
52
|
+
QueryType.add_item :BY_DOMAIN, "DOMAIN"
|
53
|
+
QueryType.add_item :BY_RESULT, "RESULT"
|
54
|
+
QueryType.add_item :BY_ENTITY_HANDLE, "ENTITYHANDLE"
|
55
|
+
QueryType.add_item :BY_NAMESERVER, "NAMESERVER"
|
56
|
+
QueryType.add_item :SRCH_ENTITY_BY_NAME, "ESBYNAME"
|
57
|
+
QueryType.add_item :SRCH_DOMAINS, "DOMAINS"
|
58
|
+
QueryType.add_item :SRCH_DOMAIN_BY_NAME, "DSBYNAME"
|
59
|
+
QueryType.add_item :SRCH_DOMAIN_BY_NSNAME, "DSBYNSNAME"
|
60
|
+
QueryType.add_item :SRCH_DOMAIN_BY_NSIP, "DSBYNSIP"
|
61
|
+
QueryType.add_item :SRCH_NS, "NAMESERVERS"
|
62
|
+
QueryType.add_item :SRCH_NS_BY_NAME, "NSBYNAME"
|
63
|
+
QueryType.add_item :SRCH_NS_BY_IP, "NSBYIP"
|
64
|
+
QueryType.add_item :BY_SERVER_HELP, "HELP"
|
65
|
+
QueryType.add_item :BY_URL, "URL"
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
# The main class for the nicinfo command.
|
70
|
+
class Main
|
71
|
+
|
72
|
+
def initialize args, config = nil
|
73
|
+
|
74
|
+
if config
|
75
|
+
@config = config
|
76
|
+
else
|
77
|
+
@config = NicInfo::Config.new(NicInfo::Config::formulate_app_data_dir())
|
78
|
+
end
|
79
|
+
|
80
|
+
@config.options.require_query = true
|
81
|
+
|
82
|
+
@opts = OptionParser.new do |opts|
|
83
|
+
|
84
|
+
opts.banner = "Usage: nicinfo [options] QUERY_VALUE"
|
85
|
+
opts.version = NicInfo::VERSION_LABEL
|
86
|
+
|
87
|
+
opts.separator ""
|
88
|
+
opts.separator "Query Options:"
|
89
|
+
|
90
|
+
opts.on("-t", "--type TYPE",
|
91
|
+
"Specify type of the query value.",
|
92
|
+
" ip4addr - IPv4 address",
|
93
|
+
" ip6addr - IPv6 address",
|
94
|
+
" ip4cidr - IPv4 cidr block",
|
95
|
+
" ip6cidr - IPv6 cidr block",
|
96
|
+
" asnumber - autonomous system number",
|
97
|
+
" domain - domain name",
|
98
|
+
" entityhandle - handle or id of a contact, organization, registrar or other entity",
|
99
|
+
" nameserver - fully qualified domain name of a nameserver",
|
100
|
+
" result - result from a previous query",
|
101
|
+
" esbyname - entity search by name",
|
102
|
+
" dsbyname - domain search by name",
|
103
|
+
" dsbynsname - domain search by nameserver name",
|
104
|
+
" dsbynsip - domain search by nameserver IP address",
|
105
|
+
" nsbyname - nameserver search by nameserver name",
|
106
|
+
" nsbyip - nameserver search by IP address",
|
107
|
+
" url - RDAP URL",
|
108
|
+
" help - server help") do |type|
|
109
|
+
uptype = type.upcase
|
110
|
+
raise OptionParser::InvalidArgument, type.to_s unless QueryType.has_value?(uptype)
|
111
|
+
@config.options.query_type = uptype
|
112
|
+
@config.options.require_query = false if uptype == "HELP"
|
113
|
+
end
|
114
|
+
|
115
|
+
opts.on("-r", "--reverse",
|
116
|
+
"Creates a reverse DNS name from an IP address. ") do |reverse|
|
117
|
+
@config.options.reverse_ip = true
|
118
|
+
end
|
119
|
+
|
120
|
+
opts.on("-b", "--base (or bootstrap) URL",
|
121
|
+
"The base URL of the RDAP Service.",
|
122
|
+
"When set, the internal bootstrap is bypassed.") do |url|
|
123
|
+
@config.config[ NicInfo::BOOTSTRAP][ NicInfo::BOOTSTRAP_URL ] = url
|
124
|
+
end
|
125
|
+
|
126
|
+
opts.separator ""
|
127
|
+
opts.separator "Cache Options:"
|
128
|
+
|
129
|
+
opts.on("--cache-expiry SECONDS",
|
130
|
+
"Age in seconds of items in the cache to be considered expired.") do |s|
|
131
|
+
@config.config[ NicInfo::CACHE ][ NicInfo::CACHE_EXPIRY ] = s
|
132
|
+
end
|
133
|
+
|
134
|
+
opts.on("--cache YES|NO|TRUE|FALSE",
|
135
|
+
"Controls if the cache is used or not.") do |cc|
|
136
|
+
@config.config[ NicInfo::CACHE ][ NicInfo::USE_CACHE ] = false if cc =~ /no|false/i
|
137
|
+
@config.config[ NicInfo::CACHE ][ NicInfo::USE_CACHE ] = true if cc =~ /yes|true/i
|
138
|
+
raise OptionParser::InvalidArgument, cc.to_s unless cc =~ /yes|no|true|false/i
|
139
|
+
end
|
140
|
+
|
141
|
+
opts.on("--empty-cache",
|
142
|
+
"Empties the cache of all files regardless of eviction policy.") do |cc|
|
143
|
+
@config.options.empty_cache = true
|
144
|
+
@config.options.require_query = false
|
145
|
+
end
|
146
|
+
|
147
|
+
opts.on("--demo",
|
148
|
+
"Populates the cache with demonstration results.") do |cc|
|
149
|
+
@config.options.demo = true
|
150
|
+
@config.options.require_query = false
|
151
|
+
end
|
152
|
+
|
153
|
+
opts.separator ""
|
154
|
+
opts.separator "Output Options:"
|
155
|
+
|
156
|
+
opts.on( "--messages MESSAGE_LEVEL",
|
157
|
+
"Specify the message level",
|
158
|
+
" none - no messages are to be output",
|
159
|
+
" some - some messages but not all",
|
160
|
+
" all - all messages to be outupt" ) do |m|
|
161
|
+
@config.logger.message_level = m.to_s.upcase
|
162
|
+
begin
|
163
|
+
@config.logger.validate_message_level
|
164
|
+
rescue
|
165
|
+
raise OptionParser::InvalidArgument, m.to_s
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
opts.on( "--messages-out FILE",
|
170
|
+
"FILE where messages will be written." ) do |f|
|
171
|
+
@config.logger.messages_out = File.open( f, "w+" )
|
172
|
+
end
|
173
|
+
|
174
|
+
opts.on( "--data DATA_AMOUNT",
|
175
|
+
"Specify the amount of data",
|
176
|
+
" terse - enough data to identify the object",
|
177
|
+
" normal - normal view of data on objects",
|
178
|
+
" extra - all data about the object" ) do |d|
|
179
|
+
@config.logger.data_amount = d.to_s.upcase
|
180
|
+
begin
|
181
|
+
@config.logger.validate_data_amount
|
182
|
+
rescue
|
183
|
+
raise OptionParser::InvalidArgument, d.to_s
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
opts.on( "--data-out FILE",
|
188
|
+
"FILE where data will be written." ) do |f|
|
189
|
+
@config.logger.data_out = File.open( f, "w+" )
|
190
|
+
end
|
191
|
+
|
192
|
+
opts.on( "--pager YES|NO|TRUE|FALSE",
|
193
|
+
"Turns the pager on and off." ) do |pager|
|
194
|
+
@config.logger.pager = false if pager =~ /no|false/i
|
195
|
+
@config.logger.pager = true if pager =~ /yes|true/i
|
196
|
+
raise OptionParser::InvalidArgument, pager.to_s unless pager =~ /yes|no|true|false/i
|
197
|
+
end
|
198
|
+
|
199
|
+
opts.on( "-V",
|
200
|
+
"Equivalent to --messages all and --data extra" ) do |v|
|
201
|
+
@config.logger.data_amount = NicInfo::DataAmount::EXTRA_DATA
|
202
|
+
@config.logger.message_level = NicInfo::MessageLevel::ALL_MESSAGES
|
203
|
+
end
|
204
|
+
|
205
|
+
opts.on( "-Q",
|
206
|
+
"Equivalent to --messages none and --data extra and --pager false" ) do |q|
|
207
|
+
@config.logger.data_amount = NicInfo::DataAmount::EXTRA_DATA
|
208
|
+
@config.logger.message_level = NicInfo::MessageLevel::NO_MESSAGES
|
209
|
+
@config.logger.pager = false
|
210
|
+
end
|
211
|
+
|
212
|
+
opts.on( "--json",
|
213
|
+
"Output raw JSON response." ) do |json|
|
214
|
+
@config.options.output_json = true
|
215
|
+
end
|
216
|
+
|
217
|
+
opts.on( "--jv VALUE",
|
218
|
+
"Outputs a specific JSON value." ) do |value|
|
219
|
+
unless @config.options.json_values
|
220
|
+
@config.options.json_values = Array.new
|
221
|
+
end
|
222
|
+
@config.options.json_values << value
|
223
|
+
end
|
224
|
+
|
225
|
+
opts.separator ""
|
226
|
+
opts.separator "General Options:"
|
227
|
+
|
228
|
+
opts.on( "-h", "--help",
|
229
|
+
"Show this message" ) do
|
230
|
+
@config.options.help = true
|
231
|
+
@config.options.require_query = false
|
232
|
+
end
|
233
|
+
|
234
|
+
opts.on( "--reset",
|
235
|
+
"Reset configuration to defaults" ) do
|
236
|
+
@config.options.reset_config = true
|
237
|
+
@config.options.require_query = false
|
238
|
+
end
|
239
|
+
|
240
|
+
opts.on( "--iana",
|
241
|
+
"Download RDAP bootstrap files from IANA" ) do
|
242
|
+
@config.options.get_iana_files = true
|
243
|
+
@config.options.require_query = false
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
begin
|
249
|
+
@opts.parse!(args)
|
250
|
+
rescue OptionParser::InvalidOption => e
|
251
|
+
puts e.message
|
252
|
+
puts "use -h for help"
|
253
|
+
exit
|
254
|
+
rescue OptionParser::InvalidArgument => e
|
255
|
+
puts e.message
|
256
|
+
puts "use -h for help"
|
257
|
+
exit
|
258
|
+
end
|
259
|
+
@config.options.argv = args
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
def make_rdap_url( base_url, resource_path )
|
264
|
+
unless base_url.end_with?("/")
|
265
|
+
base_url << "/"
|
266
|
+
end
|
267
|
+
base_url << resource_path
|
268
|
+
end
|
269
|
+
|
270
|
+
# Do an HTTP GET with the path.
|
271
|
+
def get url, try
|
272
|
+
|
273
|
+
data = @cache.get(url)
|
274
|
+
if data == nil
|
275
|
+
|
276
|
+
@config.logger.trace("Issuing GET for " + url)
|
277
|
+
uri = URI.parse( URI::encode( url ) )
|
278
|
+
req = Net::HTTP::Get.new(uri.request_uri)
|
279
|
+
req["User-Agent"] = NicInfo::VERSION_LABEL
|
280
|
+
req["Accept"] = NicInfo::RDAP_CONTENT_TYPE + ", " + NicInfo::JSON_CONTENT_TYPE
|
281
|
+
req["Connection"] = "close"
|
282
|
+
http = Net::HTTP.new( uri.host, uri.port )
|
283
|
+
if uri.scheme == "https"
|
284
|
+
http.use_ssl=true
|
285
|
+
http.verify_mode=OpenSSL::SSL::VERIFY_NONE
|
286
|
+
end
|
287
|
+
res = http.start do |http_req|
|
288
|
+
http_req.request(req)
|
289
|
+
end
|
290
|
+
|
291
|
+
case res
|
292
|
+
when Net::HTTPSuccess
|
293
|
+
content_type = res[ "content-type" ].downcase
|
294
|
+
unless content_type.include?(NicInfo::RDAP_CONTENT_TYPE) or content_type.include?(NicInfo::JSON_CONTENT_TYPE)
|
295
|
+
raise Net::HTTPServerException.new("Bad Content Type", res)
|
296
|
+
end
|
297
|
+
if content_type.include? NicInfo::JSON_CONTENT_TYPE
|
298
|
+
@config.conf_msgs << "Server responded with non-RDAP content type but it is JSON"
|
299
|
+
end
|
300
|
+
data = res.body
|
301
|
+
@cache.create_or_update(url, data)
|
302
|
+
else
|
303
|
+
if res.code == "301" or res.code == "302" or res.code == "303" or res.code == "307" or res.code == "308"
|
304
|
+
res.error! if try >= 5
|
305
|
+
location = res["location"]
|
306
|
+
return get( location, try + 1)
|
307
|
+
end
|
308
|
+
res.error!
|
309
|
+
end #end case
|
310
|
+
|
311
|
+
end #end if
|
312
|
+
|
313
|
+
return data
|
314
|
+
|
315
|
+
end #end def
|
316
|
+
|
317
|
+
# Do an HTTP GET of a file
|
318
|
+
def get_file_via_http url, file_name, try
|
319
|
+
|
320
|
+
@config.logger.trace("Downloading " + url + " to " + file_name )
|
321
|
+
uri = URI.parse( URI::encode( url ) )
|
322
|
+
req = Net::HTTP::Get.new(uri.request_uri)
|
323
|
+
req["User-Agent"] = NicInfo::VERSION_LABEL
|
324
|
+
req["Accept"] = NicInfo::JSON_CONTENT_TYPE
|
325
|
+
req["Connection"] = "close"
|
326
|
+
http = Net::HTTP.new( uri.host, uri.port )
|
327
|
+
if uri.scheme == "https"
|
328
|
+
http.use_ssl=true
|
329
|
+
http.verify_mode=OpenSSL::SSL::VERIFY_NONE
|
330
|
+
end
|
331
|
+
res = http.start do |http_req|
|
332
|
+
http_req.request(req)
|
333
|
+
end
|
334
|
+
|
335
|
+
case res
|
336
|
+
when Net::HTTPSuccess
|
337
|
+
File.write(file_name, res.body)
|
338
|
+
else
|
339
|
+
if res.code == "301" or res.code == "302" or res.code == "303" or res.code == "307" or res.code == "308"
|
340
|
+
res.error! if try >= 5
|
341
|
+
location = res["location"]
|
342
|
+
return get_file_via_http( location, file_name, try + 1)
|
343
|
+
end
|
344
|
+
res.error!
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
|
349
|
+
def run
|
350
|
+
|
351
|
+
@config.logger.run_pager
|
352
|
+
@config.logger.mesg(NicInfo::VERSION_LABEL)
|
353
|
+
@config.setup_workspace
|
354
|
+
@cache = Cache.new(@config)
|
355
|
+
@cache.clean if @config.config[ NicInfo::CACHE ][ NicInfo::CLEAN_CACHE ]
|
356
|
+
|
357
|
+
if @config.options.empty_cache
|
358
|
+
@cache.empty
|
359
|
+
end
|
360
|
+
|
361
|
+
if @config.options.get_iana_files
|
362
|
+
get_file_via_http( "http://data.iana.org/rdap/asn.json", File.join( @config.rdap_bootstrap_dir, "asn.json" ), 0 )
|
363
|
+
get_file_via_http( "http://data.iana.org/rdap/ipv4.json", File.join( @config.rdap_bootstrap_dir, "ipv4.json" ), 0 )
|
364
|
+
get_file_via_http( "http://data.iana.org/rdap/ipv6.json", File.join( @config.rdap_bootstrap_dir, "ipv6.json" ), 0 )
|
365
|
+
get_file_via_http( "http://data.iana.org/rdap/dns.json", File.join( @config.rdap_bootstrap_dir, "dns.json" ), 0 )
|
366
|
+
end
|
367
|
+
|
368
|
+
if @config.options.demo
|
369
|
+
@config.logger.mesg( "Populating cache with demonstration results" )
|
370
|
+
@config.logger.mesg( "Try the following demonstration queries:" )
|
371
|
+
demo_dir = File.join( File.dirname( __FILE__ ), NicInfo::DEMO_DIR )
|
372
|
+
demo_files = Dir::entries( demo_dir )
|
373
|
+
demo_files.each do |file|
|
374
|
+
df = File.join( demo_dir, file )
|
375
|
+
if File.file?( df )
|
376
|
+
demo_data = File.read( df )
|
377
|
+
json_data = JSON.load demo_data
|
378
|
+
demo_url = json_data[ NicInfo::NICINFO_DEMO_URL ]
|
379
|
+
demo_hint = json_data[ NicInfo::NICINFO_DEMO_HINT ]
|
380
|
+
@cache.create( demo_url, demo_data )
|
381
|
+
@config.logger.mesg( " " + demo_hint )
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
if @config.options.help
|
387
|
+
help()
|
388
|
+
end
|
389
|
+
|
390
|
+
if @config.options.argv == nil || @config.options.argv == [] && !@config.options.query_type
|
391
|
+
unless @config.options.require_query
|
392
|
+
exit
|
393
|
+
else
|
394
|
+
help
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
if @config.options.query_type == nil
|
399
|
+
@config.options.query_type = guess_query_value_type(@config.options.argv)
|
400
|
+
if (@config.options.query_type == QueryType::BY_IP4_ADDR ||
|
401
|
+
@config.options.query_type == QueryType::BY_IP6_ADDR ) && @config.options.reverse_ip == true
|
402
|
+
ip = IPAddr.new( @config.options.argv[ 0 ] )
|
403
|
+
@config.options.argv[ 0 ] = ip.reverse.split( "\." )[ 1..-1 ].join( "." ) if ip.ipv4?
|
404
|
+
@config.options.argv[ 0 ] = ip.reverse.split( "\." )[ 24..-1 ].join( "." ) if ip.ipv6?
|
405
|
+
@config.logger.mesg( "Query value changed to " + @config.options.argv[ 0 ] )
|
406
|
+
@config.options.query_type = QueryType::BY_DOMAIN
|
407
|
+
@config.options.externally_queriable = true
|
408
|
+
elsif @config.options.query_type == QueryType::BY_RESULT
|
409
|
+
data_tree = @config.load_as_yaml( NicInfo::LASTTREE_YAML )
|
410
|
+
node = data_tree.find_node( @config.options.argv[ 0 ] )
|
411
|
+
if node and node.rest_ref
|
412
|
+
@config.options.argv[ 0 ] = node.rest_ref
|
413
|
+
@config.options.url = true
|
414
|
+
if node.data_type
|
415
|
+
@config.options.query_type = node.data_type
|
416
|
+
@config.options.externally_queriable = false
|
417
|
+
elsif node.rest_ref
|
418
|
+
@config.options.query_type = get_query_type_from_url( node.rest_ref )
|
419
|
+
@config.options.externally_queriable = true
|
420
|
+
end
|
421
|
+
else
|
422
|
+
@config.logger.mesg( "#{@config.options.argv[0]} is not retrievable.")
|
423
|
+
exit
|
424
|
+
end
|
425
|
+
elsif @config.options.query_type == QueryType::BY_URL
|
426
|
+
@config.options.url = @config.options.argv[0]
|
427
|
+
@config.options.query_type = get_query_type_from_url( @config.options.url )
|
428
|
+
else
|
429
|
+
@config.options.externally_queriable = true
|
430
|
+
end
|
431
|
+
if @config.options.query_type == nil
|
432
|
+
@config.logger.mesg("Unable to guess type of query. You must specify it.")
|
433
|
+
exit
|
434
|
+
else
|
435
|
+
@config.logger.trace("Assuming query value is " + @config.options.query_type)
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
if @config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] == nil && !@config.options.url
|
440
|
+
bootstrap = Bootstrap.new( @config )
|
441
|
+
qtype = @config.options.query_type
|
442
|
+
if qtype == QueryType::BY_SERVER_HELP
|
443
|
+
qtype = guess_query_value_type( @config.options.argv )
|
444
|
+
end
|
445
|
+
case qtype
|
446
|
+
when QueryType::BY_IP4_ADDR
|
447
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = bootstrap.find_url_by_ip( @config.options.argv[ 0 ] )
|
448
|
+
when QueryType::BY_IP6_ADDR
|
449
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = bootstrap.find_url_by_ip( @config.options.argv[ 0 ] )
|
450
|
+
when QueryType::BY_IP4_CIDR
|
451
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = bootstrap.find_url_by_ip( @config.options.argv[ 0 ] )
|
452
|
+
when QueryType::BY_IP6_CIDR
|
453
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = bootstrap.find_url_by_ip( @config.options.argv[ 0 ] )
|
454
|
+
when QueryType::BY_AS_NUMBER
|
455
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = bootstrap.find_url_by_as( @config.options.argv[ 0 ] )
|
456
|
+
when QueryType::BY_DOMAIN
|
457
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = bootstrap.find_url_by_domain( @config.options.argv[ 0 ] )
|
458
|
+
when QueryType::BY_NAMESERVER
|
459
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = bootstrap.find_url_by_domain( @config.options.argv[ 0 ] )
|
460
|
+
when QueryType::BY_ENTITY_HANDLE
|
461
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = bootstrap.find_url_by_entity( @config.options.argv[ 0 ] )
|
462
|
+
when QueryType::SRCH_ENTITY_BY_NAME
|
463
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = @config.config[ NicInfo::BOOTSTRAP ][ NicInfo::ENTITY_ROOT_URL ]
|
464
|
+
when QueryType::SRCH_DOMAIN_BY_NAME
|
465
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = bootstrap.find_url_by_domain( @config.options.argv[ 0 ] )
|
466
|
+
when QueryType::SRCH_DOMAIN_BY_NSNAME
|
467
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = bootstrap.find_url_by_domain( @config.options.argv[ 0 ] )
|
468
|
+
when QueryType::SRCH_DOMAIN_BY_NSIP
|
469
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = @config.config[ NicInfo::BOOTSTRAP ][ NicInfo::DOMAIN_ROOT_URL ]
|
470
|
+
when QueryType::SRCH_NS_BY_NAME
|
471
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = bootstrap.find_url_by_domain( @config.options.argv[ 0 ] )
|
472
|
+
when QueryType::SRCH_NS_BY_IP
|
473
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = bootstrap.find_url_by_ip( @config.options.argv[ 0 ] )
|
474
|
+
else
|
475
|
+
@config.config[ NicInfo::BOOTSTRAP ][ NicInfo::BOOTSTRAP_URL ] = @config.config[ NicInfo::BOOTSTRAP ][ NicInfo::HELP_ROOT_URL ]
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
begin
|
480
|
+
rdap_url = nil
|
481
|
+
unless @config.options.url
|
482
|
+
path = create_resource_url(@config.options.argv, @config.options.query_type)
|
483
|
+
rdap_url = make_rdap_url(@config.config[NicInfo::BOOTSTRAP][NicInfo::BOOTSTRAP_URL], path)
|
484
|
+
else
|
485
|
+
rdap_url = @config.options.argv[0]
|
486
|
+
end
|
487
|
+
data = get( rdap_url, 0 )
|
488
|
+
json_data = JSON.load data
|
489
|
+
if (ec = json_data[ NicInfo::NICINFO_DEMO_ERROR ]) != nil
|
490
|
+
res = MyHTTPResponse.new( "1.1", ec, "Demo Exception" )
|
491
|
+
res["content-type"] = NicInfo::RDAP_CONTENT_TYPE
|
492
|
+
res.body=data
|
493
|
+
raise Net::HTTPServerException.new( "Demo Exception", res )
|
494
|
+
end
|
495
|
+
inspect_rdap_compliance json_data
|
496
|
+
cache_self_references json_data
|
497
|
+
if @config.options.output_json
|
498
|
+
@config.logger.raw( DataAmount::TERSE_DATA, data, false )
|
499
|
+
elsif @config.options.json_values
|
500
|
+
@config.options.json_values.each do |value|
|
501
|
+
@config.logger.raw( DataAmount::TERSE_DATA, eval_json_value( value, json_data), false )
|
502
|
+
end
|
503
|
+
else
|
504
|
+
Notices.new.display_notices json_data, @config, @config.options.query_type == QueryType::BY_SERVER_HELP
|
505
|
+
if @config.options.query_type != QueryType::BY_SERVER_HELP
|
506
|
+
result_type = get_query_type_from_result( json_data )
|
507
|
+
if result_type != nil
|
508
|
+
if result_type != @config.options.query_type
|
509
|
+
@config.logger.mesg( "Query type is " + @config.options.query_type + ". Result type is " + result_type + "." )
|
510
|
+
else
|
511
|
+
@config.logger.mesg( "Result type is " + result_type + "." )
|
512
|
+
end
|
513
|
+
@config.options.query_type = result_type
|
514
|
+
elsif json_data[ "errorCode" ] == nil
|
515
|
+
@config.conf_msgs << "Response has no result type."
|
516
|
+
end
|
517
|
+
data_tree = DataTree.new( )
|
518
|
+
case @config.options.query_type
|
519
|
+
when QueryType::BY_IP4_ADDR
|
520
|
+
NicInfo::display_ip( json_data, @config, data_tree )
|
521
|
+
when QueryType::BY_IP6_ADDR
|
522
|
+
NicInfo::display_ip( json_data, @config, data_tree )
|
523
|
+
when QueryType::BY_IP4_CIDR
|
524
|
+
NicInfo::display_ip( json_data, @config, data_tree )
|
525
|
+
when QueryType::BY_IP6_CIDR
|
526
|
+
NicInfo::display_ip( json_data, @config, data_tree )
|
527
|
+
when QueryType::BY_IP
|
528
|
+
NicInfo::display_ip( json_data, @config, data_tree )
|
529
|
+
when QueryType::BY_AS_NUMBER
|
530
|
+
NicInfo::display_autnum( json_data, @config, data_tree )
|
531
|
+
when "NicInfo::DsData"
|
532
|
+
NicInfo::display_ds_data( json_data, @config, data_tree )
|
533
|
+
when "NicInfo::KeyData"
|
534
|
+
NicInfo::display_key_data( json_data, @config, data_tree )
|
535
|
+
when QueryType::BY_DOMAIN
|
536
|
+
NicInfo::display_domain( json_data, @config, data_tree )
|
537
|
+
when QueryType::BY_NAMESERVER
|
538
|
+
NicInfo::display_ns( json_data, @config, data_tree )
|
539
|
+
when QueryType::BY_ENTITY_HANDLE
|
540
|
+
NicInfo::display_entity( json_data, @config, data_tree )
|
541
|
+
when QueryType::SRCH_DOMAINS
|
542
|
+
NicInfo::display_domains( json_data, @config, data_tree )
|
543
|
+
when QueryType::SRCH_DOMAIN_BY_NAME
|
544
|
+
NicInfo::display_domains( json_data, @config, data_tree )
|
545
|
+
when QueryType::SRCH_DOMAIN_BY_NSNAME
|
546
|
+
NicInfo::display_domains( json_data, @config, data_tree )
|
547
|
+
when QueryType::SRCH_DOMAIN_BY_NSIP
|
548
|
+
NicInfo::display_domains( json_data, @config, data_tree )
|
549
|
+
when QueryType::SRCH_ENTITY_BY_NAME
|
550
|
+
NicInfo::display_entities( json_data, @config, data_tree )
|
551
|
+
when QueryType::SRCH_NS
|
552
|
+
NicInfo::display_nameservers( json_data, @config, data_tree )
|
553
|
+
when QueryType::SRCH_NS_BY_NAME
|
554
|
+
NicInfo::display_nameservers( json_data, @config, data_tree )
|
555
|
+
when QueryType::SRCH_NS_BY_IP
|
556
|
+
NicInfo::display_nameservers( json_data, @config, data_tree )
|
557
|
+
end
|
558
|
+
@config.save_as_yaml( NicInfo::LASTTREE_YAML, data_tree ) if !data_tree.empty?
|
559
|
+
show_search_results_truncated json_data
|
560
|
+
show_conformance_messages
|
561
|
+
show_helpful_messages json_data, data_tree
|
562
|
+
end
|
563
|
+
end
|
564
|
+
@config.logger.end_run
|
565
|
+
rescue JSON::ParserError => a
|
566
|
+
@config.logger.mesg( "Server returned invalid JSON!" )
|
567
|
+
rescue SocketError => a
|
568
|
+
@config.logger.mesg(a.message)
|
569
|
+
rescue ArgumentError => a
|
570
|
+
@config.logger.mesg(a.message)
|
571
|
+
rescue Net::HTTPServerException => e
|
572
|
+
case e.response.code
|
573
|
+
when "200"
|
574
|
+
@config.logger.mesg( e.message )
|
575
|
+
when "401"
|
576
|
+
@config.logger.mesg("Authorization is required.")
|
577
|
+
handle_error_response e.response
|
578
|
+
when "404"
|
579
|
+
@config.logger.mesg("Query yielded no results.")
|
580
|
+
handle_error_response e.response
|
581
|
+
else
|
582
|
+
@config.logger.mesg("Error #{e.response.code}.")
|
583
|
+
handle_error_response e.response
|
584
|
+
end
|
585
|
+
@config.logger.trace("Server response code was " + e.response.code)
|
586
|
+
rescue Net::HTTPFatalError => e
|
587
|
+
case e.response.code
|
588
|
+
when "500"
|
589
|
+
@config.logger.mesg("RDAP server is reporting an internal error.")
|
590
|
+
handle_error_response e.response
|
591
|
+
when "501"
|
592
|
+
@config.logger.mesg("RDAP server does not implement the query.")
|
593
|
+
handle_error_response e.response
|
594
|
+
when "503"
|
595
|
+
@config.logger.mesg("RDAP server is reporting that it is unavailable.")
|
596
|
+
handle_error_response e.response
|
597
|
+
else
|
598
|
+
@config.logger.mesg("Error #{e.response.code}.")
|
599
|
+
handle_error_response e.response
|
600
|
+
end
|
601
|
+
@config.logger.trace("Server response code was " + e.response.code)
|
602
|
+
end
|
603
|
+
|
604
|
+
end
|
605
|
+
|
606
|
+
def handle_error_response (res)
|
607
|
+
if res["content-type"] == NicInfo::RDAP_CONTENT_TYPE && res.body && res.body.to_s.size > 0
|
608
|
+
json_data = JSON.load( res.body )
|
609
|
+
inspect_rdap_compliance json_data
|
610
|
+
Notices.new.display_notices json_data, @config, true
|
611
|
+
ErrorCode.new.display_error_code json_data, @config
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
def inspect_rdap_compliance json
|
616
|
+
rdap_conformance = json[ "rdapConformance" ]
|
617
|
+
if rdap_conformance
|
618
|
+
rdap_conformance.each do |conformance|
|
619
|
+
@config.logger.trace( "Server conforms to #{conformance}" )
|
620
|
+
end
|
621
|
+
else
|
622
|
+
@config.conf_msgs << "Response has no RDAP Conformance level specified."
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
def help
|
627
|
+
|
628
|
+
puts NicInfo::VERSION_LABEL
|
629
|
+
puts NicInfo::COPYRIGHT
|
630
|
+
puts <<HELP_SUMMARY
|
631
|
+
|
632
|
+
SYNOPSIS
|
633
|
+
nicinfo [OPTIONS] QUERY_VALUE
|
634
|
+
|
635
|
+
SUMMARY
|
636
|
+
NicInfo is a Registry Data Access Protocol (RDAP) client capable of querying RDAP
|
637
|
+
servers containing IP address, Autonomous System, and Domain name information.
|
638
|
+
|
639
|
+
The general usage is "nicinfo QUERY_VALUE" where the type of QUERY_VALUE influences the
|
640
|
+
type of query performed. This program will attempt to guess the type of QUERY_VALUE,
|
641
|
+
but the QUERY_VALUE type maybe explicitly set using the -t option.
|
642
|
+
|
643
|
+
Given the type of query to perform, this program will attempt to use the most appropriate
|
644
|
+
RDAP server it can determine, and follow referrals from that server if necessary.
|
645
|
+
|
646
|
+
HELP_SUMMARY
|
647
|
+
puts @opts.help
|
648
|
+
puts EXTENDED_HELP
|
649
|
+
exit
|
650
|
+
|
651
|
+
end
|
652
|
+
|
653
|
+
# Looks at the returned JSON and attempts to match that
|
654
|
+
# to a query type.
|
655
|
+
def get_query_type_from_result( json_data )
|
656
|
+
retval = nil
|
657
|
+
object_class_name = json_data[ "objectClassName" ]
|
658
|
+
if object_class_name != nil
|
659
|
+
case object_class_name
|
660
|
+
when "domain"
|
661
|
+
retval = QueryType::BY_DOMAIN
|
662
|
+
when "ip network"
|
663
|
+
retval = QueryType::BY_IP
|
664
|
+
when "entity"
|
665
|
+
retval = QueryType::BY_ENTITY_HANDLE
|
666
|
+
when "autnum"
|
667
|
+
retval = QueryType::BY_AS_NUMBER
|
668
|
+
when "nameserver"
|
669
|
+
retval = QueryType::BY_NAMESERVER
|
670
|
+
end
|
671
|
+
end
|
672
|
+
if json_data[ "domainSearchResults" ]
|
673
|
+
retval = QueryType::SRCH_DOMAINS
|
674
|
+
elsif json_data[ "nameserverSearchResults" ]
|
675
|
+
retval = QueryType::SRCH_NS
|
676
|
+
elsif json_data[ "entitySearchResults" ]
|
677
|
+
retval = QueryType::SRCH_ENTITY_BY_NAME
|
678
|
+
end
|
679
|
+
return retval
|
680
|
+
end
|
681
|
+
|
682
|
+
# Evaluates the args and guesses at the type of query.
|
683
|
+
# Args is an array of strings, most likely what is left
|
684
|
+
# over after parsing ARGV
|
685
|
+
def guess_query_value_type(args)
|
686
|
+
retval = nil
|
687
|
+
|
688
|
+
if args.length() == 1
|
689
|
+
|
690
|
+
case args[0]
|
691
|
+
when NicInfo::URL_REGEX
|
692
|
+
retval = QueryType::BY_URL
|
693
|
+
when NicInfo::IPV4_REGEX
|
694
|
+
retval = QueryType::BY_IP4_ADDR
|
695
|
+
when NicInfo::IPV6_REGEX
|
696
|
+
retval = QueryType::BY_IP6_ADDR
|
697
|
+
when NicInfo::IPV6_HEXCOMPRESS_REGEX
|
698
|
+
retval = QueryType::BY_IP6_ADDR
|
699
|
+
when NicInfo::AS_REGEX
|
700
|
+
retval = QueryType::BY_AS_NUMBER
|
701
|
+
when NicInfo::ASN_REGEX
|
702
|
+
old = args[0]
|
703
|
+
args[0] = args[0].sub(/^AS/i, "")
|
704
|
+
@config.logger.trace("Interpretting " + old + " as autonomous system number " + args[0])
|
705
|
+
retval = QueryType::BY_AS_NUMBER
|
706
|
+
when NicInfo::IP4_ARPA
|
707
|
+
retval = QueryType::BY_DOMAIN
|
708
|
+
when NicInfo::IP6_ARPA
|
709
|
+
retval = QueryType::BY_DOMAIN
|
710
|
+
when /(.*)\/\d/
|
711
|
+
ip = $+
|
712
|
+
if ip =~ NicInfo::IPV4_REGEX
|
713
|
+
retval = QueryType::BY_IP4_CIDR
|
714
|
+
elsif ip =~ NicInfo::IPV6_REGEX || ip =~ NicInfo::IPV6_HEXCOMPRESS_REGEX
|
715
|
+
retval = QueryType::BY_IP6_CIDR
|
716
|
+
end
|
717
|
+
when NicInfo::DATA_TREE_ADDR_REGEX
|
718
|
+
retval = QueryType::BY_RESULT
|
719
|
+
when NicInfo::NS_REGEX
|
720
|
+
retval = QueryType::BY_NAMESERVER
|
721
|
+
when NicInfo::DOMAIN_REGEX
|
722
|
+
retval = QueryType::BY_DOMAIN
|
723
|
+
when NicInfo::ENTITY_REGEX
|
724
|
+
retval = QueryType::BY_ENTITY_HANDLE
|
725
|
+
else
|
726
|
+
last_name = args[ 0 ].sub( /\*/, '' ).upcase
|
727
|
+
if NicInfo::is_last_name( last_name )
|
728
|
+
retval = QueryType::SRCH_ENTITY_BY_NAME
|
729
|
+
end
|
730
|
+
end
|
731
|
+
|
732
|
+
elsif args.length() == 2
|
733
|
+
|
734
|
+
last_name = args[ 1 ].sub( /\*/, '' ).upcase
|
735
|
+
first_name = args[ 0 ].sub( /\*/, '' ).upcase
|
736
|
+
if NicInfo::is_last_name(last_name) && (NicInfo::is_male_name(first_name) || NicInfo::is_female_name(first_name))
|
737
|
+
retval = QueryType::SRCH_ENTITY_BY_NAME
|
738
|
+
end
|
739
|
+
|
740
|
+
elsif args.length() == 3
|
741
|
+
|
742
|
+
last_name = args[ 2 ].sub( /\*/, '' ).upcase
|
743
|
+
first_name = args[ 0 ].sub( /\*/, '' ).upcase
|
744
|
+
if NicInfo::is_last_name(last_name) && (NicInfo::is_male_name(first_name) || NicInfo::is_female_name(first_name))
|
745
|
+
retval = QueryType::SRCH_ENTITY_BY_NAME
|
746
|
+
end
|
747
|
+
|
748
|
+
end
|
749
|
+
|
750
|
+
return retval
|
751
|
+
end
|
752
|
+
|
753
|
+
# Creates a query type
|
754
|
+
def create_resource_url(args, queryType)
|
755
|
+
|
756
|
+
path = ""
|
757
|
+
case queryType
|
758
|
+
when QueryType::BY_IP4_ADDR
|
759
|
+
path << "ip/" << args[0]
|
760
|
+
when QueryType::BY_IP6_ADDR
|
761
|
+
path << "ip/" << args[0]
|
762
|
+
when QueryType::BY_IP4_CIDR
|
763
|
+
path << "ip/" << args[0]
|
764
|
+
when QueryType::BY_IP6_CIDR
|
765
|
+
path << "ip/" << args[0]
|
766
|
+
when QueryType::BY_AS_NUMBER
|
767
|
+
path << "autnum/" << args[0]
|
768
|
+
when QueryType::BY_NAMESERVER
|
769
|
+
path << "nameserver/" << args[0]
|
770
|
+
when QueryType::BY_DOMAIN
|
771
|
+
path << "domain/" << args[0]
|
772
|
+
when QueryType::BY_RESULT
|
773
|
+
tree = @config.load_as_yaml(NicInfo::ARININFO_LASTTREE_YAML)
|
774
|
+
path = tree.find_rest_ref(args[0])
|
775
|
+
raise ArgumentError.new("Unable to find result for " + args[0]) unless path
|
776
|
+
when QueryType::BY_ENTITY_HANDLE
|
777
|
+
path << "entity/" << URI.escape( args[ 0 ] )
|
778
|
+
when QueryType::SRCH_ENTITY_BY_NAME
|
779
|
+
case args.length
|
780
|
+
when 1
|
781
|
+
path << "entities?fn=" << URI.escape( args[ 0 ] )
|
782
|
+
when 2
|
783
|
+
path << "entities?fn=" << URI.escape( args[ 0 ] + " " + args[ 1 ] )
|
784
|
+
when 3
|
785
|
+
path << "entities?fn=" << URI.escape( args[ 0 ] + " " + args[ 1 ] + " " + args[ 2 ] )
|
786
|
+
end
|
787
|
+
when QueryType::SRCH_DOMAIN_BY_NAME
|
788
|
+
path << "domains?name=" << args[ 0 ]
|
789
|
+
when QueryType::SRCH_DOMAIN_BY_NSNAME
|
790
|
+
path << "domains?nsLdhName=" << args[ 0 ]
|
791
|
+
when QueryType::SRCH_DOMAIN_BY_NSIP
|
792
|
+
path << "domains?nsIp=" << args[ 0 ]
|
793
|
+
when QueryType::SRCH_NS_BY_NAME
|
794
|
+
path << "nameservers?name=" << args[ 0 ]
|
795
|
+
when QueryType::SRCH_NS_BY_IP
|
796
|
+
path << "nameservers?ip=" << args[ 0 ]
|
797
|
+
when QueryType::BY_SERVER_HELP
|
798
|
+
path << "help"
|
799
|
+
else
|
800
|
+
raise ArgumentError.new("Unable to create a resource URL for " + queryType)
|
801
|
+
end
|
802
|
+
|
803
|
+
return path
|
804
|
+
end
|
805
|
+
|
806
|
+
def get_query_type_from_url url
|
807
|
+
queryType = nil
|
808
|
+
case url
|
809
|
+
when /.*\/ip\/.*/
|
810
|
+
# covers all IP cases
|
811
|
+
queryType = QueryType::BY_IP
|
812
|
+
when /.*\/autnum\/.*/
|
813
|
+
queryType = QueryType::BY_AS_NUMBER
|
814
|
+
when /.*\/nameserver\/.*/
|
815
|
+
queryType = QueryType::BY_NAMESERVER
|
816
|
+
when /.*\/domain\/.*/
|
817
|
+
queryType = QueryType::BY_DOMAIN
|
818
|
+
when /.*\/entity\/.*/
|
819
|
+
queryType = QueryType::BY_ENTITY_HANDLE
|
820
|
+
when /.*\/entities.*/
|
821
|
+
queryType = QueryType::SRCH_ENTITY_BY_NAME
|
822
|
+
when /.*\/domains.*/
|
823
|
+
# covers all domain searches
|
824
|
+
queryType = QueryType::SRCH_DOMAIN
|
825
|
+
when /.*\/nameservers.*/
|
826
|
+
# covers all nameserver searches
|
827
|
+
queryType = QueryType::SRCH_NS
|
828
|
+
when /.*\/help.*/
|
829
|
+
queryType = QueryType::BY_SERVER_HELP
|
830
|
+
else
|
831
|
+
raise ArgumentError.new( "Unable to determine query type from url '#{url}'" )
|
832
|
+
end
|
833
|
+
return queryType
|
834
|
+
end
|
835
|
+
|
836
|
+
def eval_json_value json_value, json_data
|
837
|
+
appended_code = String.new
|
838
|
+
values = json_value.split( "." )
|
839
|
+
values.each do |value|
|
840
|
+
i = Integer( value ) rescue false
|
841
|
+
if i
|
842
|
+
appended_code << "[#{i}]"
|
843
|
+
else
|
844
|
+
appended_code << "[\"#{value}\"]"
|
845
|
+
end
|
846
|
+
end
|
847
|
+
code = "json_data#{appended_code}"
|
848
|
+
return eval( code )
|
849
|
+
end
|
850
|
+
|
851
|
+
def cache_self_references json_data
|
852
|
+
links = NicInfo::get_links json_data, @config
|
853
|
+
if links
|
854
|
+
self_link = NicInfo.get_self_link links
|
855
|
+
if self_link
|
856
|
+
pretty = JSON::pretty_generate( json_data )
|
857
|
+
@cache.create( self_link, pretty )
|
858
|
+
end
|
859
|
+
end
|
860
|
+
entities = NicInfo::get_entitites json_data
|
861
|
+
entities.each do |entity|
|
862
|
+
cache_self_references( entity )
|
863
|
+
end if entities
|
864
|
+
nameservers = NicInfo::get_nameservers json_data
|
865
|
+
nameservers.each do |ns|
|
866
|
+
cache_self_references( ns )
|
867
|
+
end if nameservers
|
868
|
+
ds_data_objs = NicInfo::get_ds_data_objs json_data
|
869
|
+
ds_data_objs.each do |ds|
|
870
|
+
cache_self_references( ds )
|
871
|
+
end if ds_data_objs
|
872
|
+
key_data_objs = NicInfo::get_key_data_objs json_data
|
873
|
+
key_data_objs.each do |key|
|
874
|
+
cache_self_references( key )
|
875
|
+
end if key_data_objs
|
876
|
+
end
|
877
|
+
|
878
|
+
def show_conformance_messages
|
879
|
+
return if @config.conf_msgs.size == 0
|
880
|
+
@config.logger.mesg( "** WARNING: There are problems in the response that might cause some data to discarded. **" )
|
881
|
+
i = 1
|
882
|
+
@config.conf_msgs.each do |msg|
|
883
|
+
@config.logger.trace( "#{i} : #{msg}" )
|
884
|
+
i = i + 1
|
885
|
+
end
|
886
|
+
end
|
887
|
+
|
888
|
+
def show_search_results_truncated json_data
|
889
|
+
truncated = json_data[ "searchResultsTruncated" ]
|
890
|
+
if truncated.instance_of?(TrueClass) || truncated.instance_of?(FalseClass)
|
891
|
+
if truncated
|
892
|
+
@config.logger.mesg( "Results have been truncated by the server." )
|
893
|
+
end
|
894
|
+
end
|
895
|
+
if truncated != nil
|
896
|
+
@config.conf_msgs << "'searchResultsTruncated' is not part of the RDAP specification and was removed before standardization."
|
897
|
+
end
|
898
|
+
end
|
899
|
+
|
900
|
+
def show_helpful_messages json_data, data_tree
|
901
|
+
arg = @config.options.argv[0]
|
902
|
+
case @config.options.query_type
|
903
|
+
when QueryType::BY_IP4_ADDR
|
904
|
+
@config.logger.mesg("Use \"nicinfo -r #{arg}\" to see reverse DNS information.");
|
905
|
+
when QueryType::BY_IP6_ADDR
|
906
|
+
@config.logger.mesg("Use \"nicinfo -r #{arg}\" to see reverse DNS information.");
|
907
|
+
when QueryType::BY_AS_NUMBER
|
908
|
+
@config.logger.mesg("Use \"nicinfo #{arg}\" or \"nicinfo as#{arg}\" for autnums.");
|
909
|
+
end
|
910
|
+
unless data_tree.empty?
|
911
|
+
@config.logger.mesg("Use \"nicinfo 1=\" to show #{data_tree.roots.first}")
|
912
|
+
unless data_tree.roots.first.empty?
|
913
|
+
children = data_tree.roots.first.children
|
914
|
+
@config.logger.mesg("Use \"nicinfo 1.1=\" to show #{children.first}") if children.first.rest_ref
|
915
|
+
if children.first != children.last
|
916
|
+
len = children.length
|
917
|
+
@config.logger.mesg("Use \"nicinfo 1.#{len}=\" to show #{children.last}") if children.last.rest_ref
|
918
|
+
end
|
919
|
+
end
|
920
|
+
end
|
921
|
+
self_link = NicInfo.get_self_link( NicInfo.get_links( json_data, @config ) )
|
922
|
+
@config.logger.mesg("Use \"nicinfo #{self_link}\" to directly query this resource in the future.") if self_link and @config.options.externally_queriable
|
923
|
+
@config.logger.mesg('Use "nicinfo -h" for help.')
|
924
|
+
end
|
925
|
+
|
926
|
+
end
|
927
|
+
|
928
|
+
class MyHTTPResponse < Net::HTTPResponse
|
929
|
+
attr_accessor :body
|
930
|
+
end
|
931
|
+
|
932
|
+
EXTENDED_HELP = <<EXTENDED_HELP
|
933
|
+
|
934
|
+
QUERIES
|
935
|
+
For most query values, the query type is inferred. However, some types of queries
|
936
|
+
cannot be inferred and so the -t option must be used. The domain search by name
|
937
|
+
(dsbyname) and entity search by name (esbyname) queries can take wildcards ('*'),
|
938
|
+
but these must be quoted or escaped to avoid processing by the invoking OS shell
|
939
|
+
on Unix-like operating systems.
|
940
|
+
|
941
|
+
CONFIGURATION
|
942
|
+
When this program is run for the first time, it creates a directory called .NicInfo
|
943
|
+
(on Unix style platforms) or NicInfo (on Windows) in the users home directory. The
|
944
|
+
home directory is determined by the $HOME environment variable on Unix style platforms
|
945
|
+
and $APPDATA on Windows.
|
946
|
+
|
947
|
+
A configuration file is created in this directory called config.yaml. This is a YAML
|
948
|
+
file and contains a means for specifying most of the features of this program (instead
|
949
|
+
of needing to specify them on the command line as options). To set the configuration
|
950
|
+
back to the installation defaults, use the --reset option. This maybe desirable when
|
951
|
+
updating versions of this program.
|
952
|
+
|
953
|
+
A directory called rdap_cache is also created inside this directory. It holds cached
|
954
|
+
values from previously executed queries.
|
955
|
+
|
956
|
+
CACHING
|
957
|
+
This program will write query responses to a cache. By default, answers are pulled
|
958
|
+
from the cache if present. This can be turned on or off with the --cache option or
|
959
|
+
using the cache/use_cache value in the configuration file.
|
960
|
+
|
961
|
+
Expiration of items in the cache and eviction of items from the cache can also be
|
962
|
+
controlled. The cache can be manually emptied using the --empty-cache option.
|
963
|
+
|
964
|
+
BOOTSTRAPPING
|
965
|
+
Bootstrapping is the process of finding an appropriate RDAP server in which to send
|
966
|
+
queries. This program has a three tier bootstrapping process.
|
967
|
+
|
968
|
+
The first tier looks up the most appropriate server using internal tables compiled
|
969
|
+
from IANA registries. If an appropriate server cannot be found, bootstrapping falls
|
970
|
+
to the second tier.
|
971
|
+
|
972
|
+
The second tier has a default server for each type of RDAP query (domain, ip, autnum,
|
973
|
+
nameserver, and entity). If this program cannot determine the type of query, bootstrapping
|
974
|
+
falls to the third tier.
|
975
|
+
|
976
|
+
The third tier is a default server for all queries.
|
977
|
+
|
978
|
+
All bootstrap URLs are specified in the configuration file. Bootstrapping maybe
|
979
|
+
bypassed using the -b or --base option (or by setting the bootstrap/base_url in the
|
980
|
+
configuration file).
|
981
|
+
|
982
|
+
USAGE FOR SCRIPTING
|
983
|
+
For usage with shell scripting, there are a couple of useful command line switches.
|
984
|
+
|
985
|
+
The --json option suppresses the human-readable output and instead emits the JSON
|
986
|
+
returned by the server. When not writing to an output file, this options should be
|
987
|
+
used with the -Q option to suppress the pager and program runtime messages so that
|
988
|
+
the JSON maybe run through a JSON parser.
|
989
|
+
|
990
|
+
The --jv option instructs this program to parse the JSON and emit specific JSON
|
991
|
+
values. This option is also useful in combination with the -Q option to feed the
|
992
|
+
JSON values into other programs. The syntax for specifying a JSON value is a
|
993
|
+
list of JSON object member names or integers signifying JSON array indexes separated
|
994
|
+
by a period, such as name1.name2.3.name4.5. For example, "entities.0.handle" would
|
995
|
+
be useful for getting at the "handle" value from the following JSON:
|
996
|
+
|
997
|
+
{ "entities" : [ { "handle": "foo" } ] }
|
998
|
+
|
999
|
+
Multiple --jv options may be specified.
|
1000
|
+
|
1001
|
+
DEMONSTRATION QUERIES
|
1002
|
+
There are several built-in demonstration queries that may be exercised to show the
|
1003
|
+
utility of RDAP. To use these queries, the --demo option must be used to populate
|
1004
|
+
the query answers into the cache. If the cache is already populated with items, it
|
1005
|
+
may be necessary to clean the cache using the --empty-cache option.
|
1006
|
+
|
1007
|
+
When the --demo option is given, the list of demonstration queries will be printed
|
1008
|
+
out.
|
1009
|
+
EXTENDED_HELP
|
1010
|
+
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
|