passivedns-client 1.1.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/pdnstool +195 -182
- data/lib/passivedns/client/bfk.rb +7 -2
- data/lib/passivedns/client/certee.rb +11 -3
- data/lib/passivedns/client/dnsdb.rb +7 -3
- data/lib/passivedns/client/tcpiputils.rb +80 -0
- data/lib/passivedns/client/version.rb +1 -1
- data/lib/passivedns/client/virustotal.rb +7 -2
- data/lib/passivedns/client.rb +8 -6
- data/passivedns-client.gemspec +2 -2
- data/test/test_passivedns-client.rb +49 -53
- metadata +18 -40
- checksums.yaml.gz.sig +0 -0
- data/lib/passivedns/client/dnsparse.rb +0 -89
- data.tar.gz.sig +0 -1
- metadata.gz.sig +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41a0a59329a330d5830052e03a99a39f9ce5a819
|
4
|
+
data.tar.gz: 361993fddb9ef65fef2f4721dba03257b818dddd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: edbb6d872501226acc1aa067a432b63908f9063657f708d1ccf234cd207c681b85eb071c405a7fa772ac51acda85cb6cc71db2d18109282856dd91e19c87061a
|
7
|
+
data.tar.gz: 56c04abc0c89251b2303721a2ded1dee6da155bd4a66c43bb12de5ab52e3884fe32b21ec463c083d0e7900ed862068f31c343d58c3bd51d9142e855c908178fb
|
data/bin/pdnstool
CHANGED
@@ -4,198 +4,211 @@ require 'structformatter'
|
|
4
4
|
require 'getoptlong'
|
5
5
|
require 'yaml'
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
state.add_result(r)
|
20
|
-
end
|
7
|
+
def pdnslookup(state,pdnsclient,recursedepth=1,wait=0,debug=false,limit=nil)
|
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)
|
21
19
|
end
|
22
|
-
else
|
23
|
-
state.update_query(rv,'failed')
|
24
20
|
end
|
25
|
-
|
21
|
+
else
|
22
|
+
state.update_query(rv,'failed')
|
26
23
|
end
|
27
|
-
level
|
28
|
-
end
|
29
|
-
state
|
30
|
-
end
|
31
|
-
|
32
|
-
def printresults(state,format,sep="\t")
|
33
|
-
case format
|
34
|
-
when 'text'
|
35
|
-
puts PassiveDNS::PDNSResult.members.join(sep)
|
36
|
-
puts state.to_s(sep)
|
37
|
-
when 'yaml'
|
38
|
-
puts state.to_yaml
|
39
|
-
when 'xml'
|
40
|
-
puts state.to_xml
|
41
|
-
when 'json'
|
42
|
-
puts state.to_json
|
43
|
-
when 'gdf'
|
44
|
-
puts state.to_gdf
|
45
|
-
when 'graphviz'
|
46
|
-
puts state.to_graphviz
|
47
|
-
when 'graphml'
|
48
|
-
puts state.to_graphml
|
24
|
+
sleep wait if level < recursedepth
|
49
25
|
end
|
26
|
+
level += 1
|
50
27
|
end
|
28
|
+
state
|
29
|
+
end
|
51
30
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
puts
|
56
|
-
puts
|
57
|
-
|
58
|
-
puts
|
59
|
-
|
60
|
-
puts
|
61
|
-
|
62
|
-
puts
|
63
|
-
|
64
|
-
puts
|
65
|
-
|
66
|
-
puts
|
67
|
-
|
68
|
-
puts
|
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 " -l outputs debugging information"
|
75
|
-
exit
|
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
|
76
48
|
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def usage
|
52
|
+
puts "Usage: #{$0} [-d [bedvt]] [-og|-ov|-om|-oc|-ox|-oy|-oj|-ot] [-os <sep>] [-f <file>] [-r#|-w#|-v] [-l <count>] <ip|domain|cidr>"
|
53
|
+
puts " -dbedvt uses all of the available passive dns databases"
|
54
|
+
puts " -db only use BFK"
|
55
|
+
puts " -de only use CERT-EE (default)"
|
56
|
+
puts " -dd only use DNSDB (formerly ISC)"
|
57
|
+
puts " -dv only use VirusTotal"
|
58
|
+
puts " -dt only use TCPIPUtils"
|
59
|
+
puts " -dvt uses VirusTotal and TCPIPUtils (for example)"
|
60
|
+
puts ""
|
61
|
+
puts " -og outputs a link-nodal GDF visualization definition"
|
62
|
+
puts " -ov outputs a link-nodal graphviz visualization definition"
|
63
|
+
puts " -om output a link-nodal graphml visualization definition"
|
64
|
+
puts " -oc outputs CSV"
|
65
|
+
puts " -ox outputs XML"
|
66
|
+
puts " -oy outputs YAML"
|
67
|
+
puts " -oj outputs JSON"
|
68
|
+
puts " -ot outputs ASCII text (default)"
|
69
|
+
puts " -os <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 ],
|
77
83
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
[ '--gdf', '-g', GetoptLong::NO_ARGUMENT ],
|
89
|
-
[ '--graphviz', '-v', GetoptLong::NO_ARGUMENT ],
|
90
|
-
[ '--graphml', '-m', GetoptLong::NO_ARGUMENT ],
|
91
|
-
[ '--csv', '-c', GetoptLong::NO_ARGUMENT ],
|
92
|
-
[ '--xml', '-x', GetoptLong::NO_ARGUMENT ],
|
93
|
-
[ '--yaml', '-y', GetoptLong::NO_ARGUMENT ],
|
94
|
-
[ '--json', '-j', GetoptLong::NO_ARGUMENT ],
|
95
|
-
[ '--text', '-t', GetoptLong::NO_ARGUMENT ],
|
96
|
-
[ '--sep', '-s', GetoptLong::REQUIRED_ARGUMENT ],
|
97
|
-
|
98
|
-
[ '--sqlite3', '-f', GetoptLong::REQUIRED_ARGUMENT ],
|
99
|
-
[ '--recurse', '-r', GetoptLong::REQUIRED_ARGUMENT ],
|
100
|
-
[ '--wait', '-w', GetoptLong::REQUIRED_ARGUMENT ]
|
101
|
-
)
|
102
|
-
|
103
|
-
# sets the default search methods
|
104
|
-
pdnsdbs = []
|
105
|
-
format = "text"
|
106
|
-
sep = "\t"
|
107
|
-
recursedepth = 1
|
108
|
-
wait = 0
|
109
|
-
res = nil
|
110
|
-
debug = false
|
111
|
-
sqlitedb = nil
|
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 ],
|
112
93
|
|
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
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
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
|
+
# sets the default search methods
|
101
|
+
pdnsdbs = []
|
102
|
+
format = "text"
|
103
|
+
sep = "\t"
|
104
|
+
recursedepth = 1
|
105
|
+
wait = 0
|
106
|
+
res = nil
|
107
|
+
debug = false
|
108
|
+
sqlitedb = nil
|
109
|
+
limit = nil
|
110
|
+
|
111
|
+
opts.each do |opt, arg|
|
112
|
+
case opt
|
113
|
+
when '--help'
|
114
|
+
usage
|
115
|
+
when '--debug'
|
116
|
+
debug = true
|
117
|
+
when '--database'
|
118
|
+
arg.split(//).each do |c|
|
119
|
+
case c
|
120
|
+
when ','
|
121
|
+
when 'b'
|
122
|
+
pdnsdbs << "bfk"
|
123
|
+
when 'e'
|
124
|
+
pdnsdbs << "certee"
|
125
|
+
when 'd'
|
126
|
+
pdnsdbs << "dnsdb"
|
127
|
+
when 'v'
|
128
|
+
pdnsdbs << "virustotal"
|
129
|
+
when 't'
|
130
|
+
pdnsdbs << "tcpiputils"
|
131
|
+
else
|
132
|
+
raise "Unknown passive DNS database identifier: #{c}"
|
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
|
167
159
|
end
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
if pdnsdbs.index("bfk") and recursedepth > 1 and wait < 60
|
175
|
-
wait = 60
|
176
|
-
$stderr.puts "Enforcing a minimal 60 second wait when using BFK for recursive crawling"
|
177
|
-
end
|
178
|
-
|
179
|
-
state = nil
|
180
|
-
if sqlitedb
|
181
|
-
state = PassiveDNS::PDNSToolStateDB.new(sqlitedb)
|
160
|
+
when '--wait'
|
161
|
+
wait = arg.to_i
|
162
|
+
when '--sqlite3'
|
163
|
+
sqlitedb = arg
|
164
|
+
when '--limit'
|
165
|
+
limit = arg.to_i
|
182
166
|
else
|
183
|
-
|
167
|
+
usage
|
184
168
|
end
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
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)
|
198
211
|
end
|
199
|
-
|
200
|
-
|
201
|
-
|
212
|
+
end
|
213
|
+
pdnslookup(state,pdnsclient,recursedepth,wait,debug,limit)
|
214
|
+
printresults(state,format,sep)
|
@@ -38,7 +38,7 @@ module PassiveDNS
|
|
38
38
|
raise e
|
39
39
|
end
|
40
40
|
|
41
|
-
def lookup(label)
|
41
|
+
def lookup(label, limit=nil)
|
42
42
|
$stderr.puts "DEBUG: BFKClient.lookup(#{label})" if @debug
|
43
43
|
Timeout::timeout(240) {
|
44
44
|
t1 = Time.now
|
@@ -48,7 +48,12 @@ module PassiveDNS
|
|
48
48
|
:http_basic_authentication => [@user,@pass]
|
49
49
|
) do |f|
|
50
50
|
t2 = Time.now
|
51
|
-
parse(f.read,t2-t1)
|
51
|
+
recs = parse(f.read,t2-t1)
|
52
|
+
if limit
|
53
|
+
recs[0,limit]
|
54
|
+
else
|
55
|
+
recs
|
56
|
+
end
|
52
57
|
end
|
53
58
|
}
|
54
59
|
rescue Timeout::Error => e
|
@@ -6,7 +6,7 @@ module PassiveDNS
|
|
6
6
|
attr_accessor :debug
|
7
7
|
def initialize
|
8
8
|
end
|
9
|
-
def lookup(label)
|
9
|
+
def lookup(label, limit=nil)
|
10
10
|
$stderr.puts "DEBUG: CERTEE.lookup(#{label})" if @debug
|
11
11
|
recs = []
|
12
12
|
begin
|
@@ -14,6 +14,10 @@ module PassiveDNS
|
|
14
14
|
s = TCPSocket.new(@@host,43)
|
15
15
|
s.puts(label)
|
16
16
|
s.each_line do |l|
|
17
|
+
if l =~ /Traceback \(most recent call last\):/
|
18
|
+
# there is a bug in the CERTEE lookup tool
|
19
|
+
raise "CERTEE is currently offline"
|
20
|
+
end
|
17
21
|
(lbl,ans,fs,ls) = l.chomp.split(/\t/)
|
18
22
|
rrtype = 'A'
|
19
23
|
if ans =~ /^\d+\.\d+\.\d+\.\d+$/
|
@@ -30,7 +34,11 @@ module PassiveDNS
|
|
30
34
|
$stderr.puts e
|
31
35
|
end
|
32
36
|
return nil unless recs.length > 0
|
33
|
-
|
34
|
-
|
37
|
+
if limit
|
38
|
+
recs = recs[0,limit]
|
39
|
+
else
|
40
|
+
recs
|
41
|
+
end
|
42
|
+
end
|
35
43
|
end
|
36
44
|
end
|
@@ -48,7 +48,7 @@ module PassiveDNS
|
|
48
48
|
raise e
|
49
49
|
end
|
50
50
|
|
51
|
-
def lookup(label)
|
51
|
+
def lookup(label, limit=nil)
|
52
52
|
$stderr.puts "DEBUG: DNSDB.lookup(#{label})" if @debug
|
53
53
|
Timeout::timeout(240) {
|
54
54
|
url = nil
|
@@ -63,14 +63,18 @@ module PassiveDNS
|
|
63
63
|
http.use_ssl = (url.scheme == 'https')
|
64
64
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
65
65
|
http.verify_depth = 5
|
66
|
-
|
66
|
+
path = url.path
|
67
|
+
if limit
|
68
|
+
path << "?limit=#{limit}"
|
69
|
+
end
|
70
|
+
request = Net::HTTP::Get.new(path)
|
67
71
|
request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
|
68
72
|
request.add_field("X-API-Key", @key)
|
69
73
|
request.add_field("Accept", "application/json")
|
70
74
|
t1 = Time.now
|
71
75
|
response = http.request(request)
|
72
76
|
t2 = Time.now
|
73
|
-
$stderr.puts response if @debug
|
77
|
+
$stderr.puts response.body if @debug
|
74
78
|
parse_json(response.body,t2-t1)
|
75
79
|
}
|
76
80
|
rescue Timeout::Error => e
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'openssl'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
# Please read http://www.tcpiputils.com/terms-of-service under automated requests
|
7
|
+
|
8
|
+
module PassiveDNS
|
9
|
+
class TCPIPUtils
|
10
|
+
attr_accessor :debug
|
11
|
+
def initialize(config="#{ENV['HOME']}/.tcpiputils")
|
12
|
+
@debug = false
|
13
|
+
if File.exist?(config)
|
14
|
+
@apikey = File.open(config).read.split(/\n/)[0]
|
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
|
21
|
+
end
|
22
|
+
|
23
|
+
def format_recs(reply_data, question, delta)
|
24
|
+
recs = []
|
25
|
+
reply_data.each do |key, data|
|
26
|
+
case key
|
27
|
+
when "ipv4"
|
28
|
+
data.each do |rec|
|
29
|
+
recs << PDNSResult.new("tcpiputils", delta, question, rec["ip"], "A", nil, nil, rec["updatedate"], nil)
|
30
|
+
end
|
31
|
+
when "ipv6"
|
32
|
+
data.each do |rec|
|
33
|
+
recs << PDNSResult.new("tcpiputils", delta, question, rec["ip"], "AAAA", nil, nil, rec["updatedate"], nil)
|
34
|
+
end
|
35
|
+
when "dns"
|
36
|
+
data.each do |rec|
|
37
|
+
recs << PDNSResult.new("tcpiputils", delta, question, rec["dns"], "NS", nil, nil, rec["updatedate"], nil)
|
38
|
+
end
|
39
|
+
when "mx"
|
40
|
+
data.each do |rec|
|
41
|
+
recs << PDNSResult.new("tcpiputils", delta, question, rec["dns"], "MX", nil, nil, rec["updatedate"], nil)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
recs
|
46
|
+
end
|
47
|
+
|
48
|
+
def lookup(label, limit=nil)
|
49
|
+
$stderr.puts "DEBUG: TCPIPUtils.lookup(#{label})" if @debug
|
50
|
+
url = "https://www.utlsapi.com/api.php?version=1.0&apikey=#{@apikey}&type=domainipdnshistory&q=#{label}"
|
51
|
+
recs = []
|
52
|
+
Timeout::timeout(240) {
|
53
|
+
url = URI.parse url
|
54
|
+
http = Net::HTTP.new(url.host, url.port)
|
55
|
+
http.use_ssl = (url.scheme == 'https')
|
56
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
57
|
+
http.verify_depth = 5
|
58
|
+
request = Net::HTTP::Get.new(url.path+"?"+url.query)
|
59
|
+
request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
|
60
|
+
t1 = Time.now
|
61
|
+
response = http.request(request)
|
62
|
+
delta = (Time.now - t1).to_f
|
63
|
+
reply = JSON.parse(response.body)
|
64
|
+
if reply["status"] and reply["status"] == "succeed"
|
65
|
+
question = reply["data"]["question"]
|
66
|
+
recs = format_recs(reply["data"], question, delta)
|
67
|
+
elsif reply["status"] and reply["status"] == "error"
|
68
|
+
raise "TCPIPUtils: error from web API: #{reply["data"]}"
|
69
|
+
end
|
70
|
+
if limit
|
71
|
+
recs[0,limit]
|
72
|
+
else
|
73
|
+
recs
|
74
|
+
end
|
75
|
+
}
|
76
|
+
rescue Timeout::Error => e
|
77
|
+
$stderr.puts "TCPIPUtils lookup timed out: #{label}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -34,7 +34,7 @@ module PassiveDNS
|
|
34
34
|
raise e
|
35
35
|
end
|
36
36
|
|
37
|
-
def lookup(label)
|
37
|
+
def lookup(label, limit=nil)
|
38
38
|
$stderr.puts "DEBUG: VirusTotal.lookup(#{label})" if @debug
|
39
39
|
Timeout::timeout(240) {
|
40
40
|
url = nil
|
@@ -54,7 +54,12 @@ module PassiveDNS
|
|
54
54
|
t1 = Time.now
|
55
55
|
response = http.request(request)
|
56
56
|
t2 = Time.now
|
57
|
-
parse_json(response.body, label, t2-t1)
|
57
|
+
recs = parse_json(response.body, label, t2-t1)
|
58
|
+
if limit
|
59
|
+
recs[0,limit]
|
60
|
+
else
|
61
|
+
recs
|
62
|
+
end
|
58
63
|
}
|
59
64
|
rescue Timeout::Error => e
|
60
65
|
$stderr.puts "VirusTotal lookup timed out: #{label}"
|
data/lib/passivedns/client.rb
CHANGED
@@ -5,9 +5,9 @@ require "passivedns/client/version"
|
|
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
6
|
require 'passivedns/client/bfk.rb'
|
7
7
|
require 'passivedns/client/certee.rb'
|
8
|
-
require 'passivedns/client/dnsparse.rb'
|
9
8
|
require 'passivedns/client/dnsdb.rb'
|
10
9
|
require 'passivedns/client/virustotal.rb'
|
10
|
+
require 'passivedns/client/tcpiputils.rb'
|
11
11
|
require 'passivedns/client/state.rb'
|
12
12
|
|
13
13
|
module PassiveDNS
|
@@ -15,7 +15,7 @@ module PassiveDNS
|
|
15
15
|
class PDNSResult < Struct.new(:source, :response_time, :query, :answer, :rrtype, :ttl, :firstseen, :lastseen, :count); end
|
16
16
|
|
17
17
|
class Client
|
18
|
-
def initialize(pdns=['bfk','certee','
|
18
|
+
def initialize(pdns=['bfk','certee','dnsdb','virustotal','tcpiputils'])
|
19
19
|
@pdnsdbs = []
|
20
20
|
pdns.uniq.each do |pd|
|
21
21
|
case pd
|
@@ -23,14 +23,16 @@ module PassiveDNS
|
|
23
23
|
@pdnsdbs << PassiveDNS::BFK.new
|
24
24
|
when 'certee'
|
25
25
|
@pdnsdbs << PassiveDNS::CERTEE.new
|
26
|
-
|
27
|
-
|
26
|
+
#when 'dnsparse'
|
27
|
+
# @pdnsdbs << PassiveDNS::DNSParse.new
|
28
28
|
when 'dnsdb'
|
29
29
|
@pdnsdbs << PassiveDNS::DNSDB.new
|
30
30
|
when 'isc'
|
31
31
|
@pdnsdbs << PassiveDNS::DNSDB.new
|
32
32
|
when 'virustotal'
|
33
33
|
@pdnsdbs << PassiveDNS::VirusTotal.new
|
34
|
+
when 'tcpiputils'
|
35
|
+
@pdnsdbs << PassiveDNS::TCPIPUtils.new
|
34
36
|
else
|
35
37
|
raise "Unknown Passive DNS provider: #{pd}"
|
36
38
|
end
|
@@ -43,11 +45,11 @@ module PassiveDNS
|
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
46
|
-
def query(item)
|
48
|
+
def query(item, limit=nil)
|
47
49
|
threads = []
|
48
50
|
@pdnsdbs.each do |pdnsdb|
|
49
51
|
threads << Thread.new(item) do |q|
|
50
|
-
pdnsdb.lookup(q)
|
52
|
+
pdnsdb.lookup(q, limit)
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
data/passivedns-client.gemspec
CHANGED
@@ -24,6 +24,6 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_development_dependency "bundler", "~> 1.3"
|
25
25
|
spec.add_development_dependency "rake"
|
26
26
|
|
27
|
-
spec.signing_key = "#{File.dirname(__FILE__)}/../gem-private_key.pem"
|
28
|
-
spec.cert_chain = ["#{File.dirname(__FILE__)}/../gem-public_cert.pem"]
|
27
|
+
#spec.signing_key = "#{File.dirname(__FILE__)}/../gem-private_key.pem"
|
28
|
+
#spec.cert_chain = ["#{File.dirname(__FILE__)}/../gem-public_cert.pem"]
|
29
29
|
end
|
@@ -15,41 +15,6 @@ class TestPassiveDnsQuery < Test::Unit::TestCase
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def test_instantiate_BFK_Client
|
19
|
-
assert_not_nil(PassiveDNS::BFK.new)
|
20
|
-
assert_nothing_raised do
|
21
|
-
PassiveDNS::Client.new(['bfk'])
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_instantiate_CERTEE_Client
|
26
|
-
assert_not_nil(PassiveDNS::CERTEE.new)
|
27
|
-
assert_nothing_raised do
|
28
|
-
PassiveDNS::Client.new(['certee'])
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_instantiate_DNSParse_Client
|
33
|
-
assert_not_nil(PassiveDNS::DNSParse.new)
|
34
|
-
assert_nothing_raised do
|
35
|
-
PassiveDNS::Client.new(['dnsparse'])
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_instantiate_DNSDB_Client
|
40
|
-
assert_not_nil(PassiveDNS::DNSDB.new)
|
41
|
-
assert_nothing_raised do
|
42
|
-
PassiveDNS::Client.new(['dnsdb'])
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_instantiate_VirusTotal_Client
|
47
|
-
assert_not_nil(PassiveDNS::VirusTotal.new)
|
48
|
-
assert_nothing_raised do
|
49
|
-
PassiveDNS::Client.new(['virustotal'])
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
18
|
def test_instantiate_All_Clients
|
54
19
|
assert_nothing_raised do
|
55
20
|
PassiveDNS::Client.new()
|
@@ -70,49 +35,80 @@ class TestPassiveDnsQuery < Test::Unit::TestCase
|
|
70
35
|
end
|
71
36
|
end
|
72
37
|
|
73
|
-
def
|
74
|
-
|
38
|
+
def test_BFK
|
39
|
+
assert_not_nil(PassiveDNS::BFK.new)
|
40
|
+
assert_nothing_raised do
|
41
|
+
PassiveDNS::Client.new(['bfk'])
|
42
|
+
end
|
43
|
+
rows = PassiveDNS::BFK.new.lookup("example.org",3)
|
75
44
|
assert_not_nil(rows)
|
76
45
|
assert_not_nil(rows.to_s)
|
77
46
|
assert_not_nil(rows.to_xml)
|
78
47
|
assert_not_nil(rows.to_json)
|
79
48
|
assert_not_nil(rows.to_yaml)
|
49
|
+
assert_equal(3, rows.length)
|
80
50
|
end
|
81
51
|
|
82
|
-
def
|
83
|
-
|
84
|
-
assert_not_nil(
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
end
|
90
|
-
|
91
|
-
def test_query_DNSParse
|
92
|
-
rows = PassiveDNS::DNSParse.new.lookup("example.org")
|
52
|
+
def test_CERTEE
|
53
|
+
assert(false, "CERTEE is still offline")
|
54
|
+
assert_not_nil(PassiveDNS::CERTEE.new)
|
55
|
+
assert_nothing_raised do
|
56
|
+
PassiveDNS::Client.new(['certee'])
|
57
|
+
end
|
58
|
+
rows = PassiveDNS::CERTEE.new.lookup("sim.cert.ee",3)
|
93
59
|
assert_not_nil(rows)
|
94
60
|
assert_not_nil(rows.to_s)
|
95
61
|
assert_not_nil(rows.to_xml)
|
96
62
|
assert_not_nil(rows.to_json)
|
97
63
|
assert_not_nil(rows.to_yaml)
|
64
|
+
assert_equal(3, rows.length)
|
98
65
|
end
|
99
66
|
|
100
|
-
def
|
101
|
-
|
67
|
+
def test_DNSDB
|
68
|
+
assert_not_nil(PassiveDNS::DNSDB.new)
|
69
|
+
assert_nothing_raised do
|
70
|
+
PassiveDNS::Client.new(['dnsdb'])
|
71
|
+
end
|
72
|
+
rows = PassiveDNS::DNSDB.new.lookup("example.org",3)
|
102
73
|
assert_not_nil(rows)
|
103
74
|
assert_not_nil(rows.to_s)
|
104
75
|
assert_not_nil(rows.to_xml)
|
105
76
|
assert_not_nil(rows.to_json)
|
106
77
|
assert_not_nil(rows.to_yaml)
|
78
|
+
assert_equal(3, rows.length) # this will fail since DNSDB has an off by one error
|
107
79
|
end
|
108
80
|
|
109
|
-
def
|
110
|
-
|
81
|
+
def test_VirusTotal
|
82
|
+
assert_not_nil(PassiveDNS::VirusTotal.new)
|
83
|
+
assert_nothing_raised do
|
84
|
+
PassiveDNS::Client.new(['virustotal'])
|
85
|
+
end
|
86
|
+
rows = PassiveDNS::VirusTotal.new.lookup("google.com",3)
|
111
87
|
assert_not_nil(rows)
|
112
88
|
assert_not_nil(rows.to_s)
|
113
89
|
assert_not_nil(rows.to_xml)
|
114
90
|
assert_not_nil(rows.to_json)
|
115
91
|
assert_not_nil(rows.to_yaml)
|
92
|
+
assert_equal(3, rows.length)
|
116
93
|
end
|
117
|
-
|
94
|
+
|
95
|
+
def test_TCPIPUtils
|
96
|
+
assert_not_nil(PassiveDNS::TCPIPUtils.new)
|
97
|
+
assert_nothing_raised do
|
98
|
+
PassiveDNS::Client.new(['tcpiputils'])
|
99
|
+
end
|
100
|
+
rows = PassiveDNS::TCPIPUtils.new.lookup("example.org")
|
101
|
+
assert_not_nil(rows)
|
102
|
+
assert_not_nil(rows.to_s)
|
103
|
+
assert_not_nil(rows.to_xml)
|
104
|
+
assert_not_nil(rows.to_json)
|
105
|
+
assert_not_nil(rows.to_yaml)
|
106
|
+
rows = PassiveDNS::TCPIPUtils.new.lookup("example.org",3)
|
107
|
+
assert_not_nil(rows)
|
108
|
+
assert_not_nil(rows.to_s)
|
109
|
+
assert_not_nil(rows.to_xml)
|
110
|
+
assert_not_nil(rows.to_json)
|
111
|
+
assert_not_nil(rows.to_yaml)
|
112
|
+
assert_equal(3, rows.length)
|
113
|
+
end
|
118
114
|
end
|
metadata
CHANGED
@@ -1,105 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: passivedns-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- chrislee35
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
-
-
|
12
|
-
-----BEGIN CERTIFICATE-----
|
13
|
-
MIIDYjCCAkqgAwIBAgIBADANBgkqhkiG9w0BAQUFADBXMREwDwYDVQQDDAhydWJ5
|
14
|
-
Z2VtczEYMBYGCgmSJomT8ixkARkWCGNocmlzbGVlMRMwEQYKCZImiZPyLGQBGRYD
|
15
|
-
ZGhzMRMwEQYKCZImiZPyLGQBGRYDb3JnMB4XDTEzMDUyMjEyNTk0N1oXDTE0MDUy
|
16
|
-
MjEyNTk0N1owVzERMA8GA1UEAwwIcnVieWdlbXMxGDAWBgoJkiaJk/IsZAEZFghj
|
17
|
-
aHJpc2xlZTETMBEGCgmSJomT8ixkARkWA2RoczETMBEGCgmSJomT8ixkARkWA29y
|
18
|
-
ZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANcPrx8BZiWIR9xWWG8I
|
19
|
-
tqR538tS1t+UJ4FZFl+1vrtU9TiuWX3Vj37TwUpa2fFkziK0n5KupVThyEhcem5m
|
20
|
-
OGRjvgrRFbWQJSSscIKOpwqURHVKRpV9gVz/Hnzk8S+xotUR1Buo3Ugr+I1jHewD
|
21
|
-
Cgr+y+zgZbtjtHsJtsuujkOcPhEjjUinj68L9Fz9BdeJQt+IacjwAzULix6jWCht
|
22
|
-
Uc+g+0z8Esryca2G6I1GsrgX6WHw8dykyQDT9dCtS2flCOwSC1R0K5T/xHW54f+5
|
23
|
-
wcw8mm53KLNe+tmgVC6ZHyME+qJsBnP6uxF0aTEnGA/jDBQDhQNTF0ZP/abzyTsL
|
24
|
-
zjUCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFO8w
|
25
|
-
+aeP7T6kVJblCg6eusOII9DfMA0GCSqGSIb3DQEBBQUAA4IBAQBCQyRJLXsBo2Fy
|
26
|
-
8W6e/W4RemQRrlAw9DK5O6U71JtedVob2oq+Ob+zmS+PifE2+L+3RiJ2H6VTlOzi
|
27
|
-
x+A061MUXhGraqVq4J2FC8kt4EQywAD0P0Ta5GU24CGSF08Y3GkJy1Sa4XqTC2YC
|
28
|
-
o51s7JP+tkCCtpVYSdzJhTllieRAWBpGV1dtaoeUKE6tYPMBkosxSRcVGczk/Sc3
|
29
|
-
7eQCpexYy9JlUBI9u3BqIY9E+l+MSn8ihXSPmyK0DgrhaCu+voaSFVOX6Y+B5qbo
|
30
|
-
jLXMQu2ZgISYwXNjNbGVHehut82U7U9oiHoWcrOGazaRUmGO9TXP+aJLH0gw2dcK
|
31
|
-
AfMglXPi
|
32
|
-
-----END CERTIFICATE-----
|
33
|
-
date: 2013-09-21 00:00:00.000000000 Z
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-09-22 00:00:00.000000000 Z
|
34
12
|
dependencies:
|
35
13
|
- !ruby/object:Gem::Dependency
|
36
14
|
name: json
|
37
15
|
requirement: !ruby/object:Gem::Requirement
|
38
16
|
requirements:
|
39
|
-
- -
|
17
|
+
- - ">="
|
40
18
|
- !ruby/object:Gem::Version
|
41
19
|
version: 1.4.3
|
42
20
|
type: :runtime
|
43
21
|
prerelease: false
|
44
22
|
version_requirements: !ruby/object:Gem::Requirement
|
45
23
|
requirements:
|
46
|
-
- -
|
24
|
+
- - ">="
|
47
25
|
- !ruby/object:Gem::Version
|
48
26
|
version: 1.4.3
|
49
27
|
- !ruby/object:Gem::Dependency
|
50
28
|
name: sqlite3
|
51
29
|
requirement: !ruby/object:Gem::Requirement
|
52
30
|
requirements:
|
53
|
-
- -
|
31
|
+
- - ">="
|
54
32
|
- !ruby/object:Gem::Version
|
55
33
|
version: 1.3.3
|
56
34
|
type: :runtime
|
57
35
|
prerelease: false
|
58
36
|
version_requirements: !ruby/object:Gem::Requirement
|
59
37
|
requirements:
|
60
|
-
- -
|
38
|
+
- - ">="
|
61
39
|
- !ruby/object:Gem::Version
|
62
40
|
version: 1.3.3
|
63
41
|
- !ruby/object:Gem::Dependency
|
64
42
|
name: structformatter
|
65
43
|
requirement: !ruby/object:Gem::Requirement
|
66
44
|
requirements:
|
67
|
-
- - ~>
|
45
|
+
- - "~>"
|
68
46
|
- !ruby/object:Gem::Version
|
69
47
|
version: 0.0.1
|
70
48
|
type: :runtime
|
71
49
|
prerelease: false
|
72
50
|
version_requirements: !ruby/object:Gem::Requirement
|
73
51
|
requirements:
|
74
|
-
- - ~>
|
52
|
+
- - "~>"
|
75
53
|
- !ruby/object:Gem::Version
|
76
54
|
version: 0.0.1
|
77
55
|
- !ruby/object:Gem::Dependency
|
78
56
|
name: bundler
|
79
57
|
requirement: !ruby/object:Gem::Requirement
|
80
58
|
requirements:
|
81
|
-
- - ~>
|
59
|
+
- - "~>"
|
82
60
|
- !ruby/object:Gem::Version
|
83
61
|
version: '1.3'
|
84
62
|
type: :development
|
85
63
|
prerelease: false
|
86
64
|
version_requirements: !ruby/object:Gem::Requirement
|
87
65
|
requirements:
|
88
|
-
- - ~>
|
66
|
+
- - "~>"
|
89
67
|
- !ruby/object:Gem::Version
|
90
68
|
version: '1.3'
|
91
69
|
- !ruby/object:Gem::Dependency
|
92
70
|
name: rake
|
93
71
|
requirement: !ruby/object:Gem::Requirement
|
94
72
|
requirements:
|
95
|
-
- -
|
73
|
+
- - ">="
|
96
74
|
- !ruby/object:Gem::Version
|
97
75
|
version: '0'
|
98
76
|
type: :development
|
99
77
|
prerelease: false
|
100
78
|
version_requirements: !ruby/object:Gem::Requirement
|
101
79
|
requirements:
|
102
|
-
- -
|
80
|
+
- - ">="
|
103
81
|
- !ruby/object:Gem::Version
|
104
82
|
version: '0'
|
105
83
|
description: This provides interfaces to various passive DNS databases to do the query
|
@@ -112,7 +90,7 @@ executables:
|
|
112
90
|
extensions: []
|
113
91
|
extra_rdoc_files: []
|
114
92
|
files:
|
115
|
-
- .gitignore
|
93
|
+
- ".gitignore"
|
116
94
|
- Gemfile
|
117
95
|
- LICENSE.txt
|
118
96
|
- README.md
|
@@ -122,8 +100,8 @@ files:
|
|
122
100
|
- lib/passivedns/client/bfk.rb
|
123
101
|
- lib/passivedns/client/certee.rb
|
124
102
|
- lib/passivedns/client/dnsdb.rb
|
125
|
-
- lib/passivedns/client/dnsparse.rb
|
126
103
|
- lib/passivedns/client/state.rb
|
104
|
+
- lib/passivedns/client/tcpiputils.rb
|
127
105
|
- lib/passivedns/client/version.rb
|
128
106
|
- lib/passivedns/client/virustotal.rb
|
129
107
|
- passivedns-client.gemspec
|
@@ -139,17 +117,17 @@ require_paths:
|
|
139
117
|
- lib
|
140
118
|
required_ruby_version: !ruby/object:Gem::Requirement
|
141
119
|
requirements:
|
142
|
-
- -
|
120
|
+
- - ">="
|
143
121
|
- !ruby/object:Gem::Version
|
144
122
|
version: '0'
|
145
123
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
124
|
requirements:
|
147
|
-
- -
|
125
|
+
- - ">="
|
148
126
|
- !ruby/object:Gem::Version
|
149
127
|
version: '0'
|
150
128
|
requirements: []
|
151
129
|
rubyforge_project:
|
152
|
-
rubygems_version: 2.
|
130
|
+
rubygems_version: 2.2.2
|
153
131
|
signing_key:
|
154
132
|
specification_version: 4
|
155
133
|
summary: Query passive DNS databases
|
checksums.yaml.gz.sig
DELETED
Binary file
|
@@ -1,89 +0,0 @@
|
|
1
|
-
# DESCRIPTION: this is a module for pdns.rb, primarily used by pdnstool.rb, to query Bojan Zdrnja's passive DNS database, DNSParse
|
2
|
-
require 'net/http'
|
3
|
-
require 'net/https'
|
4
|
-
require 'openssl'
|
5
|
-
|
6
|
-
module PassiveDNS
|
7
|
-
class DNSParse
|
8
|
-
attr_accessor :debug
|
9
|
-
@@dns_rtypes = {1 => 'A', 2 => 'NS', 3 => 'MD', 4 => 'MF', 5 => 'CNAME', 6 => 'SOA', 7 => 'MB', 8 => 'MG', 9 => 'MR', 10 => 'NULL', 11 => 'WKS', 12 => 'PTR', 13 => 'HINFO', 14 => 'MINFO', 15 => 'MX', 16 => 'TXT', 17 => 'RP', 18 => 'AFSDB', 19 => 'X25', 20 => 'ISDN', 21 => 'RT', 22 => 'NSAP', 23 => 'NSAP-PTR', 24 => 'SIG', 25 => 'KEY', 26 => 'PX', 27 => 'GPOS', 28 => 'AAAA', 29 => 'LOC', 30 => 'NXT', 31 => 'EID', 32 => 'NIMLOC', 33 => 'SRV', 34 => 'ATMA', 35 => 'NAPTR', 36 => 'KX', 37 => 'CERT', 38 => 'A6', 39 => 'DNAME', 40 => 'SINK', 41 => 'OPT', 42 => 'APL', 43 => 'DS', 44 => 'SSHFP', 45 => 'IPSECKEY', 46 => 'RRSIG', 47 => 'NSEC', 48 => 'DNSKEY', 49 => 'DHCID', 55 => 'HIP', 99 => 'SPF', 100 => 'UINFO', 101 => 'UID', 102 => 'GID', 103 => 'UNSPEC', 249 => 'TKEY', 250 => 'TSIG', 251 => 'IXFR', 252 => 'AXFR', 253 => 'MAILB', 254 => 'MAILA', 255 => 'ALL'}
|
10
|
-
def initialize(config="#{ENV['HOME']}/.dnsparse")
|
11
|
-
if File.exist?(config)
|
12
|
-
@base,@user,@pass = File.open(config).read.split(/\n/)
|
13
|
-
$stderr.puts "DEBUG: DNSParse#initialize(#{@base}, #{@user}, #{@pass})" if @debug
|
14
|
-
else
|
15
|
-
raise "Configuration file for DNSParse is required for intialization\nFormat of configuration file (default: #{ENV['HOME']}/.dnsparse) is:\n<url>\n<username>\n<password>\n"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def parse_json(page,response_time=0)
|
20
|
-
res = []
|
21
|
-
# need to remove the json_class tag or the parser will crap itself trying to find a class to align it to
|
22
|
-
page = page.gsub(/\"json_class\"\:\"PDNSResult\"\,/,'')
|
23
|
-
recs = JSON.parse(page)
|
24
|
-
recs.each do |row|
|
25
|
-
res << PDNSResult.new('DNSParse',response_time,row["query"],row["answer"],@@dns_rtypes[row["rrtype"].to_i],row["ttl"],row["firstseen"],row["lastseen"])
|
26
|
-
end
|
27
|
-
res
|
28
|
-
rescue Exception => e
|
29
|
-
$stderr.puts "DNSParse Exception: #{e}"
|
30
|
-
raise e
|
31
|
-
end
|
32
|
-
|
33
|
-
def parse_html(page,response_time=0)
|
34
|
-
rows = []
|
35
|
-
line = page.split(/<table/).grep(/ id=\"dnsparse\"/)
|
36
|
-
return [] unless line.length > 0
|
37
|
-
line = line[0].gsub(/[\t\n]/,'').gsub(/<\/table.*/,'')
|
38
|
-
rows = line.split(/<tr.*?>/)
|
39
|
-
res = []
|
40
|
-
rows.collect do |row|
|
41
|
-
r = row.split(/<td>/).map{|x| x.gsub(/<.*?>/,'').gsub(/\&.*?;/,'').gsub(/[\t\n]/,'')}[1,1000]
|
42
|
-
if r and r[0] =~ /\w/
|
43
|
-
#TXT records screw up other functions and don't provide much without a lot of subparshing. Dropping for now.
|
44
|
-
if r[2]!="TXT" then
|
45
|
-
res << PDNSResult.new('DNSParse',response_time,r[0],r[1],r[2],r[3],r[4],r[5])
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
res
|
50
|
-
rescue Exception => e
|
51
|
-
$stderr.puts "DNSParse Exception: #{e}"
|
52
|
-
raise e
|
53
|
-
end
|
54
|
-
|
55
|
-
def lookup(label)
|
56
|
-
$stderr.puts "DEBUG: DNSParse.lookup(#{label})" if @debug
|
57
|
-
Timeout::timeout(240) {
|
58
|
-
year = Time.now.strftime("%Y").to_i
|
59
|
-
month = Time.now.strftime("%m").to_i
|
60
|
-
url = "#{@base}#{label}&year=#{year - 1}"
|
61
|
-
url = "#{@base}#{label}&year=#{year}" if month > 3
|
62
|
-
if label =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}$/
|
63
|
-
url.gsub!(/query\.php/,'cidr.php')
|
64
|
-
elsif label =~ /\*$/
|
65
|
-
url.gsub!(/query\.php/,'wildcard.php')
|
66
|
-
end
|
67
|
-
$stderr.puts "DEBUG: DNSParse url = #{url}" if @debug
|
68
|
-
url = URI.parse url
|
69
|
-
http = Net::HTTP.new(url.host, url.port)
|
70
|
-
http.use_ssl = (url.scheme == 'https')
|
71
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
72
|
-
http.verify_depth = 5
|
73
|
-
request = Net::HTTP::Get.new(url.path+"?"+url.query)
|
74
|
-
request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
|
75
|
-
request.basic_auth @user, @pass
|
76
|
-
t1 = Time.now
|
77
|
-
response = http.request(request)
|
78
|
-
t2 = Time.now
|
79
|
-
if @base =~ /format=json/
|
80
|
-
parse_json(response.body,t2-t1)
|
81
|
-
else
|
82
|
-
parse_html(response.body,t2-t1)
|
83
|
-
end
|
84
|
-
}
|
85
|
-
rescue Timeout::Error => e
|
86
|
-
$stderr.puts "DNSParse lookup timed out: #{label}"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
data.tar.gz.sig
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
��mѯm��]�y��!���N�I��̡U�媫=1��:���1:H�L�s��g�����0g�'$�Za�/dX�e�Dϳ�Y*�k���;���q�`��J|�����Usu4L:�?U�'!*j%@?�{Q[��H#c#u��߱�h��ܚ�d�@!�nv�=K�`Ȩ0�'����А���-"Ê�R�t�]M�i�m��2g�L���澠�rz�ݲ���{���xޢ<I4��P�B�K��"R������
|
metadata.gz.sig
DELETED