A tor server manager running multiple clients load-balanced using iptables.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

tor_controller.pl 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #!/usr/bin/perl
  2. use strict;
  3. use Data::Dumper;
  4. use warnings;
  5. my %conf = (
  6. avail => 10,
  7. spare => 3,
  8. ipt_chain => "PREROUTING",
  9. ipt_rule => "-p tcp -m tcp --dport 777 -m statistic --mode random --probability %s -j REDIRECT --to-ports %s",
  10. ipt_table => 'nat',
  11. socks_offset => 9000,
  12. path => '/opt/tor',
  13. dns_check => [
  14. 'www.microsoft.com',
  15. 'www.google.com',
  16. ],
  17. );
  18. my @var;
  19. run();
  20. sub run {
  21. check_processes();
  22. check_dns();
  23. check_download();
  24. sleep(10);
  25. }
  26. sub check_processes {
  27. my $inuse=0;
  28. my @spares;
  29. for(my $id=0; defined $var[$id]; $id++) {
  30. if ( $var[$id]{state} eq "ready" ) {
  31. if ( $var[$id]{mode} eq "spare" ) {
  32. push @spares, $id;
  33. }
  34. elsif ( $var[$id]{mode} eq "live" ) {
  35. $inuse++;
  36. }
  37. }
  38. }
  39. if ( $inuse < $conf{avail} ) {
  40. print "missing live processes. looking for spares.\n";
  41. for(my $x=0; $x<($conf{avail}-$inuse; $x++) {
  42. my $new = pop @spares;
  43. if ( defined $new ) {
  44. print "moving spare to prod.\n";
  45. tor_prod($id);
  46. }
  47. }
  48. }
  49. if ( @spares < $conf{spares} ) {
  50. print "missing spare processes, starting new ones.\n";
  51. for(my $x=0; $x< @spares-$conf{spares}; $x++) {
  52. tor_new();
  53. }
  54. }
  55. }
  56. sub check_dns {
  57. my($id) = @_;
  58. my $ok = 0;
  59. foreach my $hostname ( @{$conf{dns_check} ) {
  60. system("tor-resolve $hostname 127.0.0.1:$var[$id]{port} 2>/dev/null 2>&1");
  61. $ok++ if ! $?;
  62. }
  63. switch(get_state($id)) {
  64. case "STARTUP" { set_state("SPARE") if $ok; }
  65. case "SPARE" { set_state("PROBLEM") if !$ok; }
  66. }
  67. if ( $s eq 'DNS_CHECK' && $ok ) {
  68. $var[$id]{state}++;
  69. }
  70. elsif ( $s eq 'AVAILABLE' && ! $ok ) {
  71. $var[$id]{state}++;
  72. }
  73. elsif ( $s eq 'TEMPORARY_UNAVAILABLE' ) {
  74. $var[$id}{state}++
  75. if ( ! $ok ) {
  76. }
  77. }
  78. sub tor_new {
  79. my $next;
  80. # try to recycle a position
  81. for(my $id=0; defined $var[$id]; $id++) {
  82. if ( $state[$var[$id]{state}] eq 'KILLED' ) {
  83. $next = $id;
  84. last;
  85. }
  86. }
  87. # alternatively, create a new position
  88. if ( !defined $next ) {
  89. $next = @var;
  90. }
  91. $var[$next] = {
  92. state => 0,
  93. port => $conf{port_offset} + $next,
  94. pid => undef,
  95. };
  96. # create a config file and the required files and directories
  97. my $datadir = "$conf{path}/var/lib/$id";
  98. my %files = (
  99. config => "$conf{path}/etc/$id.conf",
  100. pidfile => "$conf{path}/run/$id.pid",
  101. socket => "$conf{path}/run/$id.socks",
  102. ctrl => "$conf{path}/run/$id.ctrl",
  103. cookie => "$conf{path}/run/$id.cookie",
  104. );
  105. system("mkdir -p $datadir");
  106. system("chmod 700 $datadir");
  107. system("chown debian-tor:debian-tor $datadir");
  108. foreach my $f ( keys $files ) {
  109. system("touch $files{$f}");
  110. system("chown debian-tor:debian-tor $files{$f}");
  111. }
  112. open(C,">$files{config}");
  113. print C <<EOF;
  114. DataDirectory $datadir
  115. PidFile $files{pidfile}
  116. RunAsDaemon 0
  117. User debian-tor
  118. ControlSocket $files{ctrl} GroupWritable RelaxDirModeCheck
  119. ControlSocketsGroupWritable 1
  120. SocksPort unix:$files{socks} WorldWritable
  121. SocksPort $var[$id]{port}
  122. CookieAuthentication 1
  123. CookieAuthFileGroupReadable 1
  124. CookieAuthFile $files{cookie}
  125. BandwidthRate 10MB
  126. Log notice syslog
  127. EOF
  128. close(C);
  129. system("cd $conf{dir} && tor -f $files{config}");
  130. }
  131. sub tor_prod {
  132. my($id) = @_;
  133. # move process from spare to prod
  134. $var[$id]{state}++;
  135. ipt_add($var[$id]{port});
  136. }
  137. sub ipt_add {
  138. my($port) = @_;
  139. system("iptables -t $conf{ipt_table} -A $conf{ipt_chain} " . sprintf($conf{ipt_rule}, "1.0", $port));
  140. ipt_recalc();
  141. }
  142. sub ipt_del {
  143. my($port) = @_;
  144. open(IPT,"iptables -t $conf{ipt_table} -L $conf{ipt_chain} -n --line-numbers |");
  145. while(<IPT>) {
  146. chomp;
  147. if ( /^(\d+) .*mode random probability .* redir ports $port$/ ) {
  148. system("iptables -t $conf{ipt_table} -D $conf{ipt_chain} $1");
  149. }
  150. }
  151. close(IPT);
  152. ipt_recalc();
  153. }
  154. sub ipt_recalc {
  155. my @rules;
  156. open(IPT,"iptables -t $conf{ipt_table} -L $conf{ipt_chain} -n --line-numbers |");
  157. while(<IPT>) {
  158. chomp;
  159. if ( /^(\d+) .*mode random probability .* redir ports (\d+)$/ ) {
  160. push @rules, [ $1, $2 ];
  161. }
  162. }
  163. close(IPT);
  164. my $nums = @rules;
  165. for(my $num = 0; defined $rules[$num]; $num++) {
  166. my($rulenum,$port)=@{$rules[$num]};
  167. my $prob = 1 / ($nums - $num);
  168. system("iptables -t $conf{ipt_table} -R $conf{ipt_chain} $rulenum " . sprintf($conf{ipt_rule}, $prob, $port));
  169. }
  170. }