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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 06d7ff1c185b1d52a22829c78ac3f393527f4d61
4
- data.tar.gz: b6fb23b393f3d87948da754ce6c4a69476fb280f
3
+ metadata.gz: 41a0a59329a330d5830052e03a99a39f9ce5a819
4
+ data.tar.gz: 361993fddb9ef65fef2f4721dba03257b818dddd
5
5
  SHA512:
6
- metadata.gz: ade09d0cbf82ea14e6ea216b228e9b1434d5cac2cfc3ab54145ca7be77142880f0fedc220e77839422f9e38976752fbdf6ffdf68fd3ecfde61792ea91d8bc2cd
7
- data.tar.gz: 08d846c8d67746c2864b627346641079c8daba8efe151334ff284b5bc7d2922deac58628d294104571f32481e67759903d13cdc8e1f916b050625c4f8bd9b94c
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
- #if __FILE__ == $0
8
- def pdnslookup(state,pdnsclient,recursedepth=1,wait=0,debug=false)
9
- puts "pdnslookup: #{state.level} #{recursedepth}" if debug
10
- level = 0
11
- while level < recursedepth
12
- puts "pdnslookup: #{level} < #{recursedepth}" if debug
13
- state.each_query(recursedepth) do |q|
14
- rv = pdnsclient.query(q)
15
- if rv
16
- rv.each do |r|
17
- if ["A","AAAA","NS","CNAME","PTR"].index(r.rrtype)
18
- puts "pdnslookup: #{r.to_s}" if debug
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
- sleep wait if level < recursedepth
21
+ else
22
+ state.update_query(rv,'failed')
26
23
  end
27
- level += 1
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
- def usage
53
- puts "Usage: #{$0} [-a|-b|-e|-d|-i|-V] [-c|-x|-y|-j|-t] [-s <sep>] [-f <file>] [-r#|-w#|-l] <ip|domain|cidr>"
54
- puts " -a uses all of the available passive dns databases"
55
- puts " -b only use BFK"
56
- puts " -e only use CERT-EE"
57
- puts " -d only use DNSParse (default)"
58
- puts " -i only use DNSDB (formerly ISC)"
59
- puts " -V only use VirusTotal"
60
- puts ""
61
- puts " -g outputs a link-nodal GDF visualization definition"
62
- puts " -v outputs a link-nodal graphviz visualization definition"
63
- puts " -m output a link-nodal graphml visualization definition"
64
- puts " -c outputs CSV"
65
- puts " -x outputs XML"
66
- puts " -y outputs YAML"
67
- puts " -j outputs JSON"
68
- puts " -t outputs ASCII text (default)"
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
- opts = GetoptLong.new(
79
- [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
80
- [ '--debug', '-l', GetoptLong::NO_ARGUMENT ],
81
- [ '--all', '-a', GetoptLong::NO_ARGUMENT ],
82
- [ '--bfk', '-b', GetoptLong::NO_ARGUMENT ],
83
- [ '--dnsparse', '-d', GetoptLong::NO_ARGUMENT ],
84
- [ '--certee', '-e', GetoptLong::NO_ARGUMENT ],
85
- [ '--isc', '-i', GetoptLong::NO_ARGUMENT ],
86
- [ '--virustotal', '-V', GetoptLong::NO_ARGUMENT ],
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
- opts.each do |opt, arg|
114
- case opt
115
- when '--help'
116
- usage
117
- when '--debug'
118
- debug = true
119
- $stderr.puts "Using proxy settings: http_proxy=#{ENV['http_proxy']}, https_proxy=#{ENV['https_proxy']}"
120
- when '--all'
121
- pdnsdbs << "bfk"
122
- pdnsdbs << "certee"
123
- pdnsdbs << "dnsparse"
124
- pdnsdbs << "dnsdb"
125
- pdnsdbs << "virustotal"
126
- when '--bfk'
127
- pdnsdbs << "bfk"
128
- when '--certee'
129
- pdnsdbs << "certee"
130
- when '--dnsparse'
131
- pdnsdbs << "dnsparse"
132
- when '--isc'
133
- pdnsdbs << "dnsdb"
134
- when '--virustotal'
135
- pdnsdbs << "virustotal"
136
- when '--gdf'
137
- format = 'gdf'
138
- when '--graphviz'
139
- format = 'graphviz'
140
- when '--graphml'
141
- format = 'graphml'
142
- when '--csv'
143
- format = 'text'
144
- sep = ','
145
- when '--yaml'
146
- format = 'yaml'
147
- when '--xml'
148
- format = 'xml'
149
- when '--json'
150
- format = 'json'
151
- when '--text'
152
- format = 'text'
153
- when '--sep'
154
- sep = arg
155
- when '--recurse'
156
- recursedepth = arg.to_i
157
- if recursedepth > 3
158
- $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)"
159
- sleep 60
160
- end
161
- when '--wait'
162
- wait = arg.to_i
163
- when '--sqlite3'
164
- sqlitedb = arg
165
- else
166
- usage
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
- end
169
-
170
- if pdnsdbs.length == 0
171
- pdnsdbs << "dnsparse"
172
- end
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
- state = PassiveDNS::PDNSToolState.new
167
+ usage
184
168
  end
185
- state.debug = true if debug
186
-
187
- pdnsclient = PassiveDNS::Client.new(pdnsdbs)
188
- pdnsclient.debug = debug
189
-
190
- if ARGV.length > 0
191
- ARGV.each do |arg|
192
- state.add_query(arg,'pending',0)
193
- end
194
- else
195
- $stdin.each_line do |l|
196
- state.add_query(l.chomp,'pending',0)
197
- end
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
- pdnslookup(state,pdnsclient,recursedepth,wait,debug)
200
- printresults(state,format,sep)
201
- #end
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
- recs
34
- end
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
- request = Net::HTTP::Get.new(url.path)
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
@@ -1,5 +1,5 @@
1
1
  module PassiveDNS
2
2
  class Client
3
- VERSION = "1.1.1"
3
+ VERSION = "1.3.0"
4
4
  end
5
5
  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}"
@@ -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','dnsparse','dnsdb','virustotal'])
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
- when 'dnsparse'
27
- @pdnsdbs << PassiveDNS::DNSParse.new
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
 
@@ -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 test_query_BFK
74
- rows = PassiveDNS::BFK.new.lookup("example.org")
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 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")
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 test_query_DNSDB
101
- rows = PassiveDNS::DNSDB.new.lookup("example.org")
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 test_query_VirusTotal
110
- rows = PassiveDNS::VirusTotal.new.lookup("sim.cert.ee")
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.1.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.0.3
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�@!� n v�=K�`Ȩ0�'����А���-"Ê�R�t�]M�i�m��2g�L���澠� rz�ݲ���{���xޢ<I4��P�B�K��"R������
metadata.gz.sig DELETED
@@ -1,2 +0,0 @@
1
- ��$Y��]B�Z�y�d��� ���Z��Uy�H(�D������d4肩���j��߄l�s�:�L"�Bq���`D�������۰��
2
- �𧞇�T_���~k��`�pxc���'��ZjP~c�!E }վMS�A���H&�m�F�� �h�=ig�j�X���xd����-0_Ƣ;a_�?Z��pX�t��2�u�j�@l 2u�x�d�(�(@R����1�Bܳ�81B��C����M���8� �S��