File Coverage

blib/lib/IO/Socket/Socks.pm
Criterion Covered Total %
statement 707 1021 69.2
branch 268 534 50.1
condition 64 172 37.2
subroutine 58 72 80.5
pod 8 13 61.5
total 1105 1812 60.9


line stmt bran cond sub pod time code
1             package IO::Socket::Socks;
2              
3 34     34   579903 use strict;
  34         71  
  34         861  
4 34     34   13899 use IO::Select;
  34         42243  
  34         1372  
5 34     34   5440 use Socket;
  34         26015  
  34         13260  
6 34     34   17486 use Errno qw(EWOULDBLOCK EAGAIN EINPROGRESS ETIMEDOUT ECONNABORTED);
  34         41712  
  34         3584  
7 34     34   258 use Carp;
  34         67  
  34         2339  
8 34     34   233 use vars qw( $SOCKET_CLASS @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION $SOCKS_ERROR $SOCKS5_RESOLVE $SOCKS4_RESOLVE $SOCKS_DEBUG %CODES );
  34         68  
  34         9778  
9             require Exporter;
10              
11             $VERSION = '0.74';
12              
13             use constant {
14 34 50       8913 SOCKS_WANT_READ => 20,
15             SOCKS_WANT_WRITE => 21,
16             ESOCKSPROTO => exists &Errno::EPROTO ? &Errno::EPROTO : 7000,
17 34     34   242 };
  34         65  
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         6925 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   238 };
  34         87  
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         8121 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   238 };
  34         105  
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         4288 REQUEST_GRANTED => 90,
125             REQUEST_FAILED => 91,
126             REQUEST_REJECTED_IDENTD => 92,
127             REQUEST_REJECTED_USERID => 93,
128 34     34   548 };
  34         87  
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         299756 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   208 };
  34         61  
145              
146             our $CAN_CHANGE_SOCKET = 1;
147             sub new_from_fd {
148 4     4 1 5165 my ($class, $sock, %arg) = @_;
149              
150 4         19 bless $sock, $class;
151              
152 4         63 $sock->autoflush(1);
153 4 50       420 if (exists $arg{Timeout}) {
154 0         0 ${*$sock}{'io_socket_timeout'} = delete $arg{Timeout};
  0         0  
155             }
156              
157 4 50       37 scalar(%arg) or return $sock;
158            
159             # do not allow to create new socket
160 4         34 local $CAN_CHANGE_SOCKET = 0;
161 4 50 33     39 $sock->configure(\%arg) || $SOCKS_ERROR == SOCKS_WANT_WRITE || return;
162 4         63 $sock;
163             }
164              
165             *new_from_socket = \&new_from_fd;
166              
167             sub start_SOCKS {
168 4     4 1 1419 my ($class, $sock, %arg) = @_;
169              
170 4         20 bless $sock, $class;
171              
172 4         28 $sock->autoflush(1);
173 4 50       207 if (exists $arg{Timeout}) {
174 0         0 ${*$sock}{'io_socket_timeout'} = delete $arg{Timeout};
  0         0  
175             }
176              
177 4         30 ${*$sock}->{SOCKS} = { RequireAuth => 0 };
  4         24  
178              
179 4         27 $SOCKS_ERROR->set();
180 4 50       55 return $sock->command(%arg) ? $sock : undef;
181             }
182              
183             sub socket {
184 164     164 0 67166 my $self = shift;
185              
186 164 100       572 return $self unless $CAN_CHANGE_SOCKET;
187 160         762 return $self->SUPER::socket(@_);
188             }
189              
190             sub configure {
191 164     164 0 224438 my $self = shift;
192 164         537 my $args = shift;
193              
194 164 50       1003 $self->_configure($args)
195             or return;
196              
197 164         526 ${*$self}->{SOCKS}->{ProxyAddr} = (
198             exists($args->{ProxyAddr})
199             ? delete($args->{ProxyAddr})
200 164 100       554 : undef
201             );
202              
203 164         471 ${*$self}->{SOCKS}->{ProxyPort} = (
204             exists($args->{ProxyPort})
205             ? delete($args->{ProxyPort})
206 164 100       545 : undef
207             );
208              
209 164         385 ${*$self}->{SOCKS}->{COMMAND} = [];
  164         440  
210              
211 164 100 33     533 if (exists($args->{Listen})) {
    50          
212 67         141 $args->{LocalAddr} = ${*$self}->{SOCKS}->{ProxyAddr};
  67         266  
213 67         163 $args->{LocalPort} = ${*$self}->{SOCKS}->{ProxyPort};
  67         282  
214 67         182 $args->{Reuse} = 1;
215 67         147 ${*$self}->{SOCKS}->{Listen} = 1;
  67         201  
216             }
217 97         706 elsif (${*$self}->{SOCKS}->{ProxyAddr} && ${*$self}->{SOCKS}->{ProxyPort}) {
  97         520  
218 97         202 $args->{PeerAddr} = ${*$self}->{SOCKS}->{ProxyAddr};
  97         320  
219 97         250 $args->{PeerPort} = ${*$self}->{SOCKS}->{ProxyPort};
  97         444  
220             }
221              
222 164 50 0     313 unless (defined ${*$self}->{SOCKS}->{TCP}) {
  164         573  
223 164         364 $args->{Proto} = "tcp";
224 164         382 $args->{Type} = SOCK_STREAM;
225             }
226             elsif (!defined $args->{Proto}) {
227             $args->{Proto} = "udp";
228             $args->{Type} = SOCK_DGRAM;
229             }
230              
231 164         1377 $SOCKS_ERROR->set();
232 164 100       1433 unless ($self->SUPER::configure($args)) {
233 8 50       480 if ($SOCKS_ERROR == undef) {
234 0         0 $SOCKS_ERROR->set($!, $@);
235             }
236 8         544 return;
237             }
238              
239 156         10780 return $self;
240             }
241              
242             sub _configure {
243 168     168   361 my $self = shift;
244 168         508 my $args = shift;
245              
246 168         1008 ${*$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     1904 : croak("Unsupported socks version specified. Should be 4 or 5")
    100          
256             )
257             : 5
258             );
259              
260 168         724 ${*$self}->{SOCKS}->{AuthType} = (
261             exists($args->{AuthType})
262             ? delete($args->{AuthType})
263 168 100       858 : "none"
264             );
265              
266 168         849 ${*$self}->{SOCKS}->{RequireAuth} = (
267             exists($args->{RequireAuth})
268             ? delete($args->{RequireAuth})
269 168 100       766 : 0
270             );
271              
272 168         521 ${*$self}->{SOCKS}->{UserAuth} = (
273             exists($args->{UserAuth})
274             ? delete($args->{UserAuth})
275 168 100       561 : undef
276             );
277              
278 168         713 ${*$self}->{SOCKS}->{Username} = (
279             exists($args->{Username}) ? delete($args->{Username})
280             : (
281 168 50       717 (${*$self}->{SOCKS}->{AuthType} eq "none") ? undef
  142 100       717  
282             : croak("If you set AuthType to userpass, then you must provide a username.")
283             )
284             );
285              
286 168         456 ${*$self}->{SOCKS}->{Password} = (
287             exists($args->{Password}) ? delete($args->{Password})
288             : (
289 168 50       568 (${*$self}->{SOCKS}->{AuthType} eq "none") ? undef
  142 100       458  
290             : croak("If you set AuthType to userpass, then you must provide a password.")
291             )
292             );
293              
294 168         485 ${*$self}->{SOCKS}->{Debug} = (
295             exists($args->{SocksDebug})
296             ? delete($args->{SocksDebug})
297 168 50       485 : $SOCKS_DEBUG
298             );
299              
300 168         665 ${*$self}->{SOCKS}->{Resolve} = (
301             exists($args->{SocksResolve})
302             ? delete($args->{SocksResolve})
303 168 100       583 : undef
304             );
305              
306 168         550 ${*$self}->{SOCKS}->{AuthMethods} = [ 0, 0, 0 ];
  168         486  
307 153         402 ${*$self}->{SOCKS}->{AuthMethods}->[AUTHMECH_ANON] = 1
308 168 100       361 unless ${*$self}->{SOCKS}->{RequireAuth};
  168         694  
309              
310             #${*$self}->{SOCKS}->{AuthMethods}->[AUTHMECH_GSSAPI] = 1
311             # if (${*$self}->{SOCKS}->{AuthType} eq "gssapi");
312 88         6233 ${*$self}->{SOCKS}->{AuthMethods}->[AUTHMECH_USERPASS] = 1
313             if (
314 101         1192 (!exists($args->{Listen}) && (${*$self}->{SOCKS}->{AuthType} eq "userpass"))
315             || (exists($args->{Listen})
316 168 100 100     1313 && defined(${*$self}->{SOCKS}->{UserAuth}))
  67   100     379  
      66        
317             );
318              
319 168 50 33     2164 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         457 ${*$self}->{SOCKS}->{CmdAddr} = delete($args->{ConnectAddr});
  101         392  
341 101         265 ${*$self}->{SOCKS}->{CmdPort} = delete($args->{ConnectPort});
  101         299  
342             }
343              
344 168         699 return 1;
345             }
346              
347             sub version {
348 62     62 1 22934 my $self = shift;
349 62         122 return ${*$self}->{SOCKS}->{Version};
  62         455  
350             }
351              
352             sub connect {
353 97     97 0 7886 my $self = shift;
354              
355 97 50       428 croak("Undefined IO::Socket::Socks object passed to connect.")
356             unless defined($self);
357              
358             my $ok =
359 97         962 defined(${*$self}->{SOCKS}->{TCP})
360 97 50       178 ? 1
361             : $self->SUPER::connect(@_);
362              
363 97 100 66     11263 if (($! == EINPROGRESS || $! == EWOULDBLOCK) &&
    50 33        
      66        
364             (${*$self}->{SOCKS}->{TCP} || $self)->blocking == 0) {
365 47         461 ${*$self}->{SOCKS}->{_in_progress} = 1;
  47         127  
366 47         174 $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         225 $SOCKS_ERROR->set();
375             }
376              
377             return $ok # proxy address was not specified, so do not make socks handshake
378 97 50 33     208 unless ${*$self}->{SOCKS}->{ProxyAddr} && ${*$self}->{SOCKS}->{ProxyPort};
  97         666  
  97         355  
379            
380 97         425 $self->_connect();
381             }
382              
383             sub _connect {
384 101     101   220 my $self = shift;
385 101         187 ${*$self}->{SOCKS}->{ready} = 0;
  101         552  
386              
387 101 100       221 if (${*$self}->{SOCKS}->{Version} == 4) {
  101         409  
388 41         198 ${*$self}->{SOCKS}->{queue} = [
389              
390             # [sub, [@args], buf, [@reads], sends_cnt]
391 41 50       99 [ '_socks4_connect_command', [ ${*$self}->{SOCKS}->{Bind} ? CMD_BIND : CMD_CONNECT ], undef, [], 0 ],
  41         269  
392             [ '_socks4_connect_reply', [], undef, [], 0 ]
393             ];
394             }
395             else {
396 60         394 ${*$self}->{SOCKS}->{queue} = [
397             [ '_socks5_connect', [], undef, [], 0 ],
398             [ '_socks5_connect_if_auth', [], undef, [], 0 ],
399             [
400             '_socks5_connect_command',
401             [
402 60         277 ${*$self}->{SOCKS}->{Bind} ? CMD_BIND
403 60 50       453 : ${*$self}->{SOCKS}->{TCP} ? CMD_UDPASSOC
  60 50       563  
404             : CMD_CONNECT
405             ],
406             undef,
407             [],
408             0
409             ],
410             [ '_socks5_connect_reply', [], undef, [], 0 ]
411             ];
412             }
413              
414 101 100       271 if (delete ${*$self}->{SOCKS}->{_in_progress}) { # socket connection not estabilished yet
  101         382  
415 47 50       494 if ($self->isa('IO::Socket::IP')) {
416             # IO::Socket::IP requires multiple connect calls
417             # when performing non-blocking multi-homed connect
418 47         88 unshift @{ ${*$self}->{SOCKS}->{queue} }, ['_socket_connect', [], undef, [], 0];
  47         75  
  47         277  
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         174 return; # connect() return value
424             }
425             }
426             else {
427 54 100       237 defined($self->_run_queue())
428             or return;
429             }
430              
431 46         233 return $self;
432             }
433              
434             sub _socket_connect {
435 47     47   116 my $self = shift;
436 47   33     119 my $sock = ${*$self}->{SOCKS}->{TCP} || $self;
437            
438 47 50       224 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 390     390   817 my $self = shift;
452              
453 390         887 my $retval;
454             my $sub;
455              
456 390         691 while (my $elt = ${*$self}->{SOCKS}->{queue}[0]) {
  881         4482  
457 704         1637 $sub = $elt->[Q_SUB];
458 704         1517 $retval = $self->$sub(@{ $elt->[Q_ARGS] });
  704         4418  
459 704 100       4491 unless (defined $retval) {
460 13         34 ${*$self}->{SOCKS}->{queue} = [];
  13         47  
461 13         68 ${*$self}->{SOCKS}->{queue_results} = {};
  13         47  
462 13         55 last;
463             }
464              
465 691 100       1900 last if ($retval == -1);
466 491         870 ${*$self}->{SOCKS}->{queue_results}{$sub} = $retval;
  491         5113  
467 491 50       1472 if ($elt->[Q_OKCB]) {
468 0         0 $elt->[Q_OKCB]->();
469             }
470 491         832 shift @{ ${*$self}->{SOCKS}->{queue} };
  491         820  
  491         2060  
471             }
472              
473 390 100 100     1598 if (defined($retval) && !@{ ${*$self}->{SOCKS}->{queue} }) {
  359         709  
  359         1862  
474 159         400 ${*$self}->{SOCKS}->{queue_results} = {};
  159         435  
475 159 50       693 ${*$self}->{SOCKS}->{ready} = $SOCKS_ERROR ? 0 : 1;
  159         446  
476             }
477              
478 390         1346 return $retval;
479             }
480              
481             sub ready {
482 241     241 1 71890587 my $self = shift;
483              
484 241         1015 $self->_run_queue();
485 241         371 return ${*$self}->{SOCKS}->{ready};
  241         986  
486             }
487              
488             sub _socks5_connect {
489 102     102   303 my $self = shift;
490 102 50       249 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  102         536  
491 102         365 my ($reads, $sends, $debugs) = (0, 0, 0);
492             my $sock =
493 102         421 defined(${*$self}->{SOCKS}->{TCP})
494 0         0 ? ${*$self}->{SOCKS}->{TCP}
495 102 50       206 : $self;
496              
497             #--------------------------------------------------------------------------
498             # Send the auth mechanisms
499             #--------------------------------------------------------------------------
500             # +----+----------+----------+
501             # |VER | NMETHODS | METHODS |
502             # +----+----------+----------+
503             # | 1 | 1 | 1 to 255 |
504             # +----+----------+----------+
505              
506 102         229 my $nmethods = 0;
507 102         207 my $methods;
508 102         204 foreach my $method (0 .. $#{ ${*$self}->{SOCKS}->{AuthMethods} }) {
  102         202  
  102         684  
509 306 100       489 if (${*$self}->{SOCKS}->{AuthMethods}->[$method] == 1) {
  306         971  
510 158         557 $methods .= pack('C', $method);
511 158         355 $nmethods++;
512             }
513             }
514              
515 102         186 my $reply;
516 102 50       1164 $reply = $sock->_socks_send(pack('CCa*', SOCKS5_VER, $nmethods, $methods), ++$sends)
517             or return _fail($reply);
518              
519 102 50 33     443 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 102 100       496 $reply = $sock->_socks_read(2, ++$reads)
538             or return _fail($reply);
539              
540 57         268 my ($version, $auth_method) = unpack('CC', $reply);
541              
542 57 50 33     206 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 57 50       212 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 57         141 return $auth_method;
557             }
558              
559             sub _socks5_connect_if_auth {
560 60     60   142 my $self = shift;
561 60 100       99 if (${*$self}->{SOCKS}->{queue_results}{'_socks5_connect'} != AUTHMECH_ANON) {
  60         349  
562 26         129 unshift @{ ${*$self}->{SOCKS}->{queue} }, [ '_socks5_connect_auth', [], undef, [], 0 ];
  26         71  
  26         149  
563 26         65 (${*$self}->{SOCKS}->{queue}[0], ${*$self}->{SOCKS}->{queue}[1]) = (${*$self}->{SOCKS}->{queue}[1], ${*$self}->{SOCKS}->{queue}[0]);
  26         78  
  26         94  
  26         81  
  26         65  
564             }
565              
566 60         160 1;
567             }
568              
569             sub _socks5_connect_auth {
570             # rfc1929
571 36     36   133 my $self = shift;
572 36 50       78 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  36         1005  
573 36         164 my ($reads, $sends, $debugs) = (0, 0, 0);
574             my $sock =
575 36         161 defined(${*$self}->{SOCKS}->{TCP})
576 0         0 ? ${*$self}->{SOCKS}->{TCP}
577 36 50       57 : $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         85 my $uname = ${*$self}->{SOCKS}->{Username};
  36         98  
589 36         67 my $passwd = ${*$self}->{SOCKS}->{Password};
  36         95  
590 36         85 my $ulen = length($uname);
591 36         62 my $plen = length($passwd);
592 36         72 my $reply;
593 36 50       276 $reply = $sock->_socks_send(pack("CCa${ulen}Ca*", 1, $ulen, $uname, $plen, $passwd), ++$sends)
594             or return _fail($reply);
595              
596 36 50 33     297 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       218 $reply = $sock->_socks_read(2, ++$reads)
617             or return _fail($reply);
618              
619 26         117 my ($ver, $status) = unpack('CC', $reply);
620              
621 26 50 33     120 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       86 if ($status != AUTHREPLY_SUCCESS) {
630 13         42 $! = ESOCKSPROTO;
631 13         52 $SOCKS_ERROR->set(AUTHREPLY_FAILURE, $@ = "Authentication failed with SOCKS5 proxy");
632 13         34 return;
633             }
634              
635 13         479 return 1;
636             }
637              
638             sub _socks5_connect_command {
639 47     47   103 my $self = shift;
640 47         90 my $command = shift;
641 47 50       92 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  47         248  
642 47         179 my ($reads, $sends, $debugs) = (0, 0, 0);
643 47 100       89 my $resolve = defined(${*$self}->{SOCKS}->{Resolve}) ? ${*$self}->{SOCKS}->{Resolve} : $SOCKS5_RESOLVE;
  47         192  
  4         7  
644             my $sock =
645 47         193 defined(${*$self}->{SOCKS}->{TCP})
646 0         0 ? ${*$self}->{SOCKS}->{TCP}
647 47 50       106 : $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 47         243 my ($atyp, $dstaddr) = $resolve ? (ADDR_DOMAINNAME, ${*$self}->{SOCKS}->{CmdAddr}) : _resolve(${*$self}->{SOCKS}->{CmdAddr})
  0         0  
659 47 50       164 or $SOCKS_ERROR->set(ISS_CANT_RESOLVE, $@ = "Can't resolve `" . ${*$self}->{SOCKS}->{CmdAddr} . "'"), return;
  0 50       0  
660 47 50       176 my $hlen = length($dstaddr) if $resolve;
661 47         177 my $dstport = pack('n', ${*$self}->{SOCKS}->{CmdPort});
  47         231  
662 47         104 my $reply;
663 47 50       383 $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 47 50 33     217 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 47         144 return 1;
682             }
683              
684             sub _socks5_connect_reply {
685 71     71   191 my $self = shift;
686 71 50       182 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  71         380  
687 71         278 my ($reads, $sends, $debugs) = (0, 0, 0);
688             my $sock =
689 71         307 defined(${*$self}->{SOCKS}->{TCP})
690 0         0 ? ${*$self}->{SOCKS}->{TCP}
691 71 50       148 : $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 71         137 my $reply;
703 71 100       325 $reply = $sock->_socks_read(4, ++$reads)
704             or return _fail($reply);
705              
706 33         214 my ($ver, $rep, $rsv, $atyp) = unpack('C4', $reply);
707              
708 33 50       134 if ($debug) {
709 0         0 $debug->add(
710             ver => $ver,
711             rep => $rep,
712             rsv => $rsv,
713             atyp => $atyp
714             );
715             }
716              
717 33         77 my ($bndaddr, $bndport);
718              
719 33 50       167 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       127 $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       142 $reply = $sock->_socks_read(2, ++$reads)
746             or return _fail($reply);
747 33         170 $bndport = unpack('n', $reply);
748              
749 33         76 ${*$self}->{SOCKS}->{DstAddrType} = $atyp;
  33         329  
750 33         109 ${*$self}->{SOCKS}->{DstAddr} = $bndaddr;
  33         152  
751 33         81 ${*$self}->{SOCKS}->{DstPort} = $bndport;
  33         120  
752              
753 33 50 33     175 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       137 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         93 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 38     38   86 my $self = shift;
779 38         86 my $command = shift;
780 38 50       66 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  38         137  
781 38         116 my ($reads, $sends, $debugs) = (0, 0, 0);
782 38 100       65 my $resolve = defined(${*$self}->{SOCKS}->{Resolve}) ? ${*$self}->{SOCKS}->{Resolve} : $SOCKS4_RESOLVE;
  38         125  
  16         34  
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         184 my $dstaddr = $resolve ? inet_aton('0.0.0.1') : inet_aton(${*$self}->{SOCKS}->{CmdAddr})
794 38 100       145 or $SOCKS_ERROR->set(ISS_CANT_RESOLVE, $@ = "Can't resolve `" . ${*$self}->{SOCKS}->{CmdAddr} . "'"), return;
  0 50       0  
795 38         78 my $dstport = pack('n', ${*$self}->{SOCKS}->{CmdPort});
  38         187  
796 38   50     69 my $userid = ${*$self}->{SOCKS}->{Username} || '';
797 38         81 my $dsthost = '';
798 38 100       116 if ($resolve) { # socks4a
799 16         30 $dsthost = ${*$self}->{SOCKS}->{CmdAddr} . pack('C', 0);
  16         38  
800             }
801              
802 38         62 my $reply;
803 38 50       347 $reply = $self->_socks_send(pack('CC', SOCKS4_VER, $command) . $dstport . $dstaddr . $userid . pack('C', 0) . $dsthost, ++$sends)
804             or return _fail($reply);
805              
806 38 50 33     188 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 38         105 return 1;
825             }
826              
827             sub _socks4_connect_reply {
828 71     71   188 my $self = shift;
829 71 50       130 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  71         506  
830 71         261 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 71         146 my $reply;
842 71 100       384 $reply = $self->_socks_read(8, ++$reads)
843             or return _fail($reply);
844              
845 31         240 my ($ver, $rep, $bndport) = unpack('CCn', $reply);
846 31         106 substr($reply, 0, 4) = '';
847              
848 31         108 ${*$self}->{SOCKS}->{DstAddrType} = ADDR_IPV4;
  31         177  
849 31         80 ${*$self}->{SOCKS}->{DstAddr} = $reply;
  31         131  
850 31         74 ${*$self}->{SOCKS}->{DstPort} = $bndport;
  31         105  
851              
852 31 50 33     184 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 31 50       123 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 31         93 return 1;
874             }
875              
876             sub accept {
877 49     49 1 12026227 my $self = shift;
878              
879 49 50       549 croak("Undefined IO::Socket::Socks object passed to accept.")
880             unless defined($self);
881              
882 49 50       152 if (${*$self}->{SOCKS}->{Listen}) {
  49         815  
883 49         1255 my $client = $self->SUPER::accept(@_);
884              
885 49 50       3032077 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         313 ref ${*$self}->{SOCKS}->{Version}
897 10         13 ? @{ ${*$self}->{SOCKS}->{Version} } > 1
  10         30  
898 10         21 ? ${*$self}->{SOCKS}->{Version}
899 0         0 : ${*$self}->{SOCKS}->{Version}->[0]
900 49 50       110 : ${*$self}->{SOCKS}->{Version};
  39 100       139  
901              
902             # inherit some socket parameters
903 49         153 ${*$client}->{SOCKS}->{Debug} = ${*$self}->{SOCKS}->{Debug};
  49         308  
  49         144  
904 49         141 ${*$client}->{SOCKS}->{Version} = $ver;
  49         194  
905 49         138 ${*$client}->{SOCKS}->{AuthMethods} = ${*$self}->{SOCKS}->{AuthMethods};
  49         205  
  49         158  
906 49         124 ${*$client}->{SOCKS}->{UserAuth} = ${*$self}->{SOCKS}->{UserAuth};
  49         184  
  49         180  
907 49         117 ${*$client}->{SOCKS}->{Resolve} = ${*$self}->{SOCKS}->{Resolve};
  49         147  
  49         133  
908 49         139 ${*$client}->{SOCKS}->{ready} = 0;
  49         145  
909 49         602 $client->blocking($self->blocking); # temporarily
910              
911 49 100       1071 if (ref $ver) {
    100          
912 10         35 ${*$client}->{SOCKS}->{queue} = [ [ '_socks_accept', [], undef, [], 0 ] ];
  10         25  
913             }
914             elsif ($ver == 4) {
915 17         120 ${*$client}->{SOCKS}->{queue} = [ [ '_socks4_accept_command', [], undef, [], 0 ] ];
  17         77  
916              
917             }
918             else {
919 22         99 ${*$client}->{SOCKS}->{queue} = [
920 22         343 [ '_socks5_accept', [], undef, [], 0 ],
921             [ '_socks5_accept_if_auth', [], undef, [], 0 ],
922             [ '_socks5_accept_command', [], undef, [], 0 ]
923             ];
924             }
925              
926 49 50       225 defined($client->_run_queue())
927             or return;
928              
929 49         301 $client->blocking(1); # new socket should be in blocking mode
930 49         486 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   32 my $self = shift;
951              
952 20         35 my $request;
953 20 100       49 $request = $self->_socks_read(1, 0)
954             or return _fail($request);
955              
956 10         29 my $ver = unpack('C', $request);
957 10 100       27 if ($ver == 4) {
    50          
958 6         7 ${*$self}->{SOCKS}->{Version} = 4;
  6         16  
959 6         10 push @{ ${*$self}->{SOCKS}->{queue} }, [ '_socks4_accept_command', [$ver], undef, [], 0 ];
  6         7  
  6         25  
960             }
961             elsif ($ver == 5) {
962 4         5 ${*$self}->{SOCKS}->{Version} = 5;
  4         10  
963 4         7 push @{ ${*$self}->{SOCKS}->{queue} },
  4         7  
  4         28  
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         20 1;
975             }
976              
977             sub _socks5_accept {
978 42     42   117 my ($self, $ver) = @_;
979 42 50       87 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  42         325  
980 42         145 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 42         95 my $request;
992 42 100       293 $request = $self->_socks_read($ver ? 1 : 2, ++$reads)
    100          
993             or return _fail($request);
994              
995 31 100       128 unless ($ver) {
996 27         217 $ver = unpack('C', $request);
997             }
998 31         119 my $nmethods = unpack('C', substr($request, -1, 1));
999              
1000 31 100       114 $request = $self->_socks_read($nmethods, ++$reads)
1001             or return _fail($request);
1002              
1003 26         228 my @methods = unpack('C' x $nmethods, $request);
1004              
1005 26 50 33     163 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 26 50       122 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 26 50       113 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 26         94 my $authmech;
1027              
1028 26         113 foreach my $method (@methods) {
1029 28 100       53 if (${*$self}->{SOCKS}->{AuthMethods}->[$method] == 1) {
  28         151  
1030 26         58 $authmech = $method;
1031 26         72 last;
1032             }
1033             }
1034              
1035 26 50       126 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 26 50       228 $request = $self->_socks_send(pack('CC', SOCKS5_VER, $authmech), ++$sends)
1049             or return _fail($request);
1050              
1051 26 50 33     128 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 26 50       93 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 26         90 return $authmech;
1066             }
1067              
1068             sub _socks5_accept_if_auth {
1069 26     26   65 my $self = shift;
1070              
1071 26 100       56 if (${*$self}->{SOCKS}->{queue_results}{'_socks5_accept'} == AUTHMECH_USERPASS) {
  26         129  
1072 2         7 unshift @{ ${*$self}->{SOCKS}->{queue} }, [ '_socks5_accept_auth', [], undef, [], 0 ];
  2         5  
  2         21  
1073 2         6 (${*$self}->{SOCKS}->{queue}[0], ${*$self}->{SOCKS}->{queue}[1]) = (${*$self}->{SOCKS}->{queue}[1], ${*$self}->{SOCKS}->{queue}[0]);
  2         17  
  2         8  
  2         15  
  2         7  
1074             }
1075              
1076 26         63 1;
1077             }
1078              
1079             sub _socks5_accept_auth {
1080 2     2   7 my $self = shift;
1081 2 50       5 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  2         12  
1082 2         14 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         42 my $request;
1094 2 50       13 $request = $self->_socks_read(2, ++$reads)
1095             or return _fail($request);
1096              
1097 2         12 my ($ver, $ulen) = unpack('CC', $request);
1098 2 50       13 $request = $self->_socks_read($ulen + 1, ++$reads)
1099             or return _fail($request);
1100              
1101 2         8 my $uname = substr($request, 0, $ulen);
1102 2         9 my $plen = unpack('C', substr($request, $ulen));
1103 2         7 my $passwd;
1104 2 50       10 $passwd = $self->_socks_read($plen, ++$reads)
1105             or return _fail($passwd);
1106              
1107 2 50 33     13 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         6 my $status = 1;
1119 2 50       6 if (defined(${*$self}->{SOCKS}->{UserAuth})) {
  2         19  
1120 2         8 $status = &{ ${*$self}->{SOCKS}->{UserAuth} }($uname, $passwd);
  2         9  
  2         23  
1121             }
1122              
1123             #--------------------------------------------------------------------------
1124             # Send the reply
1125             #--------------------------------------------------------------------------
1126             # +----+--------+
1127             # |VER | STATUS |
1128             # +----+--------+
1129             # | 1 | 1 |
1130             # +----+--------+
1131              
1132 2 50       37 $status = $status ? AUTHREPLY_SUCCESS : 1; #XXX AUTHREPLY_FAILURE broken
1133 2 50       14 $request = $self->_socks_send(pack('CC', 1, $status), ++$sends)
1134             or return _fail($request);
1135              
1136 2 50 33     14 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       11 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         5 return 1;
1151             }
1152              
1153             sub _socks5_accept_command {
1154 41     41   94 my $self = shift;
1155 41 50       81 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  41         169  
1156 41         130 my ($reads, $sends, $debugs) = (0, 0, 0);
1157              
1158 41         80 @{ ${*$self}->{SOCKS}->{COMMAND} } = ();
  41         69  
  41         158  
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 41         90 my $request;
1170 41 100       129 $request = $self->_socks_read(4, ++$reads)
1171             or return _fail($request);
1172              
1173 26         120 my ($ver, $cmd, $rsv, $atyp) = unpack('CCCC', $request);
1174 26 50 33     122 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 26         72 my $dstaddr;
1184 26 50       83 if ($atyp == ADDR_DOMAINNAME) {
    0          
    0          
1185 26 50       88 length($request = $self->_socks_read(1, ++$reads))
1186             or return _fail($request);
1187              
1188 26         114 my $hlen = unpack('C', $request);
1189 26 50       101 $dstaddr = $self->_socks_read($hlen, ++$reads)
1190             or return _fail($dstaddr);
1191              
1192 26 50 33     148 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 26 50       104 $request = $self->_socks_read(2, ++$reads)
1221             or return _fail($request);
1222              
1223 26         137 my $dstport = unpack('n', $request);
1224              
1225 26 50 33     128 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 26         81 @{ ${*$self}->{SOCKS}->{COMMAND} } = ($cmd, $dstaddr, $dstport, $atyp);
  26         53  
  26         134  
1234              
1235 26         85 return 1;
1236             }
1237              
1238             sub _socks5_accept_command_reply {
1239 24     24   82 my $self = shift;
1240 24         99 my $reply = shift;
1241 24         55 my $host = shift;
1242 24         138 my $port = shift;
1243 24 50       49 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  24         121  
1244 24 100       49 my $resolve = defined(${*$self}->{SOCKS}->{Resolve}) ? ${*$self}->{SOCKS}->{Resolve} : $SOCKS5_RESOLVE;
  24         98  
  4         8  
1245 24         71 my ($reads, $sends, $debugs) = (0, 0, 0);
1246              
1247 24 50 33     246 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 24 50       180 my ($atyp, $bndaddr) = $resolve ? _resolve($host) : (ADDR_DOMAINNAME, $host)
    50          
1261             or $SOCKS_ERROR->set(ISS_CANT_RESOLVE, $@ = "Can't resolve `$host'"), return;
1262 24 50       77 my $hlen = $resolve ? undef : length($bndaddr);
1263 24         47 my $rc;
1264 24 50       336 $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 24 50 33     115 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 24         66 1;
1283             }
1284              
1285             sub _socks4_accept_command {
1286 49     49   178 my ($self, $ver) = @_;
1287 49 50       100 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  49         202  
1288 49 100       104 my $resolve = defined(${*$self}->{SOCKS}->{Resolve}) ? ${*$self}->{SOCKS}->{Resolve} : $SOCKS4_RESOLVE;
  49         157  
  45         106  
1289 49         124 my ($reads, $sends, $debugs) = (0, 0, 0);
1290              
1291 49         85 @{ ${*$self}->{SOCKS}->{COMMAND} } = ();
  49         100  
  49         195  
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 49         91 my $request;
1303 49 100       236 $request = $self->_socks_read($ver ? 7 : 8, ++$reads)
    100          
1304             or return _fail($request);
1305              
1306 33 100       130 unless ($ver) {
1307 27         441 $ver = unpack('C', $request);
1308 27         109 substr($request, 0, 1) = '';
1309             }
1310              
1311 33         136 my ($cmd, $dstport) = unpack('Cn', $request);
1312 33         83 substr($request, 0, 3) = '';
1313 33 50       341 my $dstaddr = length($request) == 4 ? inet_ntoa($request) : undef;
1314              
1315 33         135 my $userid = '';
1316 33         65 my $c;
1317              
1318 33         66 while (1) {
1319 33 100       96 length($c = $self->_socks_read(1, ++$reads))
1320             or return _fail($c);
1321              
1322 30 50       95 if ($c ne "\0") {
1323 0         0 $userid .= $c;
1324             }
1325             else {
1326 30         79 last;
1327             }
1328             }
1329              
1330 30 50 33     106 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 30         86 my $atyp = ADDR_IPV4;
1342              
1343 30 100 66     288 if ($resolve && $dstaddr =~ /^0\.0\.0\.[1-9]/) { # socks4a
1344 26         58 $dstaddr = '';
1345 26         45 $atyp = ADDR_DOMAINNAME;
1346              
1347 26         43 while (1) {
1348 223 100       416 length($c = $self->_socks_read(1, ++$reads))
1349             or return _fail($c);
1350              
1351 216 100       451 if ($c ne "\0") {
1352 197         292 $dstaddr .= $c;
1353             }
1354             else {
1355 19         39 last;
1356             }
1357             }
1358              
1359 19 50 33     62 if ($debug && !$self->_debugged(++$debugs)) {
1360 0         0 $debug->add(
1361             dsthost => $dstaddr,
1362             null => 0
1363             );
1364             }
1365             }
1366              
1367 23 50 33     148 if ($debug && !$self->_debugged(++$debugs)) {
1368 0         0 $debug->show('Server Recv: ');
1369             }
1370              
1371 23 100       46 if (defined(${*$self}->{SOCKS}->{UserAuth})) {
  23         95  
1372 4 50       13 unless (&{ ${*$self}->{SOCKS}->{UserAuth} }($userid)) {
  4         11  
  4         50  
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 23 50       233 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 23         53 @{ ${*$self}->{SOCKS}->{COMMAND} } = ($cmd, $dstaddr, $dstport, $atyp);
  23         39  
  23         93  
1392              
1393 23         64 return 1;
1394             }
1395              
1396             sub _socks4_accept_command_reply {
1397 22     22   46 my $self = shift;
1398 22         46 my $reply = shift;
1399 22         48 my $host = shift;
1400 22         42 my $port = shift;
1401 22 50       58 my $debug = IO::Socket::Socks::Debug->new() if ${*$self}->{SOCKS}->{Debug};
  22         112  
1402 22         62 my ($reads, $sends, $debugs) = (0, 0, 0);
1403              
1404 22 50 33     275 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 22 50       240 my $bndaddr = inet_aton($host)
1418             or $SOCKS_ERROR->set(ISS_CANT_RESOLVE, $@ = "Can't resolve `$host'"), return;
1419 22         45 my $rc;
1420 22 50       265 $rc = $self->_socks_send(pack('CCna*', 0, $reply, $port, $bndaddr), ++$sends)
1421             or return _fail($rc);
1422              
1423 22 50 33     86 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 22         53 1;
1434             }
1435              
1436             sub command {
1437 26     26 1 18974 my $self = shift;
1438              
1439 26 100       119 unless (exists ${*$self}->{SOCKS}->{RequireAuth}) # TODO: find more correct way
  26         615  
1440             {
1441 22         184 return ${*$self}->{SOCKS}->{COMMAND};
  22         335  
1442             }
1443             else {
1444 4         32 my @keys = qw(Version AuthType RequireAuth UserAuth Username Password
1445             Debug Resolve AuthMethods CmdAddr CmdPort Bind TCP);
1446              
1447 4         14 my %tmp;
1448 4         54 $tmp{$_} = ${*$self}->{SOCKS}->{$_} for @keys;
  52         221  
1449              
1450 4         28 my %args = @_;
1451 4         40 $self->_configure(\%args);
1452              
1453 4 50       28 if ($self->_connect()) {
1454 4         70 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 12022327 my $self = shift;
1464 46         153 ${*$self}->{SOCKS}->{ready} = 0;
  46         226  
1465              
1466 46 100       188 if (${*$self}->{SOCKS}->{Version} == 4) {
  46         294  
1467 22         131 ${*$self}->{SOCKS}->{queue} = [ [ '_socks4_accept_command_reply', [@_], undef, [], 0 ] ];
  22         66  
1468             }
1469             else {
1470 24         192 ${*$self}->{SOCKS}->{queue} = [ [ '_socks5_accept_command_reply', [@_], undef, [], 0 ] ];
  24         119  
1471             }
1472              
1473 46         250 $self->_run_queue();
1474             }
1475              
1476             sub dst {
1477 19     19 1 86 my $self = shift;
1478 19         57 my ($addr, $port, $atype) = @{ ${*$self}->{SOCKS} }{qw/DstAddr DstPort DstAddrType/};
  19         67  
  19         133  
1479 19         95 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 319     319   33004211 my $self = shift;
1640 319         947 my $data = shift;
1641 319         712 my $numb = shift;
1642              
1643 319         4318 local $SIG{PIPE} = 'IGNORE';
1644 319         1640 $SOCKS_ERROR->set();
1645              
1646 319         594 my $rc;
1647 319         600 my $writed = 0;
1648 319 50       617 my $blocking = ${*$self}{io_socket_timeout} ? $self->blocking(0) : $self->blocking;
  319         2360  
1649              
1650 319 50 66     4789 unless ($blocking || ${*$self}{io_socket_timeout}) {
  187         635  
1651 187 100       321 if (${*$self}->{SOCKS}->{queue}[0][Q_SENDS] >= $numb) { # already sent
  187         677  
1652 55         522 return 1;
1653             }
1654              
1655 132 50       264 if (defined ${*$self}->{SOCKS}->{queue}[0][Q_BUF]) { # some chunk already sent
  132         402  
1656 0         0 substr($data, 0, ${*$self}->{SOCKS}->{queue}[0][Q_BUF]) = '';
  0         0  
1657             }
1658              
1659 132         416 while (length $data) {
1660 132         515 $rc = $self->syswrite($data);
1661 132 50 0     10454 if (defined $rc) {
    0          
1662 132 50       344 if ($rc > 0) {
1663 132         575 ${*$self}->{SOCKS}->{queue}[0][Q_BUF] += $rc;
  132         434  
1664 132         589 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 132         229 $writed = int(${*$self}->{SOCKS}->{queue}[0][Q_BUF]);
  132         315  
1681 132         246 ${*$self}->{SOCKS}->{queue}[0][Q_BUF] = undef;
  132         283  
1682 132         230 ${*$self}->{SOCKS}->{queue}[0][Q_SENDS]++;
  132         275  
1683 132         1026 return $writed;
1684             }
1685              
1686 132         1179 my $selector = IO::Select->new($self);
1687 132         10157 my $start = time();
1688              
1689 132         304 while (1) {
1690 132 50 33     236 if (${*$self}{io_socket_timeout} && time() - $start >= ${*$self}{io_socket_timeout}) {
  132         708  
  0         0  
1691 0         0 $! = ETIMEDOUT;
1692 0         0 last;
1693             }
1694              
1695 132 50       646 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         6965 $rc = $self->syswrite($data);
1700 132 50       6557 if ($rc > 0) { # reduce our message
1701 132         299 $writed += $rc;
1702 132         574 substr($data, 0, $rc) = '';
1703 132 50       547 if (length($data) == 0) { # all data successfully writed
1704 132         302 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       846 $self->blocking(1) if $blocking;
1714              
1715 132         3252 return $writed;
1716             }
1717              
1718             sub _socks_read {
1719 872     872   1961 my $self = shift;
1720 872   50     2073 my $length = shift || 1;
1721 872         1553 my $numb = shift;
1722              
1723 872         2857 $SOCKS_ERROR->set();
1724 872         1748 my $data = '';
1725 872         1391 my ($buf, $rc);
1726 872         2749 my $blocking = $self->blocking;
1727              
1728             # non-blocking read
1729 872 50 66     8391 unless ($blocking || ${*$self}{io_socket_timeout}) { # no timeout should be specified for non-blocking connect
  657         2074  
1730 657 100       983 if (defined ${*$self}->{SOCKS}->{queue}[0][Q_READS][$numb]) { # already readed
  657         1975  
1731 63         101 return ${*$self}->{SOCKS}->{queue}[0][Q_READS][$numb];
  63         289  
1732             }
1733              
1734 594 100       1044 if (defined ${*$self}->{SOCKS}->{queue}[0][Q_BUF]) { # some chunk already readed
  594         1685  
1735 6         17 $data = ${*$self}->{SOCKS}->{queue}[0][Q_BUF];
  6         16  
1736 6         17 $length -= length $data;
1737             }
1738              
1739 594         1507 while ($length > 0) {
1740 597         1935 $rc = $self->sysread($buf, $length);
1741 597 100 33     7630 if (defined $rc) {
    50          
1742 397 50       785 if ($rc > 0) {
1743 397         602 $length -= $rc;
1744 397         1189 $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 200 100       693 if (length $data) { # save already readed data in the queue buffer
1752 6         10 ${*$self}->{SOCKS}->{queue}[0][Q_BUF] = $data;
  6         20  
1753             }
1754 200         535 $SOCKS_ERROR->set(SOCKS_WANT_READ, 'Socks want read');
1755 200         1203 return undef;
1756             }
1757             else {
1758 0         0 $SOCKS_ERROR->set($!, $@ = "read: $!");
1759 0         0 last;
1760             }
1761             }
1762              
1763 394         600 ${*$self}->{SOCKS}->{queue}[0][Q_BUF] = undef;
  394         890  
1764 394         646 ${*$self}->{SOCKS}->{queue}[0][Q_READS][$numb] = $data;
  394         974  
1765 394         1455 return $data;
1766             }
1767              
1768             # blocking read
1769 215         1098 my $selector = IO::Select->new($self);
1770 215         13627 my $start = time();
1771              
1772 215         708 while ($length > 0) {
1773 239 50 33     466 if (${*$self}{io_socket_timeout} && time() - $start >= ${*$self}{io_socket_timeout}) {
  239         1427  
  0         0  
1774 0         0 $! = ETIMEDOUT;
1775 0         0 last;
1776             }
1777              
1778 239 100       1218 unless ($selector->can_read(1)) { # no data in socket for now, check if timeout expired and try again
1779 24         24027036 next;
1780             }
1781              
1782 215         6252314 $rc = $self->sysread($buf, $length);
1783 215 50 33     3923 if (defined $rc && $rc > 0) { # reduce limit and modify buffer
1784 215         489 $length -= $rc;
1785 215         795 $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         2243 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 200 50 33 200   1312 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 200         501 return -1;
1815             }
1816              
1817             sub _validate_multi_version {
1818 1     1   2 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       3 if (@$multi_ver == 2) {
1825             return
1826 1   33     14 $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 24     24   51 my $addr = shift;
1836 24         458 my ($err, @res) = Socket::getaddrinfo($addr, undef, { protocol => Socket::IPPROTO_TCP, socktype => Socket::SOCK_STREAM });
1837 24 50       121 return if $err;
1838              
1839 24         92 for my $r (@res) {
1840 24 50       86 if ($r->{family} == PF_INET) {
1841 24         199 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   66 my ($addr, $atype) = @_;
1850              
1851 19 50       297 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         378 '""' => \&as_str,
1868 34     34   39956 '0+' => \&as_num;
  34         33156  
1869              
1870             sub new {
1871 34     34   164 my ($class, $num, $str) = @_;
1872              
1873 34         164 my $self = {
1874             num => $num,
1875             str => $str,
1876             };
1877              
1878 34         351 bless $self, $class;
1879             }
1880              
1881             sub set {
1882 1670     1670   3983 my ($self, $num, $str) = @_;
1883              
1884 1670 100       5657 $self->{num} = defined $num ? int($num) : $num;
1885 1670         3319 $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 318     318   1185 my $self = shift;
1895 318         862 return $self->{num};
1896             }
1897              
1898             sub num_eq {
1899 189     189   875 my ($self, $num) = @_;
1900              
1901 189 100       615 unless (defined $num) {
1902 8         40 return !defined($self->{num});
1903             }
1904 181         704 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   161 my ($class, $value) = @_;
1917 34         167 bless \$value, $class;
1918             }
1919              
1920             sub FETCH {
1921 4354     4354   115605 my $self = shift;
1922 4354         13768 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   75 my ($class, $value) = @_;
1937 34         158 bless { v => $value }, $class;
1938             }
1939              
1940             sub FETCH {
1941 81     81   14422 return $_[0]->{v};
1942             }
1943              
1944             sub STORE {
1945 34     34   131 my ($self, $class) = @_;
1946              
1947 34         103 $self->{v} = $class;
1948 34 50   34   261 eval "use $class; 1" or die $@;
  34         88  
  34         132  
  34         2150  
1949 34         614 $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__