2

I installed tor on a ubuntu-server with the command

sudo apt-get install tor

and I also installed socks:

sudo cpan LWP::Protocol::socks

After this i wrote a perl script to read websites using the tor network, which works very well (simplified example):

#!/usr/bin/perl
use strict;
use LWP::UserAgent;
my $ua = LWP::UserAgent->new('agent' => 'any user agent string'},
);
$ua->proxy([qw/ http https /] => 'socks://localhost:9050'); # Tor proxy
$ua->cookie_jar({});
my $response = $ua->get('http://www.example.com/');
print $response->content;

As said before, this works very well, but there are some servers who block some tor exit nodes. Instead of sending the expected content with http-status 200 (ok) they send the status 403 (forbidden). But some minutes later the same server sends 200 (ok) together with the expected content, so I'm pretty sure that the problem are exit nodes who's IP addresses are blacklisted.

I know, that tor itself changes the route (and so the exit node) as far as I know every 10 minutes. But in the case, that a server sends 403 because it has made bad experiences with the concrete exit node that I'm using in this moment, I don't want to wait 10 minutes to get another exit node that hopefully is not blocked.

I want to change my perl script into something like this:

#!/usr/bin/perl
use strict;
use LWP::UserAgent;
my $ua = LWP::UserAgent->new('agent' => 'any user agent string'},
);
$ua->proxy([qw/ http https /] => 'socks://localhost:9050'); # Tor proxy
$ua->cookie_jar({});


my $code = 403;
my $content = '';
while ($code > 399) {
    my $response = $ua->get('http://www.example.com/');
    $code = $response->code();
    if ($code > 399) {
        #####################################
        #  TELL TOR TO USE A NEW EXIT NODE  #
        #####################################
    } else {
        $content = $response->content;
    }
}
print $content;

Note, that this example is simplified: Not all http-status above 400 are usefull to change the route, and there are also some other reasons, that make it necessary to tell tor to use a new exit node.

My question is:

a) How can a perl script tell tor to change its route?
b) What other possibilities are there to control tor from a perl script?

2

In response to part a) of your question, you can send Tor a SIGHUP. This won't kill the process, merely cause it to reload its configuration file, and create a new circuit.

In your script you could either use kill (using system(), etc.), in which case you'd need to know the pid of the Tor process you're controlling, or pkill, though in the case of the latter, you'd have no way of distinguishing between different Tor processes (if you were running more than one).

kill -SIGHUP <pid_of_tor>

Or:

pkill -SIGHUP tor

This assumes you're on a Linux box. I believe OS X has the similar -HUP signal, and I imagine Windows does too. Check the man page for more signals that can be handled by the process.

With regards to part b) of your question, I don't have any Perl-specific suggestions. If you're open to other scripting languages, have a look at Stem - a fully featured Python API - or one of the other controller libraries listed on Stem's FAQ page.

Edit

The following short script has been tested and works with the desired effect of killing an already-running Tor process:

#!/usr/bin/perl
use strict;

system('pkill -SIGHUP tor')

Edit #2

It's likely that the script won't work as desired in the OP's case (see comments below). However, the answer may be of use to others with slightly different requirements.

  • Yes, tor and my script are running under linux (Ubuntu is a well known linux distribution). To "kill" tor sounds strange, but I'll try it. Too bad that there is no perl module to control tor. But on the FAQ page I did read, that there seems to be also a way to directly interact with Tor's controller interface. – Hubert Schölnast Oct 16 '15 at 18:09
  • 1
    kill is just the command you use to deliver a signal to a process. If you don't specify which signal, it delivers a SIGTERM by default, which will terminate the process (hence the scary name). Language choice is always a controversial subject, so I'm not going to tell you not to use Perl (and I'm sure it still has valid use cases) :) What I will say is that everything I used to do in Perl, I now do in Python. – Richard Horrocks Oct 17 '15 at 9:55
  • Sorry, this solution does not work. I can execute the system call pkill -SIGHUP tor from my perl script, but TOR still keeps using the old circuit. This command only works when I stop my perl script, send this command from command line, and then restart my script. – Hubert Schölnast Oct 21 '15 at 10:08
  • It works for me. I've edited my answer to include a very short script that kills the Tor process which is already running on my system. Are you sure your script is executing the system() call? i.e. Is it falling into the correct path? Have you written your script as a different user that doesn't have permission to kill the process? Are there any warnings being output by the script? – Richard Horrocks Oct 21 '15 at 16:22
  • I used backticks instead of "system", but this does exactly the same. I wrote the script as root and I am running my script as root. No, there are no warnings. With your mini-script (with backticks instead of system) I also can manage, that tor uses a different circuit AFTER the script has ENDED. But it keeps using the old circuit WHILE the perl script is running (which means: while I have a living socks connection to TOR). See also: stackoverflow.com/questions/33256934/… – Hubert Schölnast Oct 21 '15 at 17:35
1

After crawling through manny different documentations I found a solution:

if (my $socket = new IO::Socket::INET(
            'PeerHost' => '127.0.0.1',
            'PeerPort' => '9051',
            'Proto'    => 'tcp')) {
    my @requ = ('authenticate ""','SIGNAL NEWNYM','QUIT');
    foreach my $requ (@requ) {
        print $socket $requ."\n";
        my $dummy = <$socket>;
    }
    $socket->close();
    print "OK: New circuit established\n";
} else {
    print "ERROR: couldn't connect with socket\n";
}

Explanation:

my $socket = new IO::Socket::INET(
            'PeerHost' => '127.0.0.1',
            'PeerPort' => '9051',
            'Proto'    => 'tcp')

creates a new socket object. If this did work, it returns the socket, otherwise undef.

I embedded this statement in an if-Statement. Its first block will be executed if the socket could be created, the second block prints an error message.

In the if-Block, I send this three commants through the socket to TOR:

  1. authenticate ""
  2. SIGNAL NEWNYM
  3. QUIT

1 performs the null-authentification
2 does what I really want: This command tells TOR to establish a new circuit.
3 quits the conversation

At the end I close the socket and print a message.

I don't analyze TOR's response, but I have to read it (with $dummy = <$socket>;). One could check, if TOR really answers three times with "250", and react if not. But I decided to hope, that it always works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.