File Coverage

blib/lib/IO/Stream/Proxy/SOCKSv4.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package IO::Stream::Proxy::SOCKSv4;
2              
3 2     2   35008 use warnings;
  2         4  
  2         74  
4 2     2   13 use strict;
  2         5  
  2         66  
5 2     2   12 use Carp;
  2         9  
  2         182  
6              
7 2     2   1827 use version; our $VERSION = qv('1.0.2'); # update POD & Changes & README
  2         4810  
  2         15  
8              
9             # update DEPENDENCIES in POD & Makefile.PL & README
10 2     2   1171 use IO::Stream::const;
  0            
  0            
11             use IO::Stream::EV;
12             use Scalar::Util qw( weaken );
13              
14             use constant VN => 0x04; # SOCKS protocol version number (4)
15             use constant CD => 0x01; # SOCKS protocol command code (CONNECT)
16             use constant REPLY_LEN=> 8; # SOCKS protocol reply length (bytes)
17             use constant REPLY_VN => 0; # SOCKS protocol reply code version
18             use constant REPLY_CD => 90;# SOCKS protocol reply code 'request granted'
19              
20              
21             sub new {
22             my ($class, $opt) = @_;
23             croak '{host}+{port} required'
24             if !defined $opt->{host}
25             || !defined $opt->{port}
26             ;
27             my $self = bless {
28             host => undef,
29             port => undef,
30             userid => q{},
31             %{$opt},
32             out_buf => q{}, # modified on: OUT
33             out_pos => undef, # modified on: OUT
34             out_bytes => 0, # modified on: OUT
35             in_buf => q{}, # modified on: IN
36             in_bytes => 0, # modified on: IN
37             ip => undef, # modified on: RESOLVED
38             is_eof => undef, # modified on: EOF
39             _want_write => undef,
40             }, $class;
41             return $self;
42             }
43              
44             sub PREPARE {
45             my ($self, $fh, $host, $port) = @_;
46             croak '{fh} already connected'
47             if !defined $host;
48             $self->{_slave}->PREPARE($fh, $self->{host}, $self->{port});
49             IO::Stream::EV::resolve($host, $self, sub {
50             my ($self, $ip) = @_;
51             $self->{_master}{ip} = $ip;
52             $self->{out_buf} = pack 'C C n CCCC Z*',
53             VN, CD, $port, split(/[.]/xms, $ip), $self->{userid};
54             $self->{_slave}->WRITE();
55             });
56             return;
57             }
58              
59             sub WRITE {
60             my ($self) = @_;
61             $self->{_want_write} = 1;
62             return;
63             }
64              
65             sub EVENT {
66             my ($self, $e, $err) = @_;
67             my $m = $self->{_master};
68             if ($err) {
69             $m->EVENT(0, $err);
70             }
71             if ($e & IN) {
72             if (length $self->{in_buf} < REPLY_LEN) {
73             $m->EVENT(0, 'socks v4 proxy: protocol error');
74             } else {
75             my ($vn, $cd) = unpack 'CC', $self->{in_buf};
76             substr $self->{in_buf}, 0, REPLY_LEN, q{};
77             if ($vn != REPLY_VN) {
78             $m->EVENT(0, 'socks v4 proxy: unknown version of reply code');
79             }
80             elsif ($cd != REPLY_CD) {
81             $m->EVENT(0, 'socks v4 proxy: error '.$cd);
82             }
83             else {
84             $e = CONNECTED;
85             if (my $l = length $self->{in_buf}) {
86             $e |= IN;
87             $m->{in_buf} .= $self->{in_buf};
88             $m->{in_bytes} += $l;
89             }
90             $m->EVENT($e);
91             $self->{_slave}->{_master} = $m;
92             weaken($self->{_slave}->{_master});
93             $m->{_slave} = $self->{_slave};
94             if ($self->{_want_write}) {
95             $self->{_slave}->WRITE();
96             }
97             }
98             }
99             }
100             if ($e & EOF) {
101             $m->{is_eof} = $self->{is_eof};
102             $m->EVENT(0, 'socks v4 proxy: unexpected EOF');
103             }
104             return;
105             }
106              
107              
108             1; # Magic true value required at end of module
109             __END__
110              
111             =head1 NAME
112              
113             IO::Stream::Proxy::SOCKSv4 - SOCKSv4 proxy plugin for IO::Stream
114              
115              
116             =head1 VERSION
117              
118             This document describes IO::Stream::Proxy::SOCKSv4 version 1.0.2
119              
120              
121             =head1 SYNOPSIS
122              
123             use IO::Stream;
124             use IO::Stream::Proxy::SOCKSv4;
125              
126             IO::Stream->new({
127             ...
128             plugin => [
129             ...
130             proxy => IO::Stream::Proxy::SOCKSv4->new({
131             host => 'my.proxy.com',
132             port => 3128,
133             }),
134             ...
135             ],
136             });
137              
138              
139             =head1 DESCRIPTION
140              
141             This module is plugin for L<IO::Stream> which allow you to route stream
142             through SOCKSv4 proxy.
143              
144             You may use several IO::Stream::Proxy::SOCKSv4 plugins for single IO::Stream
145             object, effectively creating proxy chain (first proxy plugin will define
146             last proxy in a chain).
147              
148             =head2 SECURITY
149              
150             Version 4 of SOCKS protocol doesn't support domain name resolving by proxy,
151             so resolving happens always on client side. This may result in leaking
152             client's DNS resolver IP address (usually it's client's address or client's
153             ISP address) and detecting the fact of using proxy.
154              
155             =head2 EVENTS
156              
157             When using this plugin event RESOLVED will never be delivered to user because
158             there may be two hosts to resolve (target host and proxy host) and it
159             isn't clear how to handle this case in right way.
160              
161             Event CONNECTED will be generated after SOCKS proxy successfully connects to
162             target {host} (and not when socket will connect to SOCKS proxy itself).
163              
164              
165             =head1 INTERFACE
166              
167             =over
168              
169             =item new({ host=>$host, port=>$port })
170              
171             =item new({ host=>$host, port=>$port, userid=>$ENV{USER} })
172              
173             Connect to proxy $host:$port, optionally using given userid (empty by default).
174              
175             =back
176              
177              
178             =head1 DIAGNOSTICS
179              
180             =over
181              
182             =item C<< {host}+{port} required >>
183              
184             You must provide both {host} and {port} to IO::Stream::Proxy::SOCKSv4->new().
185              
186             =item C<< {fh} already connected >>
187              
188             You have provided {fh} to IO::Stream->new(), but this is not supported by
189             this plugin. Either don't use this plugin or provide {host}+{port} to
190             IO::Stream->new() instead.
191              
192             =back
193              
194              
195              
196             =head1 CONFIGURATION AND ENVIRONMENT
197              
198             IO::Stream::Proxy::SOCKSv4 requires no configuration files or environment variables.
199              
200              
201             =head1 DEPENDENCIES
202              
203             L<IO::Stream>.
204              
205              
206             =head1 INCOMPATIBILITIES
207              
208             None reported.
209              
210              
211             =head1 BUGS AND LIMITATIONS
212              
213             SOCKS "BIND" request doesn't supported.
214              
215             No bugs have been reported.
216              
217             Please report any bugs or feature requests to
218             C<bug-io-stream-proxy-socksv4@rt.cpan.org>, or through the web interface at
219             L<http://rt.cpan.org>.
220              
221              
222             =head1 AUTHOR
223              
224             Alex Efros C<< <powerman-asdf@ya.ru> >>
225              
226              
227             =head1 LICENSE AND COPYRIGHT
228              
229             Copyright (c) 2009, Alex Efros C<< <powerman-asdf@ya.ru> >>. All rights reserved.
230              
231             This module is free software; you can redistribute it and/or
232             modify it under the same terms as Perl itself. See L<perlartistic>.
233              
234              
235             =head1 DISCLAIMER OF WARRANTY
236              
237             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
238             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
239             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
240             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
241             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
242             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
243             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
244             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
245             NECESSARY SERVICING, REPAIR, OR CORRECTION.
246              
247             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
248             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
249             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
250             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
251             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
252             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
253             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
254             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
255             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
256             SUCH DAMAGES.