passivedns-client 1.1.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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