IO::So...::Socks(3pm)
β¨ NAME β¨
IO::Socket::Socks β bestie, this manual page is literally from the User Contributed Perl Documentation (the header said IO::So...::Socks(3pm) but we know her π
). It provides a way to create socks client or server both 4 and 5 version. No cap. π«Ά
π¦ SYNOPSIS π¦
Client
use IO::Socket::Socks;
my $socks_client = IO::Socket::Socks->new(
ProxyAddr => "proxy host",
ProxyPort => "proxy port",
ConnectAddr => "remote host",
ConnectPort => "remote port",
) or die $SOCKS_ERROR;
print $socks_client "foo\n";
$socks_client->close();
Server
use IO::Socket::Socks ':constants';
my $socks_server = IO::Socket::Socks->new(
ProxyAddr => "localhost",
ProxyPort => 8000,
Listen => 1,
UserAuth => \&auth,
RequireAuth => 1
) or die $SOCKS_ERROR;
while(1) {
my $client = $socks_server->accept();
unless ($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, $pass) = @_;
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 (with IO::Socket interface) 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β4or5. Default is5.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. Seeready()below for more details.SocksResolveβ resolve host name to ip by proxy server or not (will resolve by client). This overrides value of$SOCKS4_RESOLVEor$SOCKS5_RESOLVEvariable. 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_DEBUGvariable. 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β Expected address where datagrams will be sent. Fill it with address of all zeros if address is not known at this moment. Proxy server may use this information to limit access to the association.UdpPortβ Expected port where datagrams will be sent. Use zero port if port is not known at this moment. Proxy server may use this information to limit access to the association.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:
- (
ProxyAddrandProxyPort) - (
ConnectAddrandConnectPort) or (BindAddrandBindPort) or (UdpAddrandUdpPort)
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 sense:
TimeoutConnectAddrConnectPortBindAddrBindPortUdpAddrUdpPortSocksVersionSocksDebugSocksResolveAuthTypeRequireAuthUsernamePasswordAuthMethods
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;
}
# NOTE: when base class ($IO::Socket::Socks::SOCKET_CLASS) is IO::Socket::IP
# and you are using kqueue or epoll to check for readable/writable sockets
# you need to readd $sock to kqueue/epoll after each call to ready() (actually until socket will be connected to proxy server),
# because IO::Socket::IP may change internal socket of $sock for milti-homed hosts.
# There is no such problem when you are using select/poll
}
# 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 sense:
ConnectAddrConnectPortBindAddrBindPortUdpAddrUdpPortSocksVersionSocksDebugSocksResolveAuthTypeRequireAuthUsernamePasswordAuthMethods
Values of the other options (Timeout for example) inherited from the constructor. Options like ProxyAddr and ProxyPort are not included.
dst( )
Return (host, port, address_type) of the remote host after connect/accept or socks server (host, port, address_type) 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β4for socks4,5for socks5 or[4,5]if you want accept both 4 and 5. Default is5.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. Seeready()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_RESOLVEor$SOCKS5_RESOLVE. See alsocommand_reply().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_DEBUGvariable. 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:
ListenProxyAddrProxyPort
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( )
β¦to be continued, bestie π (part 2 loadingβ¦)
okay so continuing with the methods, bestie, and this one is kinda iconic for servers π
version() β gives you the socks version of the socket. Real talk, this is so useful when your server is out here accepting both v4 and v5 at the same time, because then you literally have to know which version you're dealing with to send back the right response. Just call version() on the socket you got after accept(). Periodt. β¨
ready() β so after a non-blocking accept() you get this brand new client socket object that might not be ready to move data yet (like, if the socks handshake isn't done cooking). ready() returns a true value once the handshake has finished successfully, and false otherwise. Big heads up tho: the socket returned by accept() is always in blocking mode. So if your program can't afford to block, you gotta set non-blocking mode on that socket before you call ready():
$socket->blocking(0)
When ready() comes back false, you can figure out what the handshake is waiting on with the $SOCKS_ERROR variable. If it needs to read, $SOCKS_ERROR will be SOCKS_WANT_READ; if it needs to write, it'll be SOCKS_WANT_WRITE. iykyk π¦
Example, bestie β read it, love it, use it:
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 already sent the command they want you to handle. This function gets called on the socket that came back from accept(). It returns a reference to an array, formatted exactly like this:
[ COMMAND, ADDRESS, PORT, ADDRESS TYPE ]
command_reply( REPLY CODE, ADDRESS, PORT ) β after you've called command(), the client is sitting there waiting to be told what the result is. The REPLY CODE is one of the constants below, as an integer value π:
For socks v4:
REQUEST_GRANTED(90): request granted
REQUEST_FAILED(91): request rejected or failed
REQUEST_REJECTED_IDENTD(92): request rejected because 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 β like, where the server socket responsible for this command is bound.
Note, bestie: for version 5,command_replywill try to resolve the address you pass it ifSocksResolvehas a true value and the address you handed over is a domain name. Want to dodge that entirely? Just pass an ip address ($socket->sockhost) instead of a host name, or turnSocksResolveoff for that server. For version 4, though, the host name you pass will always get resolved to an ip address, even ifSocksResolveis false β because v4 literally doesn't supportADDRESSas a domain name. RIP to v4's flexibility π
β¨ VARIABLES β¨
π $SOCKS_ERROR
This scalar does the $! thing β you know, the one where undef gets returned. $SOCKS_ERROR is an IO::Socket::Socks::Error object with some overloaded operators doing the most. In string context, this variable should hold a string reason for the error. In numeric context, it holds the error code. Slay. β¨
π¦ $SOCKS4_RESOLVE
If this variable has a true value, resolving host names gets done by the proxy server; otherwise resolving happens locally. Resolving hosts via a socks proxy version 4 is an extension to the protocol that's also known as socks4a. So like β only socks4a proxies support resolving hostnames, no cap. Default value of this variable is false. This variable is not importable. See also the SocksResolve parameter in the constructor.
πΈ $SOCKS5_RESOLVE
If this variable has a true value, resolving host names gets done by the proxy server; otherwise resolving happens locally. Heads up: some buggy socks5 servers just don't support resolving host names. Default value is true. This variable is not importable. See also the SocksResolve parameter in the constructor.
π $SOCKS_DEBUG
Default value is $ENV{SOCKS_DEBUG}. If this variable has a true value and no SocksDebug option was specified in the constructor, then SocksDebug will have a true value. This variable is not importable.
π $SOCKET_CLASS
With this variable you can get/set the base socket class for IO::Socket::Socks. By default it tries to use IO::Socket::IP 0.36+ as the socket class, and falls back to IO::Socket::INET if that's not available. You can set $IO::Socket::Socks::SOCKET_CLASS before loading IO::Socket::Socks and then it won't try to detect the proper base class itself. You can also set it after loading IO::Socket::Socks, and this will automatically update @ISA β so no stress about inheritance, bestie, it handles itself. π
β CONSTANTS β
The following constants could be imported manually or using the :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 # address type sent by client/server not supported by I::S::S
ISS_BAD_VERSION # socks version sent by client/server != specified version
ISS_CANT_RESOLVE # I::S::S failed to resolve some host
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. π«Ά
π IPv6 π
Since version 0.66, IO::Socket::Socks supports IPv6 with the help of IO::Socket::IP 0.36+. It'll use IO::Socket::IP as the base class if it's available. But you can force set $SOCKET_CLASS = "IO::Socket::INET" to use IPv4 only. See also $SOCKET_CLASS β¨
π FAQ π
How to determine is connection to socks server (client accept) failed or some protocol error occurred?
You can check the $! variable. If $! == ESOCKSPROTO constant, then it was an 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
ISS_BAD_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
Patches are welcome. (fr fr, send them, we love that for you π)
π₯ 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.
and that's the whole vibe, bestie π
this page is from perl v5.36.0, dated 2022-10-15, and it lives under IO::So...::Socks(3pm). go build something iconic with it β¨π¦π
π¦ where this page comes from
- ubuntu noble: libio-socket-socks-perl 0.74-3 Β· LGPL-2.0-or-later
- ubuntu resolute: libio-socket-socks-perl 0.74-3 Β· LGPL-2.0-or-later
- ubuntu stonking: libio-socket-socks-perl 0.74-3 Β· LGPL-2.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms