passivedns-client 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in passivedns-client.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 chrislee35
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # PassiveDNS::Client
2
+
3
+ This rubygem queries 5 major Passive DNS databases: BFK, CERTEE, DNSParse, ISC, and VirusTotal.
4
+ Passive DNS is a technique where IP to hostname mappings are made by recording the answers of other people's queries.
5
+
6
+ There is a tool included, pdnstool, that wraps a lot of the functionality that you would need.
7
+
8
+ 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 strongly discouraged. 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. Remember, these passive DNS operators are my friends. I don't want to have a row with them because some jerk used this library to abuse them.
9
+
10
+ If you like this library, please buy the Passive DNS operators a round of beers.
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ gem 'passivedns-client'
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install passivedns-client
25
+
26
+ ## Usage
27
+
28
+ require 'passivedns-client'
29
+
30
+ c = PassiveDNS::Client.new(['bfk','isc']) # providers: bfk, dnsparse, certee, isc, virustotal
31
+ results = c.query("example.com")
32
+
33
+ Or use the included tool!
34
+
35
+ Usage: bin/pdnstool [-a|-b|-e|-d|-i|-V] [-c|-x|-y|-j|-t] [-s <sep>] [-f <file>] [-r#|-w#|-l] <ip|domain|cidr>
36
+ -a uses all of the available passive dns databases
37
+ -b only use BFK
38
+ -e only use CERT-EE
39
+ -d only use DNSParse (default)
40
+ -i only use ISC
41
+ -V only use VirusTotal
42
+
43
+ -g outputs a link-nodal GDF visualization definition
44
+ -v outputs a link-nodal graphviz visualization definition
45
+ -m output a link-nodal graphml visualization definition
46
+ -c outputs CSV
47
+ -x outputs XML
48
+ -y outputs YAML
49
+ -j outputs JSON
50
+ -t outputs ASCII text (default)
51
+ -s <sep> specifies a field separator for text output, default is tab
52
+
53
+ -f[file] specifies a sqlite3 database used to read the current state - useful for large result sets and generating graphs of previous runs.
54
+ -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!
55
+ -w# specifies the amount of time to wait, in seconds, between queries (Default: 0)
56
+ -l outputs debugging information
57
+
58
+ ## Contributing
59
+
60
+ 1. Fork it
61
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
62
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
63
+ 4. Push to the branch (`git push origin my-new-feature`)
64
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs << 'lib'
8
+ t.test_files = FileList['test/test_*.rb']
9
+ t.verbose = true
10
+ end
11
+
12
+ task :default => :test
data/bin/pdnstool ADDED
@@ -0,0 +1,202 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'passivedns-client'
4
+ require 'structformatter'
5
+ require 'getoptlong'
6
+ require 'yaml'
7
+
8
+ #if __FILE__ == $0
9
+ def pdnslookup(state,pdnsclient,recursedepth=1,wait=0,debug=false)
10
+ puts "pdnslookup: #{state.level} #{recursedepth}" if debug
11
+ level = 0
12
+ while level < recursedepth
13
+ puts "pdnslookup: #{level} < #{recursedepth}" if debug
14
+ state.each_query(recursedepth) do |q|
15
+ rv = pdnsclient.query(q)
16
+ if rv
17
+ rv.each do |r|
18
+ if ["A","AAAA","NS","CNAME","PTR"].index(r.rrtype)
19
+ puts "pdnslookup: #{r.to_s}" if debug
20
+ state.add_result(r)
21
+ end
22
+ end
23
+ else
24
+ state.update_query(rv,'failed')
25
+ end
26
+ sleep wait if level < recursedepth
27
+ end
28
+ level += 1
29
+ end
30
+ state
31
+ end
32
+
33
+ def printresults(state,format,sep="\t")
34
+ case format
35
+ when 'text'
36
+ puts PassiveDNS::PDNSResult.members.join(sep)
37
+ puts state.to_s(sep)
38
+ when 'yaml'
39
+ puts state.to_yaml
40
+ when 'xml'
41
+ puts state.to_xml
42
+ when 'json'
43
+ puts state.to_json
44
+ when 'gdf'
45
+ puts state.to_gdf
46
+ when 'graphviz'
47
+ puts state.to_graphviz
48
+ when 'graphml'
49
+ puts state.to_graphml
50
+ end
51
+ end
52
+
53
+ def usage
54
+ puts "Usage: #{$0} [-a|-b|-e|-d|-i|-V] [-c|-x|-y|-j|-t] [-s <sep>] [-f <file>] [-r#|-w#|-l] <ip|domain|cidr>"
55
+ puts " -a uses all of the available passive dns databases"
56
+ puts " -b only use BFK"
57
+ puts " -e only use CERT-EE"
58
+ puts " -d only use DNSParse (default)"
59
+ puts " -i only use ISC"
60
+ puts " -V only use VirusTotal"
61
+ puts ""
62
+ puts " -g outputs a link-nodal GDF visualization definition"
63
+ puts " -v outputs a link-nodal graphviz visualization definition"
64
+ puts " -m output a link-nodal graphml visualization definition"
65
+ puts " -c outputs CSV"
66
+ puts " -x outputs XML"
67
+ puts " -y outputs YAML"
68
+ puts " -j outputs JSON"
69
+ puts " -t outputs ASCII text (default)"
70
+ puts " -s <sep> specifies a field separator for text output, default is tab"
71
+ puts ""
72
+ puts " -f[file] specifies a sqlite3 database used to read the current state - useful for large result sets and generating graphs of previous runs."
73
+ 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
+ puts " -w# specifies the amount of time to wait, in seconds, between queries (Default: 0)"
75
+ puts " -l outputs debugging information"
76
+ exit
77
+ end
78
+
79
+ opts = GetoptLong.new(
80
+ [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
81
+ [ '--debug', '-l', GetoptLong::NO_ARGUMENT ],
82
+ [ '--all', '-a', GetoptLong::NO_ARGUMENT ],
83
+ [ '--bfk', '-b', GetoptLong::NO_ARGUMENT ],
84
+ [ '--dnsparse', '-d', GetoptLong::NO_ARGUMENT ],
85
+ [ '--certee', '-e', GetoptLong::NO_ARGUMENT ],
86
+ [ '--isc', '-i', GetoptLong::NO_ARGUMENT ],
87
+ [ '--virustotal', '-V', GetoptLong::NO_ARGUMENT ],
88
+
89
+ [ '--gdf', '-g', GetoptLong::NO_ARGUMENT ],
90
+ [ '--graphviz', '-v', GetoptLong::NO_ARGUMENT ],
91
+ [ '--graphml', '-m', GetoptLong::NO_ARGUMENT ],
92
+ [ '--csv', '-c', GetoptLong::NO_ARGUMENT ],
93
+ [ '--xml', '-x', GetoptLong::NO_ARGUMENT ],
94
+ [ '--yaml', '-y', GetoptLong::NO_ARGUMENT ],
95
+ [ '--json', '-j', GetoptLong::NO_ARGUMENT ],
96
+ [ '--text', '-t', GetoptLong::NO_ARGUMENT ],
97
+ [ '--sep', '-s', GetoptLong::REQUIRED_ARGUMENT ],
98
+
99
+ [ '--sqlite3', '-f', GetoptLong::REQUIRED_ARGUMENT ],
100
+ [ '--recurse', '-r', GetoptLong::REQUIRED_ARGUMENT ],
101
+ [ '--wait', '-w', GetoptLong::REQUIRED_ARGUMENT ]
102
+ )
103
+
104
+ # sets the default search methods
105
+ pdnsdbs = []
106
+ format = "text"
107
+ sep = "\t"
108
+ recursedepth = 1
109
+ wait = 0
110
+ res = nil
111
+ debug = false
112
+ sqlitedb = nil
113
+
114
+ opts.each do |opt, arg|
115
+ case opt
116
+ when '--help'
117
+ usage
118
+ when '--debug'
119
+ debug = true
120
+ $stderr.puts "Using proxy settings: http_proxy=#{ENV['http_proxy']}, https_proxy=#{ENV['https_proxy']}"
121
+ when '--all'
122
+ pdnsdbs << "bfk"
123
+ pdnsdbs << "certee"
124
+ pdnsdbs << "dnsparse"
125
+ pdnsdbs << "isc"
126
+ pdnsdbs << "virustotal"
127
+ when '--bfk'
128
+ pdnsdbs << "bfk"
129
+ when '--certee'
130
+ pdnsdbs << "certee"
131
+ when '--dnsparse'
132
+ pdnsdbs << "dnsparse"
133
+ when '--isc'
134
+ pdnsdbs << "isc"
135
+ when '--virustotal'
136
+ pdnsdbs << "virustotal"
137
+ when '--gdf'
138
+ format = 'gdf'
139
+ when '--graphviz'
140
+ format = 'graphviz'
141
+ when '--graphml'
142
+ format = 'graphml'
143
+ when '--csv'
144
+ format = 'text'
145
+ sep = ','
146
+ when '--yaml'
147
+ format = 'yaml'
148
+ when '--xml'
149
+ format = 'xml'
150
+ when '--json'
151
+ format = 'json'
152
+ when '--text'
153
+ format = 'text'
154
+ when '--sep'
155
+ sep = arg
156
+ when '--recurse'
157
+ recursedepth = arg.to_i
158
+ if recursedepth > 3
159
+ $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)"
160
+ sleep 60
161
+ end
162
+ when '--wait'
163
+ wait = arg.to_i
164
+ when '--sqlite3'
165
+ sqlitedb = arg
166
+ else
167
+ usage
168
+ end
169
+ end
170
+
171
+ if pdnsdbs.length == 0
172
+ pdnsdbs << "dnsparse"
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
+ state = nil
181
+ if sqlitedb
182
+ state = PassiveDNS::PDNSToolStateDB.new(sqlitedb)
183
+ else
184
+ state = PassiveDNS::PDNSToolState.new
185
+ end
186
+ state.debug = true if debug
187
+
188
+ pdnsclient = PassiveDNS::Client.new(pdnsdbs)
189
+ pdnsclient.debug = debug
190
+
191
+ if ARGV.length > 0
192
+ ARGV.each do |arg|
193
+ state.add_query(arg,'pending',0)
194
+ end
195
+ else
196
+ $stdin.each_line do |l|
197
+ state.add_query(l.chomp,'pending',0)
198
+ end
199
+ end
200
+ pdnslookup(state,pdnsclient,recursedepth,wait,debug)
201
+ printresults(state,format,sep)
202
+ #end
@@ -0,0 +1,68 @@
1
+ require "passivedns/client/version"
2
+ # DESCRIPTION: queries passive DNS databases
3
+ # This code is released under the LGPL: http://www.gnu.org/licenses/lgpl-3.0.txt
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
+ # 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/bfk.rb'
7
+ require 'passivedns/client/certee.rb'
8
+ require 'passivedns/client/dnsparse.rb'
9
+ require 'passivedns/client/isc.rb'
10
+ require 'passivedns/client/virustotal.rb'
11
+ require 'passivedns/client/state.rb'
12
+
13
+ module PassiveDNS
14
+
15
+ class PDNSResult < Struct.new(:source, :response_time, :query, :answer, :rrtype, :ttl, :firstseen, :lastseen, :count); end
16
+
17
+ class Client
18
+ def initialize(pdns=['bfk','certee','dnsparse','isc','virustotal'])
19
+ @pdnsdbs = []
20
+ pdns.uniq.each do |pd|
21
+ case pd
22
+ when 'bfk'
23
+ @pdnsdbs << PassiveDNS::BFK.new
24
+ when 'certee'
25
+ @pdnsdbs << PassiveDNS::CERTEE.new
26
+ when 'dnsparse'
27
+ @pdnsdbs << PassiveDNS::DNSParse.new
28
+ when 'isc'
29
+ @pdnsdbs << PassiveDNS::ISC.new
30
+ when 'virustotal'
31
+ @pdnsdbs << PassiveDNS::VirusTotal.new
32
+ else
33
+ raise "Unknown Passive DNS provider: #{pd}"
34
+ end
35
+ end
36
+ end #initialize
37
+
38
+ def debug=(d)
39
+ @pdnsdbs.each do |pdnsdb|
40
+ pdnsdb.debug = d
41
+ end
42
+ end
43
+
44
+ def query(item)
45
+ threads = []
46
+ @pdnsdbs.each do |pdnsdb|
47
+ threads << Thread.new(item) do |q|
48
+ pdnsdb.lookup(q)
49
+ end
50
+ end
51
+
52
+ results = []
53
+ threads.each do |thr|
54
+ rv = thr.join.value
55
+ if rv
56
+ rv.each do |r|
57
+ if ["A","AAAA","NS","CNAME","PTR"].index(r.rrtype)
58
+ results << r
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ return results
65
+ end #query
66
+
67
+ end # Client
68
+ end # PassiveDNS
@@ -0,0 +1,58 @@
1
+ require 'open-uri'
2
+
3
+ module PassiveDNS
4
+ class BFK
5
+ attr_accessor :debug
6
+ def initialize
7
+ @debug = false
8
+ end
9
+ @@base = "http://www.bfk.de/bfk_dnslogger.html?query="
10
+ def parse(page,response_time)
11
+ line = page.unpack('C*').pack('U*').split(/<table/).grep(/ id=\"logger\"/)
12
+ return [] unless line.length > 0
13
+ line = line[0].gsub(/[\t\n]/,'').gsub(/<\/table.*/,'')
14
+ rows = line.split(/<tr.*?>/)
15
+ res = []
16
+ rows.collect do |row|
17
+ r = row.split(/<td>/).map{|x| x.gsub(/<.*?>/,'').gsub(/\&.*?;/,'')}[1,1000]
18
+ if r and r[0] =~ /\w/
19
+ # BFK includes the MX weight in the answer response. First, find the MX records, then dump the weight to present a consistent record name to the collecting array. Otherwise the other repositories will present the same answer and your results will become cluttered with duplicates.
20
+ if r[1] == "MX" then
21
+ # MX lines look like "5 mx.domain.tld", so split on the space and assign r[2] (:answer) to the latter part.
22
+ #s = r[2].split(/\w/).map{|x| x}[1,1000]
23
+ # r[2] = s[1]
24
+ r[2] =~ /[0-9]+?\s(.+)/
25
+ s=$1
26
+ puts "DEBUG: == BFK: MX Parsing Strip: Answer: " + r[2] + " : mod: " + s if @debug
27
+ r[2] = s
28
+
29
+ ######### FIX BLANKS FOR MX
30
+
31
+ end
32
+ res << PDNSResult.new('BFK',response_time,r[0],r[2],r[1])
33
+ end
34
+ end
35
+ res
36
+ rescue Exception => e
37
+ $stderr.puts "BFKClient Exception: #{e}"
38
+ raise e
39
+ end
40
+
41
+ def lookup(label)
42
+ $stderr.puts "DEBUG: BFKClient.lookup(#{label})" if @debug
43
+ Timeout::timeout(240) {
44
+ t1 = Time.now
45
+ open(
46
+ @@base+label,
47
+ "User-Agent" => "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}",
48
+ :http_basic_authentication => [@user,@pass]
49
+ ) do |f|
50
+ t2 = Time.now
51
+ parse(f.read,t2-t1)
52
+ end
53
+ }
54
+ rescue Timeout::Error => e
55
+ $stderr.puts "BFK lookup timed out: #{label}"
56
+ end
57
+ end
58
+ end