]>
Commit | Line | Data |
---|---|---|
13b5ce6e MT |
1 | #!/usr/bin/perl |
2 | ############################################################################### | |
3 | # # | |
4 | # IPFire.org - A linux based firewall # | |
5efe8957 | 5 | # Copyright (C) 2007-2020 IPFire Team <info@ipfire.org> # |
13b5ce6e MT |
6 | # # |
7 | # This program is free software: you can redistribute it and/or modify # | |
8 | # it under the terms of the GNU General Public License as published by # | |
9 | # the Free Software Foundation, either version 3 of the License, or # | |
10 | # (at your option) any later version. # | |
11 | # # | |
12 | # This program is distributed in the hope that it will be useful, # | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
15 | # GNU General Public License for more details. # | |
16 | # # | |
17 | # You should have received a copy of the GNU General Public License # | |
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
19 | # # | |
20 | ############################################################################### | |
21 | ||
22 | use strict; | |
13b5ce6e MT |
23 | |
24 | # enable only the following on debugging purpose | |
ac2fdbb1 EK |
25 | #use warnings; |
26 | #use CGI::Carp 'fatalsToBrowser'; | |
13b5ce6e MT |
27 | |
28 | require '/var/ipfire/general-functions.pl'; | |
0893eef4 | 29 | require "${General::swroot}/location-functions.pl"; |
13b5ce6e MT |
30 | require "${General::swroot}/lang.pl"; |
31 | require "${General::swroot}/header.pl"; | |
32 | ||
33 | #workaround to suppress a warning when a variable is used only once | |
34 | my @dummy = ( ${Header::colouryellow} ); | |
35 | undef (@dummy); | |
36 | ||
37 | my @bandwidth_limits = ( | |
04f93219 | 38 | 1000 * 1024, # 1 GBit/s |
13b5ce6e MT |
39 | 500 * 1024, |
40 | 200 * 1024, | |
04f93219 | 41 | 100 * 1024, # 100 MBit/s |
13b5ce6e MT |
42 | 64 * 1024, |
43 | 50 * 1024, | |
44 | 25 * 1024, | |
45 | 20 * 1024, | |
46 | 16 * 1024, | |
47 | 10 * 1024, | |
48 | 8 * 1024, | |
49 | 4 * 1024, | |
50 | 2 * 1024, | |
04f93219 | 51 | 1024 # 1 MBit/s |
13b5ce6e MT |
52 | ); |
53 | my @accounting_periods = ('daily', 'weekly', 'monthly'); | |
54 | ||
55 | my $TOR_CONTROL_PORT = 9051; | |
56 | ||
3387469b JPT |
57 | my $string=(); |
58 | my $memory=(); | |
59 | my @memory=(); | |
60 | my @pid=(); | |
61 | my @tor=(); | |
62 | sub daemonstats | |
63 | { | |
64 | $memory = 0; | |
65 | # for pid and memory | |
66 | open(FILE, '/usr/local/bin/addonctrl tor status | '); | |
67 | @tor = <FILE>; | |
68 | close(FILE); | |
69 | $string = join("", @tor); | |
70 | $string =~ s/[a-z_]//gi; | |
71 | $string =~ s/\[[0-1]\;[0-9]+//gi; | |
72 | $string =~ s/[\(\)\.]//gi; | |
73 | $string =~ s/ //gi; | |
74 | $string =~ s/\e//gi; | |
75 | @pid = split(/\s/,$string); | |
76 | if (open(FILE, "/proc/$pid[0]/statm")){ | |
77 | my $temp = <FILE>; | |
78 | @memory = split(/ /,$temp); | |
79 | close(FILE); | |
80 | } | |
81 | $memory+=$memory[0]; | |
82 | } | |
83 | daemonstats(); | |
84 | ||
13b5ce6e MT |
85 | our %netsettings = (); |
86 | &General::readhash("${General::swroot}/ethernet/settings", \%netsettings); | |
87 | ||
3387469b JPT |
88 | our %color = (); |
89 | our %mainsettings = (); | |
90 | &General::readhash("${General::swroot}/main/settings", \%mainsettings); | |
8186b372 | 91 | &General::readhash("/srv/web/ipfire/html/themes/ipfire/include/colors.txt", \%color); |
3387469b | 92 | |
13b5ce6e MT |
93 | our %settings = (); |
94 | ||
95 | $settings{'TOR_ENABLED'} = 'off'; | |
96 | $settings{'TOR_SOCKS_PORT'} = 9050; | |
97 | $settings{'TOR_EXIT_COUNTRY'} = ''; | |
98 | $settings{'TOR_USE_EXIT_NODES'} = ''; | |
7c507f3d PM |
99 | $settings{'TOR_GUARD_COUNTRY'} = ''; |
100 | $settings{'TOR_USE_GUARD_NODES'} = ''; | |
13b5ce6e MT |
101 | $settings{'TOR_ALLOWED_SUBNETS'} = "$netsettings{'GREEN_NETADDRESS'}\/$netsettings{'GREEN_NETMASK'}"; |
102 | if (&Header::blue_used()) { | |
103 | $settings{'TOR_ALLOWED_SUBNETS'} .= ",$netsettings{'BLUE_NETADDRESS'}\/$netsettings{'BLUE_NETMASK'}"; | |
104 | } | |
105 | ||
106 | $settings{'TOR_RELAY_ENABLED'} = 'off'; | |
eea4969d | 107 | $settings{'TOR_RELAY_MODE'} = 'relay'; |
bd8b0330 | 108 | $settings{'TOR_RELAY_ADDRESS'} = ''; |
13b5ce6e | 109 | $settings{'TOR_RELAY_PORT'} = 9001; |
4245fe34 | 110 | $settings{'TOR_RELAY_DIRPORT'} = 0; |
b0449403 MT |
111 | $settings{'TOR_RELAY_NICKNAME'} = ''; |
112 | $settings{'TOR_RELAY_CONTACT_INFO'} = ''; | |
13b5ce6e MT |
113 | $settings{'TOR_RELAY_BANDWIDTH_RATE'} = 0; |
114 | $settings{'TOR_RELAY_BANDWIDTH_BURST'} = 0; | |
115 | $settings{'TOR_RELAY_ACCOUNTING_LIMIT'} = 0; | |
116 | $settings{'TOR_RELAY_ACCOUNTING_PERIOD'} = 'daily'; | |
117 | ||
118 | $settings{'ACTION'} = ''; | |
119 | ||
120 | my $errormessage = ''; | |
121 | my $warnmessage = ''; | |
122 | ||
123 | &Header::showhttpheaders(); | |
124 | ||
13b5ce6e MT |
125 | # Get GUI values. |
126 | &Header::getcgihash(\%settings); | |
127 | ||
128 | # Create tor command connection. | |
129 | our $torctrl = &TorConnect(); | |
130 | ||
131 | # Toggle enable/disable field. | |
132 | if ($settings{'ACTION'} eq $Lang::tr{'save'}) { | |
a03547fe MT |
133 | if ($settings{'TOR_RELAY_NICKNAME'} ne '') { |
134 | if ($settings{'TOR_RELAY_NICKNAME'} !~ /^[a-zA-Z0-9]+$/) { | |
135 | $errormessage = "$Lang::tr{'tor errmsg invalid relay name'}: $settings{'TOR_RELAY_NICKNAME'}"; | |
136 | } | |
b0449403 MT |
137 | } |
138 | ||
818f47d0 MT |
139 | if (!&General::validport($settings{'TOR_SOCKS_PORT'})) { |
140 | $errormessage = "$Lang::tr{'tor errmsg invalid socks port'}: $settings{'TOR_SOCKS_PORT'}"; | |
141 | } | |
142 | ||
143 | if (!&General::validport($settings{'TOR_RELAY_PORT'})) { | |
144 | $errormessage = "$Lang::tr{'tor errmsg invalid relay port'}: $settings{'TOR_RELAY_PORT'}"; | |
145 | } | |
4245fe34 JPT |
146 | if ($settings{'TOR_RELAY_DIRPORT'} ne '0') { |
147 | if (!&General::validport($settings{'TOR_RELAY_DIRPORT'})) { | |
148 | $errormessage = "$Lang::tr{'tor errmsg invalid directory port'}: $settings{'TOR_RELAY_DIRPORT'}"; | |
149 | } | |
150 | } | |
818f47d0 | 151 | |
bd8b0330 MT |
152 | if ($settings{'TOR_RELAY_ADDRESS'} ne '') { |
153 | if ((!&General::validfqdn($settings{'TOR_RELAY_ADDRESS'})) && (!&General::validip($settings{'TOR_RELAY_ADDRESS'}))) { | |
154 | $errormessage = "$Lang::tr{'tor errmsg invalid relay address'}: $settings{'TOR_RELAY_ADDRESS'}"; | |
155 | } | |
156 | } | |
157 | ||
56bf9f21 MT |
158 | if ($settings{'TOR_RELAY_ACCOUNTING_LIMIT'} !~ /^\d+$/) { |
159 | $errormessage = "$Lang::tr{'tor errmsg invalid accounting limit'}: $settings{'TOR_RELAY_ACCOUNTING_LIMIT'}"; | |
160 | } | |
161 | ||
13b5ce6e MT |
162 | my @temp = split(/[\n,]/,$settings{'TOR_ALLOWED_SUBNETS'}); |
163 | $settings{'TOR_ALLOWED_SUBNETS'} = ""; | |
164 | foreach (@temp) { | |
165 | s/^\s+//g; s/\s+$//g; | |
166 | if ($_) { | |
167 | unless (&General::validipandmask($_)) { | |
168 | $errormessage = "$Lang::tr{'tor errmsg invalid ip or mask'}: $_"; | |
169 | } | |
170 | $settings{'TOR_ALLOWED_SUBNETS'} .= $_.","; | |
171 | } | |
172 | } | |
173 | ||
174 | @temp = split(/[\n,]/,$settings{'TOR_USE_EXIT_NODES'}); | |
175 | $settings{'TOR_USE_EXIT_NODES'} = ""; | |
176 | foreach (@temp) { | |
177 | s/^\s+//g; s/\s+$//g; | |
178 | if ($_) { | |
179 | $settings{'TOR_USE_EXIT_NODES'} .= $_.","; | |
180 | } | |
181 | } | |
182 | ||
7c507f3d PM |
183 | @temp = split(/[\n,]/,$settings{'TOR_USE_GUARD_NODES'}); |
184 | $settings{'TOR_USE_GUARD_NODES'} = ""; | |
185 | foreach (@temp) { | |
186 | s/^\s+//g; s/\s+$//g; | |
187 | if ($_) { | |
188 | $settings{'TOR_USE_GUARD_NODES'} .= $_.","; | |
189 | } | |
190 | } | |
191 | ||
3308f8d0 MT |
192 | # Burst bandwidth must be less or equal to bandwidth rate. |
193 | if ($settings{'TOR_RELAY_BANDWIDTH_RATE'} == 0) { | |
194 | $settings{'TOR_RELAY_BANDWIDTH_BURST'} = 0; | |
195 | ||
196 | } elsif ($settings{'TOR_RELAY_BANDWIDTH_BURST'} < $settings{'TOR_RELAY_BANDWIDTH_RATE'}) { | |
197 | $settings{'TOR_RELAY_BANDWIDTH_BURST'} = $settings{'TOR_RELAY_BANDWIDTH_RATE'}; | |
198 | } | |
199 | ||
13b5ce6e MT |
200 | if ($errormessage eq '') { |
201 | # Write configuration settings to file. | |
202 | &General::writehash("${General::swroot}/tor/settings", \%settings); | |
203 | ||
204 | # Update configuration files. | |
205 | &BuildConfiguration(); | |
206 | } | |
b0449403 MT |
207 | } else { |
208 | # Load settings from file. | |
209 | &General::readhash("${General::swroot}/tor/settings", \%settings); | |
13b5ce6e MT |
210 | } |
211 | ||
212 | &showMainBox(); | |
213 | ||
214 | # Close Tor control connection. | |
215 | &TorClose($torctrl); | |
216 | ||
217 | # Functions | |
218 | ||
219 | sub showMainBox() { | |
220 | my %checked = (); | |
221 | my %selected = (); | |
222 | ||
223 | $checked{'TOR_ENABLED'}{'on'} = ''; | |
224 | $checked{'TOR_ENABLED'}{'off'} = ''; | |
225 | $checked{'TOR_ENABLED'}{$settings{'TOR_ENABLED'}} = 'checked'; | |
226 | ||
227 | $checked{'TOR_RELAY_ENABLED'}{'on'} = ''; | |
228 | $checked{'TOR_RELAY_ENABLED'}{'off'} = ''; | |
229 | $checked{'TOR_RELAY_ENABLED'}{$settings{'TOR_RELAY_ENABLED'}} = 'checked'; | |
230 | ||
231 | &Header::openpage($Lang::tr{'tor configuration'}, 1, ''); | |
232 | &Header::openbigbox('100%', 'left', '', $errormessage); | |
233 | ||
234 | if ($errormessage) { | |
235 | &Header::openbox('100%', 'left', $Lang::tr{'error messages'}); | |
236 | print "<font class='base'>$errormessage </font>\n"; | |
237 | &Header::closebox(); | |
238 | } | |
239 | ||
240 | print "<form method='post' action='$ENV{'SCRIPT_NAME'}'>\n"; | |
241 | ||
3387469b JPT |
242 | &Header::openbox('100%', 'center', $Lang::tr{'tor'}); |
243 | ||
244 | ||
245 | if ( ($memory != 0) && (@pid[0] ne "///") ){ | |
f76b104c AM |
246 | print "<table width='95%' cellspacing='0' class='tbl'>"; |
247 | print "<tr><th bgcolor='$color{'color20'}' colspan='3' align='left'><strong>$Lang::tr{'tor service'}</strong></th></tr>"; | |
3387469b JPT |
248 | print "<tr><td class='base'>$Lang::tr{'tor daemon'}</td>"; |
249 | print "<td align='center' colspan='2' width='75%' bgcolor='${Header::colourgreen}'><font color='white'><strong>$Lang::tr{'running'}</strong></font></td></tr>"; | |
250 | print "<tr><td class='base'></td>"; | |
251 | print "<td bgcolor='$color{'color20'}' align='center'><strong>PID</strong></td>"; | |
252 | print "<td bgcolor='$color{'color20'}' align='center'><strong>$Lang::tr{'memory'}</strong></td></tr>"; | |
253 | print "<tr><td class='base'></td>"; | |
254 | print "<td bgcolor='$color{'color22'}' align='center'>@pid[0]</td>"; | |
255 | print "<td bgcolor='$color{'color22'}' align='center'>$memory KB</td></tr>"; | |
256 | print "</table>"; | |
257 | } else { | |
f76b104c AM |
258 | print "<table width='95%' cellspacing='0' class='tbl'>"; |
259 | print "<tr><th bgcolor='$color{'color20'}' colspan='3' align='left'><strong>$Lang::tr{'tor service'}</strong></th></tr>"; | |
3387469b JPT |
260 | print "<tr><td class='base'>$Lang::tr{'tor daemon'}</td>"; |
261 | print "<td align='center' width='75%' bgcolor='${Header::colourred}'><font color='white'><strong>$Lang::tr{'stopped'}</strong></font></td></tr>"; | |
262 | print "</table>"; | |
263 | } | |
264 | ||
265 | &Header::closebox(); | |
266 | ||
267 | &Header::openbox('100%', 'center', $Lang::tr{'tor configuration'}); | |
13b5ce6e MT |
268 | |
269 | print <<END; | |
3387469b | 270 | <table width='95%'> |
13b5ce6e | 271 | <tr> |
3387469b | 272 | <td colspan='4' class='base' bgcolor='$color{'color20'}'><b>$Lang::tr{'tor common settings'}</b></td> |
13b5ce6e MT |
273 | </tr> |
274 | <tr> | |
275 | <td width='25%' class='base'>$Lang::tr{'tor enabled'}:</td> | |
005db206 | 276 | <td width='30%'><input type='checkbox' name='TOR_ENABLED' $checked{'TOR_ENABLED'}{'on'} /></td> |
e3edceeb | 277 | <td width='25%' class='base'>$Lang::tr{'tor socks port'}: <img src='/blob.gif' alt='*' /></td> |
005db206 | 278 | <td width='20%'><input type='text' name='TOR_SOCKS_PORT' value='$settings{'TOR_SOCKS_PORT'}' size='5' /></td> |
13b5ce6e MT |
279 | </tr> |
280 | <tr> | |
281 | <td width='25%' class='base'>$Lang::tr{'tor relay enabled'}:</td> | |
005db206 | 282 | <td width='30%'><input type='checkbox' name='TOR_RELAY_ENABLED' $checked{'TOR_RELAY_ENABLED'}{'on'} /></td> |
13b5ce6e | 283 | <td width='25%' class='base'></td> |
005db206 | 284 | <td width='20%'></td> |
13b5ce6e MT |
285 | </tr> |
286 | </table> | |
287 | END | |
288 | ||
a03547fe MT |
289 | my @temp = split(",", $settings{'TOR_ALLOWED_SUBNETS'}); |
290 | $settings{'TOR_ALLOWED_SUBNETS'} = join("\n", @temp); | |
291 | ||
292 | @temp = split(",", $settings{'TOR_USE_EXIT_NODES'}); | |
293 | $settings{'TOR_USE_EXIT_NODES'} = join("\n", @temp); | |
294 | ||
7c507f3d PM |
295 | @temp = split(",", $settings{'TOR_USE_GUARD_NODES'}); |
296 | $settings{'TOR_USE_GUARD_NODES'} = join("\n", @temp); | |
297 | ||
a03547fe MT |
298 | print <<END; |
299 | <br> | |
a03547fe MT |
300 | <br> |
301 | ||
3387469b | 302 | <table width='95%'> |
a03547fe | 303 | <tr> |
3387469b | 304 | <td colspan='4' class='base' bgcolor='$color{'color20'}'><b>$Lang::tr{'tor acls'}</b></td> |
a03547fe MT |
305 | </tr> |
306 | <tr> | |
307 | <td colspan='2' class='base' width='55%'> | |
308 | $Lang::tr{'tor allowed subnets'}: | |
309 | </td> | |
310 | <td colspan='2' width='45%'></td> | |
311 | </tr> | |
312 | <tr> | |
313 | <td colspan='2' class='base' width='55%'> | |
314 | <textarea name='TOR_ALLOWED_SUBNETS' cols='32' rows='3' wrap='off'>$settings{'TOR_ALLOWED_SUBNETS'}</textarea> | |
315 | </td> | |
316 | <td colspan='2' width='45%'></td> | |
317 | </tr> | |
318 | </table> | |
319 | ||
7c507f3d PM |
320 | <br /> |
321 | <br /> | |
322 | ||
323 | <table width='95%'> | |
324 | <tr> | |
325 | <td colspan='4' class='base' bgcolor='$color{'color20'}'><b>$Lang::tr{'tor guard nodes'}</b></td> | |
326 | </tr> | |
327 | <tr> | |
328 | <td colspan='2' class='base' width='55%'></td> | |
329 | <td colspan='2' class='base' width='45%'>$Lang::tr{'tor use guard nodes'}:</td> | |
330 | </tr> | |
331 | <tr> | |
332 | <td width='50%' colspan='2'> | |
333 | <select name='TOR_GUARD_COUNTRY' multiple='multiple'> | |
334 | <option value=''>- $Lang::tr{'tor guard country any'} -</option> | |
335 | END | |
336 | ||
337 | # Convert Guard country strings into lists to make comparison easier | |
338 | my @guard_countries; | |
339 | if ($settings{'TOR_GUARD_COUNTRY'} ne '') { | |
340 | @guard_countries = split(/\|/, $settings{'TOR_GUARD_COUNTRY'}); | |
341 | } | |
342 | ||
848911b2 | 343 | my @country_codes = &Location::Functions::get_locations("no_special_locations"); |
7c507f3d PM |
344 | foreach my $country_code (@country_codes) { |
345 | # Convert country code into upper case format. | |
346 | $country_code = uc($country_code); | |
347 | ||
348 | # Get country name. | |
349 | my $country_name = &Location::Functions::get_full_country_name($country_code); | |
350 | ||
351 | print "<option value='$country_code'"; | |
352 | ||
353 | if ($settings{'TOR_GUARD_COUNTRY'} ne '') { | |
354 | print " selected" if grep /$country_code/, @guard_countries; | |
355 | } | |
356 | ||
357 | print ">$country_name ($country_code)</option>\n"; | |
358 | } | |
359 | ||
360 | print <<END; | |
361 | </select> | |
362 | </td> | |
363 | <td width='50%' colspan='2'> | |
364 | <textarea name='TOR_USE_GUARD_NODES' cols='32' rows='3' wrap='off'>$settings{'TOR_USE_GUARD_NODES'}</textarea> | |
365 | </td> | |
366 | </tr> | |
367 | </table> | |
368 | ||
369 | <br /> | |
370 | <br /> | |
a03547fe | 371 | |
3387469b | 372 | <table width='95%'> |
a03547fe | 373 | <tr> |
3387469b | 374 | <td colspan='4' class='base' bgcolor='$color{'color20'}'><b>$Lang::tr{'tor exit nodes'}</b></td> |
a03547fe MT |
375 | </tr> |
376 | <tr> | |
377 | <td colspan='2' class='base' width='55%'></td> | |
378 | <td colspan='2' class='base' width='45%'>$Lang::tr{'tor use exit nodes'}:</td> | |
379 | </tr> | |
380 | <tr> | |
381 | <td width='50%' colspan='2'> | |
5efe8957 | 382 | <select name='TOR_EXIT_COUNTRY' multiple='multiple'> |
a03547fe | 383 | <option value=''>- $Lang::tr{'tor exit country any'} -</option> |
13b5ce6e | 384 | END |
07e42be9 | 385 | my @country_codes = &Location::Functions::get_locations("no_special_locations"); |
5efe8957 | 386 | |
7c507f3d | 387 | # Convert Exit country strings into lists to make comparison easier |
5efe8957 PM |
388 | my @exit_countries; |
389 | if ($settings{'TOR_EXIT_COUNTRY'} ne '') { | |
390 | @exit_countries = split(/\|/, $settings{'TOR_EXIT_COUNTRY'}); | |
391 | } | |
392 | ||
8b452573 SS |
393 | foreach my $country_code (@country_codes) { |
394 | # Convert country code into upper case format. | |
a03547fe | 395 | $country_code = uc($country_code); |
8b452573 SS |
396 | |
397 | # Get country name. | |
5fe798b5 | 398 | my $country_name = &Location::Functions::get_full_country_name($country_code); |
8b452573 | 399 | |
26cce22d MT |
400 | print "<option value='$country_code'"; |
401 | ||
5efe8957 PM |
402 | if ($settings{'TOR_EXIT_COUNTRY'} ne '') { |
403 | print " selected" if grep /$country_code/, @exit_countries; | |
26cce22d MT |
404 | } |
405 | ||
406 | print ">$country_name ($country_code)</option>\n"; | |
a03547fe | 407 | } |
13b5ce6e | 408 | |
a03547fe MT |
409 | print <<END; |
410 | </select> | |
411 | </td> | |
412 | <td width='50%' colspan='2'> | |
413 | <textarea name='TOR_USE_EXIT_NODES' cols='32' rows='3' wrap='off'>$settings{'TOR_USE_EXIT_NODES'}</textarea> | |
414 | </td> | |
415 | </tr> | |
416 | </table> | |
13b5ce6e | 417 | END |
13b5ce6e | 418 | |
005db206 MT |
419 | &Header::closebox(); |
420 | ||
a03547fe | 421 | # Tor relay box |
a03547fe MT |
422 | $selected{'TOR_RELAY_MODE'}{'bridge'} = ''; |
423 | $selected{'TOR_RELAY_MODE'}{'exit'} = ''; | |
424 | $selected{'TOR_RELAY_MODE'}{'private-bridge'} = ''; | |
425 | $selected{'TOR_RELAY_MODE'}{'relay'} = ''; | |
426 | $selected{'TOR_RELAY_MODE'}{$settings{'TOR_RELAY_MODE'}} = 'selected'; | |
13b5ce6e | 427 | |
a03547fe MT |
428 | $selected{'TOR_RELAY_BANDWIDTH_RATE'}{'0'} = ''; |
429 | foreach (@bandwidth_limits) { | |
430 | $selected{'TOR_RELAY_BANDWIDTH_RATE'}{$_} = ''; | |
431 | } | |
432 | $selected{'TOR_RELAY_BANDWIDTH_RATE'}{$settings{'TOR_RELAY_BANDWIDTH_RATE'}} = 'selected'; | |
13b5ce6e | 433 | |
a03547fe MT |
434 | $selected{'TOR_RELAY_BANDWIDTH_BURST'}{'0'} = ''; |
435 | foreach (@bandwidth_limits) { | |
436 | $selected{'TOR_RELAY_BANDWIDTH_BURST'}{$_} = ''; | |
437 | } | |
438 | $selected{'TOR_RELAY_BANDWIDTH_BURST'}{$settings{'TOR_RELAY_BANDWIDTH_BURST'}} = 'selected'; | |
13b5ce6e | 439 | |
a03547fe MT |
440 | foreach (@accounting_periods) { |
441 | $selected{'TOR_RELAY_ACCOUNTING_PERIOD'}{$_} = ''; | |
442 | } | |
443 | $selected{'TOR_RELAY_ACCOUNTING_PERIOD'}{$settings{'TOR_RELAY_ACCOUNTING_PERIOD'}} = 'selected'; | |
444 | ||
3387469b | 445 | &Header::openbox('100%', 'center', $Lang::tr{'tor relay configuration'}); |
a03547fe MT |
446 | |
447 | print <<END; | |
3387469b | 448 | <table width='95%'> |
a03547fe MT |
449 | <tr> |
450 | <td width='25%' class='base'>$Lang::tr{'tor relay mode'}:</td> | |
451 | <td width='30%'> | |
452 | <select name='TOR_RELAY_MODE'> | |
453 | <option value='exit' $selected{'TOR_RELAY_MODE'}{'exit'}>$Lang::tr{'tor relay mode exit'}</option> | |
454 | <option value='relay' $selected{'TOR_RELAY_MODE'}{'relay'}>$Lang::tr{'tor relay mode relay'}</option> | |
455 | <option value='bridge' $selected{'TOR_RELAY_MODE'}{'bridge'}>$Lang::tr{'tor relay mode bridge'}</option> | |
456 | <option value='private-bridge' $selected{'TOR_RELAY_MODE'}{'private-bridge'}>$Lang::tr{'tor relay mode private bridge'}</option> | |
457 | </select> | |
458 | </td> | |
e3edceeb | 459 | <td width='25%' class='base'>$Lang::tr{'tor relay nickname'}:</td> |
a03547fe | 460 | <td width='20%'> |
b31af085 | 461 | <input type='text' name='TOR_RELAY_NICKNAME' value='$settings{'TOR_RELAY_NICKNAME'}' maxlength='19' /> |
a03547fe MT |
462 | </td> |
463 | </tr> | |
464 | <tr> | |
e3edceeb | 465 | <td width='25%' class='base'>$Lang::tr{'tor relay address'}:</td> |
a03547fe MT |
466 | <td width='30%'> |
467 | <input type='text' name='TOR_RELAY_ADDRESS' value='$settings{'TOR_RELAY_ADDRESS'}' /> | |
468 | </td> | |
e3edceeb | 469 | <td width='25%' class='base'>$Lang::tr{'tor relay port'}: <img src='/blob.gif' alt='*' /></td> |
a03547fe | 470 | <td width='20%'> |
919a5020 | 471 | <input type='text' name='TOR_RELAY_PORT' value='$settings{'TOR_RELAY_PORT'}' size='5' /> |
a03547fe | 472 | </td> |
a03547fe | 473 | </tr> |
4245fe34 JPT |
474 | <tr> |
475 | <td width='25%'> </td> | |
476 | <td width='30%'> </td> | |
e3edceeb | 477 | <td width='25%' class='base'>$Lang::tr{'tor directory port'}: <img src='/blob.gif' alt='*' /></td> |
4245fe34 JPT |
478 | <td width='20%'> |
479 | <input type='text' name='TOR_RELAY_DIRPORT' value='$settings{'TOR_RELAY_DIRPORT'}' size='5' /> $Lang::tr{'tor 0 = disabled'} | |
480 | </td> | |
481 | </tr> | |
a03547fe | 482 | <tr> |
e3edceeb | 483 | <td width='25%' class='base'>$Lang::tr{'tor contact info'}:</td> |
a03547fe | 484 | <td width='75%' colspan='3'> |
919a5020 | 485 | <input type='text' name='TOR_RELAY_CONTACT_INFO' value='$settings{'TOR_RELAY_CONTACT_INFO'}' style='width: 98%;' /> |
a03547fe MT |
486 | </td> |
487 | </tr> | |
488 | </table> | |
489 | ||
3387469b | 490 | <br> |
a03547fe | 491 | |
3387469b | 492 | <table width='95%'> |
a03547fe | 493 | <tr> |
3387469b | 494 | <td colspan='4' class='base' bgcolor='$color{'color20'}'><b>$Lang::tr{'tor bandwidth settings'}</b></td> |
a03547fe MT |
495 | </tr> |
496 | <tr> | |
497 | <td width='25%' class='base'>$Lang::tr{'tor bandwidth rate'}:</td> | |
498 | <td width='30%' class='base'> | |
499 | <select name='TOR_RELAY_BANDWIDTH_RATE'> | |
13b5ce6e MT |
500 | END |
501 | ||
a03547fe MT |
502 | foreach (@bandwidth_limits) { |
503 | if ($_ >= 1024) { | |
f00699e8 | 504 | print "<option value='$_' $selected{'TOR_RELAY_BANDWIDTH_RATE'}{$_}>". $_ / 1024 ." Mbit/s</option>\n"; |
a03547fe | 505 | } else { |
f00699e8 | 506 | print "<option value='$_' $selected{'TOR_RELAY_BANDWIDTH_RATE'}{$_}>$_ kbit/s</option>\n"; |
13b5ce6e | 507 | } |
a03547fe | 508 | } |
13b5ce6e | 509 | |
a03547fe MT |
510 | print <<END; |
511 | <option value='0' $selected{'TOR_RELAY_BANDWIDTH_RATE'}{'0'}>$Lang::tr{'tor bandwidth unlimited'}</option> | |
512 | </select> | |
513 | </td> | |
e3edceeb | 514 | <td width='25%' class='base'>$Lang::tr{'tor accounting limit'}: <img src='/blob.gif' alt='*' /></td> |
a03547fe MT |
515 | <td width='20%'> |
516 | <input type='text' name='TOR_RELAY_ACCOUNTING_LIMIT' value='$settings{'TOR_RELAY_ACCOUNTING_LIMIT'}' size='12' /> | |
517 | </td> | |
518 | </tr> | |
519 | <tr> | |
520 | <td width='25%' class='base'>$Lang::tr{'tor bandwidth burst'}:</td> | |
521 | <td width='20%' class='base'> | |
522 | <select name='TOR_RELAY_BANDWIDTH_BURST'> | |
13b5ce6e MT |
523 | END |
524 | ||
a03547fe MT |
525 | foreach (@bandwidth_limits) { |
526 | if ($_ >= 1024) { | |
f00699e8 | 527 | print "<option value='$_' $selected{'TOR_RELAY_BANDWIDTH_BURST'}{$_}>". $_ / 1024 ." Mbit/s</option>\n"; |
a03547fe | 528 | } else { |
f00699e8 | 529 | print "<option value='$_' $selected{'TOR_RELAY_BANDWIDTH_BURST'}{$_}>$_ kbit/s</option>\n"; |
13b5ce6e | 530 | } |
a03547fe MT |
531 | } |
532 | print <<END; | |
533 | <option value='0' $selected{'TOR_RELAY_BANDWIDTH_BURST'}{'0'}>$Lang::tr{'tor bandwidth unlimited'}</option> | |
534 | </select> | |
535 | </td> | |
536 | <td width='25%' class='base'>$Lang::tr{'tor accounting period'}:</td> | |
537 | <td width='20%'> | |
538 | <select name='TOR_RELAY_ACCOUNTING_PERIOD'> | |
13b5ce6e MT |
539 | END |
540 | ||
a03547fe MT |
541 | foreach (@accounting_periods) { |
542 | print "<option value='$_' $selected{'TOR_RELAY_ACCOUNTING_PERIOD'}{$_}>$Lang::tr{'tor accounting period '.$_}</option>"; | |
543 | } | |
13b5ce6e | 544 | |
a03547fe MT |
545 | print <<END; |
546 | </select> | |
547 | </td> | |
548 | </tr> | |
549 | </table> | |
13b5ce6e MT |
550 | END |
551 | ||
a03547fe | 552 | &Header::closebox(); |
13b5ce6e MT |
553 | |
554 | print <<END; | |
3387469b | 555 | <table width='95%'> |
13b5ce6e | 556 | <tr> |
e3edceeb | 557 | <td><img src='/blob.gif' align='top' alt='*' /> <font class='base'>$Lang::tr{'required field'}</font></td> |
13b5ce6e MT |
558 | <td align='right'> </td> |
559 | </tr> | |
560 | </table> | |
561 | ||
562 | <hr> | |
563 | ||
3387469b | 564 | <table width='95%'> |
13b5ce6e MT |
565 | <tr> |
566 | <td> </td> | |
567 | <td align='center'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' /></td> | |
568 | <td> </td> | |
569 | </tr> | |
570 | </table> | |
571 | END | |
572 | ||
573 | # If we have a control connection, show the stats. | |
574 | if ($torctrl) { | |
3387469b | 575 | &Header::openbox('100%', 'center', $Lang::tr{'tor stats'}); |
13b5ce6e MT |
576 | |
577 | my @traffic = &TorTrafficStats($torctrl); | |
578 | ||
579 | if (@traffic) { | |
580 | print <<END; | |
3387469b | 581 | <table width='95%'> |
13b5ce6e MT |
582 | END |
583 | ||
584 | if ($settings{'TOR_RELAY_ENABLED'} eq 'on') { | |
585 | my $fingerprint = &TorRelayFingerprint($torctrl); | |
586 | if ($fingerprint) { | |
587 | print <<END; | |
588 | <tr> | |
589 | <td width='40%' class='base'>$Lang::tr{'tor relay fingerprint'}:</td> | |
590 | <td width='60%'> | |
0675a66d | 591 | <a href='https://metrics.torproject.org/rs.html#details/$fingerprint' target='_blank'>$fingerprint</a> |
13b5ce6e MT |
592 | </td> |
593 | </tr> | |
594 | END | |
595 | } | |
596 | } | |
597 | ||
598 | my $address = TorGetInfo($torctrl, "address"); | |
599 | if ($address) { | |
600 | print <<END; | |
601 | <tr> | |
602 | <td width='40%' class='base'>$Lang::tr{'tor relay external address'}:</td> | |
603 | <td width='60%'>$address</td> | |
604 | </tr> | |
605 | END | |
606 | } | |
607 | ||
608 | print <<END; | |
609 | <tr> | |
610 | <td width='40%'>$Lang::tr{'tor traffic read written'}:</td> | |
611 | END | |
612 | print "<td width='60%'>" . &FormatBytes($traffic[0]) ."/". &FormatBytes($traffic[1]) . "</td>"; | |
613 | print <<END; | |
614 | </tr> | |
615 | </table> | |
616 | END | |
617 | } | |
618 | ||
619 | my $accounting = &TorAccountingStats($torctrl); | |
620 | if ($accounting) { | |
621 | print <<END; | |
3387469b | 622 | <table width='95%'> |
13b5ce6e MT |
623 | <tr> |
624 | <td colspan='2' class='base'><b>$Lang::tr{'tor accounting'}</b></td> | |
625 | </tr> | |
626 | END | |
627 | ||
628 | if ($accounting->{'hibernating'} eq "hard") { | |
629 | print <<END; | |
630 | <tr> | |
631 | <td class='base' colspan='2' bgcolor="$Header::colourred" align='center'> | |
632 | <font color='white'>$Lang::tr{'tor traffic limit hard'}</font> | |
633 | </td> | |
634 | </tr> | |
635 | END | |
636 | } elsif ($accounting->{'hibernating'} eq "soft") { | |
637 | print <<END; | |
638 | <tr> | |
639 | <td class='base' colspan='2' bgcolor="$Header::colourorange" align='center'> | |
640 | <font color='white'>$Lang::tr{'tor traffic limit soft'}</font> | |
641 | </td> | |
642 | </tr> | |
643 | END | |
644 | } | |
645 | ||
646 | print <<END; | |
647 | <tr> | |
648 | <td width='40%' class='base'>$Lang::tr{'tor accounting interval'}</td> | |
649 | <td width='60%'> | |
650 | $accounting->{'interval-start'} - $accounting->{'interval-end'} | |
651 | </td> | |
652 | </tr> | |
653 | <tr> | |
654 | <td width='40%' class='base'>$Lang::tr{'tor accounting bytes'}</td> | |
655 | <td width='60%'> | |
656 | END | |
657 | ||
658 | print &FormatBytes($accounting->{'bytes_read'}) . "/" . &FormatBytes($accounting->{'bytes_written'}); | |
659 | print " (" . &FormatBytes($accounting->{'bytes-left_read'}) . "/" . &FormatBytes($accounting->{'bytes-left_written'}); | |
660 | print " $Lang::tr{'tor accounting bytes left'})"; | |
661 | ||
662 | print <<END; | |
663 | </td> | |
664 | </tr> | |
665 | </table> | |
666 | END | |
667 | } | |
668 | ||
669 | my @nodes = &TorORConnStatus($torctrl); | |
670 | if (@nodes) { | |
f16bcc3e | 671 | my $nodes_length = scalar @nodes; |
13b5ce6e | 672 | print <<END; |
3387469b | 673 | <table width='95%'> |
13b5ce6e | 674 | <tr> |
f16bcc3e MT |
675 | <td width='40%' class='base'><b>$Lang::tr{'tor connected relays'}</b></td> |
676 | <td width='60%' colspan='2'>($nodes_length)</td> | |
13b5ce6e MT |
677 | </tr> |
678 | END | |
679 | ||
680 | foreach my $node (@nodes) { | |
681 | print <<END; | |
682 | <tr> | |
683 | <td width='40%'> | |
0675a66d | 684 | <a href='https://metrics.torproject.org/rs.html#details/$node->{'fingerprint'}' target='_blank'> |
13b5ce6e MT |
685 | $node->{'name'} |
686 | </a> | |
687 | </td> | |
688 | <td width='30%'> | |
689 | END | |
690 | ||
691 | if (exists($node->{'country_code'})) { | |
a9a28430 | 692 | # Get the flag icon of the country. |
0893eef4 | 693 | my $flag_icon = &Location::Functions::get_flag_icon($node->{'country_code'}); |
a9a28430 SS |
694 | |
695 | # Check if a flag for the given country is available. | |
696 | if ($flag_icon) { | |
697 | print "<a href='country.cgi#$node->{'country_code'}'><img src='$flag_icon' border='0' align='absmiddle' alt='$node->{'country_code'}'></a>"; | |
3387469b | 698 | } else { |
a9a28430 | 699 | print "<img src='/images/flags/blank.png' border='0' align='absmiddle'/>"; |
3387469b | 700 | } |
13b5ce6e MT |
701 | } |
702 | ||
703 | print <<END; | |
704 | <a href='ipinfo.cgi?ip=$node->{'address'}'>$node->{'address'}</a>:$node->{'port'} | |
705 | </td> | |
706 | <td width='30%' align='right'> | |
707 | ~$node->{'bandwidth_string'} | |
708 | </td> | |
709 | </tr> | |
710 | END | |
711 | } | |
712 | print "</table>"; | |
713 | } | |
714 | ||
715 | &Header::closebox(); | |
716 | } | |
717 | ||
718 | print "</form>\n"; | |
719 | ||
720 | &Header::closebigbox(); | |
721 | &Header::closepage(); | |
722 | } | |
723 | ||
724 | sub BuildConfiguration() { | |
725 | my %settings = (); | |
726 | &General::readhash("${General::swroot}/tor/settings", \%settings); | |
727 | ||
728 | my $torrc = "${General::swroot}/tor/torrc"; | |
729 | ||
730 | open(FILE, ">$torrc"); | |
731 | ||
732 | # Global settings. | |
733 | print FILE "ControlPort $TOR_CONTROL_PORT\n"; | |
734 | ||
735 | if ($settings{'TOR_ENABLED'} eq 'on') { | |
736 | my $strict_nodes = 0; | |
737 | ||
738 | print FILE "SocksPort 0.0.0.0:$settings{'TOR_SOCKS_PORT'}\n"; | |
739 | ||
740 | my @subnets = split(",", $settings{'TOR_ALLOWED_SUBNETS'}); | |
741 | foreach (@subnets) { | |
742 | print FILE "SocksPolicy accept $_\n" if (&General::validipandmask($_)); | |
743 | } | |
744 | print FILE "SocksPolicy reject *\n" if (@subnets); | |
745 | ||
7c507f3d PM |
746 | if ($settings{'TOR_GUARD_COUNTRY'} ne '') { |
747 | $strict_nodes = 1; | |
748 | my $countrylist; | |
749 | ||
750 | for my $singlecountry (split(/\|/, $settings{'TOR_GUARD_COUNTRY'})) { | |
751 | if ($countrylist eq '') { | |
752 | $countrylist = "{" . lc $singlecountry . "}"; | |
753 | } else { | |
754 | $countrylist = $countrylist . "," . "{" . lc $singlecountry . "}"; | |
755 | } | |
756 | } | |
757 | ||
758 | print FILE "EntryNodes $countrylist\n"; | |
759 | } | |
760 | ||
761 | if ($settings{'TOR_USE_GUARD_NODES'} ne '') { | |
762 | $strict_nodes = 1; | |
763 | ||
764 | my @nodes = split(",", $settings{'TOR_USE_GUARD_NODES'}); | |
765 | foreach (@nodes) { | |
766 | print FILE "EntryNode $_\n"; | |
767 | } | |
768 | } | |
769 | ||
13b5ce6e MT |
770 | if ($settings{'TOR_EXIT_COUNTRY'} ne '') { |
771 | $strict_nodes = 1; | |
5efe8957 PM |
772 | my $countrylist; |
773 | ||
774 | for my $singlecountry (split(/\|/, $settings{'TOR_EXIT_COUNTRY'})) { | |
775 | if ($countrylist eq '') { | |
776 | $countrylist = "{" . lc $singlecountry . "}"; | |
777 | } else { | |
778 | $countrylist = $countrylist . "," . "{" . lc $singlecountry . "}"; | |
779 | } | |
780 | } | |
13b5ce6e | 781 | |
5efe8957 | 782 | print FILE "ExitNodes $countrylist\n"; |
13b5ce6e MT |
783 | } |
784 | ||
785 | if ($settings{'TOR_USE_EXIT_NODES'} ne '') { | |
786 | $strict_nodes = 1; | |
787 | ||
788 | my @nodes = split(",", $settings{'TOR_USE_EXIT_NODES'}); | |
789 | foreach (@nodes) { | |
790 | print FILE "ExitNode $_\n"; | |
791 | } | |
792 | } | |
793 | ||
794 | if ($strict_nodes > 0) { | |
795 | print FILE "StrictNodes 1\n"; | |
796 | } | |
797 | } | |
798 | ||
799 | if ($settings{'TOR_RELAY_ENABLED'} eq 'on') { | |
800 | # Reject access to private networks. | |
801 | print FILE "ExitPolicyRejectPrivate 1\n"; | |
802 | ||
919a5020 | 803 | print FILE "ORPort $settings{'TOR_RELAY_PORT'}\n"; |
13b5ce6e | 804 | |
4245fe34 JPT |
805 | if ($settings{'TOR_RELAY_DIRPORT'} ne '0') { |
806 | print FILE "DirPort $settings{'TOR_RELAY_DIRPORT'}\n"; | |
807 | } | |
808 | ||
13b5ce6e MT |
809 | if ($settings{'TOR_RELAY_ADDRESS'} ne '') { |
810 | print FILE "Address $settings{'TOR_RELAY_ADDRESS'}\n"; | |
811 | } | |
812 | ||
813 | if ($settings{'TOR_RELAY_NICKNAME'} ne '') { | |
814 | print FILE "Nickname $settings{'TOR_RELAY_NICKNAME'}\n"; | |
815 | } | |
816 | ||
817 | if ($settings{'TOR_RELAY_CONTACT_INFO'} ne '') { | |
818 | print FILE "ContactInfo $settings{'TOR_RELAY_CONTACT_INFO'}\n"; | |
819 | } | |
820 | ||
821 | # Limit to bridge mode. | |
822 | my $is_bridge = 0; | |
823 | ||
824 | if ($settings{'TOR_RELAY_MODE'} eq 'bridge') { | |
825 | $is_bridge++; | |
826 | ||
827 | # Private bridge. | |
828 | } elsif ($settings{'TOR_RELAY_MODE'} eq 'private-bridge') { | |
829 | $is_bridge++; | |
830 | ||
831 | print FILE "PublishServerDescriptor 0\n"; | |
832 | ||
833 | # Exit node. | |
834 | } elsif ($settings{'TOR_RELAY_MODE'} eq 'exit') { | |
835 | print FILE "ExitPolicy accept *:*\n"; | |
836 | ||
837 | # Relay only. | |
838 | } elsif ($settings{'TOR_RELAY_MODE'} eq 'relay') { | |
839 | print FILE "ExitPolicy reject *:*\n"; | |
840 | } | |
841 | ||
842 | if ($is_bridge > 0) { | |
843 | print FILE "BridgeRelay 1\n"; | |
844 | print FILE "Exitpolicy reject *:*\n"; | |
845 | } | |
846 | ||
847 | if ($settings{'TOR_RELAY_BANDWIDTH_RATE'} > 0) { | |
848 | print FILE "RelayBandwidthRate "; | |
849 | print FILE $settings{'TOR_RELAY_BANDWIDTH_RATE'} / 8; | |
850 | print FILE " KB\n"; | |
851 | ||
852 | if ($settings{'TOR_RELAY_BANDWIDTH_BURST'} > 0) { | |
853 | print FILE "RelayBandwidthBurst "; | |
854 | print FILE $settings{'TOR_RELAY_BANDWIDTH_BURST'} / 8; | |
855 | print FILE " KB\n"; | |
856 | } | |
857 | } | |
858 | ||
859 | if ($settings{'TOR_RELAY_ACCOUNTING_LIMIT'} > 0) { | |
860 | print FILE "AccountingMax ".$settings{'TOR_RELAY_ACCOUNTING_LIMIT'}." MB\n"; | |
861 | ||
862 | if ($settings{'TOR_RELAY_ACCOUNTING_PERIOD'} eq 'daily') { | |
863 | print FILE "AccountingStart day 00:00\n"; | |
864 | } elsif ($settings{'TOR_RELAY_ACCOUNTING_PERIOD'} eq 'weekly') { | |
865 | print FILE "AccountingStart week 1 00:00\n"; | |
866 | } elsif ($settings{'TOR_RELAY_ACCOUNTING_PERIOD'} eq 'monthly') { | |
867 | print FILE "AccountingStart month 1 00:00\n"; | |
868 | } | |
869 | } | |
870 | } | |
871 | ||
872 | close(FILE); | |
873 | ||
874 | # Restart the service. | |
875 | if (($settings{'TOR_ENABLED'} eq 'on') || ($settings{'TOR_RELAY_ENABLED'} eq 'on')) { | |
005db206 | 876 | system("/usr/local/bin/torctrl restart &>/dev/null"); |
13b5ce6e | 877 | } else { |
005db206 | 878 | system("/usr/local/bin/torctrl stop &>/dev/null"); |
13b5ce6e | 879 | } |
3387469b JPT |
880 | # Update pid and memory |
881 | daemonstats(); | |
13b5ce6e MT |
882 | } |
883 | ||
884 | sub TorConnect() { | |
885 | my $socket = new IO::Socket::INET( | |
886 | Proto => 'tcp', PeerAddr => '127.0.0.1', PeerPort => $TOR_CONTROL_PORT, | |
887 | ) or return; | |
888 | ||
889 | $socket->autoflush(1); | |
890 | ||
891 | # Authenticate. | |
892 | &TorSendCommand($socket, "AUTHENTICATE"); | |
893 | ||
894 | return $socket; | |
895 | } | |
896 | ||
897 | sub TorSendCommand() { | |
898 | my ($socket, $cmd) = @_; | |
899 | ||
900 | # Replace line ending with \r\n. | |
901 | chomp $cmd; | |
902 | $cmd .= "\r\n"; | |
903 | ||
904 | $socket->send($cmd); | |
905 | ||
906 | my @output = (); | |
907 | while (my $line = <$socket>) { | |
908 | # Skip empty lines. | |
909 | if ($line =~ /^.\r\n$/) { | |
910 | next; | |
911 | } | |
912 | ||
913 | # Command has been successfully executed. | |
914 | if ($line =~ /250 OK/) { | |
915 | last; | |
916 | ||
917 | # Error. | |
918 | } elsif ($line =~ /^5\d+/) { | |
919 | last; | |
920 | ||
921 | } else { | |
922 | # Remove line endings. | |
923 | $line =~ s/\r\n$//; | |
924 | ||
925 | push(@output, $line); | |
926 | } | |
927 | } | |
928 | ||
929 | return @output; | |
930 | } | |
931 | ||
932 | sub TorSendCommandOneLine() { | |
933 | my ($tor, $cmd) = @_; | |
934 | ||
935 | my @output = &TorSendCommand($tor, $cmd); | |
936 | return $output[0]; | |
937 | } | |
938 | ||
939 | sub TorGetInfo() { | |
940 | my ($tor, $cmd) = @_; | |
941 | ||
942 | my $output = &TorSendCommandOneLine($tor, "GETINFO ".$cmd); | |
943 | ||
944 | my ($key, $value) = split("=", $output); | |
945 | return $value; | |
946 | } | |
947 | ||
948 | sub TorClose() { | |
949 | my $socket = shift; | |
950 | ||
951 | if ($socket) { | |
952 | $socket->shutdown(2); | |
953 | } | |
954 | } | |
955 | ||
956 | sub TorTrafficStats() { | |
957 | my $tor = shift; | |
958 | ||
959 | my $output_read = &TorGetInfo($tor, "traffic/read"); | |
960 | my $output_written = &TorGetInfo($tor, "traffic/written"); | |
961 | ||
962 | return ($output_read, $output_written); | |
963 | } | |
964 | ||
965 | sub TorRelayFingerprint() { | |
966 | my $tor = shift; | |
967 | ||
968 | return &TorGetInfo($tor, "fingerprint"); | |
969 | } | |
970 | ||
971 | sub TorORConnStatus() { | |
972 | my $tor = shift; | |
973 | my @nodes = (); | |
974 | ||
975 | my @output = &TorSendCommand($tor, "GETINFO orconn-status"); | |
976 | foreach (@output) { | |
977 | $_ =~ s/^250[\+-]orconn-status=//; | |
978 | next if ($_ eq ""); | |
979 | last if ($_ eq "."); | |
980 | next unless ($_ =~ /^\$/); | |
981 | ||
982 | my @line = split(" ", $_); | |
983 | my @node = split(/[=~]/, $line[0]); | |
984 | ||
985 | my $node = &TorNodeDescription($tor, $node[0]); | |
986 | if ($node) { | |
987 | push(@nodes, $node); | |
988 | } | |
989 | } | |
990 | ||
991 | # Sort by names. | |
992 | @nodes = sort { $a->{'name'} cmp $b->{'name'} } @nodes; | |
993 | ||
994 | return @nodes; | |
995 | } | |
996 | ||
997 | sub TorNodeDescription() { | |
998 | my ($tor, $fingerprint) = @_; | |
999 | $fingerprint =~ s/\$//; | |
1000 | ||
1001 | my $node = { | |
1002 | fingerprint => $fingerprint, | |
1003 | exit_node => 0, | |
1004 | }; | |
1005 | ||
1006 | my @output = &TorSendCommand($tor, "GETINFO ns/id/$node->{'fingerprint'}"); | |
1007 | ||
1008 | foreach (@output) { | |
1009 | # Router | |
1010 | if ($_ =~ /^r (\w+) (.*) (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) (\d+)/) { | |
1011 | $node->{'name'} = $1; | |
1012 | $node->{'address'} = $3; | |
1013 | $node->{'port'} = $4; | |
1014 | ||
07e42be9 | 1015 | my $country_code = &Location::Functions::lookup_country_code($node->{'address'}); |
13b5ce6e MT |
1016 | $node->{'country_code'} = $country_code; |
1017 | ||
1018 | # Flags | |
1019 | } elsif ($_ =~ /^s (.*)$/) { | |
1020 | $node->{'flags'} = split(" ", $1); | |
1021 | ||
1022 | foreach my $flag ($node->{'flags'}) { | |
1023 | if ($flag eq "Exit") { | |
1024 | $node->{'exit_node'}++; | |
1025 | } | |
1026 | } | |
1027 | ||
1028 | # Bandwidth | |
1029 | } elsif ($_ =~ /^w Bandwidth=(\d+)/) { | |
1030 | $node->{'bandwidth'} = $1 * 8; | |
1031 | $node->{'bandwidth_string'} = &FormatBitsPerSecond($node->{'bandwidth'}); | |
1032 | } | |
1033 | } | |
1034 | ||
1035 | if (exists($node->{'name'})) { | |
1036 | return $node; | |
1037 | } | |
1038 | } | |
1039 | ||
1040 | sub TorAccountingStats() { | |
1041 | my $tor = shift; | |
1042 | my $ret = {}; | |
1043 | ||
1044 | my $enabled = &TorGetInfo($tor, "accounting/enabled"); | |
1045 | if ($enabled ne '1') { | |
1046 | return; | |
1047 | } | |
1048 | ||
1049 | my @cmds = ("hibernating", "interval-start", "interval-end"); | |
1050 | foreach (@cmds) { | |
1051 | $ret->{$_} = &TorGetInfo($tor, "accounting/$_"); | |
1052 | } | |
1053 | ||
1054 | my @cmds = ("bytes", "bytes-left"); | |
1055 | foreach (@cmds) { | |
1056 | my $output = &TorGetInfo($tor, "accounting/$_"); | |
1057 | my @bytes = split(" ", $output); | |
1058 | ||
1059 | $ret->{$_."_read"} = $bytes[0]; | |
1060 | $ret->{$_."_written"} = $bytes[1]; | |
1061 | } | |
1062 | ||
1063 | return $ret; | |
1064 | } | |
1065 | ||
1066 | sub FormatBytes() { | |
1067 | my $bytes = shift; | |
1068 | ||
1069 | my @units = ("B", "KB", "MB", "GB", "TB"); | |
1070 | my $units_index = 0; | |
1071 | ||
1072 | while (($units_index <= $#units) && ($bytes >= 1024)) { | |
1073 | $units_index++; | |
1074 | $bytes /= 1024; | |
1075 | } | |
1076 | ||
1077 | return sprintf("%.2f %s", $bytes, $units[$units_index]); | |
1078 | } | |
1079 | ||
1080 | sub FormatBitsPerSecond() { | |
1081 | my $bits = shift; | |
1082 | ||
f00699e8 | 1083 | my @units = ("bit/s", "kbit/s", "Mbit/s", "Gbit/s", "Tbit/s"); |
13b5ce6e MT |
1084 | my $units_index = 0; |
1085 | ||
1086 | while (($units_index <= $#units) && ($bits >= 1024)) { | |
1087 | $units_index++; | |
1088 | $bits /= 1024; | |
1089 | } | |
1090 | ||
1091 | return sprintf("%.2f %s", $bits, $units[$units_index]); | |
1092 | } |