File Coverage

blib/lib/IO/Socket/Socks.pm
Criterion Covered Total %
statement 707 1023 69.1
branch 268 536 50.0
condition 64 169 37.8
subroutine 58 72 80.5
pod 8 13 61.5
total 1105 1813 60.9


line stmt bran cond sub pod time code
1             package IO::Socket::Socks;
2              
3 34     34   469962 use strict;
  34         62  
  34         826  
4 34     34   14324 use IO::Select;
  34         38997  
  34         1313  
5 34     34   5313 use Socket;
  34         24397  
  34         11302  
6 34     34   15275 use Errno qw(EWOULDBLOCK EAGAIN EINPROGRESS ETIMEDOUT ECONNABORTED);
  34         44242  
  34         2852  
7 34     34   167 use Carp;
  34         34  
  34         1446  
8 34     34   94 use vars qw( $SOCKET_CLASS @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION $SOCKS_ERROR $SOCKS5_RESOLVE $SOCKS4_RESOLVE $SOCKS_DEBUG %CODES );
  34         41  
  34         3897  
9             require Exporter;
10              
11             $VERSION = '0.71';
12              
13             use constant {
14 34 50       7127 SOCKS_WANT_READ => 20,
15             SOCKS_WANT_WRITE => 21,
16             ESOCKSPROTO => exists &Errno::EPROTO ? &Errno::EPROTO : 7000,
17 34     34   123 };
  34         38  
18              
19             @ISA = ('Exporter', $SOCKET_CLASS||'');
20              
21             tie $SOCKET_CLASS, 'IO::Socket::Socks::SocketClassVar', $SOCKET_CLASS;
22             unless ($SOCKET_CLASS) {
23             if (eval { require IO::Socket::IP; IO::Socket::IP->VERSION(0.36) }) {
24             $SOCKET_CLASS = 'IO::Socket::IP';
25             }
26             else {
27             $SOCKET_CLASS = 'IO::Socket::INET';
28             }
29             }
30              
31             @EXPORT = qw( $SOCKS_ERROR SOCKS_WANT_READ SOCKS_WANT_WRITE ESOCKSPROTO );
32             @EXPORT_OK = qw(
33             SOCKS5_VER
34             SOCKS4_VER
35             ADDR_IPV4
36             ADDR_DOMAINNAME
37             ADDR_IPV6
38             CMD_CONNECT
39             CMD_BIND
40             CMD_UDPASSOC
41             AUTHMECH_ANON
42             AUTHMECH_USERPASS
43             AUTHMECH_INVALID
44             AUTHREPLY_SUCCESS
45             AUTHREPLY_FAILURE
46             ISS_UNKNOWN_ADDRESS
47             ISS_BAD_VERSION
48             ISS_CANT_RESOLVE
49             REPLY_SUCCESS
50             REPLY_GENERAL_FAILURE
51             REPLY_CONN_NOT_ALLOWED
52             REPLY_NETWORK_UNREACHABLE
53             REPLY_HOST_UNREACHABLE
54             REPLY_CONN_REFUSED
55             REPLY_TTL_EXPIRED
56             REPLY_CMD_NOT_SUPPORTED
57             REPLY_ADDR_NOT_SUPPORTED
58             REQUEST_GRANTED
59             REQUEST_FAILED
60             REQUEST_REJECTED_IDENTD
61             REQUEST_REJECTED_USERID
62             );
63             %EXPORT_TAGS = (constants => [ 'SOCKS_WANT_READ', 'SOCKS_WANT_WRITE', @EXPORT_OK ]);
64             tie $SOCKS_ERROR, 'IO::Socket::Socks::ReadOnlyVar', IO::Socket::Socks::Error->new();
65              
66             $SOCKS5_RESOLVE = 1;
67             $SOCKS4_RESOLVE = 0;
68             $SOCKS_DEBUG = $ENV{SOCKS_DEBUG};
69              
70             use constant {
71 34         10291 SOCKS5_VER => 5,
72             SOCKS4_VER => 4,
73              
74             ADDR_IPV4 => 1,
75             ADDR_DOMAINNAME => 3,
76             ADDR_IPV6 => 4,
77              
78             CMD_CONNECT => 1,
79             CMD_BIND => 2,
80             CMD_UDPASSOC => 3,
81              
82             AUTHMECH_ANON => 0,
83              
84             #AUTHMECH_GSSAPI => 1,
85             AUTHMECH_USERPASS => 2,
86             AUTHMECH_INVALID => 255,
87              
88             AUTHREPLY_SUCCESS => 0,
89             AUTHREPLY_FAILURE => 10, # to not intersect with other socks5 constants
90              
91             ISS_UNKNOWN_ADDRESS => 500,
92             ISS_BAD_VERSION => 501,
93             ISS_CANT_RESOLVE => 502,
94 34     34   150 };
  34         35  
95              
96             $CODES{AUTHMECH}->[AUTHMECH_INVALID] = "No valid auth mechanisms";
97             $CODES{AUTHREPLY}->[AUTHREPLY_FAILURE] = "Failed to authenticate";
98              
99             # socks5
100             use constant {
101 34         6212 REPLY_SUCCESS => 0,
102             REPLY_GENERAL_FAILURE => 1,
103             REPLY_CONN_NOT_ALLOWED => 2,
104             REPLY_NETWORK_UNREACHABLE => 3,
105             REPLY_HOST_UNREACHABLE => 4,
106             REPLY_CONN_REFUSED => 5,
107             REPLY_TTL_EXPIRED => 6,
108             REPLY_CMD_NOT_SUPPORTED => 7,
109             REPLY_ADDR_NOT_SUPPORTED => 8,
110 34     34   139 };
  34         33  
111              
112             $CODES{REPLY}->{&REPLY_SUCCESS} = "Success";
113             $CODES{REPLY}->{&REPLY_GENERAL_FAILURE} = "General failure";
114             $CODES{REPLY}->{&REPLY_CONN_NOT_ALLOWED} = "Not allowed";
115             $CODES{REPLY}->{&REPLY_NETWORK_UNREACHABLE} = "Network unreachable";
116             $CODES{REPLY}->{&REPLY_HOST_UNREACHABLE} = "Host unreachable";
117             $CODES{REPLY}->{&REPLY_CONN_REFUSED} = "Connection refused";
118             $CODES{REPLY}->{&REPLY_TTL_EXPIRED} = "TTL expired";
119             $CODES{REPLY}->{&REPLY_CMD_NOT_SUPPORTED} = "Command not supported";
120             $CODES{REPLY}->{&REPLY_ADDR_NOT_SUPPORTED} = "Address not supported";
121              
122             # socks4
123             use constant {
124 34         3836 REQUEST_GRANTED => 90,
125             REQUEST_FAILED => 91,
126             REQUEST_REJECTED_IDENTD => 92,
127             REQUEST_REJECTED_USERID => 93,
128 34     34   347 };
  34         32  
129              
130             $CODES{REPLY}->{&REQUEST_GRANTED} = "request granted";
131             $CODES{REPLY}->{&REQUEST_FAILED} = "request rejected or failed";
132             $CODES{REPLY}->{&REQUEST_REJECTED_IDENTD} = "request rejected because SOCKS server cannot connect to identd on the client";
133             $CODES{REPLY}->{&REQUEST_REJECTED_USERID} = "request rejected because the client program and identd report different user-ids";
134              
135             # queue
136             use constant {
137 34         233239 Q_SUB => 0,
138             Q_ARGS => 1,
139             Q_BUF => 2,
140             Q_READS => 3,
141             Q_SENDS => 4,
142             Q_OKCB => 5,
143             Q_DEBUGS => 6,
144 34     34   141 };
  34         8  
145              
146             our $CAN_CHANGE_SOCKET = 1;
147             sub new_from_fd {
148 4     4 1 4429 my ($class, $sock, %arg) = @_;
149              
150 4         21 bless $sock, $class;
151              
152 4         70 $sock->autoflush(1);
153 4 50       297 if (exists $arg{Timeout}) {
154 0         0 ${*$sock}{'io_socket_timeout'} = delete $arg{Timeout};
  0         0  
155             }
156              
157 4 50       23 scalar(%arg) or return $sock;
158            
159             # do not allow to create new socket
160 4         24 local $CAN_CHANGE_SOCKET = 0;
161 4 50 33     30 $sock->configure(\%arg) || !$sock->blocking || return undef;
162 4         25 $sock;
163             }
164              
165             *new_from_socket = \&new_from_fd;
166              
167             sub start_SOCKS {
168 4     4 1 1085 my ($class, $sock, %arg) = @_;
169              
170 4         11 bless $sock, $class;
171              
172 4         16 $sock->autoflush(1);
173 4 50       113 if (exists $arg{Timeout}) {
174 0         0 ${*$sock}{'io_socket_timeout'} = delete $arg{Timeout};
  0         0  
175             }
176              
177 4         21 ${*$sock}->{SOCKS} = { RequireAuth => 0 };
  4         17  
178              
179 4         16 $SOCKS_ERROR->set();
180 4 50       41 return $sock->command(%arg) ? $sock : undef;
181             }
182              
183             sub socket {
184 164     164 0 66248 my $self = shift;
185              
186 164 100       423 return $self unless $CAN_CHANGE_SOCKET;
187 160         658 return $self->SUPER::socket(@_);
188             }
189              
190             sub configure {
191 164     164 0 219622 my $self = shift;
192 164         364 my $args = shift;
193              
194 164 50       702 $self->_configure($args)
195             or return;
196              
197 164         304 ${*$self}->{SOCKS}->{ProxyAddr} = (
198             exists($args->{ProxyAddr})
199             ? delete($args->{ProxyAddr})
200 164 100       485 : undef
201             );
202              
203 164         289 ${*$self}->{SOCKS}->{ProxyPort} = (
204             exists($args->{ProxyPort})
205             ? delete($args->{ProxyPort})
206 164 100       300 : undef
207             );
208              
209 164         243 ${*$self}->{SOCKS}->{COMMAND} = [];
  164         294  
210              
211 164 100 33     338 if (exists($args->{Listen})) {
    50          
212 67         86 $args->{LocalAddr} = ${*$self}->{SOCKS}->{ProxyAddr};
  67         158  
213 67         99 $args->{LocalPort} = ${*$self}->{SOCKS}->{ProxyPort};
  67         124  
214 67         113 $args->{Reuse} = 1;
215 67         99 ${*$self}->{SOCKS}->{Listen} = 1;
  67         110  
216             }
217 97         591 elsif (${*$self}->{SOCKS}->{ProxyAddr} && ${*$self}->{SOCKS}->{ProxyPort}) {
  97         489  
218 97         155 $args->{PeerAddr} = ${*$self}->{SOCKS}->{ProxyAddr};
  97         191  
219 97         94 $args->{PeerPort} = ${*$self}->{SOCKS}->{ProxyPort};
  97         335  
220             }
221              
222 164 50       198 unless (defined ${*$self}->{SOCKS}->{TCP}) {
  164 0       396  
223 164         251 $args->{Proto} = "tcp";
224 164         230 $args->{Type} = SOCK_STREAM;
225             }
226             elsif (!defined $args->{Proto}) {
227 0         0 $args->{Proto} = "udp";
228 0         0 $args->{Type} = SOCK_DGRAM;
229             }
230              
231 164         1193 $SOCKS_ERROR->set();
232 164 100       900 unless ($self->SUPER::configure($args)) {
233 8 50       288 if ($SOCKS_ERROR == undef) {
234 0         0 $SOCKS_ERROR->set($!, $@);
235             }
236 8         368 return;
237             }
238              
239 156         8812 return $self;
240             }
241              
242             sub _configure {
243 168     168   309 my $self = shift;
244 168         291 my $args = shift;
245              
246 168         1031 ${*$self}->{SOCKS}->{Version} = (
247             exists($args->{SocksVersion})
248             ? (
249             $args->{SocksVersion} == 4
250             || $args->{SocksVersion} == 5
251             || ( exists $args->{Listen}
252             && ref $args->{SocksVersion} eq 'ARRAY'
253             && _validate_multi_version($args->{SocksVersion}))
254             ? delete($args->{SocksVersion})
255 168 50 66     1597 : croak("Unsupported socks version specified. Should be 4 or 5")
    100          
256             )
257             : 5
258             );
259              
260 168         458 ${*$self}->{SOCKS}->{AuthType} = (
261             exists($args->{AuthType})
262             ? delete($args->{AuthType})
263 168 100       621 : "none"
264             );
265              
266 168         303 ${*$self}->{SOCKS}->{RequireAuth} = (
267             exists($args->{RequireAuth})
268             ? delete($args->{RequireAuth})
269 168 100       632 : 0
270             );
271              
272 168         549 ${*$self}->{SOCKS}->{UserAuth} = (
273             exists($args->{UserAuth})
274             ? delete($args->{UserAuth})
275 168 100       595 : undef
276             );
277              
278 168         354 ${*$self}->{SOCKS}->{Username} = (
279             exists($args->{Username}) ? delete($args->{Username})
280             : (
281 168 50       597 (${*$self}->{SOCKS}->{AuthType} eq "none") ? undef
  142 100       508  
282             : croak("If you set AuthType to userpass, then you must provide a username.")
283             )
284             );
285              
286 168         304 ${*$self}->{SOCKS}->{Password} = (
287             exists($args->{Password}) ? delete($args->{Password})
288             : (
289 168 50       501 (${*$self}->{SOCKS}->{AuthType} eq "none") ? undef
  142 100       365  
290             : croak("If you set AuthType to userpass, then you must provide a password.")
291             )
292             );
293              
294 168         360 ${*$self}->{SOCKS}->{Debug} = (
295             exists($args->{SocksDebug})
296             ? delete($args->{SocksDebug})
297 168 50       349 : $SOCKS_DEBUG
298             );
299              
300 168         416 ${*$self}->{SOCKS}->{Resolve} = (
301             exists($args->{SocksResolve})
302             ? delete($args->{SocksResolve})
303 168 100       295 : undef
304             );
305              
306 168         403 ${*$self}->{SOCKS}->{AuthMethods} = [ 0, 0, 0 ];
  168         324  
307 153         235 ${*$self}->{SOCKS}->{AuthMethods}->[AUTHMECH_ANON] = 1
308 168 100       168 unless ${*$self}->{SOCKS}->{RequireAuth};
  168         482  
309              
310             #${*$self}->{SOCKS}->{AuthMethods}->[AUTHMECH_GSSAPI] = 1
311             # if (${*$self}->{SOCKS}->{AuthType} eq "gssapi");
312 88         234 ${*$self}->{SOCKS}->{AuthMethods}->[AUTHMECH_USERPASS] = 1
313             if (
314 101         868 (!exists($args->{Listen}) && (${*$self}->{SOCKS}->{AuthType} eq "userpass"))
315             || (exists($args->{Listen})
316 168 100 100     1028 && defined(${*$self}->{SOCKS}->{UserAuth}))
  67   100     292  
      66        
317             );
318              
319 168 50 33     1508 if (exists($args->{BindAddr}) && exists($args->{BindPort})) {
    50 33        
    100 66        
320 0         0 ${*$self}->{SOCKS}->{CmdAddr} = delete($args->{BindAddr});
  0         0  
321 0         0 ${*$self}->{SOCKS}->{CmdPort} = delete($args->{BindPort});
  0         0  
322 0         0 ${*$self}->{SOCKS}->{Bind} = 1;
  0         0  
323             }
324             elsif (exists($args->{UdpAddr}) && exists($args->{UdpPort})) {
325 0 0       0 if (${*$self}->{SOCKS}->{Version} == 4) {
  0         0  
326 0         0 croak("Socks v4 doesn't support UDP association");
327             }
328 0         0 ${*$self}->{SOCKS}->{CmdAddr} = delete($args->{UdpAddr});
  0         0  
329 0         0 ${*$self}->{SOCKS}->{CmdPort} = delete($args->{UdpPort});
  0         0  
330 0         0 ${*$self}->{SOCKS}->{TCP} = __PACKAGE__->new( # TCP backend for UDP socket
331             Timeout => $args->{Timeout},
332             Proto => 'tcp',
333             PeerAddr => $args->{ProxyAddr},
334             PeerPort => $args->{ProxyPort},
335             exists $args->{Blocking} ?
336 0 0       0 (Blocking => $args->{Blocking}) : ()
    0          
337             ) or return;
338             }
339             elsif (exists($args->{ConnectAddr}) && exists($args->{ConnectPort})) {
340 101         196 ${*$self}->{SOCKS}->{CmdAddr} = delete($args->{ConnectAddr});
  101         326  
341 101         153 ${*$self}->{SOCKS}->{CmdPort} = delete($args->{ConnectPort});
  101         226  
342             }
343              
344 168         401 return 1;
345             }
346              
347             sub version {
348 62     62 1 20812 my $self = shift;
349 62         61 return ${*$self}->{SOCKS}->{Version};
  62         341  
350             }
351              
352             sub connect {
353 97     97 0 5400 my $self = shift;
354              
355 97 50       381 croak("Undefined IO::Socket::Socks object passed to connect.")
356             unless defined($self);
357              
358             my $ok =
359 97         735 defined(${*$self}->{SOCKS}->{TCP})
360 97 50       79 ? 1
361             : $self->SUPER::connect(@_);
362              
363 97 100 66     14783 if (($! == EINPROGRESS || $! == EWOULDBLOCK) &&
    50 33        
      66        
364             (${*$self}->{SOCKS}->{TCP} || $self)->blocking == 0) {
365 47         372 ${*$self}->{SOCKS}->{_in_progress} = 1;
  47         123  
366 47         138 $SOCKS_ERROR->set(SOCKS_WANT_WRITE, 'Socks want write');
367             }
368             elsif (!$ok) {
369 0         0 $SOCKS_ERROR->set($!, $@ = "Connection to proxy failed: $!");
370 0         0 return;
371             }
372             else {
373             # connect() may be called several times by SUPER class
374 50         172 $SOCKS_ERROR->set();
375             }
376              
377             return $ok # proxy address was not specified, so do not make socks handshake
378 97 50 33     106 unless ${*$self}->{SOCKS}->{ProxyAddr} && ${*$self}->{SOCKS}->{ProxyPort};
  97         673  
  97         225  
379            
380 97         400 $self->_connect();
381             }
382              
383             sub _connect {
384 101     101   104 my $self = shift;
385 101         113 ${*$self}->{SOCKS}->{ready} = 0;
  101         370  
386              
387 101 100       177 if (${*$self}->{SOCKS}->{Version} == 4) {
  101         318  
388 39         238 ${*$self}->{SOCKS}->{queue} = [
389              
390             # [sub, [@args], buf, [@reads], sends_cnt]
391 39 50       74 [ '_socks4_connect_command', [ ${*$self}->{SOCKS}->{Bind} ? CMD_BIND : CMD_CONNECT ], undef, [], 0 ],
  39         274  
392             [ '_socks4_connect_reply', [], undef, [], 0 ]
393             ];
394             }
395             else {
396 62         250 ${*$self}->{SOCKS}->{queue} = [
397             [ '_socks5_connect', [], undef, [], 0 ],
398             [ '_socks5_connect_if_auth', [], undef, [], 0 ],
399             [
400             '_socks5_connect_command',
401             [
402 62         196 ${*$self}->{SOCKS}->{Bind} ? CMD_BIND
403 62 50       337 : ${*$self}->{SOCKS}->{TCP} ? CMD_UDPASSOC
  62 50       465  
404             : CMD_CONNECT
405             ],
406             undef,
407             [],
408             0
409             ],
410             [ '_socks5_connect_reply', [], undef, [], 0 ]
411             ];
412             }
413              
414 101 100       251 if (delete ${*$self}->{SOCKS}->{_in_progress}) { # socket connection not estabilished yet
  101         256  
415 47 50       349 if ($self->isa('IO::Socket::IP')) {
416             # IO::Socket::IP requires multiple connect calls
417             # when performing non-blocking multi-homed connect
418 47         35 unshift @{ ${*$self}->{SOCKS}->{queue} }, ['_socket_connect', [], undef, [], 0];
  47         43  
  47         246  
419            
420             # IO::Socket::IP::connect() returns false for non-blocking connections in progress
421             # IO::Socket::INET::connect() returns true for non-blocking connections in progress
422             # LOL
423 47         139 return; # connect() return value
424             }
425             }
426             else {
427 54 100       169 defined($self->_run_queue())
428             or return;
429             }
430              
431 46         153 return $self;
432             }
433              
434             sub _socket_connect {
435 47     47   90 my $self = shift;
436 47   33     65 my $sock = ${*$self}->{SOCKS}->{TCP} || $self;
437            
438 47 50       156 return 1 if $sock->SUPER::connect();
439 0 0 0     0 if ($! == EINPROGRESS || $! == EWOULDBLOCK) {
440 0         0 $SOCKS_ERROR->set(SOCKS_WANT_WRITE, 'Socks want write');
441 0         0 return -1;
442             }
443            
444 0         0 $SOCKS_ERROR->set($!, $@ = "Connection to proxy failed: $!");
445 0         0 return;
446             }
447              
448             sub _run_queue {
449             # run tasks from queue, return undef on error, -1 if one of the task
450             # returned not completed because of the possible blocking on network operation
451 393     393   644 my $self = shift;
452              
453 393         381 my $retval;
454             my $sub;
455              
456 393         396 while (my $elt = ${*$self}->{SOCKS}->{queue}[0]) {
  890         3058  
457 715         900 $sub = $elt->[Q_SUB];
458 715         1251 $retval = $self->$sub(@{ $elt->[Q_ARGS] });
  715         5040  
459 715 100       3105 unless (defined $retval) {
460 13         26 ${*$self}->{SOCKS}->{queue} = [];
  13         34  
461 13         101 ${*$self}->{SOCKS}->{queue_results} = {};
  13         26  
462 13         36 last;
463             }
464              
465 702 100       1175 last if ($retval == -1);
466 497         401 ${*$self}->{SOCKS}->{queue_results}{$sub} = $retval;
  497         2328  
467 497 50       899 if ($elt->[Q_OKCB]) {
468 0         0 $elt->[Q_OKCB]->();
469             }
470 497         411 shift @{ ${*$self}->{SOCKS}->{queue} };
  497         515  
  497         1369  
471             }
472              
473 393 100 100     1350 if (defined($retval) && !@{ ${*$self}->{SOCKS}->{queue} }) {
  362         327  
  362         1443  
474 157         184 ${*$self}->{SOCKS}->{queue_results} = {};
  157         239  
475 157 50       675 ${*$self}->{SOCKS}->{ready} = $SOCKS_ERROR ? 0 : 1;
  157         394  
476             }
477              
478 393         825 return $retval;
479             }
480              
481             sub ready {
482 244     244 1 71951470 my $self = shift;
483              
484 244         642 $self->_run_queue();
485 244         224 return ${*$self}->{SOCKS}->{ready};
  244         607  
486             }
487              
488             sub _socks5_connect {
489 106     106   133 my $self = shift;
490 106 50       135 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  106         332  
491 106         261 my ($reads, $sends, $debugs) = (0, 0, 0);
492             my $sock =
493 106         309 defined(${*$self}->{SOCKS}->{TCP})
494 0         0 ? ${*$self}->{SOCKS}->{TCP}
495 106 50       84 : $self;
496              
497             #--------------------------------------------------------------------------
498             # Send the auth mechanisms
499             #--------------------------------------------------------------------------
500             # +----+----------+----------+
501             # |VER | NMETHODS | METHODS |
502             # +----+----------+----------+
503             # | 1 | 1 | 1 to 255 |
504             # +----+----------+----------+
505              
506 106         138 my $nmethods = 0;
507 106         93 my $methods;
508 106         138 foreach my $method (0 .. $#{ ${*$self}->{SOCKS}->{AuthMethods} }) {
  106         99  
  106         533  
509 318 100       228 if (${*$self}->{SOCKS}->{AuthMethods}->[$method] == 1) {
  318         744  
510 162         384 $methods .= pack('C', $method);
511 162         220 $nmethods++;
512             }
513             }
514              
515 106         107 my $reply;
516 106 50       1024 $reply = $sock->_socks_send(pack('CCa*', SOCKS5_VER, $nmethods, $methods), ++$sends)
517             or return _fail($reply);
518              
519 106 50 33     279 if ($debug && !$self->_debugged(++$debugs)) {
520 0         0 $debug->add(
521             ver => SOCKS5_VER,
522             nmethods => $nmethods,
523             methods => join('', unpack("C$nmethods", $methods))
524             );
525 0         0 $debug->show('Client Send: ');
526             }
527              
528             #--------------------------------------------------------------------------
529             # Read the reply
530             #--------------------------------------------------------------------------
531             # +----+--------+
532             # |VER | METHOD |
533             # +----+--------+
534             # | 1 | 1 |
535             # +----+--------+
536              
537 106 100       261 $reply = $sock->_socks_read(2, ++$reads)
538             or return _fail($reply);
539              
540 59         160 my ($version, $auth_method) = unpack('CC', $reply);
541              
542 59 50 33     146 if ($debug && !$self->_debugged(++$debugs)) {
543 0         0 $debug->add(
544             ver => $version,
545             method => $auth_method
546             );
547 0         0 $debug->show('Client Recv: ');
548             }
549              
550 59 50       143 if ($auth_method == AUTHMECH_INVALID) {
551 0         0 $! = ESOCKSPROTO;
552 0         0 $SOCKS_ERROR->set(AUTHMECH_INVALID, $@ = $CODES{AUTHMECH}->[$auth_method]);
553 0         0 return;
554             }
555              
556 59         88 return $auth_method;
557             }
558              
559             sub _socks5_connect_if_auth {
560 62     62   87 my $self = shift;
561 62 100       54 if (${*$self}->{SOCKS}->{queue_results}{'_socks5_connect'} != AUTHMECH_ANON) {
  62         220  
562 26         55 unshift @{ ${*$self}->{SOCKS}->{queue} }, [ '_socks5_connect_auth', [], undef, [], 0 ];
  26         34  
  26         108  
563 26         60 (${*$self}->{SOCKS}->{queue}[0], ${*$self}->{SOCKS}->{queue}[1]) = (${*$self}->{SOCKS}->{queue}[1], ${*$self}->{SOCKS}->{queue}[0]);
  26         76  
  26         65  
  26         44  
  26         47  
564             }
565              
566 62         95 1;
567             }
568              
569             sub _socks5_connect_auth {
570             # rfc1929
571 36     36   49 my $self = shift;
572 36 50       78 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  36         121  
573 36         70 my ($reads, $sends, $debugs) = (0, 0, 0);
574             my $sock =
575 36         121 defined(${*$self}->{SOCKS}->{TCP})
576 0         0 ? ${*$self}->{SOCKS}->{TCP}
577 36 50       36 : $self;
578              
579             #--------------------------------------------------------------------------
580             # Send the auth
581             #--------------------------------------------------------------------------
582             # +----+------+----------+------+----------+
583             # |VER | ULEN | UNAME | PLEN | PASSWD |
584             # +----+------+----------+------+----------+
585             # | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
586             # +----+------+----------+------+----------+
587              
588 36         31 my $uname = ${*$self}->{SOCKS}->{Username};
  36         59  
589 36         39 my $passwd = ${*$self}->{SOCKS}->{Password};
  36         62  
590 36         44 my $ulen = length($uname);
591 36         39 my $plen = length($passwd);
592 36         28 my $reply;
593 36 50       193 $reply = $sock->_socks_send(pack("CCa${ulen}Ca*", 1, $ulen, $uname, $plen, $passwd), ++$sends)
594             or return _fail($reply);
595              
596 36 50 33     101 if ($debug && !$self->_debugged(++$debugs)) {
597 0         0 $debug->add(
598             ver => 1,
599             ulen => $ulen,
600             uname => $uname,
601             plen => $plen,
602             passwd => $passwd
603             );
604 0         0 $debug->show('Client Send: ');
605             }
606              
607             #--------------------------------------------------------------------------
608             # Read the reply
609             #--------------------------------------------------------------------------
610             # +----+--------+
611             # |VER | STATUS |
612             # +----+--------+
613             # | 1 | 1 |
614             # +----+--------+
615              
616 36 100       91 $reply = $sock->_socks_read(2, ++$reads)
617             or return _fail($reply);
618              
619 26         120 my ($ver, $status) = unpack('CC', $reply);
620              
621 26 50 33     113 if ($debug && !$self->_debugged(++$debugs)) {
622 0         0 $debug->add(
623             ver => $ver,
624             status => $status
625             );
626 0         0 $debug->show('Client Recv: ');
627             }
628              
629 26 100       81 if ($status != AUTHREPLY_SUCCESS) {
630 13         37 $! = ESOCKSPROTO;
631 13         117 $SOCKS_ERROR->set(AUTHREPLY_FAILURE, $@ = "Authentication failed with SOCKS5 proxy");
632 13         26 return;
633             }
634              
635 13         34 return 1;
636             }
637              
638             sub _socks5_connect_command {
639 49     49   62 my $self = shift;
640 49         46 my $command = shift;
641 49 50       59 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  49         136  
642 49         74 my ($reads, $sends, $debugs) = (0, 0, 0);
643 49 100       54 my $resolve = defined(${*$self}->{SOCKS}->{Resolve}) ? ${*$self}->{SOCKS}->{Resolve} : $SOCKS5_RESOLVE;
  49         156  
  6         7  
644             my $sock =
645 49         155 defined(${*$self}->{SOCKS}->{TCP})
646 0         0 ? ${*$self}->{SOCKS}->{TCP}
647 49 50       45 : $self;
648              
649             #--------------------------------------------------------------------------
650             # Send the command
651             #--------------------------------------------------------------------------
652             # +----+-----+-------+------+----------+----------+
653             # |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
654             # +----+-----+-------+------+----------+----------+
655             # | 1 | 1 | X'00' | 1 | Variable | 2 |
656             # +----+-----+-------+------+----------+----------+
657              
658 49         187 my ($atyp, $dstaddr) = $resolve ? (ADDR_DOMAINNAME, ${*$self}->{SOCKS}->{CmdAddr}) : _resolve(${*$self}->{SOCKS}->{CmdAddr})
  0         0  
659 49 50       113 or $SOCKS_ERROR->set(ISS_CANT_RESOLVE, $@ = "Can't resolve `" . ${*$self}->{SOCKS}->{CmdAddr} . "'"), return;
  0 50       0  
660 49 50       103 my $hlen = length($dstaddr) if $resolve;
661 49         46 my $dstport = pack('n', ${*$self}->{SOCKS}->{CmdPort});
  49         142  
662 49         89 my $reply;
663 49 50       263 $reply = $sock->_socks_send(pack('C4', SOCKS5_VER, $command, 0, $atyp) . (defined($hlen) ? pack('C', $hlen) : '') . $dstaddr . $dstport, ++$sends)
    50          
664             or return _fail($reply);
665              
666 49 50 33     152 if ($debug && !$self->_debugged(++$debugs)) {
667 0         0 $debug->add(
668             ver => SOCKS5_VER,
669             cmd => $command,
670             rsv => 0,
671             atyp => $atyp
672             );
673 0 0       0 $debug->add(hlen => $hlen) if defined $hlen;
674             $debug->add(
675             dstaddr => $resolve ? $dstaddr : _addr_ntoa($dstaddr, $atyp),
676 0         0 dstport => ${*$self}->{SOCKS}->{CmdPort}
677 0 0       0 );
678 0         0 $debug->show('Client Send: ');
679             }
680              
681 49         127 return 1;
682             }
683              
684             sub _socks5_connect_reply {
685 73     73   94 my $self = shift;
686 73 50       73 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  73         244  
687 73         155 my ($reads, $sends, $debugs) = (0, 0, 0);
688             my $sock =
689 73         217 defined(${*$self}->{SOCKS}->{TCP})
690 0         0 ? ${*$self}->{SOCKS}->{TCP}
691 73 50       55 : $self;
692              
693             #--------------------------------------------------------------------------
694             # Read the reply
695             #--------------------------------------------------------------------------
696             # +----+-----+-------+------+----------+----------+
697             # |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
698             # +----+-----+-------+------+----------+----------+
699             # | 1 | 1 | X'00' | 1 | Variable | 2 |
700             # +----+-----+-------+------+----------+----------+
701              
702 73         74 my $reply;
703 73 100       223 $reply = $sock->_socks_read(4, ++$reads)
704             or return _fail($reply);
705              
706 33         157 my ($ver, $rep, $rsv, $atyp) = unpack('C4', $reply);
707              
708 33 50       113 if ($debug) {
709 0         0 $debug->add(
710             ver => $ver,
711             rep => $rep,
712             rsv => $rsv,
713             atyp => $atyp
714             );
715             }
716              
717 33         40 my ($bndaddr, $bndport);
718              
719 33 50       131 if ($atyp == ADDR_DOMAINNAME) {
    50          
    0          
720 0 0       0 length($reply = $sock->_socks_read(1, ++$reads))
721             or return _fail($reply);
722              
723 0         0 my $hlen = unpack('C', $reply);
724 0 0       0 $bndaddr = $sock->_socks_read($hlen, ++$reads)
725             or return _fail($bndaddr);
726              
727 0 0       0 if ($debug) {
728 0         0 $debug->add(hlen => $hlen);
729             }
730             }
731             elsif ($atyp == ADDR_IPV4) {
732 33 50       88 $bndaddr = $sock->_socks_read(4, ++$reads)
733             or return _fail($bndaddr);
734             }
735             elsif ($atyp == ADDR_IPV6) {
736 0 0       0 $bndaddr = $sock->_socks_read(16, ++$reads)
737             or return _fail($bndaddr);
738             }
739             else {
740 0         0 $! = ESOCKSPROTO;
741 0         0 $SOCKS_ERROR->set(ISS_UNKNOWN_ADDRESS, $@ = "Unsupported address type returned by socks server: $atyp");
742 0         0 return;
743             }
744              
745 33 50       133 $reply = $sock->_socks_read(2, ++$reads)
746             or return _fail($reply);
747 33         80 $bndport = unpack('n', $reply);
748              
749 33         55 ${*$self}->{SOCKS}->{DstAddrType} = $atyp;
  33         212  
750 33         44 ${*$self}->{SOCKS}->{DstAddr} = $bndaddr;
  33         99  
751 33         55 ${*$self}->{SOCKS}->{DstPort} = $bndport;
  33         71  
752              
753 33 50 33     164 if ($debug && !$self->_debugged(++$debugs)) {
754 0         0 my ($addr) = $self->dst;
755 0         0 $debug->add(
756             bndaddr => $addr,
757             bndport => $bndport
758             );
759 0         0 $debug->show('Client Recv: ');
760             }
761              
762 33 50       842 if ($rep != REPLY_SUCCESS) {
763 0         0 $! = ESOCKSPROTO;
764 0 0       0 unless (exists $CODES{REPLY}->{$rep}) {
765 0         0 $rep = REPLY_GENERAL_FAILURE;
766             }
767 0         0 $SOCKS_ERROR->set($rep, $@ = $CODES{REPLY}->{$rep});
768 0         0 return;
769             }
770              
771 33         65 return 1;
772             }
773              
774              
775             sub _socks4_connect_command {
776             # http://ss5.sourceforge.net/socks4.protocol.txt
777             # http://ss5.sourceforge.net/socks4A.protocol.txt
778 36     36   33 my $self = shift;
779 36         39 my $command = shift;
780 36 50       33 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  36         120  
781 36         67 my ($reads, $sends, $debugs) = (0, 0, 0);
782 36 100       30 my $resolve = defined(${*$self}->{SOCKS}->{Resolve}) ? ${*$self}->{SOCKS}->{Resolve} : $SOCKS4_RESOLVE;
  36         93  
  14         23  
783              
784             #--------------------------------------------------------------------------
785             # Send the command
786             #--------------------------------------------------------------------------
787             # +-----+-----+----------+---------------+----------+------+
788             # | VER | CMD | DST.PORT | DST.ADDR | USERID | NULL |
789             # +-----+-----+----------+---------------+----------+------+
790             # | 1 | 1 | 2 | 4 | variable | 1 |
791             # +-----+-----+----------+---------------+----------+------+
792              
793 22         162 my $dstaddr = $resolve ? inet_aton('0.0.0.1') : inet_aton(${*$self}->{SOCKS}->{CmdAddr})
794 36 100       105 or $SOCKS_ERROR->set(ISS_CANT_RESOLVE, $@ = "Can't resolve `" . ${*$self}->{SOCKS}->{CmdAddr} . "'"), return;
  0 50       0  
795 36         63 my $dstport = pack('n', ${*$self}->{SOCKS}->{CmdPort});
  36         145  
796 36   50     57 my $userid = ${*$self}->{SOCKS}->{Username} || '';
797 36         35 my $dsthost = '';
798 36 100       142 if ($resolve) { # socks4a
799 14         9 $dsthost = ${*$self}->{SOCKS}->{CmdAddr} . pack('C', 0);
  14         23  
800             }
801              
802 36         33 my $reply;
803 36 50       429 $reply = $self->_socks_send(pack('CC', SOCKS4_VER, $command) . $dstport . $dstaddr . $userid . pack('C', 0) . $dsthost, ++$sends)
804             or return _fail($reply);
805              
806 36 50 33     120 if ($debug && !$self->_debugged(++$debugs)) {
807             $debug->add(
808             ver => SOCKS4_VER,
809             cmd => $command,
810 0         0 dstport => ${*$self}->{SOCKS}->{CmdPort},
811 0 0       0 dstaddr => length($dstaddr) == 4 ? inet_ntoa($dstaddr) : undef,
812             userid => $userid,
813             null => 0
814             );
815 0 0       0 if ($dsthost) {
816             $debug->add(
817 0         0 dsthost => ${*$self}->{SOCKS}->{CmdAddr},
818 0         0 null => 0
819             );
820             }
821 0         0 $debug->show('Client Send: ');
822             }
823              
824 36         64 return 1;
825             }
826              
827             sub _socks4_connect_reply {
828 67     67   109 my $self = shift;
829 67 50       53 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  67         237  
830 67         138 my ($reads, $sends, $debugs) = (0, 0, 0);
831              
832             #--------------------------------------------------------------------------
833             # Read the reply
834             #--------------------------------------------------------------------------
835             # +-----+-----+----------+---------------+
836             # | VER | REP | BND.PORT | BND.ADDR |
837             # +-----+-----+----------+---------------+
838             # | 1 | 1 | 2 | 4 |
839             # +-----+-----+----------+---------------+
840              
841 67         50 my $reply;
842 67 100       278 $reply = $self->_socks_read(8, ++$reads)
843             or return _fail($reply);
844              
845 29         156 my ($ver, $rep, $bndport) = unpack('CCn', $reply);
846 29         57 substr($reply, 0, 4) = '';
847              
848 29         46 ${*$self}->{SOCKS}->{DstAddrType} = ADDR_IPV4;
  29         239  
849 29         30 ${*$self}->{SOCKS}->{DstAddr} = $reply;
  29         76  
850 29         37 ${*$self}->{SOCKS}->{DstPort} = $bndport;
  29         62  
851              
852 29 50 33     172 if ($debug && !$self->_debugged(++$debugs)) {
853 0         0 my ($addr) = $self->dst;
854              
855 0         0 $debug->add(
856             ver => $ver,
857             rep => $rep,
858             bndport => $bndport,
859             bndaddr => $addr
860             );
861 0         0 $debug->show('Client Recv: ');
862             }
863              
864 29 50       65 if ($rep != REQUEST_GRANTED) {
865 0         0 $! = ESOCKSPROTO;
866 0 0       0 unless (exists $CODES{REPLY}->{$rep}) {
867 0         0 $rep = REQUEST_FAILED;
868             }
869 0         0 $SOCKS_ERROR->set($rep, $@ = $CODES{REPLY}->{$rep});
870 0         0 return;
871             }
872              
873 29         62 return 1;
874             }
875              
876             sub accept {
877 49     49 1 12020499 my $self = shift;
878              
879 49 50       336 croak("Undefined IO::Socket::Socks object passed to accept.")
880             unless defined($self);
881              
882 49 50       120 if (${*$self}->{SOCKS}->{Listen}) {
  49         473  
883 49         1015 my $client = $self->SUPER::accept(@_);
884              
885 49 50       3024851 if (!$client) {
886 0 0 0     0 if ($! == EAGAIN || $! == EWOULDBLOCK) {
887 0         0 $SOCKS_ERROR->set(SOCKS_WANT_READ, "Socks want read");
888             }
889             else {
890 0         0 $SOCKS_ERROR->set($!, $@ = "Proxy accept new client failed: $!");
891             }
892 0         0 return;
893             }
894              
895             my $ver =
896 49         198 ref ${*$self}->{SOCKS}->{Version}
897 10         7 ? @{ ${*$self}->{SOCKS}->{Version} } > 1
  10         18  
898 10         14 ? ${*$self}->{SOCKS}->{Version}
899 0         0 : ${*$self}->{SOCKS}->{Version}->[0]
900 49 50       80 : ${*$self}->{SOCKS}->{Version};
  39 100       104  
901              
902             # inherit some socket parameters
903 49         66 ${*$client}->{SOCKS}->{Debug} = ${*$self}->{SOCKS}->{Debug};
  49         158  
  49         104  
904 49         45 ${*$client}->{SOCKS}->{Version} = $ver;
  49         103  
905 49         74 ${*$client}->{SOCKS}->{AuthMethods} = ${*$self}->{SOCKS}->{AuthMethods};
  49         101  
  49         96  
906 49         56 ${*$client}->{SOCKS}->{UserAuth} = ${*$self}->{SOCKS}->{UserAuth};
  49         87  
  49         100  
907 49         81 ${*$client}->{SOCKS}->{Resolve} = ${*$self}->{SOCKS}->{Resolve};
  49         93  
  49         87  
908 49         58 ${*$client}->{SOCKS}->{ready} = 0;
  49         95  
909 49         493 $client->blocking($self->blocking); # temporarily
910              
911 49 100       741 if (ref $ver) {
    100          
912 10         22 ${*$client}->{SOCKS}->{queue} = [ [ '_socks_accept', [], undef, [], 0 ] ];
  10         20  
913             }
914             elsif ($ver == 4) {
915 17         107 ${*$client}->{SOCKS}->{queue} = [ [ '_socks4_accept_command', [], undef, [], 0 ] ];
  17         48  
916              
917             }
918             else {
919 22         59 ${*$client}->{SOCKS}->{queue} = [
920 22         201 [ '_socks5_accept', [], undef, [], 0 ],
921             [ '_socks5_accept_if_auth', [], undef, [], 0 ],
922             [ '_socks5_accept_command', [], undef, [], 0 ]
923             ];
924             }
925              
926 49 50       172 defined($client->_run_queue())
927             or return;
928              
929 49         173 $client->blocking(1); # new socket should be in blocking mode
930 49         305 return $client;
931             }
932             else {
933 0         0 ${*$self}->{SOCKS}->{ready} = 0;
  0         0  
934 0 0       0 if ({*$self}->{SOCKS}->{Version} == 4) {
935 0         0 push @{ ${*$self}->{SOCKS}->{queue} }, [ '_socks4_connect_reply', [], undef, [], 0 ];
  0         0  
  0         0  
936             }
937             else {
938 0         0 push @{ ${*$self}->{SOCKS}->{queue} }, [ '_socks5_connect_reply', [], undef, [], 0 ];
  0         0  
  0         0  
939             }
940              
941 0 0       0 defined($self->_run_queue())
942             or return;
943              
944 0         0 return $self;
945             }
946             }
947              
948             sub _socks_accept {
949             # when 4 and 5 version allowed
950 20     20   13 my $self = shift;
951              
952 20         14 my $request;
953 20 100       31 $request = $self->_socks_read(1, 0)
954             or return _fail($request);
955              
956 10         18 my $ver = unpack('C', $request);
957 10 100       15 if ($ver == 4) {
    50          
958 4         3 ${*$self}->{SOCKS}->{Version} = 4;
  4         7  
959 4         3 push @{ ${*$self}->{SOCKS}->{queue} }, [ '_socks4_accept_command', [$ver], undef, [], 0 ];
  4         4  
  4         17  
960             }
961             elsif ($ver == 5) {
962 6         4 ${*$self}->{SOCKS}->{Version} = 5;
  6         9  
963 6         5 push @{ ${*$self}->{SOCKS}->{queue} },
  6         4  
  6         30  
964             [ '_socks5_accept', [$ver], undef, [], 0 ],
965             [ '_socks5_accept_if_auth', [], undef, [], 0 ],
966             [ '_socks5_accept_command', [], undef, [], 0 ];
967             }
968             else {
969 0         0 $! = ESOCKSPROTO;
970 0         0 $SOCKS_ERROR->set(ISS_BAD_VERSION, $@ = "Socks version should be 4 or 5, $ver recieved");
971 0         0 return;
972             }
973              
974 10         16 1;
975             }
976              
977             sub _socks5_accept {
978 45     45   71 my ($self, $ver) = @_;
979 45 50       83 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  45         240  
980 45         65 my ($reads, $sends, $debugs) = (0, 0, 0);
981              
982             #--------------------------------------------------------------------------
983             # Read the auth mechanisms
984             #--------------------------------------------------------------------------
985             # +----+----------+----------+
986             # |VER | NMETHODS | METHODS |
987             # +----+----------+----------+
988             # | 1 | 1 | 1 to 255 |
989             # +----+----------+----------+
990              
991 45         51 my $request;
992 45 100       185 $request = $self->_socks_read($ver ? 1 : 2, ++$reads)
    100          
993             or return _fail($request);
994              
995 33 100       87 unless ($ver) {
996 27         127 $ver = unpack('C', $request);
997             }
998 33         104 my $nmethods = unpack('C', substr($request, -1, 1));
999              
1000 33 100       71 $request = $self->_socks_read($nmethods, ++$reads)
1001             or return _fail($request);
1002              
1003 28         144 my @methods = unpack('C' x $nmethods, $request);
1004              
1005 28 50 33     82 if ($debug && !$self->_debugged(++$debugs)) {
1006 0         0 $debug->add(
1007             ver => $ver,
1008             nmethods => $nmethods,
1009             methods => join('', @methods)
1010             );
1011 0         0 $debug->show('Server Recv: ');
1012             }
1013              
1014 28 50       61 if ($ver != SOCKS5_VER) {
1015 0         0 $! = ESOCKSPROTO;
1016 0         0 $SOCKS_ERROR->set(ISS_BAD_VERSION, $@ = "Socks version should be 5, $ver recieved");
1017 0         0 return;
1018             }
1019              
1020 28 50       59 if ($nmethods == 0) {
1021 0         0 $! = ESOCKSPROTO;
1022 0         0 $SOCKS_ERROR->set(AUTHMECH_INVALID, $@ = "No auth methods sent");
1023 0         0 return;
1024             }
1025              
1026 28         32 my $authmech;
1027              
1028 28         99 foreach my $method (@methods) {
1029 30 100       36 if (${*$self}->{SOCKS}->{AuthMethods}->[$method] == 1) {
  30         111  
1030 28         29 $authmech = $method;
1031 28         44 last;
1032             }
1033             }
1034              
1035 28 50       71 if (!defined($authmech)) {
1036 0         0 $authmech = AUTHMECH_INVALID;
1037             }
1038              
1039             #--------------------------------------------------------------------------
1040             # Send the reply
1041             #--------------------------------------------------------------------------
1042             # +----+--------+
1043             # |VER | METHOD |
1044             # +----+--------+
1045             # | 1 | 1 |
1046             # +----+--------+
1047              
1048 28 50       167 $request = $self->_socks_send(pack('CC', SOCKS5_VER, $authmech), ++$sends)
1049             or return _fail($request);
1050              
1051 28 50 33     105 if ($debug && !$self->_debugged(++$debugs)) {
1052 0         0 $debug->add(
1053             ver => SOCKS5_VER,
1054             method => $authmech
1055             );
1056 0         0 $debug->show('Server Send: ');
1057             }
1058              
1059 28 50       54 if ($authmech == AUTHMECH_INVALID) {
1060 0         0 $! = ESOCKSPROTO;
1061 0         0 $SOCKS_ERROR->set(AUTHMECH_INVALID, $@ = "No available auth methods");
1062 0         0 return;
1063             }
1064              
1065 28         52 return $authmech;
1066             }
1067              
1068             sub _socks5_accept_if_auth {
1069 28     28   54 my $self = shift;
1070              
1071 28 100       32 if (${*$self}->{SOCKS}->{queue_results}{'_socks5_accept'} == AUTHMECH_USERPASS) {
  28         112  
1072 2         2 unshift @{ ${*$self}->{SOCKS}->{queue} }, [ '_socks5_accept_auth', [], undef, [], 0 ];
  2         1  
  2         6  
1073 2         10 (${*$self}->{SOCKS}->{queue}[0], ${*$self}->{SOCKS}->{queue}[1]) = (${*$self}->{SOCKS}->{queue}[1], ${*$self}->{SOCKS}->{queue}[0]);
  2         6  
  2         4  
  2         4  
  2         3  
1074             }
1075              
1076 28         46 1;
1077             }
1078              
1079             sub _socks5_accept_auth {
1080 2     2   2 my $self = shift;
1081 2 50       5 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  2         9  
1082 2         20 my ($reads, $sends, $debugs) = (0, 0, 0);
1083              
1084             #--------------------------------------------------------------------------
1085             # Read the auth
1086             #--------------------------------------------------------------------------
1087             # +----+------+----------+------+----------+
1088             # |VER | ULEN | UNAME | PLEN | PASSWD |
1089             # +----+------+----------+------+----------+
1090             # | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
1091             # +----+------+----------+------+----------+
1092              
1093 2         127 my $request;
1094 2 50       10 $request = $self->_socks_read(2, ++$reads)
1095             or return _fail($request);
1096              
1097 2         7 my ($ver, $ulen) = unpack('CC', $request);
1098 2 50       7 $request = $self->_socks_read($ulen + 1, ++$reads)
1099             or return _fail($request);
1100              
1101 2         6 my $uname = substr($request, 0, $ulen);
1102 2         6 my $plen = unpack('C', substr($request, $ulen));
1103 2         3 my $passwd;
1104 2 50       5 $passwd = $self->_socks_read($plen, ++$reads)
1105             or return _fail($passwd);
1106              
1107 2 50 33     8 if ($debug && !$self->_debugged(++$debugs)) {
1108 0         0 $debug->add(
1109             ver => $ver,
1110             ulen => $ulen,
1111             uname => $uname,
1112             plen => $plen,
1113             passwd => $passwd
1114             );
1115 0         0 $debug->show('Server Recv: ');
1116             }
1117              
1118 2         4 my $status = 1;
1119 2 50       4 if (defined(${*$self}->{SOCKS}->{UserAuth})) {
  2         7  
1120 2         3 $status = &{ ${*$self}->{SOCKS}->{UserAuth} }($uname, $passwd);
  2         2  
  2         13  
1121             }
1122              
1123             #--------------------------------------------------------------------------
1124             # Send the reply
1125             #--------------------------------------------------------------------------
1126             # +----+--------+
1127             # |VER | STATUS |
1128             # +----+--------+
1129             # | 1 | 1 |
1130             # +----+--------+
1131              
1132 2 50       23 $status = $status ? AUTHREPLY_SUCCESS : 1; #XXX AUTHREPLY_FAILURE broken
1133 2 50       10 $request = $self->_socks_send(pack('CC', 1, $status), ++$sends)
1134             or return _fail($request);
1135              
1136 2 50 33     12 if ($debug && !$self->_debugged(++$debugs)) {
1137 0         0 $debug->add(
1138             ver => 1,
1139             status => $status
1140             );
1141 0         0 $debug->show('Server Send: ');
1142             }
1143              
1144 2 50       7 if ($status != AUTHREPLY_SUCCESS) {
1145 0         0 $! = ESOCKSPROTO;
1146 0         0 $SOCKS_ERROR->set(AUTHREPLY_FAILURE, $@ = "Authentication failed with SOCKS5 proxy");
1147 0         0 return;
1148             }
1149              
1150 2         3 return 1;
1151             }
1152              
1153             sub _socks5_accept_command {
1154 44     44   56 my $self = shift;
1155 44 50       41 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  44         108  
1156 44         65 my ($reads, $sends, $debugs) = (0, 0, 0);
1157              
1158 44         37 @{ ${*$self}->{SOCKS}->{COMMAND} } = ();
  44         41  
  44         104  
1159              
1160             #--------------------------------------------------------------------------
1161             # Read the command
1162             #--------------------------------------------------------------------------
1163             # +----+-----+-------+------+----------+----------+
1164             # |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
1165             # +----+-----+-------+------+----------+----------+
1166             # | 1 | 1 | X'00' | 1 | Variable | 2 |
1167             # +----+-----+-------+------+----------+----------+
1168              
1169 44         38 my $request;
1170 44 100       122 $request = $self->_socks_read(4, ++$reads)
1171             or return _fail($request);
1172              
1173 28         78 my ($ver, $cmd, $rsv, $atyp) = unpack('CCCC', $request);
1174 28 50 33     100 if ($debug && !$self->_debugged(++$debugs)) {
1175 0         0 $debug->add(
1176             ver => $ver,
1177             cmd => $cmd,
1178             rsv => $rsv,
1179             atyp => $atyp
1180             );
1181             }
1182              
1183 28         33 my $dstaddr;
1184 28 50       71 if ($atyp == ADDR_DOMAINNAME) {
    0          
    0          
1185 28 50       55 length($request = $self->_socks_read(1, ++$reads))
1186             or return _fail($request);
1187              
1188 28         55 my $hlen = unpack('C', $request);
1189 28 50       69 $dstaddr = $self->_socks_read($hlen, ++$reads)
1190             or return _fail($dstaddr);
1191              
1192 28 50 33     91 if ($debug && !$self->_debugged(++$debugs)) {
1193 0         0 $debug->add(hlen => $hlen);
1194             }
1195             }
1196             elsif ($atyp == ADDR_IPV4) {
1197 0 0       0 $request = $self->_socks_read(4, ++$reads)
1198             or return _fail($request);
1199              
1200 0 0       0 $dstaddr = length($request) == 4 ? inet_ntoa($request) : undef;
1201             }
1202             elsif ($atyp == ADDR_IPV6) {
1203 0 0       0 $request = $self->_socks_read(16, ++$reads)
1204             or return _fail($request);
1205              
1206 0 0       0 $dstaddr = length($request) == 16 ? Socket::inet_ntop(AF_INET6, $request) : undef;
1207             }
1208             else { # unknown address type - how many bytes to read?
1209 0         0 push @{${*$self}->{SOCKS}->{queue}}, [
  0         0  
1210             '_socks5_accept_command_reply', [ REPLY_ADDR_NOT_SUPPORTED, '0.0.0.0', 0 ], undef, [], 0,
1211             sub {
1212 0     0   0 $! = ESOCKSPROTO;
1213 0         0 $SOCKS_ERROR->set(REPLY_ADDR_NOT_SUPPORTED, $@ = $CODES{REPLY}->{REPLY_ADDR_NOT_SUPPORTED});
1214             }
1215 0         0 ];
1216            
1217 0         0 return 0;
1218             }
1219              
1220 28 50       60 $request = $self->_socks_read(2, ++$reads)
1221             or return _fail($request);
1222              
1223 28         88 my $dstport = unpack('n', $request);
1224              
1225 28 50 33     107 if ($debug && !$self->_debugged(++$debugs)) {
1226 0         0 $debug->add(
1227             dstaddr => $dstaddr,
1228             dstport => $dstport
1229             );
1230 0         0 $debug->show('Server Recv: ');
1231             }
1232              
1233 28         33 @{ ${*$self}->{SOCKS}->{COMMAND} } = ($cmd, $dstaddr, $dstport, $atyp);
  28         28  
  28         91  
1234              
1235 28         53 return 1;
1236             }
1237              
1238             sub _socks5_accept_command_reply {
1239 26     26   43 my $self = shift;
1240 26         131 my $reply = shift;
1241 26         69 my $host = shift;
1242 26         52 my $port = shift;
1243 26 50       60 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  26         144  
1244 26 100       40 my $resolve = defined(${*$self}->{SOCKS}->{Resolve}) ? ${*$self}->{SOCKS}->{Resolve} : $SOCKS5_RESOLVE;
  26         112  
  6         6  
1245 26         52 my ($reads, $sends, $debugs) = (0, 0, 0);
1246              
1247 26 50 33     243 if (!defined($reply) || !defined($host) || !defined($port)) {
      33        
1248 0         0 croak("You must provide a reply, host, and port on the command reply.");
1249             }
1250              
1251             #--------------------------------------------------------------------------
1252             # Send the reply
1253             #--------------------------------------------------------------------------
1254             # +----+-----+-------+------+----------+----------+
1255             # |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
1256             # +----+-----+-------+------+----------+----------+
1257             # | 1 | 1 | X'00' | 1 | Variable | 2 |
1258             # +----+-----+-------+------+----------+----------+
1259              
1260 26 50       266 my ($atyp, $bndaddr) = $resolve ? _resolve($host) : (ADDR_DOMAINNAME, $host)
    50          
1261             or $SOCKS_ERROR->set(ISS_CANT_RESOLVE, $@ = "Can't resolve `$host'"), return;
1262 26 50       73 my $hlen = $resolve ? undef : length($bndaddr);
1263 26         80 my $rc;
1264 26 50       650 $rc = $self->_socks_send(pack('CCCC', SOCKS5_VER, $reply, 0, $atyp) . ($resolve ? '' : pack('C', $hlen)) . $bndaddr . pack('n', $port), ++$sends)
    50          
1265             or return _fail($rc);
1266              
1267 26 50 33     89 if ($debug && !$self->_debugged(++$debugs)) {
1268 0         0 $debug->add(
1269             ver => SOCKS5_VER,
1270             rep => $reply,
1271             rsv => 0,
1272             atyp => $atyp
1273             );
1274 0 0       0 $debug->add(hlen => $hlen) unless $resolve;
1275 0 0       0 $debug->add(
1276             bndaddr => $resolve ? _addr_ntoa($bndaddr, $atyp) : $bndaddr,
1277             bndport => $port
1278             );
1279 0         0 $debug->show('Server Send: ');
1280             }
1281              
1282 26         42 1;
1283             }
1284              
1285             sub _socks4_accept_command {
1286 48     48   127 my ($self, $ver) = @_;
1287 48 50       79 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  48         147  
1288 48 100       65 my $resolve = defined(${*$self}->{SOCKS}->{Resolve}) ? ${*$self}->{SOCKS}->{Resolve} : $SOCKS4_RESOLVE;
  48         114  
  44         72  
1289 48         70 my ($reads, $sends, $debugs) = (0, 0, 0);
1290              
1291 48         39 @{ ${*$self}->{SOCKS}->{COMMAND} } = ();
  48         57  
  48         130  
1292              
1293             #--------------------------------------------------------------------------
1294             # Read the auth mechanisms
1295             #--------------------------------------------------------------------------
1296             # +-----+-----+----------+---------------+----------+------+
1297             # | VER | CMD | DST.PORT | DST.ADDR | USERID | NULL |
1298             # +-----+-----+----------+---------------+----------+------+
1299             # | 1 | 1 | 2 | 4 | variable | 1 |
1300             # +-----+-----+----------+---------------+----------+------+
1301              
1302 48         51 my $request;
1303 48 100       195 $request = $self->_socks_read($ver ? 7 : 8, ++$reads)
    100          
1304             or return _fail($request);
1305              
1306 31 100       78 unless ($ver) {
1307 27         119 $ver = unpack('C', $request);
1308 27         63 substr($request, 0, 1) = '';
1309             }
1310              
1311 31         76 my ($cmd, $dstport) = unpack('Cn', $request);
1312 31         46 substr($request, 0, 3) = '';
1313 31 50       276 my $dstaddr = length($request) == 4 ? inet_ntoa($request) : undef;
1314              
1315 31         101 my $userid = '';
1316 31         31 my $c;
1317              
1318 31         34 while (1) {
1319 31 100       69 length($c = $self->_socks_read(1, ++$reads))
1320             or return _fail($c);
1321              
1322 28 50       82 if ($c ne "\0") {
1323 0         0 $userid .= $c;
1324             }
1325             else {
1326 28         34 last;
1327             }
1328             }
1329              
1330 28 50 33     70 if ($debug && !$self->_debugged(++$debugs)) {
1331 0         0 $debug->add(
1332             ver => $ver,
1333             cmd => $cmd,
1334             dstport => $dstport,
1335             dstaddr => $dstaddr,
1336             userid => $userid,
1337             null => 0
1338             );
1339             }
1340              
1341 28         39 my $atyp = ADDR_IPV4;
1342              
1343 28 100 66     193 if ($resolve && $dstaddr =~ /^0\.0\.0\.[1-9]/) { # socks4a
1344 24         28 $dstaddr = '';
1345 24         23 $atyp = ADDR_DOMAINNAME;
1346              
1347 24         32 while (1) {
1348 205 100       261 length($c = $self->_socks_read(1, ++$reads))
1349             or return _fail($c);
1350              
1351 198 100       265 if ($c ne "\0") {
1352 181         153 $dstaddr .= $c;
1353             }
1354             else {
1355 17         18 last;
1356             }
1357             }
1358              
1359 17 50 33     42 if ($debug && !$self->_debugged(++$debugs)) {
1360 0         0 $debug->add(
1361             dsthost => $dstaddr,
1362             null => 0
1363             );
1364             }
1365             }
1366              
1367 21 50 33     58 if ($debug && !$self->_debugged(++$debugs)) {
1368 0         0 $debug->show('Server Recv: ');
1369             }
1370              
1371 21 100       21 if (defined(${*$self}->{SOCKS}->{UserAuth})) {
  21         55  
1372 4 50       5 unless (&{ ${*$self}->{SOCKS}->{UserAuth} }($userid)) {
  4         7  
  4         37  
1373 0         0 push @{${*$self}->{SOCKS}->{queue}}, [
  0         0  
1374             '_socks4_accept_command_reply', [ REQUEST_REJECTED_USERID, '0.0.0.0', 0 ], undef, [], 0,
1375             sub {
1376 0     0   0 $! = ESOCKSPROTO;
1377 0         0 $SOCKS_ERROR->set(REQUEST_REJECTED_USERID, $@ = 'Authentication failed with SOCKS4 proxy');
1378             }
1379 0         0 ];
1380            
1381 0         0 return 0;
1382             }
1383             }
1384              
1385 21 50       113 if ($ver != SOCKS4_VER) {
1386 0         0 $! = ESOCKSPROTO;
1387 0         0 $SOCKS_ERROR->set(ISS_BAD_VERSION, $@ = "Socks version should be 4, $ver recieved");
1388 0         0 return;
1389             }
1390              
1391 21         28 @{ ${*$self}->{SOCKS}->{COMMAND} } = ($cmd, $dstaddr, $dstport, $atyp);
  21         16  
  21         56  
1392              
1393 21         36 return 1;
1394             }
1395              
1396             sub _socks4_accept_command_reply {
1397 20     20   34 my $self = shift;
1398 20         22 my $reply = shift;
1399 20         23 my $host = shift;
1400 20         41 my $port = shift;
1401 20 50       30 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  20         76  
1402 20         57 my ($reads, $sends, $debugs) = (0, 0, 0);
1403              
1404 20 50 33     188 if (!defined($reply) || !defined($host) || !defined($port)) {
      33        
1405 0         0 croak("You must provide a reply, host, and port on the command reply.");
1406             }
1407              
1408             #--------------------------------------------------------------------------
1409             # Send the reply
1410             #--------------------------------------------------------------------------
1411             # +-----+-----+----------+---------------+
1412             # | VER | REP | BND.PORT | BND.ADDR |
1413             # +-----+-----+----------+---------------+
1414             # | 1 | 1 | 2 | 4 |
1415             # +-----+-----+----------+---------------+
1416              
1417 20 50       207 my $bndaddr = inet_aton($host)
1418             or $SOCKS_ERROR->set(ISS_CANT_RESOLVE, $@ = "Can't resolve `$host'"), return;
1419 20         24 my $rc;
1420 20 50       252 $rc = $self->_socks_send(pack('CCna*', 0, $reply, $port, $bndaddr), ++$sends)
1421             or return _fail($rc);
1422              
1423 20 50 33     60 if ($debug && !$self->_debugged(++$debugs)) {
1424 0 0       0 $debug->add(
1425             ver => 0,
1426             rep => $reply,
1427             bndport => $port,
1428             bndaddr => length($bndaddr) == 4 ? inet_ntoa($bndaddr) : undef
1429             );
1430 0         0 $debug->show('Server Send: ');
1431             }
1432              
1433 20         29 1;
1434             }
1435              
1436             sub command {
1437 26     26 1 13775 my $self = shift;
1438              
1439 26 100       149 unless (exists ${*$self}->{SOCKS}->{RequireAuth}) # TODO: find more correct way
  26         600  
1440             {
1441 22         133 return ${*$self}->{SOCKS}->{COMMAND};
  22         281  
1442             }
1443             else {
1444 4         28 my @keys = qw(Version AuthType RequireAuth UserAuth Username Password
1445             Debug Resolve AuthMethods CmdAddr CmdPort Bind TCP);
1446              
1447 4         4 my %tmp;
1448 4         13 $tmp{$_} = ${*$self}->{SOCKS}->{$_} for @keys;
  52         93  
1449              
1450 4         10 my %args = @_;
1451 4         16 $self->_configure(\%args);
1452              
1453 4 50       16 if ($self->_connect()) {
1454 4         43 return 1;
1455             }
1456              
1457 0         0 ${*$self}->{SOCKS}->{$_} = $tmp{$_} for @keys;
  0         0  
1458 0         0 return 0;
1459             }
1460             }
1461              
1462             sub command_reply {
1463 46     46 1 12021248 my $self = shift;
1464 46         118 ${*$self}->{SOCKS}->{ready} = 0;
  46         169  
1465              
1466 46 100       81 if (${*$self}->{SOCKS}->{Version} == 4) {
  46         380  
1467 20         96 ${*$self}->{SOCKS}->{queue} = [ [ '_socks4_accept_command_reply', [@_], undef, [], 0 ] ];
  20         40  
1468             }
1469             else {
1470 26         177 ${*$self}->{SOCKS}->{queue} = [ [ '_socks5_accept_command_reply', [@_], undef, [], 0 ] ];
  26         85  
1471             }
1472              
1473 46         170 $self->_run_queue();
1474             }
1475              
1476             sub dst {
1477 19     19 1 38 my $self = shift;
1478 19         38 my ($addr, $port, $atype) = @{ ${*$self}->{SOCKS} }{qw/DstAddr DstPort DstAddrType/};
  19         19  
  19         113  
1479 19         133 return (_addr_ntoa($addr, $atype), $port, $atype);
1480             }
1481              
1482             sub send {
1483 0     0 0 0 my $self = shift;
1484              
1485 0 0       0 unless (defined ${*$self}->{SOCKS}->{TCP}) {
  0         0  
1486 0         0 return $self->SUPER::send(@_);
1487             }
1488              
1489 0         0 my ($msg, $flags, $peer) = @_;
1490 0 0       0 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  0         0  
1491 0 0       0 my $resolve = defined(${*$self}->{SOCKS}->{Resolve}) ? ${*$self}->{SOCKS}->{Resolve} : $SOCKS5_RESOLVE;
  0         0  
  0         0  
1492              
1493 0 0       0 croak "send: Cannot determine peer address"
1494             unless defined $peer;
1495              
1496 0         0 my ($dstport, $dstaddr, $dstaddr_type);
1497 0 0       0 if (ref $peer eq 'ARRAY') {
1498 0         0 $dstaddr = $peer->[0];
1499 0         0 $dstport = $peer->[1];
1500 0         0 $dstaddr_type = ADDR_DOMAINNAME;
1501             }
1502             else {
1503 0 0       0 unless (($dstport, $dstaddr, $dstaddr_type) = eval { (unpack_sockaddr_in($peer), ADDR_IPV4) }) {
  0         0  
1504 0         0 ($dstport, $dstaddr, $dstaddr_type) = ((unpack_sockaddr_in6($peer))[ 0, 1 ], ADDR_IPV6);
1505             }
1506             }
1507              
1508 0         0 my ($sndaddr, $sndport, $sndaddr_type) = $self->dst;
1509 0 0 0     0 if (($sndaddr eq '0.0.0.0' && $sndaddr_type == ADDR_IPV4) || ($sndaddr eq '::' && $sndaddr_type == ADDR_IPV6)) {
      0        
      0        
1510 0         0 $sndaddr = ${*$self}->{SOCKS}->{ProxyAddr};
  0         0  
1511 0         0 $sndaddr_type = ADDR_DOMAINNAME;
1512             }
1513 0 0       0 if ($sndaddr_type == ADDR_DOMAINNAME) {
1514 0 0       0 ($sndaddr_type, $sndaddr) = _resolve($sndaddr)
1515             or $SOCKS_ERROR->set(ISS_CANT_RESOLVE, $@ = "Can't resolve `$sndaddr'"), return;
1516             }
1517             else {
1518 0         0 $sndaddr = ${*$self}->{SOCKS}->{DstAddr};
  0         0  
1519             }
1520              
1521 0 0       0 $peer = $sndaddr_type == ADDR_IPV4 ? pack_sockaddr_in($sndport, $sndaddr) : pack_sockaddr_in6($sndport, $sndaddr);
1522              
1523 0         0 my $hlen;
1524 0 0       0 if ($dstaddr_type == ADDR_DOMAINNAME) {
1525 0 0       0 if ($resolve) {
1526 0         0 $hlen = length $dstaddr;
1527             }
1528             else {
1529 0 0       0 ($dstaddr_type, $dstaddr) = _resolve($dstaddr)
1530             or $SOCKS_ERROR->set(ISS_CANT_RESOLVE, $@ = "Can't resolve `$dstaddr'"), return;
1531             }
1532             }
1533              
1534 0 0       0 my $msglen = $debug ? length($msg) : 0;
1535              
1536             # we need to add socks header to the message
1537             # +----+------+------+----------+----------+----------+
1538             # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
1539             # +----+------+------+----------+----------+----------+
1540             # | 2 | 1 | 1 | Variable | 2 | Variable |
1541             # +----+------+------+----------+----------+----------+
1542 0 0       0 $msg = pack('C4', 0, 0, 0, $dstaddr_type) . (defined $hlen ? pack('C', $hlen) : '') . $dstaddr . pack('n', $dstport) . $msg;
1543              
1544 0 0       0 if ($debug) {
1545 0         0 $debug->add(
1546             rsv => '00',
1547             frag => '0',
1548             atyp => $dstaddr_type
1549             );
1550 0 0       0 $debug->add(hlen => $hlen) if defined $hlen;
1551 0 0       0 $debug->add(
1552             dstaddr => defined $hlen ? $dstaddr : _addr_ntoa($dstaddr, $dstaddr_type),
1553             dstport => $dstport,
1554             data => "...($msglen)"
1555             );
1556 0         0 $debug->show('Client Send: ');
1557             }
1558              
1559 0         0 $self->SUPER::send($msg, $flags, $peer);
1560             }
1561              
1562             sub recv {
1563 0     0 0 0 my $self = shift;
1564              
1565 0 0       0 unless (defined ${*$self}->{SOCKS}->{TCP}) {
  0         0  
1566 0         0 return $self->SUPER::recv(@_);
1567             }
1568              
1569 0 0       0 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  0         0  
1570              
1571 0 0       0 defined($self->SUPER::recv($_[0], $_[1] + 262, $_[2]))
1572             or return;
1573              
1574             # we need to remove socks header from the message
1575             # +----+------+------+----------+----------+----------+
1576             # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
1577             # +----+------+------+----------+----------+----------+
1578             # | 2 | 1 | 1 | Variable | 2 | Variable |
1579             # +----+------+------+----------+----------+----------+
1580 0         0 my $rsv = join('', unpack('C2', $_[0]));
1581 0         0 substr($_[0], 0, 2) = '';
1582              
1583 0         0 my ($frag, $atyp) = unpack('C2', $_[0]);
1584 0         0 substr($_[0], 0, 2) = '';
1585              
1586 0 0       0 if ($debug) {
1587 0         0 $debug->add(
1588             rsv => $rsv,
1589             frag => $frag,
1590             atyp => $atyp
1591             );
1592             }
1593              
1594 0         0 my $dstaddr;
1595 0 0       0 if ($atyp == ADDR_DOMAINNAME) {
    0          
    0          
1596 0         0 my $hlen = unpack('C', $_[0]);
1597 0         0 $dstaddr = substr($_[0], 1, $hlen);
1598 0         0 substr($_[0], 0, $hlen + 1) = '';
1599              
1600 0 0       0 if ($debug) {
1601 0         0 $debug->add(hlen => $hlen);
1602             }
1603             }
1604             elsif ($atyp == ADDR_IPV4) {
1605 0         0 $dstaddr = substr($_[0], 0, 4);
1606 0         0 substr($_[0], 0, 4) = '';
1607             }
1608             elsif ($atyp == ADDR_IPV6) {
1609 0         0 $dstaddr = substr($_[0], 0, 16);
1610 0         0 substr($_[0], 0, 16) = '';
1611             }
1612             else {
1613 0         0 $! = ESOCKSPROTO;
1614 0         0 $SOCKS_ERROR->set(ISS_UNKNOWN_ADDRESS, $@ = "Unsupported address type returned by socks server: $atyp");
1615 0         0 return;
1616             }
1617              
1618 0         0 my $dstport = unpack('n', $_[0]);
1619 0         0 substr($_[0], 0, 2) = '';
1620              
1621 0 0       0 if ($debug) {
1622 0         0 $debug->add(
1623             dstaddr => _addr_ntoa($dstaddr, $atyp),
1624             dstport => $dstport,
1625             data => "...(" . length($_[0]) . ")"
1626             );
1627 0         0 $debug->show('Client Recv: ');
1628             }
1629              
1630 0 0       0 return pack_sockaddr_in($dstport, $dstaddr) if $atyp == ADDR_IPV4;
1631 0 0       0 return pack_sockaddr_in6($dstport, $dstaddr) if $atyp == ADDR_IPV6;
1632 0         0 return [ $dstaddr, $dstport ];
1633             }
1634              
1635             #+-----------------------------------------------------------------------------
1636             #| Helper Functions
1637             #+-----------------------------------------------------------------------------
1638             sub _socks_send {
1639 325     325   33003244 my $self = shift;
1640 325         483 my $data = shift;
1641 325         281 my $numb = shift;
1642              
1643 325         3657 local $SIG{PIPE} = 'IGNORE';
1644 325         1405 $SOCKS_ERROR->set();
1645              
1646 325         285 my $rc;
1647 325         310 my $writed = 0;
1648 325 50       572 my $blocking = ${*$self}{io_socket_timeout} ? $self->blocking(0) : $self->blocking;
  325         2027  
1649              
1650 325 50 66     3439 unless ($blocking || ${*$self}{io_socket_timeout}) {
  193         718  
1651 193 100       153 if (${*$self}->{SOCKS}->{queue}[0][Q_SENDS] >= $numb) { # already sent
  193         483  
1652 57         397 return 1;
1653             }
1654              
1655 136 50       128 if (defined ${*$self}->{SOCKS}->{queue}[0][Q_BUF]) { # some chunk already sent
  136         279  
1656 0         0 substr($data, 0, ${*$self}->{SOCKS}->{queue}[0][Q_BUF]) = '';
  0         0  
1657             }
1658              
1659 136         257 while (length $data) {
1660 136         389 $rc = $self->syswrite($data);
1661 136 50 0     11196 if (defined $rc) {
    0          
1662 136 50       216 if ($rc > 0) {
1663 136         576 ${*$self}->{SOCKS}->{queue}[0][Q_BUF] += $rc;
  136         349  
1664 136         440 substr($data, 0, $rc) = '';
1665             }
1666             else { # XXX: socket closed? if smth writed, but not all?
1667 0         0 last;
1668             }
1669             }
1670             elsif ($! == EWOULDBLOCK || $! == EAGAIN) {
1671 0         0 $SOCKS_ERROR->set(SOCKS_WANT_WRITE, 'Socks want write');
1672 0         0 return undef;
1673             }
1674             else {
1675 0         0 $SOCKS_ERROR->set($!, $@ = "send: $!");
1676 0         0 last;
1677             }
1678             }
1679              
1680 136         107 $writed = int(${*$self}->{SOCKS}->{queue}[0][Q_BUF]);
  136         230  
1681 136         148 ${*$self}->{SOCKS}->{queue}[0][Q_BUF] = undef;
  136         158  
1682 136         103 ${*$self}->{SOCKS}->{queue}[0][Q_SENDS]++;
  136         160  
1683 136         866 return $writed;
1684             }
1685              
1686 132         1151 my $selector = IO::Select->new($self);
1687 132         6401 my $start = time();
1688              
1689 132         149 while (1) {
1690 132 50 33     135 if (${*$self}{io_socket_timeout} && time() - $start >= ${*$self}{io_socket_timeout}) {
  132         509  
  0         0  
1691 0         0 $! = ETIMEDOUT;
1692 0         0 last;
1693             }
1694              
1695 132 50       438 unless ($selector->can_write(1)) { # socket couldn't accept data for now, check if timeout expired and try again
1696 0         0 next;
1697             }
1698              
1699 132         4241 $rc = $self->syswrite($data);
1700 132 50       17481 if ($rc > 0) { # reduce our message
1701 132         151 $writed += $rc;
1702 132         350 substr($data, 0, $rc) = '';
1703 132 50       310 if (length($data) == 0) { # all data successfully writed
1704 132         187 last;
1705             }
1706             }
1707             else { # some error in the socket; will return false
1708 0 0       0 $SOCKS_ERROR->set($!, $@ = "send: $!") unless defined $rc;
1709 0         0 last;
1710             }
1711             }
1712              
1713 132 50       537 $self->blocking(1) if $blocking;
1714              
1715 132         2219 return $writed;
1716             }
1717              
1718             sub _socks_read {
1719 867     867   971 my $self = shift;
1720 867   50     1368 my $length = shift || 1;
1721 867         642 my $numb = shift;
1722              
1723 867         1901 $SOCKS_ERROR->set();
1724 867         911 my $data = '';
1725 867         589 my ($buf, $rc);
1726 867         1888 my $blocking = $self->blocking;
1727              
1728             # non-blocking read
1729 867 50 66     7673 unless ($blocking || ${*$self}{io_socket_timeout}) { # no timeout should be specified for non-blocking connect
  652         1839  
1730 652 100       441 if (defined ${*$self}->{SOCKS}->{queue}[0][Q_READS][$numb]) { # already readed
  652         1346  
1731 63         51 return ${*$self}->{SOCKS}->{queue}[0][Q_READS][$numb];
  63         207  
1732             }
1733              
1734 589 100       454 if (defined ${*$self}->{SOCKS}->{queue}[0][Q_BUF]) { # some chunk already readed
  589         1100  
1735 5         6 $data = ${*$self}->{SOCKS}->{queue}[0][Q_BUF];
  5         11  
1736 5         8 $length -= length $data;
1737             }
1738              
1739 589         974 while ($length > 0) {
1740 592         1423 $rc = $self->sysread($buf, $length);
1741 592 100 33     5957 if (defined $rc) {
    50          
1742 387 50       460 if ($rc > 0) {
1743 387         306 $length -= $rc;
1744 387         710 $data .= $buf;
1745             }
1746             else { # XXX: socket closed, if smth readed but not all?
1747 0         0 last;
1748             }
1749             }
1750             elsif ($! == EWOULDBLOCK || $! == EAGAIN) { # no data to read
1751 205 100       392 if (length $data) { # save already readed data in the queue buffer
1752 5         3 ${*$self}->{SOCKS}->{queue}[0][Q_BUF] = $data;
  5         10  
1753             }
1754 205         338 $SOCKS_ERROR->set(SOCKS_WANT_READ, 'Socks want read');
1755 205         957 return undef;
1756             }
1757             else {
1758 0         0 $SOCKS_ERROR->set($!, $@ = "read: $!");
1759 0         0 last;
1760             }
1761             }
1762              
1763 384         299 ${*$self}->{SOCKS}->{queue}[0][Q_BUF] = undef;
  384         574  
1764 384         313 ${*$self}->{SOCKS}->{queue}[0][Q_READS][$numb] = $data;
  384         662  
1765 384         988 return $data;
1766             }
1767              
1768             # blocking read
1769 215         742 my $selector = IO::Select->new($self);
1770 215         7025 my $start = time();
1771              
1772 215         421 while ($length > 0) {
1773 239 50 33     245 if (${*$self}{io_socket_timeout} && time() - $start >= ${*$self}{io_socket_timeout}) {
  239         913  
  0         0  
1774 0         0 $! = ETIMEDOUT;
1775 0         0 last;
1776             }
1777              
1778 239 100       784 unless ($selector->can_read(1)) { # no data in socket for now, check if timeout expired and try again
1779 24         24026142 next;
1780             }
1781              
1782 215         6162693 $rc = $self->sysread($buf, $length);
1783 215 50 33     2894 if (defined $rc && $rc > 0) { # reduce limit and modify buffer
1784 215         216 $length -= $rc;
1785 215         545 $data .= $buf;
1786             }
1787             else { # EOF or error in the socket
1788 0 0       0 $SOCKS_ERROR->set($!, $@ = "read: $!") unless defined $rc;
1789 0         0 last; # TODO handle unexpected EOF more correct
1790             }
1791             }
1792              
1793             # XXX it may return incomplete $data if timed out. Could it break smth?
1794 215         1169 return $data;
1795             }
1796              
1797             sub _debugged {
1798 0     0   0 my ($self, $debugs) = @_;
1799              
1800 0 0       0 if (${*$self}->{SOCKS}->{queue}[0][Q_DEBUGS] >= $debugs) {
  0         0  
1801 0         0 return 1;
1802             }
1803              
1804 0         0 ${*$self}->{SOCKS}->{queue}[0][Q_DEBUGS] = $debugs;
  0         0  
1805 0         0 return 0;
1806             }
1807              
1808             sub _fail {
1809 205 50 33 205   1031 if (!@_ || defined($_[0])) {
1810 0 0       0 $SOCKS_ERROR->set(ECONNABORTED, $@ = 'Socket closed by remote side') if $SOCKS_ERROR == undef;
1811 0         0 return;
1812             }
1813              
1814 205         310 return -1;
1815             }
1816              
1817             sub _validate_multi_version {
1818 1     1   1 my $multi_ver = shift;
1819              
1820 1 50       4 if (@$multi_ver == 1) {
1821 0   0     0 return $multi_ver->[0] == 4 || $multi_ver->[0] == 5;
1822             }
1823              
1824 1 50       2 if (@$multi_ver == 2) {
1825             return
1826 1   33     13 $multi_ver->[0] != $multi_ver->[1]
1827             && ($multi_ver->[0] == 4 || $multi_ver->[0] == 5)
1828             && ($multi_ver->[1] == 4 || $multi_ver->[1] == 5);
1829             }
1830              
1831 0         0 return;
1832             }
1833              
1834             sub _resolve {
1835 26     26   37 my $addr = shift;
1836 26         471 my ($err, @res) = Socket::getaddrinfo($addr, undef, { protocol => Socket::IPPROTO_TCP, socktype => Socket::SOCK_STREAM });
1837 26 50       85 return if $err;
1838              
1839 26         48 for my $r (@res) {
1840 26 50       77 if ($r->{family} == PF_INET) {
1841 26         176 return (ADDR_IPV4, (unpack_sockaddr_in($r->{addr}))[1]);
1842             }
1843             }
1844              
1845 0         0 return (ADDR_IPV6, (unpack_sockaddr_in6($res[0]{addr}))[1]);
1846             }
1847              
1848             sub _addr_ntoa {
1849 19     19   29 my ($addr, $atype) = @_;
1850              
1851 19 50       200 return inet_ntoa($addr) if ($atype == ADDR_IPV4);
1852 0 0       0 return Socket::inet_ntop(AF_INET6, $addr) if ($atype == ADDR_IPV6);
1853 0         0 return $addr;
1854             }
1855              
1856             ###############################################################################
1857             #+-----------------------------------------------------------------------------
1858             #| Helper Package to bring some magic in $SOCKS_ERROR
1859             #+-----------------------------------------------------------------------------
1860             ###############################################################################
1861              
1862             package IO::Socket::Socks::Error;
1863              
1864             use overload
1865             '==' => \&num_eq,
1866 0     0   0 '!=' => sub { !num_eq(@_) },
1867 34         280 '""' => \&as_str,
1868 34     34   33052 '0+' => \&as_num;
  34         24595  
1869              
1870             sub new {
1871 34     34   88 my ($class, $num, $str) = @_;
1872              
1873 34         98 my $self = {
1874             num => $num,
1875             str => $str,
1876             };
1877              
1878 34         157 bless $self, $class;
1879             }
1880              
1881             sub set {
1882 1676     1676   2051 my ($self, $num, $str) = @_;
1883              
1884 1676 100       3922 $self->{num} = defined $num ? int($num) : $num;
1885 1676         1755 $self->{str} = $str;
1886             }
1887              
1888             sub as_str {
1889 0     0   0 my $self = shift;
1890 0         0 return $self->{str};
1891             }
1892              
1893             sub as_num {
1894 314     314   703 my $self = shift;
1895 314         558 return $self->{num};
1896             }
1897              
1898             sub num_eq {
1899 194     194   476 my ($self, $num) = @_;
1900              
1901 194 100       491 unless (defined $num) {
1902 8         40 return !defined($self->{num});
1903             }
1904 186         461 return $self->{num} == int($num);
1905             }
1906              
1907             ###############################################################################
1908             #+-----------------------------------------------------------------------------
1909             #| Helper Package to prevent modifications of $SOCKS_ERROR outside this package
1910             #+-----------------------------------------------------------------------------
1911             ###############################################################################
1912              
1913             package IO::Socket::Socks::ReadOnlyVar;
1914              
1915             sub TIESCALAR {
1916 34     34   60 my ($class, $value) = @_;
1917 34         91 bless \$value, $class;
1918             }
1919              
1920             sub FETCH {
1921 4368     4368   51363 my $self = shift;
1922 4368         8808 return $$self;
1923             }
1924              
1925 0     0   0 *STORE = *UNTIE = sub { Carp::croak 'Modification of readonly value attempted' };
1926              
1927             ###############################################################################
1928             #+-----------------------------------------------------------------------------
1929             #| Helper Package to handle assigning of $SOCKET_CLASS
1930             #+-----------------------------------------------------------------------------
1931             ###############################################################################
1932              
1933             package IO::Socket::Socks::SocketClassVar;
1934              
1935             sub TIESCALAR {
1936 34     34   62 my ($class, $value) = @_;
1937 34         105 bless { v => $value }, $class;
1938             }
1939              
1940             sub FETCH {
1941 85     85   4715 return $_[0]->{v};
1942             }
1943              
1944             sub STORE {
1945 34     34   69 my ($self, $class) = @_;
1946              
1947 34         90 $self->{v} = $class;
1948 34 50   34   179 eval "use $class; 1" or die $@;
  34         57  
  34         107  
  34         1872  
1949 34         489 $IO::Socket::Socks::ISA[1] = $class;
1950             }
1951              
1952             sub UNTIE {
1953 0     0     Carp::croak 'Untie of tied variable is denied';
1954             }
1955              
1956             ###############################################################################
1957             #+-----------------------------------------------------------------------------
1958             #| Helper Package to display pretty debug messages
1959             #+-----------------------------------------------------------------------------
1960             ###############################################################################
1961              
1962             package IO::Socket::Socks::Debug;
1963              
1964             sub new {
1965 0     0     my ($class) = @_;
1966 0           my $self = [];
1967              
1968 0           bless $self, $class;
1969             }
1970              
1971             sub add {
1972 0     0     my $self = shift;
1973 0           push @{$self}, @_;
  0            
1974             }
1975              
1976             sub show {
1977 0     0     my ($self, $tag) = @_;
1978              
1979 0           $self->_separator($tag);
1980 0           $self->_row(0, $tag);
1981 0           $self->_separator($tag);
1982 0           $self->_row(1, $tag);
1983 0           $self->_separator($tag);
1984              
1985 0           print STDERR "\n";
1986              
1987 0           @{$self} = ();
  0            
1988             }
1989              
1990             sub _separator {
1991 0     0     my $self = shift;
1992 0           my $tag = shift;
1993 0           my ($row1_len, $row2_len, $len);
1994              
1995 0           print STDERR $tag, '+';
1996              
1997 0           for (my $i = 0 ; $i < @$self ; $i += 2) {
1998 0           $row1_len = length($self->[$i]);
1999 0           $row2_len = length($self->[ $i + 1 ]);
2000 0 0         $len = ($row1_len > $row2_len ? $row1_len : $row2_len) + 2;
2001              
2002 0           print STDERR '-' x $len, '+';
2003             }
2004              
2005 0           print STDERR "\n";
2006             }
2007              
2008             sub _row {
2009 0     0     my $self = shift;
2010 0           my $row = shift;
2011 0           my $tag = shift;
2012 0           my ($row1_len, $row2_len, $len);
2013              
2014 0           print STDERR $tag, '|';
2015              
2016 0           for (my $i = 0 ; $i < @$self ; $i += 2) {
2017 0           $row1_len = length($self->[$i]);
2018 0           $row2_len = length($self->[ $i + 1 ]);
2019 0 0         $len = ($row1_len > $row2_len ? $row1_len : $row2_len);
2020              
2021 0           printf STDERR ' %-' . $len . 's |', $self->[ $i + $row ];
2022             }
2023              
2024 0           print STDERR "\n";
2025             }
2026              
2027             1;
2028              
2029             __END__