passivedns-client 2.0.1 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/pdnstool +2 -211
- data/lib/passivedns/client.rb +13 -10
- data/lib/passivedns/client/circl.rb +80 -0
- data/lib/passivedns/client/cli.rb +245 -0
- data/lib/passivedns/client/passivetotal.rb +77 -0
- data/lib/passivedns/client/version.rb +1 -1
- data/passivedns-client.gemspec +1 -0
- data/test/helper.rb +5 -1
- data/test/test_passivedns-client.rb +154 -121
- metadata +19 -3
- data/lib/passivedns/client/certee.rb +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e141cbc5d84ea9c25ee8c207db9c7758869117e
|
4
|
+
data.tar.gz: 81c70c9a9a4c272133c4e33a2e043fab650fd00a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fffadc8b47040b55d25255cf62ab2b8f2498a8a39d89caa1812da37944da266f411cf9b384cb1f6ab70718ac106811313a0d4987c792487919f239ad388bc4ed
|
7
|
+
data.tar.gz: d0592a94d6f4cec71afdf55d3cccedf1cfc1fe8ecf17cc3f3d746d92b184a694e3c1e1655c17d03f3972a63bc56de433d3cb7ec9eb067172d02183f7c7ff4a5b
|
data/bin/pdnstool
CHANGED
@@ -1,214 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'passivedns/client'
|
3
|
-
require '
|
4
|
-
require 'getoptlong'
|
5
|
-
require 'yaml'
|
3
|
+
require 'passivedns/client/cli'
|
6
4
|
|
7
|
-
|
8
|
-
puts "pdnslookup: #{state.level} #{recursedepth}" if debug
|
9
|
-
level = 0
|
10
|
-
while level < recursedepth
|
11
|
-
puts "pdnslookup: #{level} < #{recursedepth}" if debug
|
12
|
-
state.each_query(recursedepth) do |q|
|
13
|
-
rv = pdnsclient.query(q,limit)
|
14
|
-
if rv
|
15
|
-
rv.each do |r|
|
16
|
-
if ["A","AAAA","NS","CNAME","PTR"].index(r.rrtype)
|
17
|
-
puts "pdnslookup: #{r.to_s}" if debug
|
18
|
-
state.add_result(r)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
else
|
22
|
-
state.update_query(rv,'failed')
|
23
|
-
end
|
24
|
-
sleep wait if level < recursedepth
|
25
|
-
end
|
26
|
-
level += 1
|
27
|
-
end
|
28
|
-
state
|
29
|
-
end
|
30
|
-
|
31
|
-
def printresults(state,format,sep="\t")
|
32
|
-
case format
|
33
|
-
when 'text'
|
34
|
-
puts PassiveDNS::PDNSResult.members.join(sep)
|
35
|
-
puts state.to_s(sep)
|
36
|
-
when 'yaml'
|
37
|
-
puts state.to_yaml
|
38
|
-
when 'xml'
|
39
|
-
puts state.to_xml
|
40
|
-
when 'json'
|
41
|
-
puts state.to_json
|
42
|
-
when 'gdf'
|
43
|
-
puts state.to_gdf
|
44
|
-
when 'graphviz'
|
45
|
-
puts state.to_graphviz
|
46
|
-
when 'graphml'
|
47
|
-
puts state.to_graphml
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def usage(letter_map)
|
52
|
-
databases = letter_map.keys.sort.join("")
|
53
|
-
|
54
|
-
puts "Usage: #{$0} [-d [#{databases}]] [-g|-v|-m|-c|-x|-y|-j|-t] [-os <sep>] [-f <file>] [-r#|-w#|-v] [-l <count>] <ip|domain|cidr>"
|
55
|
-
puts " -d#{databases} uses all of the available passive dns databases"
|
56
|
-
letter_map.keys.sort.each do |l|
|
57
|
-
puts " -d#{l} use #{letter_map[l][0]}"
|
58
|
-
end
|
59
|
-
puts " -dvt uses VirusTotal and TCPIPUtils (for example)"
|
60
|
-
puts ""
|
61
|
-
puts " -g outputs a link-nodal GDF visualization definition"
|
62
|
-
puts " -v outputs a link-nodal graphviz visualization definition"
|
63
|
-
puts " -m output a link-nodal graphml visualization definition"
|
64
|
-
puts " -c outputs CSV"
|
65
|
-
puts " -x outputs XML"
|
66
|
-
puts " -y outputs YAML"
|
67
|
-
puts " -j outputs JSON"
|
68
|
-
puts " -t outputs ASCII text (default)"
|
69
|
-
puts " -s <sep> specifies a field separator for text output, default is tab"
|
70
|
-
puts ""
|
71
|
-
puts " -f[file] specifies a sqlite3 database used to read the current state - useful for large result sets and generating graphs of previous runs."
|
72
|
-
puts " -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!"
|
73
|
-
puts " -w# specifies the amount of time to wait, in seconds, between queries (Default: 0)"
|
74
|
-
puts " -v outputs debugging information"
|
75
|
-
puts " -l <count> limits the number of records returned per passive dns database queried."
|
76
|
-
exit
|
77
|
-
end
|
78
|
-
|
79
|
-
opts = GetoptLong.new(
|
80
|
-
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
81
|
-
[ '--debug', '-z', GetoptLong::NO_ARGUMENT ],
|
82
|
-
[ '--database', '-d', GetoptLong::REQUIRED_ARGUMENT ],
|
83
|
-
|
84
|
-
[ '--gdf', '-g', GetoptLong::NO_ARGUMENT ],
|
85
|
-
[ '--graphviz', '-v', GetoptLong::NO_ARGUMENT ],
|
86
|
-
[ '--graphml', '-m', GetoptLong::NO_ARGUMENT ],
|
87
|
-
[ '--csv', '-c', GetoptLong::NO_ARGUMENT ],
|
88
|
-
[ '--xml', '-x', GetoptLong::NO_ARGUMENT ],
|
89
|
-
[ '--yaml', '-y', GetoptLong::NO_ARGUMENT ],
|
90
|
-
[ '--json', '-j', GetoptLong::NO_ARGUMENT ],
|
91
|
-
[ '--text', '-t', GetoptLong::NO_ARGUMENT ],
|
92
|
-
[ '--sep', '-s', GetoptLong::REQUIRED_ARGUMENT ],
|
93
|
-
|
94
|
-
[ '--sqlite3', '-f', GetoptLong::REQUIRED_ARGUMENT ],
|
95
|
-
[ '--recurse', '-r', GetoptLong::REQUIRED_ARGUMENT ],
|
96
|
-
[ '--wait', '-w', GetoptLong::REQUIRED_ARGUMENT ],
|
97
|
-
[ '--limit', '-l', GetoptLong::REQUIRED_ARGUMENT ]
|
98
|
-
)
|
99
|
-
|
100
|
-
letter_map = {}
|
101
|
-
PassiveDNS.constants.each do |const|
|
102
|
-
if PassiveDNS.const_get(const).is_a?(Class) and PassiveDNS.const_get(const).superclass == PassiveDNS::PassiveDB
|
103
|
-
letter_map[PassiveDNS.const_get(const).option_letter] = [PassiveDNS.const_get(const).name, PassiveDNS.const_get(const).config_section_name]
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
# sets the default search methods
|
108
|
-
pdnsdbs = []
|
109
|
-
format = "text"
|
110
|
-
sep = "\t"
|
111
|
-
recursedepth = 1
|
112
|
-
wait = 0
|
113
|
-
res = nil
|
114
|
-
debug = false
|
115
|
-
sqlitedb = nil
|
116
|
-
limit = nil
|
117
|
-
|
118
|
-
opts.each do |opt, arg|
|
119
|
-
case opt
|
120
|
-
when '--help'
|
121
|
-
usage(letter_map)
|
122
|
-
when '--debug'
|
123
|
-
debug = true
|
124
|
-
when '--database'
|
125
|
-
arg.split(//).each do |c|
|
126
|
-
if c == ','
|
127
|
-
next
|
128
|
-
elsif letter_map[c]
|
129
|
-
pdnsdbs << letter_map[c][1]
|
130
|
-
else
|
131
|
-
$stderr.puts "ERROR: Unknown passive DNS database identifier: #{c}."
|
132
|
-
usage(letter_map)
|
133
|
-
end
|
134
|
-
end
|
135
|
-
when '--gdf'
|
136
|
-
format = 'gdf'
|
137
|
-
when '--graphviz'
|
138
|
-
format = 'graphviz'
|
139
|
-
when '--graphml'
|
140
|
-
format = 'graphml'
|
141
|
-
when '--csv'
|
142
|
-
format = 'text'
|
143
|
-
sep = ','
|
144
|
-
when '--yaml'
|
145
|
-
format = 'yaml'
|
146
|
-
when '--xml'
|
147
|
-
format = 'xml'
|
148
|
-
when '--json'
|
149
|
-
format = 'json'
|
150
|
-
when '--text'
|
151
|
-
format = 'text'
|
152
|
-
when '--sep'
|
153
|
-
sep = arg
|
154
|
-
when '--recurse'
|
155
|
-
recursedepth = arg.to_i
|
156
|
-
if recursedepth > 3
|
157
|
-
$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)"
|
158
|
-
sleep 60
|
159
|
-
end
|
160
|
-
when '--wait'
|
161
|
-
wait = arg.to_i
|
162
|
-
when '--sqlite3'
|
163
|
-
sqlitedb = arg
|
164
|
-
when '--limit'
|
165
|
-
limit = arg.to_i
|
166
|
-
else
|
167
|
-
usage(letter_map)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
if pdnsdbs.length == 0
|
172
|
-
pdnsdbs << "certee"
|
173
|
-
end
|
174
|
-
|
175
|
-
if pdnsdbs.index("bfk") and recursedepth > 1 and wait < 60
|
176
|
-
wait = 60
|
177
|
-
$stderr.puts "Enforcing a minimal 60 second wait when using BFK for recursive crawling"
|
178
|
-
end
|
179
|
-
|
180
|
-
if debug
|
181
|
-
$stderr.puts "Using the following databases: #{pdnsdbs.join(", ")}"
|
182
|
-
$stderr.puts "Recursions: #{recursedepth}, Wait time: #{wait}, Limit: #{limit or 'none'}"
|
183
|
-
if format == "text" or format == "csv"
|
184
|
-
$stderr.puts "Output format: #{format} (sep=\"#{sep}\")"
|
185
|
-
else
|
186
|
-
$stderr.puts "Output format: #{format}"
|
187
|
-
end
|
188
|
-
if ENV['http_proxy']
|
189
|
-
$stderr.puts "Using proxy settings: http_proxy=#{ENV['http_proxy']}, https_proxy=#{ENV['https_proxy']}"
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
state = nil
|
194
|
-
if sqlitedb
|
195
|
-
state = PassiveDNS::PDNSToolStateDB.new(sqlitedb)
|
196
|
-
else
|
197
|
-
state = PassiveDNS::PDNSToolState.new
|
198
|
-
end
|
199
|
-
state.debug = true if debug
|
200
|
-
|
201
|
-
pdnsclient = PassiveDNS::Client.new(pdnsdbs)
|
202
|
-
pdnsclient.debug = debug
|
203
|
-
|
204
|
-
if ARGV.length > 0
|
205
|
-
ARGV.each do |arg|
|
206
|
-
state.add_query(arg,'pending',0)
|
207
|
-
end
|
208
|
-
else
|
209
|
-
$stdin.each_line do |l|
|
210
|
-
state.add_query(l.chomp,'pending',0)
|
211
|
-
end
|
212
|
-
end
|
213
|
-
pdnslookup(state,pdnsclient,recursedepth,wait,debug,limit)
|
214
|
-
printresults(state,format,sep)
|
5
|
+
puts PassiveDNS::CLI.run(ARGV)
|
data/lib/passivedns/client.rb
CHANGED
@@ -3,15 +3,18 @@ require "passivedns/client/version"
|
|
3
3
|
# This code is released under the LGPL: http://www.gnu.org/licenses/lgpl-3.0.txt
|
4
4
|
# Please note that use of any passive dns database is subject to the terms of use of that passive dns database. Use of this script in violation of their terms is not encouraged in any way. Also, please do not add any obfuscation to try to work around their terms of service. If you need special services, ask the providers for help/permission.
|
5
5
|
# Remember, these passive DNS operators are my friends. I don't want to have a row with them because some asshat used this library to abuse them.
|
6
|
-
require 'passivedns/client/
|
7
|
-
require 'passivedns/client/
|
8
|
-
|
9
|
-
require 'passivedns/client/
|
10
|
-
require 'passivedns/client/
|
11
|
-
require 'passivedns/client/
|
12
|
-
require 'passivedns/client/
|
13
|
-
require 'passivedns/client/
|
14
|
-
require 'passivedns/client/
|
6
|
+
require 'passivedns/client/state'
|
7
|
+
require 'passivedns/client/passivedb'
|
8
|
+
|
9
|
+
require 'passivedns/client/bfk'
|
10
|
+
require 'passivedns/client/circl'
|
11
|
+
require 'passivedns/client/cn360'
|
12
|
+
require 'passivedns/client/dnsdb'
|
13
|
+
require 'passivedns/client/mnemonic'
|
14
|
+
require 'passivedns/client/passivetotal'
|
15
|
+
require 'passivedns/client/tcpiputils'
|
16
|
+
require 'passivedns/client/virustotal'
|
17
|
+
|
15
18
|
require 'configparser'
|
16
19
|
require 'pp'
|
17
20
|
|
@@ -20,7 +23,7 @@ module PassiveDNS
|
|
20
23
|
class PDNSResult < Struct.new(:source, :response_time, :query, :answer, :rrtype, :ttl, :firstseen, :lastseen, :count); end
|
21
24
|
|
22
25
|
class Client
|
23
|
-
def initialize(pdns=['bfk','
|
26
|
+
def initialize(pdns=['bfk','dnsdb','virustotal','tcpiputils','cn360','mnemonic','passivetotal','CIRCL'], configfile="#{ENV['HOME']}/.passivedns-client")
|
24
27
|
cp = ConfigParser.new(configfile)
|
25
28
|
# this creates a map of all the PassiveDNS provider names and their classes
|
26
29
|
class_map = {}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# DESCRIPTION: Module to query PassiveTotal's passive DNS repository
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'net/https'
|
5
|
+
require 'openssl'
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
module PassiveDNS
|
9
|
+
class Circl < PassiveDB
|
10
|
+
# override
|
11
|
+
def self.name
|
12
|
+
"CIRCL"
|
13
|
+
end
|
14
|
+
#override
|
15
|
+
def self.config_section_name
|
16
|
+
"CIRCL"
|
17
|
+
end
|
18
|
+
#override
|
19
|
+
def self.option_letter
|
20
|
+
"c"
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :debug
|
24
|
+
def initialize(options={})
|
25
|
+
@debug = options[:debug] || true
|
26
|
+
@username = options["USERNAME"]
|
27
|
+
@password = options["PASSWORD"]
|
28
|
+
@auth_token = options["AUTH_TOKEN"]
|
29
|
+
@url = options["URL"] || "https://www.circl.lu/pdns/query"
|
30
|
+
end
|
31
|
+
|
32
|
+
def parse_json(page,query,response_time=0)
|
33
|
+
res = []
|
34
|
+
# need to remove the json_class tag or the parser will crap itself trying to find a class to align it to
|
35
|
+
page.split(/\n/).each do |line|
|
36
|
+
row = JSON.parse(line)
|
37
|
+
res << PDNSResult.new(self.class.name,response_time,
|
38
|
+
row['rrname'], row['rdata'], row['rrtype'], 0,
|
39
|
+
row['time_first'], row['time_last'], row['count'])
|
40
|
+
end
|
41
|
+
res
|
42
|
+
rescue Exception => e
|
43
|
+
$stderr.puts "#{self.class.name} Exception: #{e}"
|
44
|
+
raise e
|
45
|
+
end
|
46
|
+
|
47
|
+
def lookup(label, limit=nil)
|
48
|
+
$stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
|
49
|
+
Timeout::timeout(240) {
|
50
|
+
url = @url+"/"+label
|
51
|
+
$stderr.puts "DEBUG: #{self.class.name} url = #{url}" if @debug
|
52
|
+
url = URI.parse url
|
53
|
+
http = Net::HTTP.new(url.host, url.port)
|
54
|
+
http.use_ssl = (url.scheme == 'https')
|
55
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
56
|
+
http.verify_depth = 5
|
57
|
+
request = Net::HTTP::Get.new(url.request_uri)
|
58
|
+
request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
|
59
|
+
if @username
|
60
|
+
request.basic_auth(@username, @password)
|
61
|
+
end
|
62
|
+
if @auth_token
|
63
|
+
request.add_field("Authorization", @auth_token)
|
64
|
+
end
|
65
|
+
t1 = Time.now
|
66
|
+
response = http.request(request)
|
67
|
+
t2 = Time.now
|
68
|
+
recs = parse_json(response.body, label, t2-t1)
|
69
|
+
if limit
|
70
|
+
recs[0,limit]
|
71
|
+
else
|
72
|
+
recs
|
73
|
+
end
|
74
|
+
}
|
75
|
+
rescue Timeout::Error => e
|
76
|
+
$stderr.puts "#{self.class.name} lookup timed out: #{label}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
CIRCL = PassiveDNS::Circl
|
80
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
require 'getoptlong'
|
2
|
+
require 'structformatter'
|
3
|
+
require 'getoptlong'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
module PassiveDNS
|
7
|
+
class CLInterface
|
8
|
+
def self.parse_command_line(args)
|
9
|
+
opts = GetoptLong.new(
|
10
|
+
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
11
|
+
[ '--debug', '-z', GetoptLong::NO_ARGUMENT ],
|
12
|
+
[ '--database', '-d', GetoptLong::REQUIRED_ARGUMENT ],
|
13
|
+
|
14
|
+
[ '--gdf', '-g', GetoptLong::NO_ARGUMENT ],
|
15
|
+
[ '--graphviz', '-v', GetoptLong::NO_ARGUMENT ],
|
16
|
+
[ '--graphml', '-m', GetoptLong::NO_ARGUMENT ],
|
17
|
+
[ '--csv', '-c', GetoptLong::NO_ARGUMENT ],
|
18
|
+
[ '--xml', '-x', GetoptLong::NO_ARGUMENT ],
|
19
|
+
[ '--yaml', '-y', GetoptLong::NO_ARGUMENT ],
|
20
|
+
[ '--json', '-j', GetoptLong::NO_ARGUMENT ],
|
21
|
+
[ '--text', '-t', GetoptLong::NO_ARGUMENT ],
|
22
|
+
[ '--sep', '-s', GetoptLong::REQUIRED_ARGUMENT ],
|
23
|
+
|
24
|
+
[ '--sqlite3', '-f', GetoptLong::REQUIRED_ARGUMENT ],
|
25
|
+
[ '--recurse', '-r', GetoptLong::REQUIRED_ARGUMENT ],
|
26
|
+
[ '--wait', '-w', GetoptLong::REQUIRED_ARGUMENT ],
|
27
|
+
[ '--limit', '-l', GetoptLong::REQUIRED_ARGUMENT ]
|
28
|
+
)
|
29
|
+
|
30
|
+
letter_map = {}
|
31
|
+
PassiveDNS.constants.each do |const|
|
32
|
+
if PassiveDNS.const_get(const).is_a?(Class) and PassiveDNS.const_get(const).superclass == PassiveDNS::PassiveDB
|
33
|
+
letter_map[PassiveDNS.const_get(const).option_letter] = [PassiveDNS.const_get(const).name, PassiveDNS.const_get(const).config_section_name]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# sets the default search methods
|
38
|
+
options = {
|
39
|
+
:pdnsdbs => [],
|
40
|
+
:format => "text",
|
41
|
+
:sep => "\t",
|
42
|
+
:recursedepth => 1,
|
43
|
+
:wait => 0,
|
44
|
+
:res => nil,
|
45
|
+
:debug => false,
|
46
|
+
:sqlitedb => nil,
|
47
|
+
:limit => nil
|
48
|
+
}
|
49
|
+
|
50
|
+
opts.each do |opt, arg|
|
51
|
+
case opt
|
52
|
+
when '--help'
|
53
|
+
puts usage(letter_map)
|
54
|
+
exit
|
55
|
+
when '--debug'
|
56
|
+
options[:debug] = true
|
57
|
+
when '--database'
|
58
|
+
arg.split(//).each do |c|
|
59
|
+
if c == ','
|
60
|
+
next
|
61
|
+
elsif letter_map[c]
|
62
|
+
options[:pdnsdbs] << letter_map[c][1]
|
63
|
+
else
|
64
|
+
$stderr.puts "ERROR: Unknown passive DNS database identifier: #{c}."
|
65
|
+
usage(letter_map)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
when '--gdf'
|
69
|
+
options[:format] = 'gdf'
|
70
|
+
when '--graphviz'
|
71
|
+
options[:format] = 'graphviz'
|
72
|
+
when '--graphml'
|
73
|
+
options[:format] = 'graphml'
|
74
|
+
when '--csv'
|
75
|
+
options[:format] = 'text'
|
76
|
+
options[:sep] = ','
|
77
|
+
when '--yaml'
|
78
|
+
options[:format] = 'yaml'
|
79
|
+
when '--xml'
|
80
|
+
options[:format] = 'xml'
|
81
|
+
when '--json'
|
82
|
+
options[:format] = 'json'
|
83
|
+
when '--text'
|
84
|
+
options[:format] = 'text'
|
85
|
+
when '--sep'
|
86
|
+
options[:sep] = arg
|
87
|
+
when '--recurse'
|
88
|
+
options[:recursedepth] = arg.to_i
|
89
|
+
if options[:recursedepth] > 3
|
90
|
+
$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)"
|
91
|
+
sleep 60
|
92
|
+
end
|
93
|
+
when '--wait'
|
94
|
+
options[:wait] = arg.to_i
|
95
|
+
when '--sqlite3'
|
96
|
+
options[:sqlitedb] = arg
|
97
|
+
when '--limit'
|
98
|
+
otions[:limit] = arg.to_i
|
99
|
+
else
|
100
|
+
puts usage(letter_map)
|
101
|
+
exit
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
if options[:pdnsdbs].length == 0
|
106
|
+
options[:pdnsdbs] << "bfk"
|
107
|
+
end
|
108
|
+
|
109
|
+
if options[:pdnsdbs].index("bfk") and recursedepth > 1 and wait < 60
|
110
|
+
options[:wait] = 60
|
111
|
+
$stderr.puts "Enforcing a minimal 60 second wait when using BFK for recursive crawling"
|
112
|
+
end
|
113
|
+
|
114
|
+
if options[:debug]
|
115
|
+
$stderr.puts "Using the following databases: #{options[:pdnsdbs].join(", ")}"
|
116
|
+
$stderr.puts "Recursions: #{options[:recursedepth]}, Wait time: #{options[:wait]}, Limit: #{options[:limit] or 'none'}"
|
117
|
+
if options[:format] == "text" or options[:format] == "csv"
|
118
|
+
$stderr.puts "Output format: #{options[:format]} (sep=\"#{options[:sep]}\")"
|
119
|
+
else
|
120
|
+
$stderr.puts "Output format: #{options[:format]}"
|
121
|
+
end
|
122
|
+
if ENV['http_proxy']
|
123
|
+
$stderr.puts "Using proxy settings: http_proxy=#{ENV['http_proxy']}, https_proxy=#{ENV['https_proxy']}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
[options, args]
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.usage(letter_map)
|
131
|
+
databases = letter_map.keys.sort.join("")
|
132
|
+
help_text = "\n"
|
133
|
+
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"
|
134
|
+
help_text << "Passive DNS Providers"
|
135
|
+
help_text << " -d#{databases} uses all of the available passive dns database\n"
|
136
|
+
letter_map.keys.sort.each do |l|
|
137
|
+
help_text << " -d#{l} use #{letter_map[l][0]}\n"
|
138
|
+
end
|
139
|
+
help_text << " -dvt uses VirusTotal and TCPIPUtils (for example)\n"
|
140
|
+
help_text << "\n"
|
141
|
+
help_text << "Output Formatting\n"
|
142
|
+
help_text << " -g link-nodal GDF visualization definition\n"
|
143
|
+
help_text << " -v link-nodal graphviz visualization definition\n"
|
144
|
+
help_text << " -m link-nodal graphml visualization definition\n"
|
145
|
+
help_text << " -c CSV\n"
|
146
|
+
help_text << " -x XML\n"
|
147
|
+
help_text << " -y YAML\n"
|
148
|
+
help_text << " -j JSON\n"
|
149
|
+
help_text << " -t ASCII text (default)\n"
|
150
|
+
help_text << " -s <sep> specifies a field separator for text output, default is tab\n"
|
151
|
+
help_text << "\n"
|
152
|
+
help_text << "State and Recusion\n"
|
153
|
+
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"
|
154
|
+
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"
|
155
|
+
help_text << " -w# specifies the amount of time to wait, in seconds, between queries (Default: 0)\n"
|
156
|
+
help_text << " -l <count> limits the number of records returned per passive dns database queried.\n"
|
157
|
+
help_text << "\n"
|
158
|
+
help_text << "Getting Help\n"
|
159
|
+
help_text << " -v debugging information\n"
|
160
|
+
|
161
|
+
help_text
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.pdnslookup(state, pdnsclient, options)
|
165
|
+
recursedepth = options[:recursedepth]
|
166
|
+
wait = options[:wait]
|
167
|
+
debug = options[:debug]
|
168
|
+
limit = options[:limit]
|
169
|
+
puts "pdnslookup: #{state.level} #{recursedepth}" if debug
|
170
|
+
level = 0
|
171
|
+
while level < recursedepth
|
172
|
+
puts "pdnslookup: #{level} < #{recursedepth}" if debug
|
173
|
+
state.each_query(recursedepth) do |q|
|
174
|
+
rv = pdnsclient.query(q,limit)
|
175
|
+
if rv
|
176
|
+
rv.each do |r|
|
177
|
+
if ["A","AAAA","NS","CNAME","PTR"].index(r.rrtype)
|
178
|
+
puts "pdnslookup: #{r.to_s}" if debug
|
179
|
+
state.add_result(r)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
else
|
183
|
+
state.update_query(rv,'failed')
|
184
|
+
end
|
185
|
+
sleep wait if level < recursedepth
|
186
|
+
end
|
187
|
+
level += 1
|
188
|
+
end
|
189
|
+
state
|
190
|
+
end
|
191
|
+
|
192
|
+
def self.results_to_s(state,options)
|
193
|
+
format = options[:format]
|
194
|
+
sep = options[:sep]
|
195
|
+
case format
|
196
|
+
when 'text'
|
197
|
+
PassiveDNS::PDNSResult.members.join(sep)+"\n"+state.to_s(sep)
|
198
|
+
when 'yaml'
|
199
|
+
state.to_yaml
|
200
|
+
when 'xml'
|
201
|
+
state.to_xml
|
202
|
+
when 'json'
|
203
|
+
state.to_json
|
204
|
+
when 'gdf'
|
205
|
+
state.to_gdf
|
206
|
+
when 'graphviz'
|
207
|
+
state.to_graphviz
|
208
|
+
when 'graphml'
|
209
|
+
state.to_graphml
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.create_state(sqlitedb=nil)
|
214
|
+
state = nil
|
215
|
+
if sqlitedb
|
216
|
+
state = PassiveDNS::PDNSToolStateDB.new(sqlitedb)
|
217
|
+
else
|
218
|
+
state = PassiveDNS::PDNSToolState.new
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def self.run(args)
|
223
|
+
options, items = parse_command_line(args)
|
224
|
+
state = create_state(options[:sqlitedb])
|
225
|
+
state.debug = options[:debug]
|
226
|
+
|
227
|
+
pdnsclient = PassiveDNS::Client.new(options[:pdnsdbs])
|
228
|
+
pdnsclient.debug = options[:debug]
|
229
|
+
|
230
|
+
if ARGV.length > 0
|
231
|
+
ARGV.each do |arg|
|
232
|
+
state.add_query(arg,'pending',0)
|
233
|
+
end
|
234
|
+
else
|
235
|
+
$stdin.each_line do |l|
|
236
|
+
state.add_query(l.chomp,'pending',0)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
pdnslookup(state,pdnsclient,options)
|
240
|
+
results_to_s(state,options)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
CLI = PassiveDNS::CLInterface
|
244
|
+
end
|
245
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# DESCRIPTION: Module to query PassiveTotal's passive DNS repository
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'net/https'
|
5
|
+
require 'openssl'
|
6
|
+
|
7
|
+
module PassiveDNS
|
8
|
+
class PassiveTotal < PassiveDB
|
9
|
+
# override
|
10
|
+
def self.name
|
11
|
+
"PassiveTotal"
|
12
|
+
end
|
13
|
+
#override
|
14
|
+
def self.config_section_name
|
15
|
+
"passivetotal"
|
16
|
+
end
|
17
|
+
#override
|
18
|
+
def self.option_letter
|
19
|
+
"p"
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_accessor :debug
|
23
|
+
def initialize(options={})
|
24
|
+
@debug = options[:debug] || false
|
25
|
+
@apikey = options["APIKEY"] || raise("#{self.class.name} requires an APIKEY")
|
26
|
+
@url = options["URL"] || "https://www.passivetotal.org/api/passive"
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_json(page,query,response_time=0)
|
30
|
+
res = []
|
31
|
+
# need to remove the json_class tag or the parser will crap itself trying to find a class to align it to
|
32
|
+
data = JSON.parse(page)
|
33
|
+
if data['results']
|
34
|
+
query = data['results']['value']
|
35
|
+
data['results']['resolutions'].each do |row|
|
36
|
+
first_seen = row['firstSeen']
|
37
|
+
last_seen = row['lastSeen']
|
38
|
+
value = row['value']
|
39
|
+
source = row['source'].join(",")
|
40
|
+
res << PDNSResult.new(self.class.name+"/"+source,response_time,
|
41
|
+
query, value, "A", 0, first_seen, last_seen)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
res
|
45
|
+
rescue Exception => e
|
46
|
+
$stderr.puts "#{self.class.name} Exception: #{e}"
|
47
|
+
raise e
|
48
|
+
end
|
49
|
+
|
50
|
+
def lookup(label, limit=nil)
|
51
|
+
$stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
|
52
|
+
Timeout::timeout(240) {
|
53
|
+
url = @url
|
54
|
+
$stderr.puts "DEBUG: #{self.class.name} url = #{url}" if @debug
|
55
|
+
url = URI.parse url
|
56
|
+
http = Net::HTTP.new(url.host, url.port)
|
57
|
+
http.use_ssl = (url.scheme == 'https')
|
58
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
59
|
+
http.verify_depth = 5
|
60
|
+
request = Net::HTTP::Post.new(url.request_uri)
|
61
|
+
request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
|
62
|
+
request.set_form_data({"apikey" => @apikey, "value" => label})
|
63
|
+
t1 = Time.now
|
64
|
+
response = http.request(request)
|
65
|
+
t2 = Time.now
|
66
|
+
recs = parse_json(response.body, label, t2-t1)
|
67
|
+
if limit
|
68
|
+
recs[0,limit]
|
69
|
+
else
|
70
|
+
recs
|
71
|
+
end
|
72
|
+
}
|
73
|
+
rescue Timeout::Error => e
|
74
|
+
$stderr.puts "#{self.class.name} lookup timed out: #{label}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/passivedns-client.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_runtime_dependency 'sqlite3', '>= 1.3.3'
|
23
23
|
spec.add_runtime_dependency 'structformatter', '~> 0.0.1'
|
24
24
|
spec.add_runtime_dependency 'configparser', '~> 0.1.3'
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.5"
|
25
26
|
spec.add_development_dependency "bundler", "~> 1.3"
|
26
27
|
spec.add_development_dependency "rake"
|
27
28
|
|
data/test/helper.rb
CHANGED
@@ -9,7 +9,7 @@ end
|
|
9
9
|
require_relative 'helper'
|
10
10
|
require 'configparser'
|
11
11
|
|
12
|
-
class TestPassiveDnsQuery < Test
|
12
|
+
class TestPassiveDnsQuery < Minitest::Test
|
13
13
|
|
14
14
|
def setup
|
15
15
|
configfile="#{ENV['HOME']}/.passivedns-client"
|
@@ -23,194 +23,227 @@ class TestPassiveDnsQuery < Test::Unit::TestCase
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def test_instantiate_Nonexisting_Client
|
26
|
-
|
26
|
+
assert_raises RuntimeError do
|
27
27
|
PassiveDNS::Client.new(['doesnotexist'])
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
def test_instantiate_All_Clients
|
32
|
-
|
33
|
-
PassiveDNS::Client.new()
|
34
|
-
end
|
32
|
+
PassiveDNS::Client.new()
|
35
33
|
end
|
36
34
|
|
37
35
|
def test_instantiate_Passive_DNS_State
|
38
|
-
|
36
|
+
refute_nil(PassiveDNS::PDNSToolState.new)
|
39
37
|
end
|
40
38
|
|
41
39
|
def test_instantiate_Passive_DNS_State_database
|
42
40
|
if File.exists?("test/test.sqlite3")
|
43
41
|
File.unlink("test/test.sqlite3")
|
44
42
|
end
|
45
|
-
|
43
|
+
refute_nil(PassiveDNS::PDNSToolStateDB.new("test/test.sqlite3"))
|
46
44
|
if File.exists?("test/test.sqlite3")
|
47
45
|
File.unlink("test/test.sqlite3")
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
51
49
|
def test_BFK
|
52
|
-
|
53
|
-
PassiveDNS::Client.new(['bfk'])
|
54
|
-
end
|
50
|
+
PassiveDNS::Client.new(['bfk'])
|
55
51
|
d = PassiveDNS::BFK.new(@cp['bfk'] || {})
|
56
|
-
|
52
|
+
refute_nil(d)
|
57
53
|
rows = d.lookup("example.org",3)
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
54
|
+
refute_nil(rows)
|
55
|
+
refute_nil(rows.to_s)
|
56
|
+
refute_nil(rows.to_xml)
|
57
|
+
refute_nil(rows.to_json)
|
58
|
+
refute_nil(rows.to_yaml)
|
63
59
|
assert_equal(3, rows.length)
|
64
60
|
rows = d.lookup("8.8.8.8")
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
61
|
+
refute_nil(rows)
|
62
|
+
refute_nil(rows.to_s)
|
63
|
+
refute_nil(rows.to_xml)
|
64
|
+
refute_nil(rows.to_json)
|
65
|
+
refute_nil(rows.to_yaml)
|
70
66
|
end
|
71
67
|
|
72
68
|
def test_CERTEE
|
73
|
-
|
74
|
-
assert_nothing_raised do
|
75
|
-
PassiveDNS::Client.new(['certee'])
|
76
|
-
end
|
69
|
+
PassiveDNS::Client.new(['certee'])
|
77
70
|
d = PassiveDNS::CERTEE.new(@cp['certee'] || {})
|
78
|
-
|
71
|
+
refute_nil(d)
|
79
72
|
rows = d.lookup("sim.cert.ee",3)
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
73
|
+
refute_nil(rows)
|
74
|
+
refute_nil(rows.to_s)
|
75
|
+
refute_nil(rows.to_xml)
|
76
|
+
refute_nil(rows.to_json)
|
77
|
+
refute_nil(rows.to_yaml)
|
85
78
|
assert_equal(3, rows.length)
|
86
79
|
rows = d.lookup("8.8.8.8")
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
80
|
+
refute_nil(rows)
|
81
|
+
refute_nil(rows.to_s)
|
82
|
+
refute_nil(rows.to_xml)
|
83
|
+
refute_nil(rows.to_json)
|
84
|
+
refute_nil(rows.to_yaml)
|
92
85
|
end
|
93
86
|
|
94
87
|
def test_DNSDB
|
95
|
-
|
96
|
-
PassiveDNS::Client.new(['dnsdb'])
|
97
|
-
end
|
88
|
+
PassiveDNS::Client.new(['dnsdb'])
|
98
89
|
d = PassiveDNS::DNSDB.new(@cp['dnsdb'] || {})
|
99
|
-
|
90
|
+
refute_nil(d)
|
100
91
|
rows = d.lookup("example.org",3)
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
92
|
+
refute_nil(rows)
|
93
|
+
refute_nil(rows.to_s)
|
94
|
+
refute_nil(rows.to_xml)
|
95
|
+
refute_nil(rows.to_json)
|
96
|
+
refute_nil(rows.to_yaml)
|
106
97
|
assert_equal(3, rows.length) # this will fail since DNSDB has an off by one error
|
107
98
|
rows = d.lookup("8.8.8.8")
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
99
|
+
refute_nil(rows)
|
100
|
+
refute_nil(rows.to_s)
|
101
|
+
refute_nil(rows.to_xml)
|
102
|
+
refute_nil(rows.to_json)
|
103
|
+
refute_nil(rows.to_yaml)
|
113
104
|
end
|
114
105
|
|
115
106
|
def test_VirusTotal
|
116
|
-
|
117
|
-
PassiveDNS::Client.new(['virustotal'])
|
118
|
-
end
|
107
|
+
PassiveDNS::Client.new(['virustotal'])
|
119
108
|
d = PassiveDNS::VirusTotal.new(@cp['virustotal'] || {})
|
120
|
-
|
109
|
+
refute_nil(d)
|
121
110
|
rows = d.lookup("google.com",3)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
111
|
+
refute_nil(rows)
|
112
|
+
refute_nil(rows.to_s)
|
113
|
+
refute_nil(rows.to_xml)
|
114
|
+
refute_nil(rows.to_json)
|
115
|
+
refute_nil(rows.to_yaml)
|
127
116
|
assert_equal(3, rows.length)
|
128
117
|
rows = d.lookup("8.8.8.8")
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
118
|
+
refute_nil(rows)
|
119
|
+
refute_nil(rows.to_s)
|
120
|
+
refute_nil(rows.to_xml)
|
121
|
+
refute_nil(rows.to_json)
|
122
|
+
refute_nil(rows.to_yaml)
|
134
123
|
end
|
135
124
|
|
136
125
|
def test_TCPIPUtils
|
137
|
-
|
138
|
-
PassiveDNS::Client.new(['tcpiputils'])
|
139
|
-
end
|
126
|
+
PassiveDNS::Client.new(['tcpiputils'])
|
140
127
|
d = PassiveDNS::TCPIPUtils.new(@cp['tcpiputils'] || {})
|
141
|
-
|
128
|
+
refute_nil(d)
|
142
129
|
rows = d.lookup("example.org")
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
130
|
+
refute_nil(rows)
|
131
|
+
refute_nil(rows.to_s)
|
132
|
+
refute_nil(rows.to_xml)
|
133
|
+
refute_nil(rows.to_json)
|
134
|
+
refute_nil(rows.to_yaml)
|
148
135
|
rows = d.lookup("example.org",3)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
136
|
+
refute_nil(rows)
|
137
|
+
refute_nil(rows.to_s)
|
138
|
+
refute_nil(rows.to_xml)
|
139
|
+
refute_nil(rows.to_json)
|
140
|
+
refute_nil(rows.to_yaml)
|
154
141
|
assert_equal(3, rows.length)
|
155
142
|
rows = d.lookup("8.8.8.8")
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
143
|
+
refute_nil(rows)
|
144
|
+
refute_nil(rows.to_s)
|
145
|
+
refute_nil(rows.to_xml)
|
146
|
+
refute_nil(rows.to_json)
|
147
|
+
refute_nil(rows.to_yaml)
|
161
148
|
end
|
162
149
|
|
163
150
|
def test_cn360
|
164
|
-
|
165
|
-
PassiveDNS::Client.new(['cn360'])
|
166
|
-
end
|
151
|
+
PassiveDNS::Client.new(['cn360'])
|
167
152
|
d = PassiveDNS::CN360.new(@cp['cn360'] || {})
|
168
|
-
|
153
|
+
refute_nil(d)
|
169
154
|
rows = d.lookup("example.org")
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
155
|
+
refute_nil(rows)
|
156
|
+
refute_nil(rows.to_s)
|
157
|
+
refute_nil(rows.to_xml)
|
158
|
+
refute_nil(rows.to_json)
|
159
|
+
refute_nil(rows.to_yaml)
|
175
160
|
rows = d.lookup("example.org",3)
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
161
|
+
refute_nil(rows)
|
162
|
+
refute_nil(rows.to_s)
|
163
|
+
refute_nil(rows.to_xml)
|
164
|
+
refute_nil(rows.to_json)
|
165
|
+
refute_nil(rows.to_yaml)
|
181
166
|
assert_equal(3, rows.length)
|
182
167
|
rows = d.lookup("8.8.8.8")
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
168
|
+
refute_nil(rows)
|
169
|
+
refute_nil(rows.to_s)
|
170
|
+
refute_nil(rows.to_xml)
|
171
|
+
refute_nil(rows.to_json)
|
172
|
+
refute_nil(rows.to_yaml)
|
188
173
|
end
|
189
174
|
|
190
175
|
def test_nmemonic
|
191
|
-
|
192
|
-
PassiveDNS::Client.new(['mnemonic'])
|
193
|
-
end
|
176
|
+
PassiveDNS::Client.new(['mnemonic'])
|
194
177
|
d = PassiveDNS::Mnemonic.new(@cp['mnemonic'] || {})
|
195
|
-
|
178
|
+
refute_nil(d)
|
179
|
+
rows = d.lookup("example.org")
|
180
|
+
refute_nil(rows)
|
181
|
+
refute_nil(rows.to_s)
|
182
|
+
refute_nil(rows.to_xml)
|
183
|
+
refute_nil(rows.to_json)
|
184
|
+
refute_nil(rows.to_yaml)
|
185
|
+
rows = d.lookup("example.org",3)
|
186
|
+
refute_nil(rows)
|
187
|
+
refute_nil(rows.to_s)
|
188
|
+
refute_nil(rows.to_xml)
|
189
|
+
refute_nil(rows.to_json)
|
190
|
+
refute_nil(rows.to_yaml)
|
191
|
+
assert_equal(3, rows.length)
|
192
|
+
rows = d.lookup("8.8.8.8")
|
193
|
+
refute_nil(rows)
|
194
|
+
refute_nil(rows.to_s)
|
195
|
+
refute_nil(rows.to_xml)
|
196
|
+
refute_nil(rows.to_json)
|
197
|
+
refute_nil(rows.to_yaml)
|
198
|
+
end
|
199
|
+
|
200
|
+
def test_passivetotal
|
201
|
+
PassiveDNS::Client.new(['passivetotal'])
|
202
|
+
d = PassiveDNS::PassiveTotal.new(@cp['passivetotal'] || {})
|
203
|
+
refute_nil(d)
|
204
|
+
rows = d.lookup("example.org")
|
205
|
+
refute_nil(rows)
|
206
|
+
refute_nil(rows.to_s)
|
207
|
+
refute_nil(rows.to_xml)
|
208
|
+
refute_nil(rows.to_json)
|
209
|
+
refute_nil(rows.to_yaml)
|
210
|
+
rows = d.lookup("example.org",3)
|
211
|
+
refute_nil(rows)
|
212
|
+
refute_nil(rows.to_s)
|
213
|
+
refute_nil(rows.to_xml)
|
214
|
+
refute_nil(rows.to_json)
|
215
|
+
refute_nil(rows.to_yaml)
|
216
|
+
assert_equal(3, rows.length)
|
217
|
+
rows = d.lookup("8.8.8.8")
|
218
|
+
refute_nil(rows)
|
219
|
+
refute_nil(rows.to_s)
|
220
|
+
refute_nil(rows.to_xml)
|
221
|
+
refute_nil(rows.to_json)
|
222
|
+
refute_nil(rows.to_yaml)
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_circl
|
226
|
+
PassiveDNS::Client.new(['CIRCL'])
|
227
|
+
d = PassiveDNS::CIRCL.new(@cp['CIRCL'] || {})
|
228
|
+
refute_nil(d)
|
196
229
|
rows = d.lookup("example.org")
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
230
|
+
refute_nil(rows)
|
231
|
+
refute_nil(rows.to_s)
|
232
|
+
refute_nil(rows.to_xml)
|
233
|
+
refute_nil(rows.to_json)
|
234
|
+
refute_nil(rows.to_yaml)
|
202
235
|
rows = d.lookup("example.org",3)
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
236
|
+
refute_nil(rows)
|
237
|
+
refute_nil(rows.to_s)
|
238
|
+
refute_nil(rows.to_xml)
|
239
|
+
refute_nil(rows.to_json)
|
240
|
+
refute_nil(rows.to_yaml)
|
208
241
|
assert_equal(3, rows.length)
|
209
242
|
rows = d.lookup("8.8.8.8")
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
243
|
+
refute_nil(rows)
|
244
|
+
refute_nil(rows.to_s)
|
245
|
+
refute_nil(rows.to_xml)
|
246
|
+
refute_nil(rows.to_json)
|
247
|
+
refute_nil(rows.to_yaml)
|
215
248
|
end
|
216
249
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: passivedns-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- chrislee35
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 0.1.3
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '5.5'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '5.5'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: bundler
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -112,11 +126,13 @@ files:
|
|
112
126
|
- bin/pdnstool
|
113
127
|
- lib/passivedns/client.rb
|
114
128
|
- lib/passivedns/client/bfk.rb
|
115
|
-
- lib/passivedns/client/
|
129
|
+
- lib/passivedns/client/circl.rb
|
130
|
+
- lib/passivedns/client/cli.rb
|
116
131
|
- lib/passivedns/client/cn360.rb
|
117
132
|
- lib/passivedns/client/dnsdb.rb
|
118
133
|
- lib/passivedns/client/mnemonic.rb
|
119
134
|
- lib/passivedns/client/passivedb.rb
|
135
|
+
- lib/passivedns/client/passivetotal.rb
|
120
136
|
- lib/passivedns/client/state.rb
|
121
137
|
- lib/passivedns/client/tcpiputils.rb
|
122
138
|
- lib/passivedns/client/version.rb
|
@@ -1,62 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
require_relative 'passivedb'
|
3
|
-
|
4
|
-
module PassiveDNS
|
5
|
-
class CERTEE < PassiveDB
|
6
|
-
# override
|
7
|
-
def self.name
|
8
|
-
"CERTEE"
|
9
|
-
end
|
10
|
-
#override
|
11
|
-
def self.config_section_name
|
12
|
-
"certee"
|
13
|
-
end
|
14
|
-
#override
|
15
|
-
def self.option_letter
|
16
|
-
"e"
|
17
|
-
end
|
18
|
-
|
19
|
-
attr_accessor :debug
|
20
|
-
def initialize(options={})
|
21
|
-
@debug = options[:debug] || false
|
22
|
-
@host = options["HOST"] || "sim.cert.ee"
|
23
|
-
@port = options["PORT"].to_i || 43
|
24
|
-
end
|
25
|
-
|
26
|
-
# override
|
27
|
-
def lookup(label, limit=nil)
|
28
|
-
$stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
|
29
|
-
recs = []
|
30
|
-
begin
|
31
|
-
t1 = Time.now
|
32
|
-
s = TCPSocket.new(@host,@port)
|
33
|
-
s.puts(label)
|
34
|
-
s.each_line do |l|
|
35
|
-
if l =~ /Traceback \(most recent call last\):/
|
36
|
-
# there is a bug in the CERTEE lookup tool
|
37
|
-
raise "#{self.class.name} is currently offline"
|
38
|
-
end
|
39
|
-
(lbl,ans,fs,ls) = l.chomp.split(/\t/)
|
40
|
-
rrtype = 'A'
|
41
|
-
if ans =~ /^\d+\.\d+\.\d+\.\d+$/
|
42
|
-
rrtype = 'A'
|
43
|
-
elsif ans =~ /^ns/
|
44
|
-
rrtype = 'NS'
|
45
|
-
else
|
46
|
-
rrtype = 'CNAME'
|
47
|
-
end
|
48
|
-
t2 = Time.now
|
49
|
-
recs << PDNSResult.new(self.class.name,t2-t1,lbl,ans,rrtype,0,Time.parse(fs).utc.strftime("%Y-%m-%dT%H:%M:%SZ"),Time.parse(ls).utc.strftime("%Y-%m-%dT%H:%M:%SZ"))
|
50
|
-
end
|
51
|
-
rescue SocketError => e
|
52
|
-
$stderr.puts e
|
53
|
-
end
|
54
|
-
return nil unless recs.length > 0
|
55
|
-
if limit
|
56
|
-
recs = recs[0,limit]
|
57
|
-
else
|
58
|
-
recs
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|