tor_extend 1.0.2
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.
- 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
|