tor_extend 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Change.log +12 -0
- data/ReadME.txt +190 -0
- data/doc/ReadME_txt.html +301 -0
- data/doc/Tor.html +140 -0
- data/doc/Tor/Bridge.html +145 -0
- data/doc/Tor/CachedDesc.html +472 -0
- data/doc/Tor/Constants.html +185 -0
- data/doc/Tor/Router.html +146 -0
- data/doc/Tor/StatsObj.html +1209 -0
- data/doc/Tor/TController.html +1111 -0
- data/doc/created.rid +7 -0
- data/doc/images/add.png +0 -0
- data/doc/images/brick.png +0 -0
- data/doc/images/brick_link.png +0 -0
- data/doc/images/bug.png +0 -0
- data/doc/images/bullet_black.png +0 -0
- data/doc/images/bullet_toggle_minus.png +0 -0
- data/doc/images/bullet_toggle_plus.png +0 -0
- data/doc/images/date.png +0 -0
- data/doc/images/delete.png +0 -0
- data/doc/images/find.png +0 -0
- data/doc/images/loadingAnimation.gif +0 -0
- data/doc/images/macFFBgHack.png +0 -0
- data/doc/images/package.png +0 -0
- data/doc/images/page_green.png +0 -0
- data/doc/images/page_white_text.png +0 -0
- data/doc/images/page_white_width.png +0 -0
- data/doc/images/plugin.png +0 -0
- data/doc/images/ruby.png +0 -0
- data/doc/images/tag_blue.png +0 -0
- data/doc/images/tag_green.png +0 -0
- data/doc/images/transparent.png +0 -0
- data/doc/images/wrench.png +0 -0
- data/doc/images/wrench_orange.png +0 -0
- data/doc/images/zoom.png +0 -0
- data/doc/index.html +90 -0
- data/doc/js/darkfish.js +153 -0
- data/doc/js/jquery.js +18 -0
- data/doc/js/navigation.js +142 -0
- data/doc/js/search.js +94 -0
- data/doc/js/search_index.js +1 -0
- data/doc/js/searcher.js +228 -0
- data/doc/lib/constants_rb.html +96 -0
- data/doc/lib/httpmod_rb.html +95 -0
- data/doc/lib/tcontroller_rb.html +93 -0
- data/doc/lib/tor_extend_rb.html +97 -0
- data/doc/lib/tstats_rb.html +93 -0
- data/doc/rdoc.css +543 -0
- data/doc/table_of_contents.html +159 -0
- data/lib/constants.rb +106 -0
- data/lib/httpmod.rb +89 -0
- data/lib/tcontroller.rb +475 -0
- data/lib/tor_extend.rb +189 -0
- data/lib/tstats.rb +514 -0
- data/tor_extend.gemspec +26 -0
- metadata +138 -0
data/lib/tor_extend.rb
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
# tor_extend library
|
2
|
+
# Author: Oluwaseun Remi-Omosowon (mailto:remi-omosowon@et.esiea-ouest.fr)
|
3
|
+
# Copyright: ...2011
|
4
|
+
|
5
|
+
|
6
|
+
# Tor includes the TController class, which inherits the methods from Bendiken's page[http://cypherpunk.rubyforge.org/tor/] Tor::Controller class and extends it with more methods.
|
7
|
+
# You are responsible for how you use the code. See the Unlicence in Bendiken's tor-ruby gem.
|
8
|
+
#
|
9
|
+
module Tor
|
10
|
+
require 'tor'
|
11
|
+
require 'active_record'
|
12
|
+
require 'builder'
|
13
|
+
require 'geoip'
|
14
|
+
require 'net/https'
|
15
|
+
|
16
|
+
# Tor::Constants module is loaded from constants.rb and other classes from seperate files
|
17
|
+
autoload :Constants, 'constants'
|
18
|
+
require 'tcontroller'
|
19
|
+
require 'tstats'
|
20
|
+
require 'httpmod'
|
21
|
+
|
22
|
+
# Tor::Router is a class for the active record database holding the ip-addresses, platform, fingerprint, country, latitude,longitude.
|
23
|
+
#
|
24
|
+
# <b>Transforming IP address to fingerprint</b>
|
25
|
+
# Tor::Router.where(:ipaddr=>"ipaddr")[0].fingerprint
|
26
|
+
#
|
27
|
+
class Router < ActiveRecord::Base
|
28
|
+
end
|
29
|
+
|
30
|
+
# Tor::Bridge is a class for the active record database holding the ip-addresses and port for the bridges discovered using the Tor::TController.getbridges.
|
31
|
+
#
|
32
|
+
# <b>Show all Bridges in the database</b>
|
33
|
+
# Tor::Bridge.all
|
34
|
+
#
|
35
|
+
class Bridge < ActiveRecord::Base
|
36
|
+
end
|
37
|
+
|
38
|
+
# Tor::CachedDesc is a class used to read cached descriptors into a database. The ip address, fingerprint, platform, country, latitude and longitude.
|
39
|
+
#
|
40
|
+
# @example Create database and read cached desciptor into it
|
41
|
+
# cached_descriptor = Tor::CachedDesc.new
|
42
|
+
# Tor::CachedDesc.dbconnect
|
43
|
+
# Tor::CachedDesc.dbconnect( { :adapter => "sqlite3",:database => "db.sqlite3"} )
|
44
|
+
# Tor::CachedDesc.readall("cached_descriptor_filename")
|
45
|
+
# Tor::CachedDesc.ors
|
46
|
+
# Tor::CachedDesc.ors.all
|
47
|
+
#
|
48
|
+
class CachedDesc
|
49
|
+
|
50
|
+
|
51
|
+
# This initialises the stat attribute of the CachedDesc class that can be used to get data from Tor::Router
|
52
|
+
#
|
53
|
+
def initialize(geoip_path)
|
54
|
+
@stat = StatsObj.new
|
55
|
+
# Tor::CachedDesc#geoipdb is an instance of GeoIP with the active database
|
56
|
+
@geoipdb = GeoIP.new(geoip_path[0])
|
57
|
+
# Tor::CachedDesc#geoipdb2 acts as a backup if records are not present in Tor::CachedDesc#geoipdb
|
58
|
+
@geoipdb2 = GeoIP.new(geoip_path[1])
|
59
|
+
end
|
60
|
+
|
61
|
+
# This initialises the stat attribute of the CachedDesc class that can be used to get data from Tor::Router
|
62
|
+
# It returns a Tor::StatsObj
|
63
|
+
#
|
64
|
+
def stat
|
65
|
+
@stat
|
66
|
+
end
|
67
|
+
|
68
|
+
# Tor::dbconnect() method connects using the optional database config passed as argument. It creates an sqlite3 file by default called db.sqlite3, and a table called routers.
|
69
|
+
# A table called routers is created in an existing database if it does not already exist.
|
70
|
+
#
|
71
|
+
# <b>Connecting to a database</b>
|
72
|
+
# Tor::CachedDesc.dbconnect
|
73
|
+
# Tor::CachedDesc.dbconnect( {:adapter => "sqlite3",:database => "db_name_here"} )
|
74
|
+
#
|
75
|
+
def dbconnect(*dbconfig)
|
76
|
+
dbconfig = [{:adapter => "sqlite3",:database => "db.sqlite3"}] if dbconfig.empty?
|
77
|
+
ActiveRecord::Base.establish_connection(dbconfig[0])
|
78
|
+
if !ActiveRecord::Base.connection.table_exists?('routers')
|
79
|
+
ActiveRecord::Schema.define do
|
80
|
+
create_table :routers do |t|
|
81
|
+
t.string :ipaddr
|
82
|
+
t.text :platform
|
83
|
+
t.string :fingerprint
|
84
|
+
t.string :city
|
85
|
+
t.string :country
|
86
|
+
t.string :country_code
|
87
|
+
t.string :continent
|
88
|
+
t.decimal :lat
|
89
|
+
t.decimal :lng
|
90
|
+
t.datetime :published_at
|
91
|
+
t.timestamps
|
92
|
+
end
|
93
|
+
create_table :bridges do |t|
|
94
|
+
t.string :ipaddr
|
95
|
+
t.integer :port
|
96
|
+
t.decimal :lat
|
97
|
+
t.decimal :lng
|
98
|
+
t.timestamps
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns the Router database class. Allows interation with the database as an instance of Active::Base if you know what you're doing.
|
105
|
+
#
|
106
|
+
# Display on ORs in the database.
|
107
|
+
# Cacheddec.or.all
|
108
|
+
#
|
109
|
+
def ors
|
110
|
+
Router
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
# This returns the Geoip record from one of the database files used in Tor::CachedDesc.
|
115
|
+
#
|
116
|
+
def get_geoiprecord(ipaddr)
|
117
|
+
or_geoip=@geoipdb.city(ipaddr)
|
118
|
+
or_geoip=@geoipdb2.city(ipaddr) if or_geoip==nil
|
119
|
+
or_geoip
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
# Read a file and put all the ralated information into the Tor::Router database.
|
124
|
+
#
|
125
|
+
def readall(filename)
|
126
|
+
cacheddesc = File.new(filename,'r:ISO-8859-1')
|
127
|
+
loopbreaker=false
|
128
|
+
|
129
|
+
until loopbreaker==true
|
130
|
+
fileline = cacheddesc.gets
|
131
|
+
fileline.chomp! if fileline != nil
|
132
|
+
case fileline
|
133
|
+
when /^published /
|
134
|
+
time_published = Time.parse fileline.sub("published ",'') # downloaded_at
|
135
|
+
when /^router /
|
136
|
+
or_ipaddr = fileline.scan(/\d+\.\d+\.\d+.\d+/)[0]
|
137
|
+
when /^platform /
|
138
|
+
case fileline
|
139
|
+
when /Windows/i
|
140
|
+
osplatform ="WINDOWS"
|
141
|
+
when /SunOS/i
|
142
|
+
osplatform ="SUN"
|
143
|
+
when /Linux/i,/Ubuntu/i
|
144
|
+
osplatform ="LINUX"
|
145
|
+
when /Unix/i, /BSD/i,/DragonFly/i,/Darwin/i
|
146
|
+
osplatform ="UNIX"
|
147
|
+
else
|
148
|
+
osplatform ="OTHER"
|
149
|
+
end
|
150
|
+
|
151
|
+
when /^opt fingerprint /
|
152
|
+
or_fingerprint=fileline.split("opt fingerprint ")[1].split.join # the fingerprint
|
153
|
+
# puts or_ipaddr
|
154
|
+
or_geoip=@geoipdb.city(or_ipaddr)
|
155
|
+
or_geoip=@geoipdb2.city(or_ipaddr) if or_geoip==nil # noticed that the august database returns nil for an address like 208.64.240.182, and smaller in size than July
|
156
|
+
if or_geoip.nil?
|
157
|
+
puts "#{or_ipaddr} not found in both geoip databases, try get an updated one, or older one."
|
158
|
+
else
|
159
|
+
or_city = or_geoip.city_name
|
160
|
+
or_country = or_geoip.country_name
|
161
|
+
orcountry_code = or_geoip.country_code2
|
162
|
+
orcontinent = or_geoip.continent_code
|
163
|
+
lng = or_geoip.longitude.to_f
|
164
|
+
lat = or_geoip.latitude.to_f
|
165
|
+
tmpr = Router.where(:ipaddr=>or_ipaddr).first
|
166
|
+
if tmpr.nil?
|
167
|
+
Router.create(:ipaddr=>or_ipaddr, :fingerprint=>or_fingerprint, :lat=>lat, :lng=>lng, :platform=>osplatform, :city=>or_city,
|
168
|
+
:country=>or_country, :continent=>orcontinent,:country_code=>orcountry_code,
|
169
|
+
:published_at=>time_published)
|
170
|
+
elsif time_published > tmpr.published_at
|
171
|
+
tmpr.fingerprint = or_fingerprint # Update fingerprint - Make sure you read newer files last
|
172
|
+
tmpr.lat = lat
|
173
|
+
tmpr.lng = lng
|
174
|
+
tmpr.platform=osplatform
|
175
|
+
tmpr.country=or_country
|
176
|
+
tmpr.save
|
177
|
+
end
|
178
|
+
end # if orgeoip.nil?
|
179
|
+
when nil
|
180
|
+
# gets returns nil for EOF
|
181
|
+
loopbreaker=true
|
182
|
+
cacheddesc.close
|
183
|
+
end
|
184
|
+
end # end of read file until eof
|
185
|
+
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
end # end of module
|
data/lib/tstats.rb
ADDED
@@ -0,0 +1,514 @@
|
|
1
|
+
module Tor
|
2
|
+
|
3
|
+
# This class can be used to obtain a variety of statistics or data from Tor::Router.
|
4
|
+
# The same user have multiple IP addresses on different days, but the fingerprint might not change, especially not withing a month. Use uniq stats when available.
|
5
|
+
#
|
6
|
+
class StatsObj
|
7
|
+
|
8
|
+
# This returns a list of all countries that have contributed to the OR IP addresses in Tor::Router
|
9
|
+
# It can return only the those that have contributed to a particular platform
|
10
|
+
#
|
11
|
+
# @example Get Countries the that use Unix
|
12
|
+
# Tor::StatsObj.country_list
|
13
|
+
# Tor::StatsObj.country_list("UNIX")
|
14
|
+
# Tor::StatsObj.country_list( ["UNIX", "LINUX"] )
|
15
|
+
#
|
16
|
+
def country_list(*platform)
|
17
|
+
tmpresult = (platform.empty? or platform == ["ALL"]) ? Router.all : Router.where(:platform=>platform)
|
18
|
+
tmpresult.group_by{|c| c.country_code}.keys
|
19
|
+
end
|
20
|
+
|
21
|
+
# This returns a list of all continents that have contributed to the OR IP addresses in Tor::Router
|
22
|
+
# It can return only the those that have contributed to a particular platform
|
23
|
+
#
|
24
|
+
# @example Get Countries the that use Unix
|
25
|
+
# Tor::StatsObj.continent_list
|
26
|
+
# Tor::StatsObj.continent_list("UNIX")
|
27
|
+
# Tor::StatsObj.continent_list( ["UNIX", "LINUX"] )
|
28
|
+
#
|
29
|
+
def continent_list(*platform)
|
30
|
+
tmpresult = (platform.empty? or platform == ["ALL"]) ? Router.all : Router.where(:platform=>platform)
|
31
|
+
tmpresult.group_by{|c| c.continent}.keys
|
32
|
+
end
|
33
|
+
|
34
|
+
# This returns the number of OR IP addresses from the country with the code used as input (and optionally platform parameter).
|
35
|
+
#
|
36
|
+
# @example Get number of OR IP addr from continents
|
37
|
+
# Tor::StatsObj.country_count("FR")
|
38
|
+
# Tor::StatsObj.country_count("FR","UNIX")
|
39
|
+
# Tor::StatsObj.country_count( ["FR","DE"] ,[ "UNIX", "LINUX" ] )
|
40
|
+
#
|
41
|
+
def country_count(code,*platform)
|
42
|
+
rslt = (platform.empty? or platform == ["ALL"] ) ?
|
43
|
+
Router.where(:country_code=>code) :
|
44
|
+
Router.where(:country_code=>code,:platform=>platform)
|
45
|
+
rslt.count
|
46
|
+
end
|
47
|
+
|
48
|
+
# This returns the total number of uniq identities found in the database.
|
49
|
+
#
|
50
|
+
# <b>Get total number of routers in countries<b>.
|
51
|
+
# Tor::StatsObj.country_count_uniq(["GB","FR"])
|
52
|
+
# Tor::StatsObj.country_count_uniq("FR","WINDOWS")
|
53
|
+
# Tor::StatsObj.country_count_uniq(["GB","FR",DE],["UNIX",LINUX"] )
|
54
|
+
#
|
55
|
+
def country_count_uniq(countryfilter,*platform)
|
56
|
+
get_uniqid(countryfilter,*platform).count
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# This returns the number of OR IP addresses from the continent with the code used as input (and optionally platform parameter).
|
61
|
+
#
|
62
|
+
# @example Get number of OR IP addr from continents
|
63
|
+
# Tor::StatsObj.continent_count("EU")
|
64
|
+
# Tor::StatsObj.continent_count("NA","UNIX")
|
65
|
+
# Tor::StatsObj.continent_count( ["EU","NA","SA"] ,[ "UNIX", "LINUX" ] )
|
66
|
+
#
|
67
|
+
def continent_count(code,*platform)
|
68
|
+
rslt = (platform.empty? or platform == ["ALL"] ) ? Router.where(:continent=>code) : Router.where(:continent=>code, :platform=>platform)
|
69
|
+
rslt.count # continent code "AF","EU","AS","NA","SA","OC"
|
70
|
+
end
|
71
|
+
|
72
|
+
# This returns the number of OR IP addresses from the continent with the code used as input (and optionally platform parameter).
|
73
|
+
#
|
74
|
+
# @example Get number of OR IP addr from continents
|
75
|
+
# Tor::StatsObj.continent_count("EU")
|
76
|
+
# Tor::StatsObj.continent_count("NA","UNIX")
|
77
|
+
# Tor::StatsObj.continent_count( ["EU","NA","SA"] ,[ "UNIX", "LINUX" ] )
|
78
|
+
#
|
79
|
+
def continent_count_uniq(code,*platform)
|
80
|
+
rslt = (platform.empty? or platform == ["ALL"] ) ?
|
81
|
+
Router.where(:id=> get_uniqid(country_list, *platform), :continent=>code) :
|
82
|
+
Router.where(:id=> get_uniqid(country_list, *platform), :continent=>code, :platform=>platform)
|
83
|
+
rslt.count # continent code "AF","EU","AS","NA","SA","OC"
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# It takes an array of country codes as input, and produces a hash with the country codes as keys and the total number of ors from the country as value.
|
88
|
+
# An optional platform can also be set.
|
89
|
+
#
|
90
|
+
# @example Get country statistics
|
91
|
+
# Tor::StatsObj.country_stat(["EU","NA","SA"]) => {"EU" => country,total, .... "SA" => country,total }
|
92
|
+
# Tor::StatsObj.country_stat(["EU","NA","SA"], "LINUX")
|
93
|
+
# Tor::StatsObj.country_stat( Tor::StatsObj.country_list )
|
94
|
+
# Tor::StatsObj.country_stat( Tor::StatsObj.country_list(platform) )
|
95
|
+
#
|
96
|
+
# Note: Results of Tor::StatsObj.country_list can be used as argument for this Tor::StatsObj.country_stat.
|
97
|
+
#
|
98
|
+
def country_stat(countrycodes,*platform)
|
99
|
+
country_count_hash={}
|
100
|
+
if countrycodes.class==String
|
101
|
+
country_count_hash[countrycodes] = country_count(countrycodes,*platform)
|
102
|
+
else
|
103
|
+
countrycodes.each{|each_country| country_count_hash[each_country] = country_count(each_country,*platform)}
|
104
|
+
end
|
105
|
+
country_count_hash
|
106
|
+
end
|
107
|
+
|
108
|
+
# This retuns an array of all OR IP addresses from the Tor::Router using a filter of countries and optional platform parameter.
|
109
|
+
#
|
110
|
+
# @example Get all OR IP addresses from France
|
111
|
+
# Tor::StatsObj.country_getip("FR")
|
112
|
+
# Tor::StatsObj.country_getip(["FR",GB"], "WINDOWS")
|
113
|
+
# Tor::StatsObj.country_getip(["FR",GB"], ["WINDOWS", "LINUX"] )
|
114
|
+
#
|
115
|
+
def country_getip(country_filter,*platform)
|
116
|
+
if platform.empty? or platform == ["ALL"]
|
117
|
+
onionr = Router.where(:country_code=>country_filter)
|
118
|
+
else
|
119
|
+
onionr=Router.where(:country_code=>country_filter,:platform=>platform )
|
120
|
+
end
|
121
|
+
onion_ipaddr=onionr.collect{|each_country| each_country.ipaddr}
|
122
|
+
end
|
123
|
+
|
124
|
+
# This retuns an array of all OR fingerprints from the Tor::Router using a filter of countries and optional platform parameter.
|
125
|
+
#
|
126
|
+
# @example Get all OR IP fingerprints from France
|
127
|
+
# Tor::StatsObj.country_getingerprint("FR")
|
128
|
+
# Tor::StatsObj.country_getingerprint(["FR",GB"], "WINDOWS")
|
129
|
+
# Tor::StatsObj.country_getingerprint(["FR",GB"], ["WINDOWS", "LINUX"] )
|
130
|
+
#
|
131
|
+
def country_getfingerprint(country_filter,*platform)
|
132
|
+
if platform.empty? or platform == ["ALL"]
|
133
|
+
onionr = Router.where(:country_code=>country_filter)
|
134
|
+
else
|
135
|
+
onionr=Router.where(:country_code=>country_filter,:platform=>platform )
|
136
|
+
end
|
137
|
+
onion_ipaddr = onionr.collect{|each_country| each_country.fingerprint}
|
138
|
+
end
|
139
|
+
|
140
|
+
# This retuns an array of all OR fingerprints from Tor::Router using a filter of continents and optional platform parameter.
|
141
|
+
#
|
142
|
+
# @example Get all OR IP fingerprints from France
|
143
|
+
# Tor::StatsObj.continent_getfingerprint("EU")
|
144
|
+
# Tor::StatsObj.continent_getfingerprint(["AF",EU"], "WINDOWS")
|
145
|
+
# Tor::StatsObj.continent_getfingerprint(["NA","SA"], ["WINDOWS", "LINUX"] )
|
146
|
+
#
|
147
|
+
def continent_getfingerprint(continent_filter,*platform)
|
148
|
+
if platform.empty? or platform == ["ALL"]
|
149
|
+
onionr = Router.where(:continent=>continent_filter,:id=>get_uniqid(countryfilter,*platform))
|
150
|
+
else
|
151
|
+
onionr=Router.where(:continent=>continent_filter,:platform=>platform ,:id=>get_uniqid(countryfilter,*platform))
|
152
|
+
end
|
153
|
+
onion_ipaddr = onionr.collect{|each_country| each_country.fingerprint}
|
154
|
+
end
|
155
|
+
|
156
|
+
# It takes an array of country codes as input, and produces a hash with the country codes as keys and the total number of unique ors from the country as value.
|
157
|
+
# An optional platform can also be set.
|
158
|
+
#
|
159
|
+
# @example Get country statistics
|
160
|
+
# Tor::StatsObj.country_stat_uniq(["FR","GB","US"]) => {"FR" => total, .... "US" => total }
|
161
|
+
# Tor::StatsObj.country_stat_uniq([DE","FR"], "LINUX")
|
162
|
+
# Tor::StatsObj.country_stat_uniq( Tor::StatsObj.country_list )
|
163
|
+
# Tor::StatsObj.country_stat_uniq( Tor::StatsObj.country_list(platform) )
|
164
|
+
#
|
165
|
+
# Note: Results of Tor::StatsObj.country_list can be used as argument for this Tor::StatsObj.country_stat_uniq.
|
166
|
+
#
|
167
|
+
def country_stat_uniq(countrycodes,*platform)
|
168
|
+
# get_uniqid can be used for this, but this that will involve more calls to Tor::Router than necessary
|
169
|
+
country_count_hash={}
|
170
|
+
if countrycodes.class==String
|
171
|
+
country_count_hash[countrycodes] = country_count_uniq(countrycodes,*platform)
|
172
|
+
else
|
173
|
+
countrycodes.each{|each_country|
|
174
|
+
country_count_hash[each_country] = country_count_uniq(each_country,*platform) }
|
175
|
+
end
|
176
|
+
country_count_hash
|
177
|
+
end
|
178
|
+
|
179
|
+
# It takes an array of continent codes as input, and produces a hash with the continent codes as keys and the total number of ors from the country as value
|
180
|
+
#
|
181
|
+
# @example Get continents statistics
|
182
|
+
# Tor::StatsObj.continent_stat(["EU","NA","SA"]) => {"EU" => total, .... "SA" => total }
|
183
|
+
# Tor::StatsObj.continent_stat(["EU","NA","SA"], "LINUX")
|
184
|
+
# Tor::StatsObj.continent_stat( Tor::StatsObj.country_list )
|
185
|
+
#
|
186
|
+
# Note: Results of Tor::StatsObj.continent_list can be used as argument for this Tor::StatsObj.continent_stat.
|
187
|
+
#
|
188
|
+
def continent_stat(allcontinents,*platform)
|
189
|
+
continent_count_hash={}
|
190
|
+
if allcontinents.class==String
|
191
|
+
continent_count_hash[allcontinents] = continent_count(allcontinents,*platform)
|
192
|
+
else
|
193
|
+
allcontinents.each{|each_continent|
|
194
|
+
continent_count_hash[each_continent] = continent_count(each_continent,*platform)
|
195
|
+
}
|
196
|
+
end
|
197
|
+
continent_count_hash
|
198
|
+
end
|
199
|
+
|
200
|
+
# It takes an array of continent codes as input, and produces a hash with the continent codes as keys and the total number of ors from the country as value
|
201
|
+
#
|
202
|
+
# @example Get continents statistics
|
203
|
+
# Tor::StatsObj.continent_stat_uniq(["EU","NA","SA"]) => {"EU" => total, .... "SA" => total }
|
204
|
+
# Tor::StatsObj.continent_stat_uniq(["EU","NA","SA"], "LINUX")
|
205
|
+
# Tor::StatsObj.continent_stat_uniq( Tor::StatsObj.country_list )
|
206
|
+
#
|
207
|
+
# Note: Results of Tor::StatsObj.continent_list can be used as argument for this Tor::StatsObj.continent_stat_uniq.
|
208
|
+
#
|
209
|
+
def continent_stat_uniq(allcontinents,*platform)
|
210
|
+
continent_count_hash={}
|
211
|
+
if allcontinents.class==String
|
212
|
+
continent_count_hash[allcontinents] = continent_count_uniq(allcontinents,*platform)
|
213
|
+
else
|
214
|
+
allcontinents.each{|each_continent|
|
215
|
+
continent_count_hash[each_continent] = continent_count_uniq(each_continent,*platform)
|
216
|
+
}
|
217
|
+
end
|
218
|
+
continent_count_hash
|
219
|
+
end
|
220
|
+
|
221
|
+
# This returns the top n-countries. An optional platform parameter can be passed to this
|
222
|
+
# and returns an array of countries and total
|
223
|
+
#
|
224
|
+
# @example Top n-countries
|
225
|
+
# Tor::StatsObj.topcountries(n) => [[country,total]....[country,total]]
|
226
|
+
# Tor::StatsObj.topcountries(n, "UNIX")
|
227
|
+
# Tor::StatsObj.topcountries(n, ["UNIX","LINUX"])
|
228
|
+
#
|
229
|
+
def topcountries(num,*platform)
|
230
|
+
countryarray = country_list(*platform)
|
231
|
+
top_countries = country_stat(countryarray,*platform).sort_by{|k,v| v}
|
232
|
+
result = (num==0) ? top_countries.reverse : top_countries.last(num).reverse
|
233
|
+
end
|
234
|
+
|
235
|
+
# This returns the top n-countries. An optional platform parameter can be passed to this
|
236
|
+
# and returns an array of countries and total
|
237
|
+
#
|
238
|
+
# @example Top n-countries
|
239
|
+
# Tor::StatsObj.topcountries_uniq(n) => [[country,total]....[country,total]]
|
240
|
+
# Tor::StatsObj.topcountries_uniq(n, "UNIX")
|
241
|
+
# Tor::StatsObj.topcountries_uniq(n, ["UNIX","LINUX"])
|
242
|
+
#
|
243
|
+
def topcountries_uniq(num,*platform)
|
244
|
+
countryarray = country_list(*platform)
|
245
|
+
top_countries = country_stat_uniq(countryarray,*platform).sort_by{|k,v| v}
|
246
|
+
result = (num==0) ? top_countries.reverse : top_countries.last(num).reverse
|
247
|
+
end
|
248
|
+
|
249
|
+
# This returns the country name from the country code.
|
250
|
+
#
|
251
|
+
# @example Get country name from country code
|
252
|
+
# Tor::StatsObj.get_countryname("FR")
|
253
|
+
#
|
254
|
+
def get_countryname(ccode)
|
255
|
+
x=Router.where(:country_code=>ccode).first
|
256
|
+
(x.nil?) ? nil : x.country
|
257
|
+
end
|
258
|
+
|
259
|
+
# This returns the [latitude,longitude] from the country code. Using the constant Tor::Constants::COUNLATLNG,
|
260
|
+
# or alternatively if Tor::COUNLATLNG has been defined in a program.
|
261
|
+
#
|
262
|
+
def get_latlng(country_code)
|
263
|
+
countrylatlng = Constants::COUNLATLNG
|
264
|
+
if (defined? COUNLATLNG)
|
265
|
+
if (COUNLATLNG.keys.include? country_code)
|
266
|
+
lat= COUNLATLNG[country_code][:lat]
|
267
|
+
lng= COUNLATLNG[country_code][:lng]
|
268
|
+
end
|
269
|
+
elsif countrylatlng.keys.include? country_code
|
270
|
+
lat=countrylatlng[country_code][:lat]
|
271
|
+
lng=countrylatlng[country_code][:lng]
|
272
|
+
else
|
273
|
+
puts "#{country_code}, #{get_countryname(country_code)} - not in the country-latitude file, using cordinates(0,0)"
|
274
|
+
lat=0.0
|
275
|
+
lng=0.0
|
276
|
+
end
|
277
|
+
[lat,lng]
|
278
|
+
end
|
279
|
+
|
280
|
+
|
281
|
+
# This returns the id of uniq identities in the database
|
282
|
+
#
|
283
|
+
# @example Get Uniq id of ORs in the UK
|
284
|
+
#
|
285
|
+
# Tor::Stats.Obj.get_uniqid("GB")
|
286
|
+
# Tor::Stats.Obj.get_uniqid("GB","WINDOWS")
|
287
|
+
# Tor::Stats.Obj.get_uniqid(["GB","FR",DE"] , ["UNIX","LINUX"])
|
288
|
+
#
|
289
|
+
def get_uniqid(countryfilter,*platform)
|
290
|
+
if platform.empty? or platform==["ALL"] or platform==["All"]
|
291
|
+
torlocations = Router.where(:country_code=>countryfilter)
|
292
|
+
else
|
293
|
+
torlocations = Router.where(:platform=>platform,:country_code=>countryfilter)
|
294
|
+
end
|
295
|
+
identitygroup = torlocations.group_by{|c| c.fingerprint}
|
296
|
+
idarray = identitygroup.keys.collect{|eachidentitykey|
|
297
|
+
#Collect just the id of the most recent location of the fingerprint
|
298
|
+
identitygroup[eachidentitykey].max{|a,b| a.published_at <=> b.published_at}.id
|
299
|
+
}
|
300
|
+
end
|
301
|
+
|
302
|
+
# This method generates a KML using the locations in Tor::Router database.
|
303
|
+
# It takes a name for the KML document as input, and an optional platform parameter.
|
304
|
+
#
|
305
|
+
# @example Generate KML file
|
306
|
+
# Tor::StatsObj.genkml("KML doc name")
|
307
|
+
# Tor::StatsObj.genkml("KML platform name", ["WINDOWS","UNIX","LINUX", "OTHER"] )
|
308
|
+
# Tor::StatsObj.genkml("KML platform name", "LINUX" )
|
309
|
+
#
|
310
|
+
def genkml(mapname,*platform)
|
311
|
+
tour_hash= (defined? WORLDTOUR) ? WORLDTOUR : Constants::WORLDTOUR
|
312
|
+
attack_tour = (defined? ATTACK_TOUR) ? ATTACK_TOUR: Constants::ATTACK_TOUR
|
313
|
+
|
314
|
+
torcountry= topcountries_uniq(0,*platform) # collect{|country,count| country}
|
315
|
+
xml = Builder::XmlMarkup.new(:indent=>2)
|
316
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
317
|
+
xml.kml("xmlns" => "http://www.opengis.net/kml/2.2",
|
318
|
+
"xmlns:gx"=>"http://www.google.com/kml/ext/2.2") do
|
319
|
+
y=1
|
320
|
+
|
321
|
+
|
322
|
+
xml.Document do
|
323
|
+
xml.name mapname
|
324
|
+
|
325
|
+
# define styles to use for placemarks and tour
|
326
|
+
xml.Style("id"=>"redplaces") do
|
327
|
+
xml.IconStyle do
|
328
|
+
xml.color "ff0000ff"
|
329
|
+
end
|
330
|
+
end
|
331
|
+
xml.Style("id"=>"greenplaces") do
|
332
|
+
xml.IconStyle do
|
333
|
+
xml.color "ff00ff00"
|
334
|
+
end
|
335
|
+
end
|
336
|
+
xml.Style("id"=>"blackplaces") do
|
337
|
+
xml.IconStyle do
|
338
|
+
xml.color "ff000000"
|
339
|
+
end
|
340
|
+
end
|
341
|
+
xml.Style("id"=>"blueplaces") do
|
342
|
+
xml.IconStyle do
|
343
|
+
xml.color "0000ff00"
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
xml.Folder("id"=>"torbridges") do
|
348
|
+
xml.name "Tor Bridges - #{Bridge.count}"
|
349
|
+
allbridges = Bridge.all
|
350
|
+
allbridges.each{|eachbridge|
|
351
|
+
brindex = 1 + allbridges.index(eachbridge)
|
352
|
+
placeid = "bridge#{brindex }"
|
353
|
+
xml.Placemark("id"=> placeid) do
|
354
|
+
xml.name "BR#{brindex.to_s}"
|
355
|
+
xml.description "#{eachbridge.ipaddr}:#{eachbridge.port}"
|
356
|
+
xml.styleUrl "#blueplaces"
|
357
|
+
xml.Point do
|
358
|
+
xml.extrude 1
|
359
|
+
xml.coordinates "#{eachbridge.lng},#{eachbridge.lat}"
|
360
|
+
end
|
361
|
+
end
|
362
|
+
}
|
363
|
+
end
|
364
|
+
|
365
|
+
# Google earth tour
|
366
|
+
xml.gx :Tour do
|
367
|
+
xml.name "Tor World"
|
368
|
+
xml.gx :Playlist do
|
369
|
+
tour_hash.keys.each{|each_centre|
|
370
|
+
xml.gx :FlyTo do
|
371
|
+
xml.gx :duration,1.0
|
372
|
+
xml.LookAt do
|
373
|
+
country_lat,country_lng= get_latlng(each_centre)
|
374
|
+
xml.longitude country_lng
|
375
|
+
xml.latitude country_lat
|
376
|
+
xml.range 4900000
|
377
|
+
end #end LookAt
|
378
|
+
end # end FlyTo
|
379
|
+
|
380
|
+
|
381
|
+
tour_hash[each_centre].each{|eachzone|
|
382
|
+
# toggle on
|
383
|
+
xml.gx :AnimatedUpdate do
|
384
|
+
xml.gx :duration,0.0
|
385
|
+
xml.Update do
|
386
|
+
xml.targetHref
|
387
|
+
xml.Change do
|
388
|
+
xml.Placemark("targetId"=> eachzone) do
|
389
|
+
xml.gx :balloonVisibility,1
|
390
|
+
end # end Placemark
|
391
|
+
end # end Change
|
392
|
+
end # end Update
|
393
|
+
end #end AnimatedUpdate
|
394
|
+
xml.gx :Wait do
|
395
|
+
xml.gx :duration,2.0
|
396
|
+
end
|
397
|
+
|
398
|
+
# toggle off
|
399
|
+
xml.gx :AnimatedUpdate do
|
400
|
+
xml.gx :duration,0.0
|
401
|
+
xml.Update do
|
402
|
+
xml.targetHref
|
403
|
+
xml.Change do
|
404
|
+
xml.Placemark("id"=> eachzone) do
|
405
|
+
xml.gx :balloonVisibility,0
|
406
|
+
end # end placemark
|
407
|
+
end # end Change
|
408
|
+
end # end Update
|
409
|
+
end # end AnimatedUpdate
|
410
|
+
xml.gx :Wait do
|
411
|
+
xml.gx :duration,2.0
|
412
|
+
end
|
413
|
+
} # eachzone
|
414
|
+
} #each_centre
|
415
|
+
end # end of gx:Playlist
|
416
|
+
end # end of gx:Tour
|
417
|
+
|
418
|
+
|
419
|
+
# Google earth attack tour
|
420
|
+
xml.gx :Tour do
|
421
|
+
xml.name "Tor - Attack"
|
422
|
+
xml.gx :Playlist do
|
423
|
+
xml.gx :FlyTo do
|
424
|
+
xml.gx :duration,1.0
|
425
|
+
xml.LookAt do
|
426
|
+
xml.longitude attack_tour[:lng]
|
427
|
+
xml.latitude attack_tour[:lat]
|
428
|
+
xml.range 2000000
|
429
|
+
end #end LookAt
|
430
|
+
end # end FlyTo
|
431
|
+
|
432
|
+
|
433
|
+
attack_tour["red"].each{|eachzone|
|
434
|
+
# toggle on
|
435
|
+
xml.gx :AnimatedUpdate do
|
436
|
+
xml.gx :duration,0.0
|
437
|
+
xml.Update do
|
438
|
+
xml.targetHref
|
439
|
+
xml.Change do
|
440
|
+
xml.Placemark("targetId"=> eachzone) do
|
441
|
+
xml.styleUrl "#redplaces"
|
442
|
+
end # end Placemark
|
443
|
+
end # end Change
|
444
|
+
end # end Update
|
445
|
+
end #end AnimatedUpdate
|
446
|
+
} # eachzone
|
447
|
+
|
448
|
+
attack_tour["black"].each{|eachzone|
|
449
|
+
# toggle on
|
450
|
+
xml.gx :AnimatedUpdate do
|
451
|
+
xml.gx :duration,2.0
|
452
|
+
xml.Update do
|
453
|
+
xml.targetHref
|
454
|
+
xml.Change do
|
455
|
+
xml.Placemark("targetId"=> eachzone) do
|
456
|
+
xml.styleUrl "#blackplaces"
|
457
|
+
end # end Placemark
|
458
|
+
end # end Change
|
459
|
+
end # end Update
|
460
|
+
end #end AnimatedUpdate
|
461
|
+
xml.gx :Wait do
|
462
|
+
xml.gx :duration,2.0
|
463
|
+
end
|
464
|
+
} # eachzone
|
465
|
+
|
466
|
+
end # end of gx:Playlist
|
467
|
+
end # end of gx:Tour
|
468
|
+
|
469
|
+
torcountry.each { |country_code,countrytotal|
|
470
|
+
countryname = get_countryname(country_code)
|
471
|
+
xml.Folder("id"=>country_code) do
|
472
|
+
xml.name "#{countryname}-#{countrytotal}"
|
473
|
+
xml.LookAt do
|
474
|
+
country_lat,country_lng = get_latlng(country_code)
|
475
|
+
xml.longitude country_lng
|
476
|
+
xml.latitude country_lat
|
477
|
+
xml.range 4500000
|
478
|
+
end
|
479
|
+
idarray = get_uniqid(country_code,*platform)
|
480
|
+
if platform.empty? or platform==["ALL"] or platform==["All"]
|
481
|
+
torlocations = Router.where(:id=>idarray,:country_code=>country_code)
|
482
|
+
else
|
483
|
+
torlocations = Router.where(:id=>idarray,:country_code=>country_code,:platform=>platform)
|
484
|
+
end
|
485
|
+
torplaces_sorted = torlocations.group_by{|c| [ c.lat, c.lng, c.country, c.city ] }.sort_by{|a,b| b.count}.reverse
|
486
|
+
torplaces_sorted.each{|lat_lng_country_city|
|
487
|
+
# Group by fingerprint here and get the size of the hash, and get the number of elements in the hash instead of get_uniqid
|
488
|
+
# but what if user is mobile? different isps, latitude-longitude, or lives the city or country
|
489
|
+
lat, lng, country, city = lat_lng_country_city[0]
|
490
|
+
pointtotal = lat_lng_country_city[1].count
|
491
|
+
placeid = "#{country_code}#{ 1 + torplaces_sorted.index(lat_lng_country_city)}"
|
492
|
+
xml.Placemark("id"=> placeid) do
|
493
|
+
strcount = (pointtotal == 1) ? 'OR' : 'ORs'
|
494
|
+
#xml.name "#{y}"
|
495
|
+
y += 1
|
496
|
+
kmlcity= (city.empty?) ? "#{country}" : "#{city}"
|
497
|
+
xml.description "#{pointtotal} #{strcount} in #{kmlcity} of #{countrytotal}(country total)"
|
498
|
+
xml.styleUrl "#greenplaces"
|
499
|
+
xml.Point do
|
500
|
+
xml.extrude 1
|
501
|
+
xml.coordinates "#{lng},#{lat}"
|
502
|
+
end
|
503
|
+
end
|
504
|
+
}
|
505
|
+
end
|
506
|
+
}
|
507
|
+
end
|
508
|
+
end
|
509
|
+
xml.target! #Return the xml file
|
510
|
+
end # end of genkml
|
511
|
+
|
512
|
+
end # end of class StatsObj
|
513
|
+
|
514
|
+
end
|