File Coverage

blib/lib/LWP/UserAgent/Tor.pm
Criterion Covered Total %
statement 29 67 43.2
branch 0 14 0.0
condition 0 11 0.0
subroutine 10 14 71.4
pod 2 2 100.0
total 41 108 37.9


line stmt bran cond sub pod time code
1             package LWP::UserAgent::Tor;
2              
3 2     2   28992 use 5.010;
  2         4  
4 2     2   6 use strict;
  2         2  
  2         27  
5 2     2   11 use warnings;
  2         4  
  2         33  
6 2     2   10 use Carp;
  2         2  
  2         99  
7 2     2   1089 use LWP::UserAgent;
  2         61229  
  2         46  
8 2     2   885 use IO::Socket::INET;
  2         30477  
  2         10  
9 2     2   2391 use LWP::Protocol::socks;
  2         129298  
  2         62  
10 2     2   800 use Net::EmptyPort qw(empty_port);
  2         5102  
  2         106  
11 2     2   850 use Proc::Background;
  2         4514  
  2         78  
12              
13 2     2   15 use base 'LWP::UserAgent';
  2         2  
  2         832  
14              
15             our $VERSION = '0.04';
16              
17             sub new {
18 0     0 1   my ($class, %args) = @_;
19              
20 0   0       my $tor_control_port = delete( $args{tor_control_port} ) // empty_port();
21 0   0       my $tor_port = delete( $args{tor_port} ) // do {
22 0           my $port;
23 0           while (($port = empty_port()) == $tor_control_port){};
24 0           $port;
25             };
26 0   0       my $tor_ip = delete( $args{tor_ip} ) // 'localhost';
27 0           my $tor_cfg = delete( $args{tor_cfg} );
28              
29 0           my $self = $class->SUPER::new(%args);
30 0           $self->{_tor_proc} = _start_tor_proc($tor_ip, $tor_port, $tor_control_port, $tor_cfg);
31 0   0       $self->{_tor_socket} = IO::Socket::INET->new(
32             PeerAddr => $tor_ip,
33             PeerPort => $tor_control_port,
34             ) // croak 'could not connect to tor';
35              
36 0           $self->proxy( [ 'http', 'https' ], "socks://$tor_ip:$tor_port" );
37              
38 0           return bless $self, $class;
39             }
40              
41             sub DESTROY {
42 0     0     my ($self) = @_;
43              
44 0           my $tor_proc = $self->{_tor_proc};
45 0 0         $tor_proc->die if defined $tor_proc;
46 0 0         $self->SUPER::DESTROY if $self->can('SUPER::DESTROY');
47              
48 0           return;
49             }
50              
51             sub _start_tor_proc {
52 0     0     my ($ip, $port, $control_port, $cfg) = @_;
53              
54 0           my $tor_cmd = "tor --ControlListenaddress $ip:$control_port --ControlPort auto --SocksPort $port --quiet";
55 0 0         if (defined $cfg){
56 0 0         croak 'tor config file does not exist' unless -e $cfg;
57 0           $tor_cmd .= " -f $cfg";
58             }
59              
60 0           my $tor_proc = Proc::Background->new($tor_cmd);
61              
62             # starting tor...
63 0           sleep 1;
64              
65 0 0         if (!$tor_proc->alive) {
66 0           croak "error running tor (probably not installed?). Run tor manually to get a hint.";
67             }
68              
69 0           return $tor_proc;
70             }
71              
72              
73             sub rotate_ip {
74 0     0 1   my ($self) = @_;
75              
76 0           my $socket = $self->{_tor_socket};
77 0           my $answer = q{};
78              
79 0           $socket->send("AUTHENTICATE\n");
80 0           $socket->recv($answer, 1024);
81 0 0         return 0 unless $answer eq "250 OK\r\n";
82              
83 0           $socket->send("SIGNAL NEWNYM\n");
84 0           $socket->recv($answer, 1024);
85 0 0         return 0 unless $answer eq "250 OK\r\n";
86              
87 0           return 1;
88             }
89              
90             1;
91              
92             __END__