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 +0 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +64 -0
- data/Rakefile +12 -0
- data/bin/pdnstool +202 -0
- data/lib/passivedns/client.rb +68 -0
- data/lib/passivedns/client/bfk.rb +58 -0
- data/lib/passivedns/client/certee.rb +36 -0
- data/lib/passivedns/client/dnsparse.rb +89 -0
- data/lib/passivedns/client/isc.rb +80 -0
- data/lib/passivedns/client/state.rb +272 -0
- data/lib/passivedns/client/version.rb +5 -0
- data/lib/passivedns/client/virustotal.rb +63 -0
- data/passivedns-client.gemspec +29 -0
- data/test/helper.rb +2 -0
- data/test/test_passivedns-client.rb +118 -0
- metadata +177 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
# DESCRIPTION: this is a module for pdns.rb, primarily used by pdnstool.rb, to query VirusTotal's passive DNS database
|
2
|
+
require 'net/http'
|
3
|
+
require 'net/https'
|
4
|
+
require 'openssl'
|
5
|
+
|
6
|
+
module PassiveDNS
|
7
|
+
class VirusTotal
|
8
|
+
attr_accessor :debug
|
9
|
+
def initialize(config="#{ENV['HOME']}/.virustotal")
|
10
|
+
if File.exist?(config)
|
11
|
+
@apikey = File.open(config).read.split(/\n/)[0]
|
12
|
+
$stderr.puts "DEBUG: VirusTotal#initialize(#{@apikey})" if @debug
|
13
|
+
else
|
14
|
+
raise "Configuration file for VirusTotal is required for intialization\nFormat of configuration file (default: #{ENV['HOME']}/.apikey) is:\n<url>\n<apikey>\n"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse_json(page,query,response_time=0)
|
19
|
+
res = []
|
20
|
+
# need to remove the json_class tag or the parser will crap itself trying to find a class to align it to
|
21
|
+
data = JSON.parse(page)
|
22
|
+
if data['resolutions']
|
23
|
+
data['resolutions'].each do |row|
|
24
|
+
if row['ip_address']
|
25
|
+
res << PDNSResult.new('VirusTotal',response_time,query,row['ip_address'],'A',nil,nil,row['last_resolved'])
|
26
|
+
elsif row['hostname']
|
27
|
+
res << PDNSResult.new('VirusTotal',response_time,row['hostname'],query,'A',nil,nil,row['last_resolved'])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
res
|
32
|
+
rescue Exception => e
|
33
|
+
$stderr.puts "VirusTotal Exception: #{e}"
|
34
|
+
raise e
|
35
|
+
end
|
36
|
+
|
37
|
+
def lookup(label)
|
38
|
+
$stderr.puts "DEBUG: VirusTotal.lookup(#{label})" if @debug
|
39
|
+
Timeout::timeout(240) {
|
40
|
+
url = nil
|
41
|
+
if label =~ /^[\d\.]+$/
|
42
|
+
url = "https://www.virustotal.com/vtapi/v2/ip-address/report?ip=#{label}&apikey=#{@apikey}"
|
43
|
+
else
|
44
|
+
url = "https://www.virustotal.com/vtapi/v2/domain/report?domain=#{label}&apikey=#{@apikey}"
|
45
|
+
end
|
46
|
+
$stderr.puts "DEBUG: VirusTotal url = #{url}" if @debug
|
47
|
+
url = URI.parse url
|
48
|
+
http = Net::HTTP.new(url.host, url.port)
|
49
|
+
http.use_ssl = (url.scheme == 'https')
|
50
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
51
|
+
http.verify_depth = 5
|
52
|
+
request = Net::HTTP::Get.new(url.path+"?"+url.query)
|
53
|
+
request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivedns-client rubygem v#{PassiveDNS::Client::VERSION}")
|
54
|
+
t1 = Time.now
|
55
|
+
response = http.request(request)
|
56
|
+
t2 = Time.now
|
57
|
+
parse_json(response.body, label, t2-t1)
|
58
|
+
}
|
59
|
+
rescue Timeout::Error => e
|
60
|
+
$stderr.puts "VirusTotal lookup timed out: #{label}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'passivedns/client/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "passivedns-client"
|
8
|
+
spec.version = PassiveDNS::Client::VERSION
|
9
|
+
spec.authors = ["chrislee35"]
|
10
|
+
spec.email = ["rubygems@chrislee.dhs.org"]
|
11
|
+
spec.description = %q{This provides interfaces to various passive DNS databases to do the query and to normalize the responses. The query tool also allows for recursive queries, using an SQLite3 database to keep state.}
|
12
|
+
spec.summary = %q{Query passive DNS databases}
|
13
|
+
spec.homepage = "https://github.com/chrislee35/passivedns-client"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'json', '>= 1.4.3'
|
22
|
+
spec.add_runtime_dependency 'sqlite3', '>= 1.3.3'
|
23
|
+
spec.add_runtime_dependency 'structformatter', '~> 0.0.1'
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
|
27
|
+
spec.signing_key = "#{File.dirname(__FILE__)}/../gem-private_key.pem"
|
28
|
+
spec.cert_chain = ["#{File.dirname(__FILE__)}/../gem-public_cert.pem"]
|
29
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
unless Kernel.respond_to?(:require_relative)
|
2
|
+
module Kernel
|
3
|
+
def require_relative(path)
|
4
|
+
require File.join(File.dirname(caller[0]), path.to_str)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require_relative 'helper'
|
10
|
+
|
11
|
+
class TestPassiveDnsQuery < Test::Unit::TestCase
|
12
|
+
def test_instantiate_Nonexisting_Client
|
13
|
+
assert_raise RuntimeError do
|
14
|
+
PassiveDNS::Client.new(['doesnotexist'])
|
15
|
+
end
|
16
|
+
end
|
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_ISC_Client
|
40
|
+
assert_not_nil(PassiveDNS::ISC.new)
|
41
|
+
assert_nothing_raised do
|
42
|
+
PassiveDNS::Client.new(['isc'])
|
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
|
+
def test_instantiate_All_Clients
|
54
|
+
assert_nothing_raised do
|
55
|
+
PassiveDNS::Client.new()
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_instantiate_Passive_DNS_State
|
60
|
+
assert_not_nil(PassiveDNS::PDNSToolState.new)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_instantiate_Passive_DNS_State_database
|
64
|
+
if File.exists?("test/test.sqlite3")
|
65
|
+
File.unlink("test/test.sqlite3")
|
66
|
+
end
|
67
|
+
assert_not_nil(PassiveDNS::PDNSToolStateDB.new("test/test.sqlite3"))
|
68
|
+
if File.exists?("test/test.sqlite3")
|
69
|
+
File.unlink("test/test.sqlite3")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_query_BFK
|
74
|
+
rows = PassiveDNS::BFK.new.lookup("example.org")
|
75
|
+
assert_not_nil(rows)
|
76
|
+
assert_not_nil(rows.to_s)
|
77
|
+
assert_not_nil(rows.to_xml)
|
78
|
+
assert_not_nil(rows.to_json)
|
79
|
+
assert_not_nil(rows.to_yaml)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_query_CERTEE
|
83
|
+
rows = PassiveDNS::CERTEE.new.lookup("sim.cert.ee")
|
84
|
+
assert_not_nil(rows)
|
85
|
+
assert_not_nil(rows.to_s)
|
86
|
+
assert_not_nil(rows.to_xml)
|
87
|
+
assert_not_nil(rows.to_json)
|
88
|
+
assert_not_nil(rows.to_yaml)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_query_DNSParse
|
92
|
+
rows = PassiveDNS::DNSParse.new.lookup("example.org")
|
93
|
+
assert_not_nil(rows)
|
94
|
+
assert_not_nil(rows.to_s)
|
95
|
+
assert_not_nil(rows.to_xml)
|
96
|
+
assert_not_nil(rows.to_json)
|
97
|
+
assert_not_nil(rows.to_yaml)
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_query_ISC
|
101
|
+
rows = PassiveDNS::ISC.new.lookup("example.org")
|
102
|
+
assert_not_nil(rows)
|
103
|
+
assert_not_nil(rows.to_s)
|
104
|
+
assert_not_nil(rows.to_xml)
|
105
|
+
assert_not_nil(rows.to_json)
|
106
|
+
assert_not_nil(rows.to_yaml)
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_query_VirusTotal
|
110
|
+
rows = PassiveDNS::VirusTotal.new.lookup("sim.cert.ee")
|
111
|
+
assert_not_nil(rows)
|
112
|
+
assert_not_nil(rows.to_s)
|
113
|
+
assert_not_nil(rows.to_xml)
|
114
|
+
assert_not_nil(rows.to_json)
|
115
|
+
assert_not_nil(rows.to_yaml)
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
metadata
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: passivedns-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- chrislee35
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain:
|
12
|
+
- !binary |-
|
13
|
+
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURZakNDQWtxZ0F3SUJB
|
14
|
+
Z0lCQURBTkJna3Foa2lHOXcwQkFRVUZBREJYTVJFd0R3WURWUVFEREFoeWRX
|
15
|
+
SjUKWjJWdGN6RVlNQllHQ2dtU0pvbVQ4aXhrQVJrV0NHTm9jbWx6YkdWbE1S
|
16
|
+
TXdFUVlLQ1pJbWlaUHlMR1FCR1JZRApaR2h6TVJNd0VRWUtDWkltaVpQeUxH
|
17
|
+
UUJHUllEYjNKbk1CNFhEVEV6TURVeU1qRXlOVGswTjFvWERURTBNRFV5Ck1q
|
18
|
+
RXlOVGswTjFvd1Z6RVJNQThHQTFVRUF3d0ljblZpZVdkbGJYTXhHREFXQmdv
|
19
|
+
SmtpYUprL0lzWkFFWkZnaGoKYUhKcGMyeGxaVEVUTUJFR0NnbVNKb21UOGl4
|
20
|
+
a0FSa1dBMlJvY3pFVE1CRUdDZ21TSm9tVDhpeGtBUmtXQTI5eQpaekNDQVNJ
|
21
|
+
d0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFOY1ByeDhC
|
22
|
+
WmlXSVI5eFdXRzhJCnRxUjUzOHRTMXQrVUo0RlpGbCsxdnJ0VTlUaXVXWDNW
|
23
|
+
ajM3VHdVcGEyZkZremlLMG41S3VwVlRoeUVoY2VtNW0KT0dSanZnclJGYldR
|
24
|
+
SlNTc2NJS09wd3FVUkhWS1JwVjlnVnovSG56azhTK3hvdFVSMUJ1bzNVZ3Ir
|
25
|
+
STFqSGV3RApDZ3IreSt6Z1pidGp0SHNKdHN1dWprT2NQaEVqalVpbmo2OEw5
|
26
|
+
Rno5QmRlSlF0K0lhY2p3QXpVTGl4NmpXQ2h0ClVjK2crMHo4RXNyeWNhMkc2
|
27
|
+
STFHc3JnWDZXSHc4ZHlreVFEVDlkQ3RTMmZsQ093U0MxUjBLNVQveEhXNTRm
|
28
|
+
KzUKd2N3OG1tNTNLTE5lK3RtZ1ZDNlpIeU1FK3FKc0JuUDZ1eEYwYVRFbkdB
|
29
|
+
L2pEQlFEaFFOVEYwWlAvYWJ6eVRzTAp6alVDQXdFQUFhTTVNRGN3Q1FZRFZS
|
30
|
+
MFRCQUl3QURBTEJnTlZIUThFQkFNQ0JMQXdIUVlEVlIwT0JCWUVGTzh3Cith
|
31
|
+
ZVA3VDZrVkpibENnNmV1c09JSTlEZk1BMEdDU3FHU0liM0RRRUJCUVVBQTRJ
|
32
|
+
QkFRQkNReVJKTFhzQm8yRnkKOFc2ZS9XNFJlbVFScmxBdzlESzVPNlU3MUp0
|
33
|
+
ZWRWb2Iyb3ErT2Irem1TK1BpZkUyK0wrM1JpSjJINlZUbE96aQp4K0EwNjFN
|
34
|
+
VVhoR3JhcVZxNEoyRkM4a3Q0RVF5d0FEMFAwVGE1R1UyNENHU0YwOFkzR2tK
|
35
|
+
eTFTYTRYcVRDMllDCm81MXM3SlArdGtDQ3RwVllTZHpKaFRsbGllUkFXQnBH
|
36
|
+
VjFkdGFvZVVLRTZ0WVBNQmtvc3hTUmNWR2N6ay9TYzMKN2VRQ3BleFl5OUps
|
37
|
+
VUJJOXUzQnFJWTlFK2wrTVNuOGloWFNQbXlLMERncmhhQ3Urdm9hU0ZWT1g2
|
38
|
+
WStCNXFibwpqTFhNUXUyWmdJU1l3WE5qTmJHVkhlaHV0ODJVN1U5b2lIb1dj
|
39
|
+
ck9HYXphUlVtR085VFhQK2FKTEgwZ3cyZGNLCkFmTWdsWFBpCi0tLS0tRU5E
|
40
|
+
IENFUlRJRklDQVRFLS0tLS0K
|
41
|
+
date: 2013-06-02 00:00:00.000000000 Z
|
42
|
+
dependencies:
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: json
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 1.4.3
|
51
|
+
type: :runtime
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: 1.4.3
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: sqlite3
|
61
|
+
requirement: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 1.3.3
|
67
|
+
type: :runtime
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 1.3.3
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: structformatter
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.0.1
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ~>
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 0.0.1
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: bundler
|
93
|
+
requirement: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ~>
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '1.3'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ~>
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '1.3'
|
107
|
+
- !ruby/object:Gem::Dependency
|
108
|
+
name: rake
|
109
|
+
requirement: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
type: :development
|
116
|
+
prerelease: false
|
117
|
+
version_requirements: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
description: This provides interfaces to various passive DNS databases to do the query
|
124
|
+
and to normalize the responses. The query tool also allows for recursive queries,
|
125
|
+
using an SQLite3 database to keep state.
|
126
|
+
email:
|
127
|
+
- rubygems@chrislee.dhs.org
|
128
|
+
executables:
|
129
|
+
- pdnstool
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- .gitignore
|
134
|
+
- Gemfile
|
135
|
+
- LICENSE.txt
|
136
|
+
- README.md
|
137
|
+
- Rakefile
|
138
|
+
- bin/pdnstool
|
139
|
+
- lib/passivedns/client.rb
|
140
|
+
- lib/passivedns/client/bfk.rb
|
141
|
+
- lib/passivedns/client/certee.rb
|
142
|
+
- lib/passivedns/client/dnsparse.rb
|
143
|
+
- lib/passivedns/client/isc.rb
|
144
|
+
- lib/passivedns/client/state.rb
|
145
|
+
- lib/passivedns/client/version.rb
|
146
|
+
- lib/passivedns/client/virustotal.rb
|
147
|
+
- passivedns-client.gemspec
|
148
|
+
- test/helper.rb
|
149
|
+
- test/test_passivedns-client.rb
|
150
|
+
homepage: https://github.com/chrislee35/passivedns-client
|
151
|
+
licenses:
|
152
|
+
- MIT
|
153
|
+
post_install_message:
|
154
|
+
rdoc_options: []
|
155
|
+
require_paths:
|
156
|
+
- lib
|
157
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
158
|
+
none: false
|
159
|
+
requirements:
|
160
|
+
- - ! '>='
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
|
+
none: false
|
165
|
+
requirements:
|
166
|
+
- - ! '>='
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
requirements: []
|
170
|
+
rubyforge_project:
|
171
|
+
rubygems_version: 1.8.25
|
172
|
+
signing_key:
|
173
|
+
specification_version: 3
|
174
|
+
summary: Query passive DNS databases
|
175
|
+
test_files:
|
176
|
+
- test/helper.rb
|
177
|
+
- test/test_passivedns-client.rb
|
metadata.gz.sig
ADDED
Binary file
|