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