class PassiveDNS::CLInterface
Handles all the command-line parsing, state tracking, and dispatching queries to the PassiveDNS::Client
instance CLInterface
is aliased by CLI
Public Class Methods
create_state(sqlitedb=nil)
click to toggle source
create a state instance
# File lib/passivedns/client/cli.rb, line 247 def self.create_state(sqlitedb=nil) state = nil if sqlitedb state = PassiveDNS::PDNSToolStateDB.new(sqlitedb) else state = PassiveDNS::PDNSToolState.new end state end
get_letter_map()
click to toggle source
generates a mapping between the option letter for each PassiveDNS
provider and the class
# File lib/passivedns/client/cli.rb, line 12 def self.get_letter_map letter_map = {} mod = PassiveDNS::Provider mod.constants.each do |const| if mod.const_get(const).is_a?(Class) and mod.const_get(const).superclass == PassiveDNS::PassiveDB letter = mod.const_get(const).option_letter name = mod.const_get(const).name config_section_name = mod.const_get(const).config_section_name letter_map[letter] = [name, config_section_name] end end letter_map end
parse_command_line(args)
click to toggle source
parses the command line and yields an options hash
Default Options¶ ↑
options = { :pdnsdbs => [], # passive dns providers to query :format => "text", # output format :sep => "\t", # field separator for text format :recursedepth => 1, # recursion depth :wait => 0, # wait period between recursions :res => nil, # unused. I don't remember why this is here. :debug => false, # debug flag :sqlitedb => nil, # filename for maintaining state in an sqlite3 db :limit => nil, # number of results per provider per recursion :help => false # display the usage text }
# File lib/passivedns/client/cli.rb, line 40 def self.parse_command_line(args) origARGV = ARGV.dup ARGV.replace(args) opts = GetoptLong.new( [ '--help', '-h', GetoptLong::NO_ARGUMENT ], [ '--debug', '-v', GetoptLong::NO_ARGUMENT ], [ '--database', '-d', GetoptLong::REQUIRED_ARGUMENT ], [ '--gdf', '-g', GetoptLong::NO_ARGUMENT ], [ '--graphviz', '-z', GetoptLong::NO_ARGUMENT ], [ '--graphml', '-m', GetoptLong::NO_ARGUMENT ], [ '--csv', '-c', GetoptLong::NO_ARGUMENT ], [ '--xml', '-x', GetoptLong::NO_ARGUMENT ], [ '--yaml', '-y', GetoptLong::NO_ARGUMENT ], [ '--json', '-j', GetoptLong::NO_ARGUMENT ], [ '--text', '-t', GetoptLong::NO_ARGUMENT ], [ '--sep', '-s', GetoptLong::REQUIRED_ARGUMENT ], [ '--sqlite3', '-f', GetoptLong::REQUIRED_ARGUMENT ], [ '--recurse', '-r', GetoptLong::REQUIRED_ARGUMENT ], [ '--wait', '-w', GetoptLong::REQUIRED_ARGUMENT ], [ '--limit', '-l', GetoptLong::REQUIRED_ARGUMENT ], [ '--config', GetoptLong::REQUIRED_ARGUMENT ] ) letter_map = get_letter_map # sets the default search methods options = { :pdnsdbs => [], :format => "text", :sep => "\t", :recursedepth => 1, :wait => 0, :res => nil, :debug => false, :sqlitedb => nil, :limit => nil, :help => false, :configfile => "#{ENV['HOME']}/.passivedns-client" } opts.each do |opt, arg| case opt when '--help' options[:help] = true when '--debug' options[:debug] = true when '--database' arg.split(//).each do |c| if c == ',' next elsif letter_map[c] options[:pdnsdbs] << letter_map[c][1] else $stderr.puts "ERROR: Unknown passive DNS database identifier: #{c}." usage(letter_map) end end when '--gdf' options[:format] = 'gdf' when '--graphviz' options[:format] = 'graphviz' when '--graphml' options[:format] = 'graphml' when '--csv' options[:format] = 'text' options[:sep] = ',' when '--yaml' options[:format] = 'yaml' when '--xml' options[:format] = 'xml' when '--json' options[:format] = 'json' when '--text' options[:format] = 'text' when '--sep' options[:sep] = arg when '--recurse' options[:recursedepth] = arg.to_i when '--wait' options[:wait] = arg.to_i when '--sqlite3' options[:sqlitedb] = arg when '--limit' options[:limit] = arg.to_i when '--config' options[:configfile] = arg else options[:help] = true end end args = ARGV.dup ARGV.replace(origARGV) if options[:pdnsdbs].length == 0 options[:pdnsdbs] << "virustotal" end if options[:debug] $stderr.puts "Using the following databases: #{options[:pdnsdbs].join(", ")}" $stderr.puts "Recursions: #{options[:recursedepth]}, Wait time: #{options[:wait]}, Limit: #{options[:limit] or 'none'}" if options[:format] == "text" or options[:format] == "csv" $stderr.puts "Output format: #{options[:format]} (sep=\"#{options[:sep]}\")" else $stderr.puts "Output format: #{options[:format]}" end if ENV['http_proxy'] $stderr.puts "Using proxy settings: http_proxy=#{ENV['http_proxy']}, https_proxy=#{ENV['https_proxy']}" end end [options, args] end
pdnslookup(state, pdnsclient, options)
click to toggle source
performs a stateful, recursive (if desired) passive DNS lookup against all specified providers
# File lib/passivedns/client/cli.rb, line 196 def self.pdnslookup(state, pdnsclient, options) recursedepth = options[:recursedepth] wait = options[:wait] debug = options[:debug] limit = options[:limit] puts "pdnslookup: #{state.level} #{recursedepth}" if debug level = 0 while level < recursedepth puts "pdnslookup: #{level} < #{recursedepth}" if debug state.each_query(recursedepth) do |q| rv = pdnsclient.query(q,limit) if rv rv.each do |r| if ["A","AAAA","NS","CNAME","PTR"].index(r.rrtype) puts "pdnslookup: #{r.to_s}" if debug state.add_result(r) end end else state.update_query(rv,'failed') end sleep wait if level < recursedepth end level += 1 end state end
results_to_s(state,options)
click to toggle source
returns a string transforming all the PassiveDNS::PDNSResult
stored in the state object into text/xml/json/etc.
# File lib/passivedns/client/cli.rb, line 225 def self.results_to_s(state,options) format = options[:format] sep = options[:sep] case format when 'text' PassiveDNS::PDNSResult.members.join(sep)+"\n"+state.to_s(sep) when 'yaml' state.to_yaml when 'xml' state.to_xml when 'json' state.to_json when 'gdf' state.to_gdf when 'graphviz' state.to_graphviz when 'graphml' state.to_graphml end end
run(args)
click to toggle source
main method, takes command-line arguments and performs the desired queries and outputs
# File lib/passivedns/client/cli.rb, line 258 def self.run(args) options, items = parse_command_line(args) if options[:help] return usage(get_letter_map) end if options[:recursedepth] > 3 $stderr.puts "WARNING: a recursedepth of > 3 can be abusive, please reconsider: sleeping 60 seconds for sense to come to you (hint: hit CTRL-C)" sleep 60 end state = create_state(options[:sqlitedb]) state.debug = options[:debug] pdnsclient = PassiveDNS::Client.new(options[:pdnsdbs], options[:configfile]) pdnsclient.debug = options[:debug] if items.length > 0 items.each do |arg| state.add_query(arg,'pending',0) end else $stdin.each_line do |l| state.add_query(l.chomp,'pending',0) end end pdnslookup(state,pdnsclient,options) results_to_s(state,options) end
usage(letter_map)
click to toggle source
returns a string containing the usage information takes in a hash of letter to passive dns providers
# File lib/passivedns/client/cli.rb, line 157 def self.usage(letter_map) databases = letter_map.keys.sort.join("") help_text = "" help_text << "Usage: #{$0} [-d [#{databases}]] [-g|-v|-m|-c|-x|-y|-j|-t] [-os <sep>] [-f <file>] [-r#|-w#|-v] [-l <count>] [--config <file>] <ip|domain|cidr>\n" help_text << "Passive DNS Providers\n" help_text << " -d#{databases} uses all of the available passive dns database\n" letter_map.keys.sort.each do |l| help_text << " -d#{l} use #{letter_map[l][0]}\n" end help_text << " -dvr uses VirusTotal and RiskIQ (for example)\n" help_text << "\n" help_text << "Output Formatting\n" help_text << " -g link-nodal GDF visualization definition\n" help_text << " -z link-nodal graphviz visualization definition\n" help_text << " -m link-nodal graphml visualization definition\n" help_text << " -c CSV\n" help_text << " -x XML\n" help_text << " -y YAML\n" help_text << " -j JSON\n" help_text << " -t ASCII text (default)\n" help_text << " -s <sep> specifies a field separator for text output, default is tab\n" help_text << "\n" help_text << "State and Recursion\n" help_text << " -f[file] specifies a sqlite3 database used to read the current state - useful for large result sets and generating graphs of previous runs.\n" help_text << " -r# specifies the levels of recursion to pull. **WARNING** This is quite taxing on the pDNS servers, so use judiciously (never more than 3 or so) or find yourself blocked!\n" help_text << " -w# specifies the amount of time to wait, in seconds, between queries (Default: 0)\n" help_text << " -l <count> limits the number of records returned per passive dns database queried.\n" help_text << "\n" help_text << "Specifying a Configuration File\n" help_text << " --config <file> specifies a config file. default: #{ENV['HOME']}/.passivedns-client\n" help_text << "\n" help_text << "Getting Help\n" help_text << " -h hello there. This option produces this helpful help information on how to access help.\n" help_text << " -v debugging information\n" help_text end