NAME¶
IO::Socket::Socks - Provides a way to create socks client or server both 4 and 5
version.
SYNOPSIS¶
Client¶
use IO::Socket::Socks;
my $socks = new IO::Socket::Socks(ProxyAddr=>"proxy host",
ProxyPort=>"proxy port",
ConnectAddr=>"remote host",
ConnectPort=>"remote port",
);
print $socks "foo\n";
$socks->close();
Server¶
use IO::Socket::Socks ':constants';
my $socks_server = new IO::Socket::Socks(ProxyAddr=>"localhost",
ProxyPort=>"8000",
Listen=>1,
UserAuth=>\&auth,
RequireAuth=>1
);
while(1)
{
my $client = $socks_server->accept();
if (!defined($client))
{
print "ERROR: $SOCKS_ERROR\n";
next;
}
my $command = $client->command();
if ($command->[0] == CMD_CONNECT)
{
# Handle the CONNECT
$client->command_reply(REPLY_SUCCESS, addr, port);
}
...
#read from the client and send to the CONNECT address
...
$client->close();
}
sub auth
{
my $user = shift;
my $pass = shift;
return 1 if (($user eq "foo") && ($pass eq "bar"));
return 0;
}
DESCRIPTION¶
IO::Socket::Socks connects to a SOCKS proxy, tells it to open a connection to a
remote host/port when the object is created. The object you receive can be
used directly as a socket for sending and receiving data from the remote host.
In addition to create socks client this module could be used to create socks
server. See examples below.
EXAMPLES¶
For complete examples of socks 4/5 client and server see `examples' subdirectory
in the distribution.
METHODS¶
Socks Client¶
new( %cfg )
new_from_socket($socket, %cfg)
new_from_fd($socket, %cfg)
Creates a new IO::Socket::Socks client object.
new_from_socket() is the
same as
new(), but allows one to create object from an existing and not
connected socket (new_from_fd is new_from_socket alias). To make
IO::Socket::Socks object from connected socket see "start_SOCKS"
Both takes the following config hash:
SocksVersion => 4 or 5. Default is 5
Timeout => connect/accept timeout
Blocking => Since IO::Socket::Socks version 0.5 you can perform non-blocking connect/bind by
passing false value for this option. Default is true - blocking. See ready()
below for more details.
SocksResolve => resolve host name to ip by proxy server or
not (will resolve by client). This
overrides value of $SOCKS4_RESOLVE or $SOCKS5_RESOLVE
variable. Boolean.
SocksDebug => This will cause all of the SOCKS traffic to
be presented on the command line in a form
similar to the tables in the RFCs. This overrides value
of $SOCKS_DEBUG variable. Boolean.
ProxyAddr => Hostname of the proxy
ProxyPort => Port of the proxy
ConnectAddr => Hostname of the remote machine
ConnectPort => Port of the remote machine
BindAddr => Hostname of the remote machine which will
connect to the proxy server after bind request
BindPort => Port of the remote machine which will
connect to the proxy server after bind request
UdpAddr => Associate UDP socket on the server with this client
hostname
UdpPort => Associate UDP socket on the server with this client
port
AuthType => What kind of authentication to support:
none - no authentication (default)
userpass - Username/Password. For socks5
proxy only.
RequireAuth => Do not send ANON as a valid auth mechanism.
For socks5 proxy only
Username => For socks5 if AuthType is set to userpass, then
you must provide a username. For socks4 proxy with
this option you can specify userid.
Password => If AuthType is set to userpass, then you must
provide a password. For socks5 proxy only.
The following options should be specified:
(ProxyAddr and ProxyPort)
(ConnectAddr and ConnectPort) or (BindAddr and BindPort) or (UdpAddr and UdpPort)
Other options are facultative.
start_SOCKS($socket, %cfg)
This is a class method to start socks handshake on already connected socket.
This will bless passed $socket to IO::Socket::Socks class. %cfg is like hash
in the constructor. Only options listed below makes sence:
Timeout
ConnectAddr
ConnectPort
BindAddr
BindPort
UdpAddr
UdpPort
SocksVersion
SocksDebug
SocksResolve
AuthType
RequireAuth
Username
Password
AuthMethods
On success this method will return same $socket, but as IO::Socket::Socks
object. On failure it will return undef (but socket will be still blessed to
IO::Socket::Socks class). See example:
use IO::Socket;
use IO::Socket::Socks;
my $sock = IO::Socket::INET->new("$proxy_host:$proxy_port") or die $@;
$sock = IO::Socket::Socks->start_SOCKS($sock, ConnectAddr => "google.com", ConnectPort => 80) or die $SOCKS_ERROR;
version( )
Returns socks version for this socket
ready( )
Returns true when socket becomes ready to transfer data (socks handshake done),
false otherwise. This is useful for non-blocking connect/bind. When this
method returns false value you can determine what socks handshake need for
with $SOCKS_ERROR variable. It may need for read, then $SOCKS_ERROR will be
SOCKS_WANT_READ or need for write, then it will be SOCKS_WANT_WRITE.
Example:
use IO::Socket::Socks;
use IO::Select;
my $sock = IO::Socket::Socks->new(
ProxyAddr => 'localhost', ProxyPort => 1080, ConnectAddr => 'mail.com', ConnectPort => 80, Blocking => 0
) or die $SOCKS_ERROR;
my $sel = IO::Select->new($sock);
until ($sock->ready) {
if ($SOCKS_ERROR == SOCKS_WANT_READ) {
$sel->can_read();
}
elsif ($SOCKS_ERROR == SOCKS_WANT_WRITE) {
$sel->can_write();
}
else {
die $SOCKS_ERROR;
}
}
# you may want to return socket to blocking state by $sock->blocking(1)
$sock->syswrite("I am ready");
accept( )
Accept an incoming connection after bind request. On failed returns undef. On
success returns socket. No new socket created, returned socket is same on
which this method was called. Because
accept(2) is not invoked on the
client side, socks server calls
accept(2) and proxify all traffic via
socket opened by client bind request. You can call accept only once on
IO::Socket::Socks client socket.
command( %cfg )
Allows one to execute socks command on already opened socket. Thus you can
create socks chain. For example see "EXAMPLES" section.
%cfg is like hash in the constructor. Only options listed below makes sence:
ConnectAddr
ConnectPort
BindAddr
BindPort
UdpAddr
UdpPort
SocksVersion
SocksDebug
SocksResolve
AuthType
RequireAuth
Username
Password
AuthMethods
Values of the other options (Timeout for example) inherited from the
constructor. Options like ProxyAddr and ProxyPort are not included.
dst( )
Return (host, port) of the remote host after connect/accept or socks server
(host, port) after bind/udpassoc.
Socks Server¶
new( %cfg )
new_from_socket($socket, %cfg)
new_from_fd($socket, %cfg)
Creates a new IO::Socket::Socks server object.
new_from_socket() is the
same as
new(), but allows one to create object from an existing socket
(new_from_fd is new_from_socket alias). Both takes the following config hash:
SocksVersion => 4 for socks4, 5 for socks5 or [4,5] if you want accept both 4 and 5. Default is 5
Timeout => Timeout value for various operations
Blocking => Since IO::Socket::Socks version 0.6 you can perform non-blocking accept by
passing false value for this option. Default is true - blocking. See ready()
below for more details.
SocksResolve => For socks v5: return destination address to the client
in form of 4 bytes if true, otherwise in form of host
length and host name.
For socks v4: allow use socks4a protocol extension if
true and not otherwise.
This overrides value of $SOCKS4_RESOLVE or $SOCKS5_RESOLVE.
SocksDebug => This will cause all of the SOCKS traffic to
be presented on the command line in a form
similar to the tables in the RFCs. This overrides value
of $SOCKS_DEBUG variable. Boolean.
ProxyAddr => Local host bind address
ProxyPort => Local host bind port
UserAuth => Reference to a function that returns 1 if client
allowed to use socks server, 0 otherwise. For
socks5 proxy it takes login and password as
arguments. For socks4 argument is userid.
RequireAuth => Not allow anonymous access for socks5 proxy.
Listen => Same as IO::Socket::INET listen option. Should be
specified as number > 0.
The following options should be specified:
Listen
ProxyAddr
ProxyPort
Other options are facultative.
accept( )
Accept an incoming connection and return a new IO::Socket::Socks object that
represents that connection. You must call
command() on this to find out
what the incoming connection wants you to do, and then call
command_reply() to send back the reply.
version( )
Returns socks version for socket. It is useful when your server accepts both 4
and 5 version. Then you should know socks version to make proper response.
Just call "version()" on socket received after "accept()".
ready( )
After non-blocking accept you will get new client socket object, which may be
not ready to transfer data (if socks handshake is not done yet).
ready() will return true value when handshake will be done successfully
and false otherwise. Note, socket returned by
accept() call will be
always in blocking mode. So if your program can't block you should set
non-blocking mode for this socket before
ready() call:
$socket->
blocking(0). When
ready() returns false value you
can determine what socks handshake needs for with $SOCKS_ERROR variable. It
may need for read, then $SOCKS_ERROR will be SOCKS_WANT_READ or need for
write, then it will be SOCKS_WANT_WRITE.
Example:
use IO::Socket::Socks;
use IO::Select;
my $server = IO::Socket::Socks->new(ProxyAddr => 'localhost', ProxyPort => 1080, Blocking => 0)
or die $@;
my $select = IO::Select->new($server);
$select->can_read(); # wait for client
my $client = $server->accept()
or die "accept(): $! ($SOCKS_ERROR)";
$client->blocking(0); # !!!
$select->add($client);
$select->remove($server); # no more connections
while (1) {
if ($client->ready) {
my $command = $client->command;
... # do client command
$client->command_reply(IO::Socket::Socks::REPLY_SUCCESS, $command->[1], $command->[2]);
... # transfer traffic
last;
}
elsif ($SOCKS_ERROR == SOCKS_WANT_READ) {
$select->can_read();
}
elsif ($SOCKS_ERROR == SOCKS_WANT_WRITE) {
$select->can_write();
}
else {
die "Unexpected error: $SOCKS_ERROR";
}
}
command( )
After you call
accept() the client has sent the command they want you to
process. This function should be called on the socket returned by
accept(). It returns a reference to an array with the following format:
[ COMMAND, ADDRESS, PORT, ADDRESS TYPE ]
command_reply( REPLY CODE, ADDRESS, PORT )
After you call
command() the client needs to be told what the result is.
The REPLY CODE is one of the constants as follows (integer value):
For socks v4
REQUEST_GRANTED(90): request granted
REQUEST_FAILED(91): request rejected or failed
REQUEST_REJECTED_IDENTD(92): request rejected becasue SOCKS server cannot connect to identd on the client
REQUEST_REJECTED_USERID(93): request rejected because the client program and identd report different user-ids
For socks v5
REPLY_SUCCESS(0): Success
REPLY_GENERAL_FAILURE(1): General Failure
REPLY_CONN_NOT_ALLOWED(2): Connection Not Allowed
REPLY_NETWORK_UNREACHABLE(3): Network Unreachable
REPLY_HOST_UNREACHABLE(4): Host Unreachable
REPLY_CONN_REFUSED(5): Connection Refused
REPLY_TTL_EXPIRED(6): TTL Expired
REPLY_CMD_NOT_SUPPORTED(7): Command Not Supported
REPLY_ADDR_NOT_SUPPORTED(8): Address Not Supported
HOST and PORT are the resulting host and port that you use for the command.
VARIABLES¶
$SOCKS_ERROR¶
This scalar behaves like $! in that if undef is returned. $SOCKS_ERROR is
IO::Socket::Socks::Error object with some overloaded operators. In string
context this variable should contain a string reason for the error. In numeric
context it contains error code.
$SOCKS4_RESOLVE¶
If this variable has true value resolving of host names will be done by proxy
server, otherwise resolving will be done locally. Resolving host by socks
proxy version 4 is extension to the protocol also known as socks4a. So, only
socks4a proxy supports resolving of hostnames. Default value of this variable
is false. This variable is not importable. See also `SocksResolve' parameter
in the constructor.
$SOCKS5_RESOLVE¶
If this variable has true value resolving of host names will be done by proxy
server, otherwise resolving will be done locally. Note: some bugous socks5
servers doesn't support resolving of host names. Default value is true. This
variable is not importable. See also `SocksResolve' parameter in the
constructor.
$SOCKS_DEBUG¶
Default value is $ENV{SOCKS_DEBUG}. If this variable has true value and no
SocksDebug option in the constructor specified, then SocksDebug will has true
value. This variable is not importable.
CONSTANTS¶
The following constants could be imported manually or using `:constants' tag:
SOCKS5_VER
SOCKS4_VER
ADDR_IPV4
ADDR_DOMAINNAME
ADDR_IPV6
CMD_CONNECT
CMD_BIND
CMD_UDPASSOC
AUTHMECH_ANON
AUTHMECH_USERPASS
AUTHMECH_INVALID
AUTHREPLY_SUCCESS
AUTHREPLY_FAILURE
ISS_UNKNOWN_ADDRESS
ISS_BAD_VERSION
REPLY_SUCCESS
REPLY_GENERAL_FAILURE
REPLY_CONN_NOT_ALLOWED
REPLY_NETWORK_UNREACHABLE
REPLY_HOST_UNREACHABLE
REPLY_CONN_REFUSED
REPLY_TTL_EXPIRED
REPLY_CMD_NOT_SUPPORTED
REPLY_ADDR_NOT_SUPPORTED
REQUEST_GRANTED
REQUEST_FAILED
REQUEST_REJECTED_IDENTD
REQUEST_REJECTED_USERID
SOCKS_WANT_READ
SOCKS_WANT_WRITE
ESOCKSPROTO
SOCKS_WANT_READ, SOCKS_WANT_WRITE and ESOCKSPROTO are imported by default.
FAQ¶
- How to determine is connection to socks server (client accept) failed or
some protocol error occurred?
- You can check $! variable. If $! == ESOCKSPROTO constant, then it was
error in the protocol. Error description could be found in
$SOCKS_ERROR.
- How to determine which error in the protocol occurred?
- You should compare $SOCKS_ERROR with constants below:
AUTHMECH_INVALID
AUTHREPLY_FAILURE
ISS_UNKNOWN_ADDRESS # address type sent by client/server not supported by I::S::S
ISS_BAD_VERSION # socks version sent by client/server != specified version
REPLY_GENERAL_FAILURE
REPLY_CONN_NOT_ALLOWED
REPLY_NETWORK_UNREACHABLE
REPLY_HOST_UNREACHABLE
REPLY_CONN_REFUSED
REPLY_TTL_EXPIRED
REPLY_CMD_NOT_SUPPORTED
REPLY_ADDR_NOT_SUPPORTED
REQUEST_FAILED
REQUEST_REJECTED_IDENTD
REQUEST_REJECTED_USERID
BUGS¶
The following options are not implemented:
- GSSAPI authentication
- UDP server side support
- IPV6 support
Patches are welcome.
SEE ALSO¶
IO::Socket::Socks::Wrapper
AUTHOR¶
Original author is Ryan Eatmon
Now maintained by Oleg G <oleg@cpan.org>
COPYRIGHT¶
This module is free software, you can redistribute it and/or modify it under the
terms of LGPL.