passivedns-client 1.4.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +85 -46
- data/bin/pdnstool +34 -39
- data/lib/passivedns/client/bfk.rb +27 -12
- data/lib/passivedns/client/certee.rb +26 -8
- data/lib/passivedns/client/cn360.rb +24 -26
- data/lib/passivedns/client/dnsdb.rb +27 -25
- data/lib/passivedns/client/mnemonic.rb +72 -0
- data/lib/passivedns/client/passivedb.rb +19 -0
- data/lib/passivedns/client/tcpiputils.rb +27 -20
- data/lib/passivedns/client/version.rb +1 -1
- data/lib/passivedns/client/virustotal.rb +27 -17
- data/lib/passivedns/client.rb +22 -21
- data/test/test_passivedns-client.rb +67 -21
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d29ccf361ef159d087a669bcb1c079cdcc9cd9d1
|
4
|
+
data.tar.gz: b04ddd8e934977225087be6782540cf00b8a3e13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f45ae94c974ebedcb3a2b3d05da9f1ce69698f34f4b275a31137508ef680381116d35525836345a6b8c1a72a4d0359d0261a939b96d3c73f243f8a007f2b0ef6
|
7
|
+
data.tar.gz: aa2f36c8c9ded9632d07af3fbb4362212b6e461c0d63e60802404995ca2175f744134950470dac3802e30a4a61fab6bb7d7d57540c54e8fabe7416be505cd852
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# PassiveDNS::Client
|
2
2
|
|
3
|
-
This rubygem queries
|
3
|
+
This rubygem queries 7 major Passive DNS databases: BFK, CERTEE, DNSParse, DNSDB, VirusTotal, PassiveDNS.cn, and Mnemonic.
|
4
4
|
Passive DNS is a technique where IP to hostname mappings are made by recording the answers of other people's queries.
|
5
5
|
|
6
6
|
There is a tool included, pdnstool, that wraps a lot of the functionality that you would need.
|
@@ -25,63 +25,48 @@ Or install it yourself as:
|
|
25
25
|
|
26
26
|
## Configuration
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
The DNSDB configuration file is located at $HOME/.dnsdb-query.conf by default. The format for its configuration file only requires one line in the following format:
|
31
|
-
|
32
|
-
APIKEY="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
33
|
-
|
34
|
-
To request an API Key, please read https://api.dnsdb.info/.
|
35
|
-
|
36
|
-
### CERTEE
|
37
|
-
|
38
|
-
CERT-EE does not require any configuration.
|
39
|
-
BFK.de
|
40
|
-
|
41
|
-
BFK.de does not require any configuration. However, please read and abide by their usage policy at BFK.de. Currently, it just says not to perform automated queries.
|
42
|
-
|
43
|
-
### VirusTotal
|
44
|
-
|
45
|
-
VirusTotal's (https://www.virustotal.com) passive DNS database requires an apikey in $HOME/.virustotal. It is a 64 character hexstring on a single line.
|
46
|
-
|
47
|
-
01234567890abcdef01234567890abcdef01234567890abcdef01234567890abcdef
|
48
|
-
|
49
|
-
|
50
|
-
### TCPIPUtils
|
51
|
-
|
52
|
-
TCPIPUtils's (http://www.tcpiputils.com/premium-access) passive DNS database requires and apikey in $HOME/.tcpiputils. It is a 64 character hexstring on a single line.
|
53
|
-
|
54
|
-
01234567890abcdef01234567890abcdef01234567890abcdef01234567890abcdef
|
55
|
-
|
56
|
-
|
57
|
-
### PassiveDNS.cn from 360.cn
|
58
|
-
|
59
|
-
PassiveDNS.cn (http://www.passivedns.cn) requires an API ID and and API KEY, which is obtainable by creating an account and sending an email to request an API key.
|
60
|
-
|
61
|
-
The configuration file can be in /etc/flint.conf (flint is the name of their tool, which is available at <a href='https://github.com/360netlab/flint'>https://github.com/360netlab/flint</a>) or in $HOME/.flint.conf (which is my preference).
|
62
|
-
|
63
|
-
The file must have three lines and looks like:
|
28
|
+
From version 2.0.0 on, all configuration keys for passive DNS providers are in one configuration file. By default the location of the file is $HOME/.passivedns-client . The syntax of this file is as follows:
|
64
29
|
|
30
|
+
[dnsdb]
|
31
|
+
APIKEY = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
32
|
+
[cn360]
|
65
33
|
API = http://some.web.address.for.their.api
|
66
34
|
API_ID = a username that is given when you register
|
67
35
|
API_KEY = a long and random password of sorts that is used along with the page request to generate a per page API key
|
36
|
+
[tcpiputils]
|
37
|
+
APIKEY = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
38
|
+
[virustotal]
|
39
|
+
APIKEY = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
40
|
+
[mnemonic]
|
41
|
+
APIKEY = 01234567890abcdef01234567890abcdef012345
|
42
|
+
|
43
|
+
## Getting Access
|
44
|
+
* 360.cn : http://www.passivedns.cn
|
45
|
+
* BFK.de : No registration required, but please, please ready their usage policy at http://bfk.de
|
46
|
+
* CERT-EE : No registration required
|
47
|
+
* DNSDB (Farsight Security) : https://api.dnsdb.info/
|
48
|
+
* Mnemonic : mss .at. mnemonic.no
|
49
|
+
* TCPIPUtils : http://www.tcpiputils.com/premium-access
|
50
|
+
* VirusTotal : https://www.virustotal.com
|
68
51
|
|
69
52
|
## Usage
|
70
53
|
|
71
|
-
require 'passivedns
|
54
|
+
require 'passivedns/client'
|
72
55
|
|
73
|
-
c = PassiveDNS::Client.new(['bfk','dnsdb']) # providers: bfk, tcpiputils, certee, dnsdb, virustotal
|
56
|
+
c = PassiveDNS::Client.new(['bfk','dnsdb']) # providers: bfk, tcpiputils, certee, dnsdb, virustotal, passivedns.cn, mnemonic
|
74
57
|
results = c.query("example.com")
|
75
58
|
|
76
59
|
Or use the included tool!
|
77
60
|
|
78
|
-
Usage: bin/pdnstool [-d [
|
79
|
-
-
|
80
|
-
-db
|
81
|
-
-de
|
82
|
-
-dd
|
83
|
-
-dv
|
84
|
-
-dt
|
61
|
+
Usage: bin/pdnstool [-d [bedvt3m]] [-g|-v|-m|-c|-x|-y|-j|-t] [-os <sep>] [-f <file>] [-r#|-w#|-v] [-l <count>] <ip|domain|cidr>
|
62
|
+
-dbedvt3m uses all of the available passive dns databases
|
63
|
+
-db use BFK
|
64
|
+
-de use CERT-EE (default)
|
65
|
+
-dd use DNSDB (formerly ISC)
|
66
|
+
-dv use VirusTotal
|
67
|
+
-dt use TCPIPUtils
|
68
|
+
-d3 use 360.cn (www.passivedns.cn)
|
69
|
+
-dm uses Mnemonic (passivedns.mnemonic.no)
|
85
70
|
-dvt uses VirusTotal and TCPIPUtils (for example)
|
86
71
|
|
87
72
|
-g outputs a link-nodal GDF visualization definition
|
@@ -100,6 +85,58 @@ Or use the included tool!
|
|
100
85
|
-v outputs debugging information
|
101
86
|
-l <count> limits the number of records returned per passive dns database queried.
|
102
87
|
|
88
|
+
## Writing Your Own Database Adaptor
|
89
|
+
|
90
|
+
module PassiveDNS
|
91
|
+
class MyDatabaseAdaptor < PassiveDB
|
92
|
+
# override
|
93
|
+
def self.name
|
94
|
+
"MyPerfectDNS" # short, proper label
|
95
|
+
end
|
96
|
+
#override
|
97
|
+
def self.config_section_name
|
98
|
+
"perfect" # very short label to use in the configuration file
|
99
|
+
end
|
100
|
+
#override
|
101
|
+
def self.option_letter
|
102
|
+
"p" # single letter to specify the option for the command line tool
|
103
|
+
end
|
104
|
+
|
105
|
+
attr_accessor :debug
|
106
|
+
def initialize(options={})
|
107
|
+
@debug = options[:debug] || false
|
108
|
+
# please include a way to change the base URL, HOST, etc., so that people can test
|
109
|
+
# against a test/alternate version of your service
|
110
|
+
@base = options["URL"] || "http://myperfectdns.example.com/pdns.cgi?query="
|
111
|
+
@apikey = options["APIKEY"] || raise("APIKEY option required for #{self.class}")
|
112
|
+
end
|
113
|
+
|
114
|
+
# override
|
115
|
+
def lookup(label, limit=nil)
|
116
|
+
$stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
|
117
|
+
recs = []
|
118
|
+
Timeout::timeout(240) {
|
119
|
+
t1 = Time.now
|
120
|
+
# TODO: your code goes here to fetch the data from your service
|
121
|
+
# TODO: don't forget to impose the limit either during the fetch or during the parse phase
|
122
|
+
response_time = Time.now - t1
|
123
|
+
# TODO: parse your data and add PDNSResult objects to recs array
|
124
|
+
recs << PDNSResult.new(self.class.name, response_time, rrname ,
|
125
|
+
rdata, rrtype, ttl, first_seen, last_seen, count )
|
126
|
+
}
|
127
|
+
recs
|
128
|
+
rescue Timeout::Error => e # using the implied "begin/try" from the beginning of the function
|
129
|
+
$stderr.puts "#{self.class.name} lookup timed out: #{label}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
## Passive DNS - Common Output Format
|
135
|
+
|
136
|
+
There is an RFC, <a href='http://tools.ietf.org/html/draft-dulaunoy-kaplan-passive-dns-cof-01'>Passive DNS - Common Output Format</a>, and a proof of concept implementation, <a href='https://github.com/adulau/pdns-qof-server'>pdns-qof-server</a>, that describes a recommened JSON format for passive DNS data. passivedns-client is very close to supporting it, but since I've never enteracted with a true implementation of this RFC, I can't attest that I could correctly parse it. I think they way that they can encode multiple results into one record would actually break what I have right now.
|
137
|
+
|
138
|
+
Right now, I'm in a wait and see mode with how this progresses before I start supporting yet another format or request that other providers start to adhere to a common output format. If you have thoughts on the matter, I would love to discuss.
|
139
|
+
|
103
140
|
## Contributing
|
104
141
|
|
105
142
|
1. Fork it
|
@@ -107,3 +144,5 @@ Or use the included tool!
|
|
107
144
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
108
145
|
4. Push to the branch (`git push origin my-new-feature`)
|
109
146
|
5. Create new Pull Request
|
147
|
+
|
148
|
+
<a href='mailto:github@chrislee[dot]dhs[dot]org[stop here]xxx'><img src='http://chrisleephd.us/images/github-email.png?passivedns-client'></a>
|
data/bin/pdnstool
CHANGED
@@ -49,15 +49,20 @@ def printresults(state,format,sep="\t")
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def usage
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
52
|
+
letter_map = {}
|
53
|
+
PassiveDNS.constants.each do |const|
|
54
|
+
if PassiveDNS.const_get(const).is_a?(Class) and PassiveDNS.const_get(const).superclass == PassiveDNS::PassiveDB
|
55
|
+
letter_map[PassiveDNS.const_get(const).option_letter] = [PassiveDNS.const_get(const).name, PassiveDNS.const_get(const).config_section_name]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
databases = letter_map.keys.sort.join("")
|
59
|
+
|
60
|
+
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>"
|
61
|
+
puts " -d#{databases} uses all of the available passive dns databases"
|
62
|
+
letter_map.keys.sort.each do |l|
|
63
|
+
puts " -d#{l} use #{letter_map[l][0]}"
|
64
|
+
end
|
65
|
+
puts " -dvt uses VirusTotal and TCPIPUtils (for example)"
|
61
66
|
puts ""
|
62
67
|
puts " -g outputs a link-nodal GDF visualization definition"
|
63
68
|
puts " -v outputs a link-nodal graphviz visualization definition"
|
@@ -73,14 +78,14 @@ def usage
|
|
73
78
|
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!"
|
74
79
|
puts " -w# specifies the amount of time to wait, in seconds, between queries (Default: 0)"
|
75
80
|
puts " -v outputs debugging information"
|
76
|
-
|
81
|
+
puts " -l <count> limits the number of records returned per passive dns database queried."
|
77
82
|
exit
|
78
83
|
end
|
79
84
|
|
80
85
|
opts = GetoptLong.new(
|
81
86
|
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
82
87
|
[ '--debug', '-z', GetoptLong::NO_ARGUMENT ],
|
83
|
-
|
88
|
+
[ '--database', '-d', GetoptLong::REQUIRED_ARGUMENT ],
|
84
89
|
|
85
90
|
[ '--gdf', '-g', GetoptLong::NO_ARGUMENT ],
|
86
91
|
[ '--graphviz', '-v', GetoptLong::NO_ARGUMENT ],
|
@@ -95,7 +100,7 @@ opts = GetoptLong.new(
|
|
95
100
|
[ '--sqlite3', '-f', GetoptLong::REQUIRED_ARGUMENT ],
|
96
101
|
[ '--recurse', '-r', GetoptLong::REQUIRED_ARGUMENT ],
|
97
102
|
[ '--wait', '-w', GetoptLong::REQUIRED_ARGUMENT ],
|
98
|
-
|
103
|
+
[ '--limit', '-l', GetoptLong::REQUIRED_ARGUMENT ]
|
99
104
|
)
|
100
105
|
|
101
106
|
# sets the default search methods
|
@@ -115,22 +120,12 @@ opts.each do |opt, arg|
|
|
115
120
|
usage
|
116
121
|
when '--debug'
|
117
122
|
debug = true
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
when 'e'
|
125
|
-
pdnsdbs << "certee"
|
126
|
-
when 'd'
|
127
|
-
pdnsdbs << "dnsdb"
|
128
|
-
when 'v'
|
129
|
-
pdnsdbs << "virustotal"
|
130
|
-
when 't'
|
131
|
-
pdnsdbs << "tcpiputils"
|
132
|
-
when '3'
|
133
|
-
pdnsdbs << "cn360"
|
123
|
+
when '--database'
|
124
|
+
arg.split(//).each do |c|
|
125
|
+
if c == ','
|
126
|
+
next
|
127
|
+
elsif letter_map[c]
|
128
|
+
pdnsdbs = letter_map[c][1]
|
134
129
|
else
|
135
130
|
raise "Unknown passive DNS database identifier: #{c}"
|
136
131
|
end
|
@@ -164,8 +159,8 @@ opts.each do |opt, arg|
|
|
164
159
|
wait = arg.to_i
|
165
160
|
when '--sqlite3'
|
166
161
|
sqlitedb = arg
|
167
|
-
|
168
|
-
|
162
|
+
when '--limit'
|
163
|
+
limit = arg.to_i
|
169
164
|
else
|
170
165
|
usage
|
171
166
|
end
|
@@ -182,15 +177,15 @@ end
|
|
182
177
|
|
183
178
|
if debug
|
184
179
|
$stderr.puts "Using the following databases: #{pdnsdbs.join(", ")}"
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
180
|
+
$stderr.puts "Recursions: #{recursedepth}, Wait time: #{wait}, Limit: #{limit or 'none'}"
|
181
|
+
if format == "text" or format == "csv"
|
182
|
+
$stderr.puts "Output format: #{format} (sep=\"#{sep}\")"
|
183
|
+
else
|
184
|
+
$stderr.puts "Output format: #{format}"
|
185
|
+
end
|
186
|
+
if ENV['http_proxy']
|
187
|
+
$stderr.puts "Using proxy settings: http_proxy=#{ENV['http_proxy']}, https_proxy=#{ENV['https_proxy']}"
|
188
|
+
end
|
194
189
|
end
|
195
190
|
|
196
191
|
state = nil
|
@@ -1,12 +1,27 @@
|
|
1
1
|
require 'open-uri'
|
2
|
+
require_relative 'passivedb'
|
2
3
|
|
3
4
|
module PassiveDNS
|
4
|
-
class BFK
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
class BFK < PassiveDB
|
6
|
+
# override
|
7
|
+
def self.name
|
8
|
+
"BFK.de"
|
9
|
+
end
|
10
|
+
#override
|
11
|
+
def self.config_section_name
|
12
|
+
"bfk"
|
13
|
+
end
|
14
|
+
#override
|
15
|
+
def self.option_letter
|
16
|
+
"b"
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :debug
|
20
|
+
def initialize(options={})
|
21
|
+
@debug = options[:debug] || false
|
22
|
+
@base = options["URL"] || "http://www.bfk.de/bfk_dnslogger.html?query="
|
8
23
|
end
|
9
|
-
|
24
|
+
|
10
25
|
def parse(page,response_time)
|
11
26
|
line = page.unpack('C*').pack('U*').split(/<table/).grep(/ id=\"logger\"/)
|
12
27
|
return [] unless line.length > 0
|
@@ -29,23 +44,23 @@ module PassiveDNS
|
|
29
44
|
######### FIX BLANKS FOR MX
|
30
45
|
|
31
46
|
end
|
32
|
-
res << PDNSResult.new(
|
47
|
+
res << PDNSResult.new(self.class.name,response_time,r[0],r[2],r[1])
|
33
48
|
end
|
34
49
|
end
|
35
50
|
res
|
36
51
|
rescue Exception => e
|
37
|
-
$stderr.puts "
|
52
|
+
$stderr.puts "#{self.class.name} Exception: #{e}"
|
38
53
|
raise e
|
39
54
|
end
|
40
55
|
|
56
|
+
# override
|
41
57
|
def lookup(label, limit=nil)
|
42
|
-
$stderr.puts "DEBUG:
|
58
|
+
$stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
|
43
59
|
Timeout::timeout(240) {
|
44
60
|
t1 = Time.now
|
45
61
|
open(
|
46
|
-
|
47
|
-
"User-Agent" => "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}"
|
48
|
-
:http_basic_authentication => [@user,@pass]
|
62
|
+
@base+label,
|
63
|
+
"User-Agent" => "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}"
|
49
64
|
) do |f|
|
50
65
|
t2 = Time.now
|
51
66
|
recs = parse(f.read,t2-t1)
|
@@ -57,7 +72,7 @@ module PassiveDNS
|
|
57
72
|
end
|
58
73
|
}
|
59
74
|
rescue Timeout::Error => e
|
60
|
-
$stderr.puts "
|
75
|
+
$stderr.puts "#{self.class.name} lookup timed out: #{label}"
|
61
76
|
end
|
62
77
|
end
|
63
78
|
end
|
@@ -1,22 +1,40 @@
|
|
1
1
|
require 'socket'
|
2
|
+
require_relative 'passivedb'
|
2
3
|
|
3
4
|
module PassiveDNS
|
4
|
-
class CERTEE
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
8
24
|
end
|
25
|
+
|
26
|
+
# override
|
9
27
|
def lookup(label, limit=nil)
|
10
|
-
$stderr.puts "DEBUG:
|
28
|
+
$stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
|
11
29
|
recs = []
|
12
30
|
begin
|
13
31
|
t1 = Time.now
|
14
|
-
s = TCPSocket.new(
|
32
|
+
s = TCPSocket.new(@host,@port)
|
15
33
|
s.puts(label)
|
16
34
|
s.each_line do |l|
|
17
35
|
if l =~ /Traceback \(most recent call last\):/
|
18
36
|
# there is a bug in the CERTEE lookup tool
|
19
|
-
raise "
|
37
|
+
raise "#{self.class.name} is currently offline"
|
20
38
|
end
|
21
39
|
(lbl,ans,fs,ls) = l.chomp.split(/\t/)
|
22
40
|
rrtype = 'A'
|
@@ -28,7 +46,7 @@ module PassiveDNS
|
|
28
46
|
rrtype = 'CNAME'
|
29
47
|
end
|
30
48
|
t2 = Time.now
|
31
|
-
recs << PDNSResult.new(
|
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"))
|
32
50
|
end
|
33
51
|
rescue SocketError => e
|
34
52
|
$stderr.puts e
|
@@ -3,34 +3,32 @@ require 'net/https'
|
|
3
3
|
require 'openssl'
|
4
4
|
require 'json'
|
5
5
|
require 'digest/md5'
|
6
|
-
|
7
|
-
require 'pp'
|
8
|
-
|
9
|
-
# Please read http://www.tcpiputils.com/terms-of-service under automated requests
|
6
|
+
require_relative 'passivedb'
|
10
7
|
|
11
8
|
module PassiveDNS
|
12
|
-
class CN360
|
9
|
+
class CN360 < PassiveDB
|
10
|
+
# override
|
11
|
+
def self.name
|
12
|
+
"360.cn"
|
13
|
+
end
|
14
|
+
#override
|
15
|
+
def self.config_section_name
|
16
|
+
"cn360"
|
17
|
+
end
|
18
|
+
#override
|
19
|
+
def self.option_letter
|
20
|
+
"3"
|
21
|
+
end
|
22
|
+
|
13
23
|
attr_accessor :debug
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
raise "Cannot find a configuration file at #{configfile} or /etc/flint.conf"
|
24
|
+
def initialize(options={})
|
25
|
+
@debug = options[:debug] || false
|
26
|
+
["API", "API_ID", "API_KEY"].each do |opt|
|
27
|
+
if not options[opt]
|
28
|
+
raise "Field #{opt} is required. See README.md"
|
20
29
|
end
|
21
|
-
configfile = "/etc/flint.conf"
|
22
|
-
end
|
23
|
-
|
24
|
-
@cp = ConfigParser.new(configfile)
|
25
|
-
if not @cp["API"]
|
26
|
-
raise "Field, API, is required in the configuration file. It should specify the URL of the JSON Web API."
|
27
|
-
end
|
28
|
-
if not @cp["API_ID"]
|
29
|
-
raise "Field, API_ID, is required in the configuration file. It should specify the user ID for the API key."
|
30
|
-
end
|
31
|
-
if not @cp["API_KEY"]
|
32
|
-
raise "Field, API_KEY, is required in the configuration file. It should specify the API key."
|
33
30
|
end
|
31
|
+
@cp = options
|
34
32
|
end
|
35
33
|
|
36
34
|
def parse_json(page,query,response_time=0)
|
@@ -41,11 +39,11 @@ module PassiveDNS
|
|
41
39
|
time_first = (row["time_first"]) ? Time.at(row["time_first"].to_i) : nil
|
42
40
|
time_last = (row["time_last"]) ? Time.at(row["time_last"].to_i) : nil
|
43
41
|
count = row["count"] || 0
|
44
|
-
res << PDNSResult.new(
|
42
|
+
res << PDNSResult.new(self.class.name, response_time, row["rrname"], row["rdata"], row["rrtype"], time_first, time_last, count)
|
45
43
|
end
|
46
44
|
res
|
47
45
|
rescue Exception => e
|
48
|
-
$stderr.puts "
|
46
|
+
$stderr.puts "#{self.class.name} Exception: #{e}"
|
49
47
|
raise e
|
50
48
|
end
|
51
49
|
|
@@ -60,7 +58,7 @@ module PassiveDNS
|
|
60
58
|
url = URI.parse url
|
61
59
|
http = Net::HTTP.new(url.host, url.port)
|
62
60
|
http.use_ssl = (url.scheme == 'https')
|
63
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
61
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # I hate doing this
|
64
62
|
http.verify_depth = 5
|
65
63
|
request = Net::HTTP::Get.new(url.path)
|
66
64
|
request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
|
@@ -3,26 +3,28 @@
|
|
3
3
|
# to request an API key, please email dnsdb-api at farsightsecurity dot com.
|
4
4
|
require 'net/http'
|
5
5
|
require 'net/https'
|
6
|
+
require_relative 'passivedb'
|
6
7
|
|
7
8
|
module PassiveDNS
|
8
|
-
class DNSDB
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
9
|
+
class DNSDB < PassiveDB
|
10
|
+
# override
|
11
|
+
def self.name
|
12
|
+
"DNSDB"
|
13
|
+
end
|
14
|
+
#override
|
15
|
+
def self.config_section_name
|
16
|
+
"dnsdb"
|
17
|
+
end
|
18
|
+
#override
|
19
|
+
def self.option_letter
|
20
|
+
"d"
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :debug
|
24
|
+
def initialize(options={})
|
25
|
+
@debug = options[:debug] || false
|
26
|
+
@key = options["APIKEY"] || raise("APIKEY option required for #{self.class}")
|
27
|
+
@base = options["URL"] || "https://api.dnsdb.info/lookup"
|
26
28
|
end
|
27
29
|
|
28
30
|
def parse_json(page,response_time)
|
@@ -35,28 +37,28 @@ module PassiveDNS
|
|
35
37
|
record['rdata'] = [record['rdata']] if record['rdata'].class == String
|
36
38
|
record['rdata'].each do |rdata|
|
37
39
|
if record['time_first']
|
38
|
-
res << PDNSResult.new(
|
40
|
+
res << PDNSResult.new(self.class.name,response_time,record['rrname'],rdata,record['rrtype'],0,Time.at(record['time_first'].to_i).utc.strftime("%Y-%m-%dT%H:%M:%SZ"),Time.at(record['time_last'].to_i).utc.strftime("%Y-%m-%dT%H:%M:%SZ"),record['count'])
|
39
41
|
else
|
40
|
-
res << PDNSResult.new(
|
42
|
+
res << PDNSResult.new(self.class.name,response_time,record['rrname'],rdata,record['rrtype'])
|
41
43
|
end
|
42
44
|
end
|
43
45
|
end
|
44
46
|
res
|
45
47
|
rescue Exception => e
|
46
|
-
$stderr.puts "
|
48
|
+
$stderr.puts "#{self.class.name} Exception: #{e}"
|
47
49
|
$stderr.puts page
|
48
50
|
raise e
|
49
51
|
end
|
50
52
|
|
51
53
|
def lookup(label, limit=nil)
|
52
|
-
$stderr.puts "DEBUG:
|
54
|
+
$stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
|
53
55
|
Timeout::timeout(240) {
|
54
56
|
url = nil
|
55
57
|
if label =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$/
|
56
58
|
label = label.gsub(/\//,',')
|
57
|
-
url = "#{
|
59
|
+
url = "#{@base}/rdata/ip/#{label}"
|
58
60
|
else
|
59
|
-
url = "#{
|
61
|
+
url = "#{@base}/rrset/name/#{label}"
|
60
62
|
end
|
61
63
|
url = URI.parse url
|
62
64
|
http = Net::HTTP.new(url.host, url.port)
|
@@ -78,7 +80,7 @@ module PassiveDNS
|
|
78
80
|
parse_json(response.body,t2-t1)
|
79
81
|
}
|
80
82
|
rescue Timeout::Error => e
|
81
|
-
$stderr.puts "
|
83
|
+
$stderr.puts "#{self.class.name} lookup timed out: #{label}"
|
82
84
|
end
|
83
85
|
end
|
84
86
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# DESCRIPTION: Module to query Mnemonic's passive DNS repository
|
2
|
+
# CONTRIBUTOR: Drew Hunt (pinowudi@yahoo.com)
|
3
|
+
require 'net/http'
|
4
|
+
require 'net/https'
|
5
|
+
require 'openssl'
|
6
|
+
|
7
|
+
module PassiveDNS
|
8
|
+
class Mnemonic < PassiveDB
|
9
|
+
# override
|
10
|
+
def self.name
|
11
|
+
"Mnemonic"
|
12
|
+
end
|
13
|
+
#override
|
14
|
+
def self.config_section_name
|
15
|
+
"mnemonic"
|
16
|
+
end
|
17
|
+
#override
|
18
|
+
def self.option_letter
|
19
|
+
"m"
|
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://passivedns.mnemonic.no/api1/?apikey="
|
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['result']
|
34
|
+
data['result'].each do |row|
|
35
|
+
if row['query']
|
36
|
+
res << PDNSResult.new(self.class.name,response_time,row['query'],row['answer'],row['type'].upcase,row['ttl'],row['first'],row['last'])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
res
|
41
|
+
rescue Exception => e
|
42
|
+
$stderr.puts "#{self.class.name} Exception: #{e}"
|
43
|
+
raise e
|
44
|
+
end
|
45
|
+
|
46
|
+
def lookup(label, limit=nil)
|
47
|
+
$stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
|
48
|
+
Timeout::timeout(240) {
|
49
|
+
url = "#{@url}#{@apikey}&query=#{label}&method=exact"
|
50
|
+
$stderr.puts "DEBUG: #{self.class.name} url = #{url}" if @debug
|
51
|
+
url = URI.parse url
|
52
|
+
http = Net::HTTP.new(url.host, url.port)
|
53
|
+
http.use_ssl = (url.scheme == 'https')
|
54
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
55
|
+
http.verify_depth = 5
|
56
|
+
request = Net::HTTP::Get.new(url.path+"?"+url.query)
|
57
|
+
request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
|
58
|
+
t1 = Time.now
|
59
|
+
response = http.request(request)
|
60
|
+
t2 = Time.now
|
61
|
+
recs = parse_json(response.body, label, t2-t1)
|
62
|
+
if limit
|
63
|
+
recs[0,limit]
|
64
|
+
else
|
65
|
+
recs
|
66
|
+
end
|
67
|
+
}
|
68
|
+
rescue Timeout::Error => e
|
69
|
+
$stderr.puts "#{self.class.name} lookup timed out: #{label}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module PassiveDNS
|
2
|
+
class PassiveDB
|
3
|
+
def self.name
|
4
|
+
raise "You should implement your own version of .name"
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.config_section_name
|
8
|
+
name
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.option_letter
|
12
|
+
raise "You should pick a unique letter to serve as your database option letter for the command line option -d"
|
13
|
+
end
|
14
|
+
|
15
|
+
def lookup(label, limit=nil)
|
16
|
+
raise "You must implement the lookup function"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -6,18 +6,25 @@ require 'json'
|
|
6
6
|
# Please read http://www.tcpiputils.com/terms-of-service under automated requests
|
7
7
|
|
8
8
|
module PassiveDNS
|
9
|
-
class TCPIPUtils
|
9
|
+
class TCPIPUtils < PassiveDB
|
10
|
+
# override
|
11
|
+
def self.name
|
12
|
+
"TCPIPUtils"
|
13
|
+
end
|
14
|
+
#override
|
15
|
+
def self.config_section_name
|
16
|
+
"tcpiputils"
|
17
|
+
end
|
18
|
+
#override
|
19
|
+
def self.option_letter
|
20
|
+
"t"
|
21
|
+
end
|
22
|
+
|
10
23
|
attr_accessor :debug
|
11
|
-
def initialize(
|
12
|
-
@debug = false
|
13
|
-
|
14
|
-
|
15
|
-
$stderr.puts "DEBUG: TCPIPUtils#initialize(#{@apikey})" if @debug
|
16
|
-
else
|
17
|
-
raise "Error: Configuration file for TCPIPUtils is required for intialization
|
18
|
-
Format of configuration file (default: #{ENV['HOME']}/.tcpiputils) is the 64 hex character apikey on one line.
|
19
|
-
To obtain an API Key, go to http://www.tcpiputils.com/premium-access and purchase premium API access."
|
20
|
-
end
|
24
|
+
def initialize(options={})
|
25
|
+
@debug = options[:debug] || false
|
26
|
+
@apikey = options["APIKEY"] || raise("#{self.class.name} requires an APIKEY. See README.md")
|
27
|
+
@url = options["URL"] || "https://www.utlsapi.com/api.php?version=1.0&apikey="
|
21
28
|
end
|
22
29
|
|
23
30
|
def format_recs(reply_data, question, delta)
|
@@ -26,23 +33,23 @@ To obtain an API Key, go to http://www.tcpiputils.com/premium-access and purchas
|
|
26
33
|
case key
|
27
34
|
when "ipv4"
|
28
35
|
data.each do |rec|
|
29
|
-
recs << PDNSResult.new(
|
36
|
+
recs << PDNSResult.new(self.class.name, delta, question, rec["ip"], "A", nil, nil, rec["updatedate"], nil)
|
30
37
|
end
|
31
38
|
when "ipv6"
|
32
39
|
data.each do |rec|
|
33
|
-
recs << PDNSResult.new(
|
40
|
+
recs << PDNSResult.new(self.class.name, delta, question, rec["ip"], "AAAA", nil, nil, rec["updatedate"], nil)
|
34
41
|
end
|
35
42
|
when "dns"
|
36
43
|
data.each do |rec|
|
37
|
-
recs << PDNSResult.new(
|
44
|
+
recs << PDNSResult.new(self.class.name, delta, question, rec["dns"], "NS", nil, nil, rec["updatedate"], nil)
|
38
45
|
end
|
39
46
|
when "mx"
|
40
47
|
data.each do |rec|
|
41
|
-
recs << PDNSResult.new(
|
48
|
+
recs << PDNSResult.new(self.class.name, delta, question, rec["dns"], "MX", nil, nil, rec["updatedate"], nil)
|
42
49
|
end
|
43
50
|
when "domains"
|
44
51
|
data.each do |rec|
|
45
|
-
recs << PDNSResult.new(
|
52
|
+
recs << PDNSResult.new(self.class.name, delta, rec, question, "A", nil, nil, nil, nil)
|
46
53
|
end
|
47
54
|
end
|
48
55
|
end
|
@@ -50,9 +57,9 @@ To obtain an API Key, go to http://www.tcpiputils.com/premium-access and purchas
|
|
50
57
|
end
|
51
58
|
|
52
59
|
def lookup(label, limit=nil)
|
53
|
-
$stderr.puts "DEBUG:
|
60
|
+
$stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
|
54
61
|
type = (label.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)) ? "domainneighbors" : "domainipdnshistory"
|
55
|
-
url = "
|
62
|
+
url = "#{@url}#{@apikey}&type=#{type}&q=#{label}"
|
56
63
|
recs = []
|
57
64
|
Timeout::timeout(240) {
|
58
65
|
url = URI.parse url
|
@@ -70,7 +77,7 @@ To obtain an API Key, go to http://www.tcpiputils.com/premium-access and purchas
|
|
70
77
|
question = reply["data"]["question"]
|
71
78
|
recs = format_recs(reply["data"], question, delta)
|
72
79
|
elsif reply["status"] and reply["status"] == "error"
|
73
|
-
raise "
|
80
|
+
raise "#{self.class.name}: error from web API: #{reply["data"]}"
|
74
81
|
end
|
75
82
|
if limit
|
76
83
|
recs[0,limit]
|
@@ -79,7 +86,7 @@ To obtain an API Key, go to http://www.tcpiputils.com/premium-access and purchas
|
|
79
86
|
end
|
80
87
|
}
|
81
88
|
rescue Timeout::Error => e
|
82
|
-
$stderr.puts "
|
89
|
+
$stderr.puts "#{self.class.name} lookup timed out: #{label}"
|
83
90
|
end
|
84
91
|
end
|
85
92
|
end
|
@@ -4,16 +4,26 @@ require 'net/https'
|
|
4
4
|
require 'openssl'
|
5
5
|
|
6
6
|
module PassiveDNS
|
7
|
-
class VirusTotal
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
7
|
+
class VirusTotal < PassiveDB
|
8
|
+
# override
|
9
|
+
def self.name
|
10
|
+
"VirusTotal"
|
11
|
+
end
|
12
|
+
#override
|
13
|
+
def self.config_section_name
|
14
|
+
"virustotal"
|
15
|
+
end
|
16
|
+
#override
|
17
|
+
def self.option_letter
|
18
|
+
"v"
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_accessor :debug
|
22
|
+
def initialize(options={})
|
23
|
+
@debug = options[:debug] || false
|
24
|
+
@apikey = options["APIKEY"] || raise("#{self.class.name} requires an APIKEY. See README.md")
|
25
|
+
@url = options["URL"] || "https://www.virustotal.com/vtapi/v2/"
|
26
|
+
end
|
17
27
|
|
18
28
|
def parse_json(page,query,response_time=0)
|
19
29
|
res = []
|
@@ -22,9 +32,9 @@ module PassiveDNS
|
|
22
32
|
if data['resolutions']
|
23
33
|
data['resolutions'].each do |row|
|
24
34
|
if row['ip_address']
|
25
|
-
res << PDNSResult.new(
|
35
|
+
res << PDNSResult.new(self.class.name,response_time,query,row['ip_address'],'A',nil,nil,row['last_resolved'])
|
26
36
|
elsif row['hostname']
|
27
|
-
res << PDNSResult.new(
|
37
|
+
res << PDNSResult.new(self.class.name,response_time,row['hostname'],query,'A',nil,nil,row['last_resolved'])
|
28
38
|
end
|
29
39
|
end
|
30
40
|
end
|
@@ -35,15 +45,15 @@ module PassiveDNS
|
|
35
45
|
end
|
36
46
|
|
37
47
|
def lookup(label, limit=nil)
|
38
|
-
$stderr.puts "DEBUG:
|
48
|
+
$stderr.puts "DEBUG: #{self.class.name}.lookup(#{label})" if @debug
|
39
49
|
Timeout::timeout(240) {
|
40
50
|
url = nil
|
41
51
|
if label =~ /^[\d\.]+$/
|
42
|
-
url = "
|
52
|
+
url = "#{@url}ip-address/report?ip=#{label}&apikey=#{@apikey}"
|
43
53
|
else
|
44
|
-
url = "
|
54
|
+
url = "#{@url}domain/report?domain=#{label}&apikey=#{@apikey}"
|
45
55
|
end
|
46
|
-
$stderr.puts "DEBUG:
|
56
|
+
$stderr.puts "DEBUG: #{self.class.name} url = #{url}" if @debug
|
47
57
|
url = URI.parse url
|
48
58
|
http = Net::HTTP.new(url.host, url.port)
|
49
59
|
http.use_ssl = (url.scheme == 'https')
|
@@ -62,7 +72,7 @@ module PassiveDNS
|
|
62
72
|
end
|
63
73
|
}
|
64
74
|
rescue Timeout::Error => e
|
65
|
-
$stderr.puts "
|
75
|
+
$stderr.puts "#{self.class.name} lookup timed out: #{label}"
|
66
76
|
end
|
67
77
|
end
|
68
78
|
end
|
data/lib/passivedns/client.rb
CHANGED
@@ -3,6 +3,7 @@ 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/passivedb.rb'
|
6
7
|
require 'passivedns/client/bfk.rb'
|
7
8
|
require 'passivedns/client/certee.rb'
|
8
9
|
require 'passivedns/client/dnsdb.rb'
|
@@ -10,34 +11,34 @@ require 'passivedns/client/virustotal.rb'
|
|
10
11
|
require 'passivedns/client/tcpiputils.rb'
|
11
12
|
require 'passivedns/client/cn360.rb'
|
12
13
|
require 'passivedns/client/state.rb'
|
14
|
+
require 'passivedns/client/mnemonic.rb'
|
15
|
+
require 'configparser'
|
16
|
+
require 'pp'
|
13
17
|
|
14
18
|
module PassiveDNS
|
15
19
|
|
16
20
|
class PDNSResult < Struct.new(:source, :response_time, :query, :answer, :rrtype, :ttl, :firstseen, :lastseen, :count); end
|
17
21
|
|
18
22
|
class Client
|
19
|
-
def initialize(pdns=['bfk','certee','dnsdb','virustotal','tcpiputils','cn360'])
|
23
|
+
def initialize(pdns=['bfk','certee','dnsdb','virustotal','tcpiputils','cn360','mnemonic'], configfile="#{ENV['HOME']}/.passivedns-client")
|
24
|
+
cp = ConfigParser.new(configfile)
|
25
|
+
# this creates a map of all the PassiveDNS provider names and their classes
|
26
|
+
class_map = {}
|
27
|
+
PassiveDNS.constants.each do |const|
|
28
|
+
if PassiveDNS.const_get(const).is_a?(Class) and PassiveDNS.const_get(const).superclass == PassiveDNS::PassiveDB
|
29
|
+
class_map[PassiveDNS.const_get(const).config_section_name] = PassiveDNS.const_get(const)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
20
33
|
@pdnsdbs = []
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
when 'isc'
|
30
|
-
@pdnsdbs << PassiveDNS::DNSDB.new
|
31
|
-
when 'virustotal'
|
32
|
-
@pdnsdbs << PassiveDNS::VirusTotal.new
|
33
|
-
when 'tcpiputils'
|
34
|
-
@pdnsdbs << PassiveDNS::TCPIPUtils.new
|
35
|
-
when 'cn360'
|
36
|
-
@pdnsdbs << PassiveDNS::CN360.new
|
37
|
-
else
|
38
|
-
raise "Unknown Passive DNS provider: #{pd}"
|
39
|
-
end
|
40
|
-
end
|
34
|
+
pdns.uniq.each do |pd|
|
35
|
+
if class_map[pd]
|
36
|
+
@pdnsdbs << class_map[pd].new(cp[pd] || {})
|
37
|
+
else
|
38
|
+
raise "Unknown Passive DNS provider: #{pd}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
41
42
|
end #initialize
|
42
43
|
|
43
44
|
def debug=(d)
|
@@ -7,8 +7,21 @@ unless Kernel.respond_to?(:require_relative)
|
|
7
7
|
end
|
8
8
|
|
9
9
|
require_relative 'helper'
|
10
|
+
require 'configparser'
|
10
11
|
|
11
12
|
class TestPassiveDnsQuery < Test::Unit::TestCase
|
13
|
+
|
14
|
+
def setup
|
15
|
+
configfile="#{ENV['HOME']}/.passivedns-client"
|
16
|
+
@cp = ConfigParser.new(configfile)
|
17
|
+
@class_map = {}
|
18
|
+
PassiveDNS.constants.each do |const|
|
19
|
+
if PassiveDNS.const_get(const).is_a?(Class) and PassiveDNS.const_get(const).superclass == PassiveDNS::PassiveDB
|
20
|
+
@class_map[PassiveDNS.const_get(const).config_section_name] = PassiveDNS.const_get(const)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
12
25
|
def test_instantiate_Nonexisting_Client
|
13
26
|
assert_raise RuntimeError do
|
14
27
|
PassiveDNS::Client.new(['doesnotexist'])
|
@@ -36,18 +49,19 @@ class TestPassiveDnsQuery < Test::Unit::TestCase
|
|
36
49
|
end
|
37
50
|
|
38
51
|
def test_BFK
|
39
|
-
assert_not_nil(PassiveDNS::BFK.new)
|
40
52
|
assert_nothing_raised do
|
41
53
|
PassiveDNS::Client.new(['bfk'])
|
42
54
|
end
|
43
|
-
|
55
|
+
d = PassiveDNS::BFK.new(@cp['bfk'] || {})
|
56
|
+
assert_not_nil(d)
|
57
|
+
rows = d.lookup("example.org",3)
|
44
58
|
assert_not_nil(rows)
|
45
59
|
assert_not_nil(rows.to_s)
|
46
60
|
assert_not_nil(rows.to_xml)
|
47
61
|
assert_not_nil(rows.to_json)
|
48
62
|
assert_not_nil(rows.to_yaml)
|
49
63
|
assert_equal(3, rows.length)
|
50
|
-
rows =
|
64
|
+
rows = d.lookup("8.8.8.8")
|
51
65
|
assert_not_nil(rows)
|
52
66
|
assert_not_nil(rows.to_s)
|
53
67
|
assert_not_nil(rows.to_xml)
|
@@ -57,18 +71,19 @@ class TestPassiveDnsQuery < Test::Unit::TestCase
|
|
57
71
|
|
58
72
|
def test_CERTEE
|
59
73
|
assert(false, "CERTEE is still offline")
|
60
|
-
assert_not_nil(PassiveDNS::CERTEE.new)
|
61
74
|
assert_nothing_raised do
|
62
75
|
PassiveDNS::Client.new(['certee'])
|
63
76
|
end
|
64
|
-
|
77
|
+
d = PassiveDNS::CERTEE.new(@cp['certee'] || {})
|
78
|
+
assert_not_nil(d)
|
79
|
+
rows = d.lookup("sim.cert.ee",3)
|
65
80
|
assert_not_nil(rows)
|
66
81
|
assert_not_nil(rows.to_s)
|
67
82
|
assert_not_nil(rows.to_xml)
|
68
83
|
assert_not_nil(rows.to_json)
|
69
84
|
assert_not_nil(rows.to_yaml)
|
70
85
|
assert_equal(3, rows.length)
|
71
|
-
rows =
|
86
|
+
rows = d.lookup("8.8.8.8")
|
72
87
|
assert_not_nil(rows)
|
73
88
|
assert_not_nil(rows.to_s)
|
74
89
|
assert_not_nil(rows.to_xml)
|
@@ -77,18 +92,19 @@ class TestPassiveDnsQuery < Test::Unit::TestCase
|
|
77
92
|
end
|
78
93
|
|
79
94
|
def test_DNSDB
|
80
|
-
assert_not_nil(PassiveDNS::DNSDB.new)
|
81
95
|
assert_nothing_raised do
|
82
96
|
PassiveDNS::Client.new(['dnsdb'])
|
83
97
|
end
|
84
|
-
|
98
|
+
d = PassiveDNS::DNSDB.new(@cp['dnsdb'] || {})
|
99
|
+
assert_not_nil(d)
|
100
|
+
rows = d.lookup("example.org",3)
|
85
101
|
assert_not_nil(rows)
|
86
102
|
assert_not_nil(rows.to_s)
|
87
103
|
assert_not_nil(rows.to_xml)
|
88
104
|
assert_not_nil(rows.to_json)
|
89
105
|
assert_not_nil(rows.to_yaml)
|
90
106
|
assert_equal(3, rows.length) # this will fail since DNSDB has an off by one error
|
91
|
-
rows =
|
107
|
+
rows = d.lookup("8.8.8.8")
|
92
108
|
assert_not_nil(rows)
|
93
109
|
assert_not_nil(rows.to_s)
|
94
110
|
assert_not_nil(rows.to_xml)
|
@@ -97,18 +113,19 @@ class TestPassiveDnsQuery < Test::Unit::TestCase
|
|
97
113
|
end
|
98
114
|
|
99
115
|
def test_VirusTotal
|
100
|
-
assert_not_nil(PassiveDNS::VirusTotal.new)
|
101
116
|
assert_nothing_raised do
|
102
117
|
PassiveDNS::Client.new(['virustotal'])
|
103
118
|
end
|
104
|
-
|
119
|
+
d = PassiveDNS::VirusTotal.new(@cp['virustotal'] || {})
|
120
|
+
assert_not_nil(d)
|
121
|
+
rows = d.lookup("google.com",3)
|
105
122
|
assert_not_nil(rows)
|
106
123
|
assert_not_nil(rows.to_s)
|
107
124
|
assert_not_nil(rows.to_xml)
|
108
125
|
assert_not_nil(rows.to_json)
|
109
126
|
assert_not_nil(rows.to_yaml)
|
110
127
|
assert_equal(3, rows.length)
|
111
|
-
rows =
|
128
|
+
rows = d.lookup("8.8.8.8")
|
112
129
|
assert_not_nil(rows)
|
113
130
|
assert_not_nil(rows.to_s)
|
114
131
|
assert_not_nil(rows.to_xml)
|
@@ -117,24 +134,25 @@ class TestPassiveDnsQuery < Test::Unit::TestCase
|
|
117
134
|
end
|
118
135
|
|
119
136
|
def test_TCPIPUtils
|
120
|
-
assert_not_nil(PassiveDNS::TCPIPUtils.new)
|
121
137
|
assert_nothing_raised do
|
122
138
|
PassiveDNS::Client.new(['tcpiputils'])
|
123
139
|
end
|
124
|
-
|
140
|
+
d = PassiveDNS::TCPIPUtils.new(@cp['tcpiputils'] || {})
|
141
|
+
assert_not_nil(d)
|
142
|
+
rows = d.lookup("example.org")
|
125
143
|
assert_not_nil(rows)
|
126
144
|
assert_not_nil(rows.to_s)
|
127
145
|
assert_not_nil(rows.to_xml)
|
128
146
|
assert_not_nil(rows.to_json)
|
129
147
|
assert_not_nil(rows.to_yaml)
|
130
|
-
rows =
|
148
|
+
rows = d.lookup("example.org",3)
|
131
149
|
assert_not_nil(rows)
|
132
150
|
assert_not_nil(rows.to_s)
|
133
151
|
assert_not_nil(rows.to_xml)
|
134
152
|
assert_not_nil(rows.to_json)
|
135
153
|
assert_not_nil(rows.to_yaml)
|
136
154
|
assert_equal(3, rows.length)
|
137
|
-
rows =
|
155
|
+
rows = d.lookup("8.8.8.8")
|
138
156
|
assert_not_nil(rows)
|
139
157
|
assert_not_nil(rows.to_s)
|
140
158
|
assert_not_nil(rows.to_xml)
|
@@ -143,28 +161,56 @@ class TestPassiveDnsQuery < Test::Unit::TestCase
|
|
143
161
|
end
|
144
162
|
|
145
163
|
def test_cn360
|
146
|
-
assert_not_nil(PassiveDNS::CN360.new)
|
147
164
|
assert_nothing_raised do
|
148
165
|
PassiveDNS::Client.new(['cn360'])
|
149
166
|
end
|
150
|
-
|
167
|
+
d = PassiveDNS::CN360.new(@cp['cn360'] || {})
|
168
|
+
assert_not_nil(d)
|
169
|
+
rows = d.lookup("example.org")
|
151
170
|
assert_not_nil(rows)
|
152
171
|
assert_not_nil(rows.to_s)
|
153
172
|
assert_not_nil(rows.to_xml)
|
154
173
|
assert_not_nil(rows.to_json)
|
155
174
|
assert_not_nil(rows.to_yaml)
|
156
|
-
rows =
|
175
|
+
rows = d.lookup("example.org",3)
|
157
176
|
assert_not_nil(rows)
|
158
177
|
assert_not_nil(rows.to_s)
|
159
178
|
assert_not_nil(rows.to_xml)
|
160
179
|
assert_not_nil(rows.to_json)
|
161
180
|
assert_not_nil(rows.to_yaml)
|
162
181
|
assert_equal(3, rows.length)
|
163
|
-
rows =
|
182
|
+
rows = d.lookup("8.8.8.8")
|
164
183
|
assert_not_nil(rows)
|
165
184
|
assert_not_nil(rows.to_s)
|
166
185
|
assert_not_nil(rows.to_xml)
|
167
186
|
assert_not_nil(rows.to_json)
|
168
187
|
assert_not_nil(rows.to_yaml)
|
169
|
-
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_nmemonic
|
191
|
+
assert_nothing_raised do
|
192
|
+
PassiveDNS::Client.new(['mnemonic'])
|
193
|
+
end
|
194
|
+
d = PassiveDNS::Mnemonic.new(@cp['mnemonic'] || {})
|
195
|
+
assert_not_nil(d)
|
196
|
+
rows = d.lookup("example.org")
|
197
|
+
assert_not_nil(rows)
|
198
|
+
assert_not_nil(rows.to_s)
|
199
|
+
assert_not_nil(rows.to_xml)
|
200
|
+
assert_not_nil(rows.to_json)
|
201
|
+
assert_not_nil(rows.to_yaml)
|
202
|
+
rows = d.lookup("example.org",3)
|
203
|
+
assert_not_nil(rows)
|
204
|
+
assert_not_nil(rows.to_s)
|
205
|
+
assert_not_nil(rows.to_xml)
|
206
|
+
assert_not_nil(rows.to_json)
|
207
|
+
assert_not_nil(rows.to_yaml)
|
208
|
+
assert_equal(3, rows.length)
|
209
|
+
rows = d.lookup("8.8.8.8")
|
210
|
+
assert_not_nil(rows)
|
211
|
+
assert_not_nil(rows.to_s)
|
212
|
+
assert_not_nil(rows.to_xml)
|
213
|
+
assert_not_nil(rows.to_json)
|
214
|
+
assert_not_nil(rows.to_yaml)
|
215
|
+
end
|
170
216
|
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:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- chrislee35
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -115,6 +115,8 @@ files:
|
|
115
115
|
- lib/passivedns/client/certee.rb
|
116
116
|
- lib/passivedns/client/cn360.rb
|
117
117
|
- lib/passivedns/client/dnsdb.rb
|
118
|
+
- lib/passivedns/client/mnemonic.rb
|
119
|
+
- lib/passivedns/client/passivedb.rb
|
118
120
|
- lib/passivedns/client/state.rb
|
119
121
|
- lib/passivedns/client/tcpiputils.rb
|
120
122
|
- lib/passivedns/client/version.rb
|