Class: PassiveDNS::CLInterface
- Inherits:
-
Object
- Object
- PassiveDNS::CLInterface
- Defined in:
- lib/passivedns/client/cli.rb
Overview
Handles all the command-line parsing, state tracking, and dispatching queries to the PassiveDNS::Client instance CLInterface is aliased by CLI
Class Method Summary collapse
-
.create_state(sqlitedb = nil) ⇒ Object
create a state instance.
-
.get_letter_map ⇒ Object
generates a mapping between the option letter for each PassiveDNS provider and the class.
-
.parse_command_line(args) ⇒ Object
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 }.
-
.pdnslookup(state, pdnsclient, options) ⇒ Object
performs a stateful, recursive (if desired) passive DNS lookup against all specified providers.
-
.results_to_s(state, options) ⇒ Object
returns a string transforming all the PassiveDNS::PDNSResult stored in the state object into text/xml/json/etc.
-
.run(args) ⇒ Object
main method, takes command-line arguments and performs the desired queries and outputs.
-
.usage(letter_map) ⇒ Object
returns a string containing the usage information takes in a hash of letter to passive dns providers.
Class Method Details
.create_state(sqlitedb = nil) ⇒ Object
create a state instance
245 246 247 248 249 250 251 252 |
# File 'lib/passivedns/client/cli.rb', line 245 def self.create_state(sqlitedb=nil) state = nil if sqlitedb state = PassiveDNS::PDNSToolStateDB.new(sqlitedb) else state = PassiveDNS::PDNSToolState.new end end |
.get_letter_map ⇒ Object
generates a mapping between the option letter for each PassiveDNS provider and the class
12 13 14 15 16 17 18 19 20 21 22 23 24 |
# 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) ⇒ Object
parses the command line and yields an options hash
Default 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
}
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# 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 ] ) letter_map = get_letter_map # sets the default search methods = { :pdnsdbs => [], :format => "text", :sep => "\t", :recursedepth => 1, :wait => 0, :res => nil, :debug => false, :sqlitedb => nil, :limit => nil, :help => false } opts.each do |opt, arg| case opt when '--help' [:help] = true when '--debug' [:debug] = true when '--database' arg.split(//).each do |c| if c == ',' next elsif letter_map[c] [:pdnsdbs] << letter_map[c][1] else $stderr.puts "ERROR: Unknown passive DNS database identifier: #{c}." usage(letter_map) end end when '--gdf' [:format] = 'gdf' when '--graphviz' [:format] = 'graphviz' when '--graphml' [:format] = 'graphml' when '--csv' [:format] = 'text' [:sep] = ',' when '--yaml' [:format] = 'yaml' when '--xml' [:format] = 'xml' when '--json' [:format] = 'json' when '--text' [:format] = 'text' when '--sep' [:sep] = arg when '--recurse' [:recursedepth] = arg.to_i when '--wait' [:wait] = arg.to_i when '--sqlite3' [:sqlitedb] = arg when '--limit' [:limit] = arg.to_i else [:help] = true end end args = ARGV.dup ARGV.replace(origARGV) if [:pdnsdbs].length == 0 [:pdnsdbs] << "bfk" end if [:pdnsdbs].index("bfk") and [:recursedepth] > 1 and [:wait] < 60 [:wait] = 60 $stderr.puts "Enforcing a minimal 60 second wait when using BFK for recursive crawling" end if [:debug] $stderr.puts "Using the following databases: #{[:pdnsdbs].join(", ")}" $stderr.puts "Recursions: #{[:recursedepth]}, Wait time: #{[:wait]}, Limit: #{[:limit] or 'none'}" if [:format] == "text" or [:format] == "csv" $stderr.puts "Output format: #{[:format]} (sep=\"#{[:sep]}\")" else $stderr.puts "Output format: #{[:format]}" end if ENV['http_proxy'] $stderr.puts "Using proxy settings: http_proxy=#{ENV['http_proxy']}, https_proxy=#{ENV['https_proxy']}" end end [, args] end |
.pdnslookup(state, pdnsclient, options) ⇒ Object
performs a stateful, recursive (if desired) passive DNS lookup against all specified providers
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'lib/passivedns/client/cli.rb', line 194 def self.pdnslookup(state, pdnsclient, ) recursedepth = [:recursedepth] wait = [:wait] debug = [:debug] limit = [: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) ⇒ Object
returns a string transforming all the PassiveDNS::PDNSResult stored in the state object into text/xml/json/etc.
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/passivedns/client/cli.rb', line 223 def self.results_to_s(state,) format = [:format] sep = [: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) ⇒ Object
main method, takes command-line arguments and performs the desired queries and outputs
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/passivedns/client/cli.rb', line 255 def self.run(args) , items = parse_command_line(args) if [:help] return usage(get_letter_map) end if [: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([:sqlitedb]) state.debug = [:debug] pdnsclient = PassiveDNS::Client.new([:pdnsdbs]) pdnsclient.debug = [: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,) results_to_s(state,) end |
.usage(letter_map) ⇒ Object
returns a string containing the usage information takes in a hash of letter to passive dns providers
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/passivedns/client/cli.rb', line 158 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>] <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 << " -dvt uses VirusTotal and TCPIPUtils (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 << "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 |