.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "IO::Socket::Socks 3pm" .TH IO::Socket::Socks 3pm "2021-01-01" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" IO::Socket::Socks \- Provides a way to create socks client or server both 4 and 5 version. .SH "SYNOPSIS" .IX Header "SYNOPSIS" .SS "Client" .IX Subsection "Client" .Vb 1 \& 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\en"; \& $socks_client\->close(); .Ve .SS "Server" .IX Subsection "Server" .Vb 1 \& use IO::Socket::Socks \*(Aq:constants\*(Aq; \& \& my $socks_server = IO::Socket::Socks\->new( \& ProxyAddr => "localhost", \& ProxyPort => 8000, \& Listen => 1, \& UserAuth => \e&auth, \& RequireAuth => 1 \& ) or die $SOCKS_ERROR; \& \& while(1) { \& my $client = $socks_server\->accept(); \& \& unless ($client) { \& print "ERROR: $SOCKS_ERROR\en"; \& 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; \& } .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\f(CW\*(C`IO::Socket::Socks\*(C'\fR connects to a \s-1SOCKS\s0 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 \f(CW\*(C`IO::Socket\*(C'\fR 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. .SH "EXAMPLES" .IX Header "EXAMPLES" For complete examples of socks 4/5 client and server see `examples' subdirectory in the distribution. .SH "METHODS" .IX Header "METHODS" .SS "Socks Client" .IX Subsection "Socks Client" \fInew( \f(CI%cfg\fI )\fR .IX Subsection "new( %cfg )" .PP \fInew_from_socket($socket, \f(CI%cfg\fI)\fR .IX Subsection "new_from_socket($socket, %cfg)" .PP \fInew_from_fd($socket, \f(CI%cfg\fI)\fR .IX Subsection "new_from_fd($socket, %cfg)" .PP Creates a new IO::Socket::Socks client object. \fBnew_from_socket()\fR is the same as \&\fBnew()\fR, 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 \f(CW\*(C`start_SOCKS\*(C'\fR .PP Both takes the following config hash: .PP .Vb 1 \& 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 => 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. .Ve .PP The following options should be specified: .PP .Vb 2 \& (ProxyAddr and ProxyPort) \& (ConnectAddr and ConnectPort) or (BindAddr and BindPort) or (UdpAddr and UdpPort) .Ve .PP Other options are facultative. .PP \fI start_SOCKS($socket, \f(CI%cfg\fI)\fR .IX Subsection " start_SOCKS($socket, %cfg)" .PP This is a class method to start socks handshake on already connected socket. This will bless passed \f(CW$socket\fR to IO::Socket::Socks class. \f(CW%cfg\fR is like hash in the constructor. Only options listed below makes sense: .PP .Vb 10 \& Timeout \& ConnectAddr \& ConnectPort \& BindAddr \& BindPort \& UdpAddr \& UdpPort \& SocksVersion \& SocksDebug \& SocksResolve \& AuthType \& RequireAuth \& Username \& Password \& AuthMethods .Ve .PP On success this method will return same \f(CW$socket\fR, 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: .PP .Vb 2 \& 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; .Ve .PP \fI version( )\fR .IX Subsection " version( )" .PP Returns socks version for this socket .PP \fI ready( )\fR .IX Subsection " ready( )" .PP 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 \f(CW$SOCKS_ERROR\fR variable. It may need for read, then \f(CW$SOCKS_ERROR\fR will be \s-1SOCKS_WANT_READ\s0 or need for write, then it will be \s-1SOCKS_WANT_WRITE.\s0 .PP Example: .PP .Vb 2 \& use IO::Socket::Socks; \& use IO::Select; \& \& my $sock = IO::Socket::Socks\->new( \& ProxyAddr => \*(Aqlocalhost\*(Aq, ProxyPort => 1080, ConnectAddr => \*(Aqmail.com\*(Aq, 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"); .Ve .PP \fI accept( )\fR .IX Subsection " accept( )" .PP 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 \fBaccept\fR\|(2) is not invoked on the client side, socks server calls \fBaccept\fR\|(2) and proxify all traffic via socket opened by client bind request. You can call accept only once on IO::Socket::Socks client socket. .PP \fI command( \f(CI%cfg\fI )\fR .IX Subsection " command( %cfg )" .PP Allows one to execute socks command on already opened socket. Thus you can create socks chain. For example see \*(L"\s-1EXAMPLES\*(R"\s0 section. .PP \&\f(CW%cfg\fR is like hash in the constructor. Only options listed below makes sense: .PP .Vb 10 \& ConnectAddr \& ConnectPort \& BindAddr \& BindPort \& UdpAddr \& UdpPort \& SocksVersion \& SocksDebug \& SocksResolve \& AuthType \& RequireAuth \& Username \& Password \& AuthMethods .Ve .PP Values of the other options (Timeout for example) inherited from the constructor. Options like ProxyAddr and ProxyPort are not included. .PP \fI dst( )\fR .IX Subsection " dst( )" .PP Return (host, port, address_type) of the remote host after connect/accept or socks server (host, port, address_type) after bind/udpassoc. .SS "Socks Server" .IX Subsection "Socks Server" \fInew( \f(CI%cfg\fI )\fR .IX Subsection "new( %cfg )" .PP \fInew_from_socket($socket, \f(CI%cfg\fI)\fR .IX Subsection "new_from_socket($socket, %cfg)" .PP \fInew_from_fd($socket, \f(CI%cfg\fI)\fR .IX Subsection "new_from_fd($socket, %cfg)" .PP Creates a new IO::Socket::Socks server object. \fBnew_from_socket()\fR is the same as \&\fBnew()\fR, but allows one to create object from an existing socket (new_from_fd is new_from_socket alias). Both takes the following config hash: .PP .Vb 1 \& 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. \& See also command_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_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. .Ve .PP The following options should be specified: .PP .Vb 3 \& Listen \& ProxyAddr \& ProxyPort .Ve .PP Other options are facultative. .PP \fIaccept( )\fR .IX Subsection "accept( )" .PP Accept an incoming connection and return a new IO::Socket::Socks object that represents that connection. You must call \fBcommand()\fR on this to find out what the incoming connection wants you to do, and then call \fBcommand_reply()\fR to send back the reply. .PP \fIversion( )\fR .IX Subsection "version( )" .PP 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 \f(CW\*(C`version()\*(C'\fR on socket received after \f(CW\*(C`accept()\*(C'\fR. .PP \fIready( )\fR .IX Subsection "ready( )" .PP 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). \fBready()\fR will return true value when handshake will be done successfully and false otherwise. Note, socket returned by \fBaccept()\fR call will be always in blocking mode. So if your program can't block you should set non-blocking mode for this socket before \fBready()\fR call: \f(CW$socket\fR\->\fBblocking\fR\|(0). When \fBready()\fR returns false value you can determine what socks handshake needs for with \f(CW$SOCKS_ERROR\fR variable. It may need for read, then \f(CW$SOCKS_ERROR\fR will be \s-1SOCKS_WANT_READ\s0 or need for write, then it will be \s-1SOCKS_WANT_WRITE.\s0 .PP Example: .PP .Vb 2 \& use IO::Socket::Socks; \& use IO::Select; \& \& my $server = IO::Socket::Socks\->new(ProxyAddr => \*(Aqlocalhost\*(Aq, 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"; \& } \& } .Ve .PP \fIcommand( )\fR .IX Subsection "command( )" .PP After you call \fBaccept()\fR the client has sent the command they want you to process. This function should be called on the socket returned by \fBaccept()\fR. It returns a reference to an array with the following format: .PP .Vb 1 \& [ COMMAND, ADDRESS, PORT, ADDRESS TYPE ] .Ve .PP \fIcommand_reply( \s-1REPLY CODE, ADDRESS, PORT\s0 )\fR .IX Subsection "command_reply( REPLY CODE, ADDRESS, PORT )" .PP After you call \fBcommand()\fR the client needs to be told what the result is. The \s-1REPLY CODE\s0 is one of the constants as follows (integer value): .PP .Vb 5 \& 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 .Ve .PP \&\s-1HOST\s0 and \s-1PORT\s0 are the resulting host and port (where server socket responsible for this command bound). .PP Note: for 5 version \f(CW\*(C`command_reply\*(C'\fR will try to resolve passed address if \&\f(CW\*(C`SocksResolve\*(C'\fR has true value and passed address is domain name. To avoid this just pass ip address (\f(CW\*(C`$socket\->sockhost\*(C'\fR) instead of host name or turn off \f(CW\*(C`SocksResolve\*(C'\fR for this server. For version 4 passed host name will always be resolved to ip address even if \f(CW\*(C`SocksResolve\*(C'\fR has false value. Because this version doesn't support \f(CW\*(C`ADDRESS\*(C'\fR as domain name. .SH "VARIABLES" .IX Header "VARIABLES" .ie n .SS "$SOCKS_ERROR" .el .SS "\f(CW$SOCKS_ERROR\fP" .IX Subsection "$SOCKS_ERROR" This scalar behaves like $! in that if undef is returned. \f(CW$SOCKS_ERROR\fR 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. .ie n .SS "$SOCKS4_RESOLVE" .el .SS "\f(CW$SOCKS4_RESOLVE\fP" .IX Subsection "$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. .ie n .SS "$SOCKS5_RESOLVE" .el .SS "\f(CW$SOCKS5_RESOLVE\fP" .IX Subsection "$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. .ie n .SS "$SOCKS_DEBUG" .el .SS "\f(CW$SOCKS_DEBUG\fP" .IX Subsection "$SOCKS_DEBUG" Default value is \f(CW$ENV\fR{\s-1SOCKS_DEBUG\s0}. 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. .ie n .SS "$SOCKET_CLASS" .el .SS "\f(CW$SOCKET_CLASS\fP" .IX Subsection "$SOCKET_CLASS" With this variable you can get/set base socket class for \f(CW\*(C`IO::Socket::Socks\*(C'\fR. By default it tries to use \f(CW\*(C`IO::Socket::IP\*(C'\fR 0.36+ as socket class. And falls back to \f(CW\*(C`IO::Socket::INET\*(C'\fR if not available. You can set \f(CW$IO::Socket::Socks::SOCKET_CLASS\fR before loading of \f(CW\*(C`IO::Socket::Socks\*(C'\fR and then it will not try to detect proper base class itself. You can also set it after loading of \f(CW\*(C`IO::Socket::Socks\*(C'\fR and this will automatically update \f(CW@ISA\fR, so you shouldn't worry about inheritance. .SH "CONSTANTS" .IX Header "CONSTANTS" The following constants could be imported manually or using `:constants' tag: .PP .Vb 10 \& 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 .Ve .PP \&\s-1SOCKS_WANT_READ, SOCKS_WANT_WRITE\s0 and \s-1ESOCKSPROTO\s0 are imported by default. .SH "IPv6" .IX Header "IPv6" Since version 0.66 \f(CW\*(C`IO::Socket::Socks\*(C'\fR supports IPv6 with help of IO::Socket::IP 0.36+. And will use \f(CW\*(C`IO::Socket::IP\*(C'\fR as base class if available. However you can force set \f(CW\*(C`$SOCKET_CLASS = "IO::Socket::INET"\*(C'\fR to use IPv4 only. See also \&\*(L"$SOCKET_CLASS\*(R" .SH "FAQ" .IX Header "FAQ" .IP "How to determine is connection to socks server (client accept) failed or some protocol error occurred?" 4 .IX Item "How to determine is connection to socks server (client accept) failed or some protocol error occurred?" You can check $! variable. If $! == \s-1ESOCKSPROTO\s0 constant, then it was error in the protocol. Error description could be found in \f(CW$SOCKS_ERROR\fR. .IP "How to determine which error in the protocol occurred?" 4 .IX Item "How to determine which error in the protocol occurred?" You should compare \f(CW$SOCKS_ERROR\fR with constants below: .Sp .Vb 10 \& 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 .Ve .SH "BUGS" .IX Header "BUGS" The following options are not implemented: .IP "\s-1GSSAPI\s0 authentication" 4 .IX Item "GSSAPI authentication" .PD 0 .IP "\s-1UDP\s0 server side support" 4 .IX Item "UDP server side support" .PD .PP Patches are welcome. .SH "SEE ALSO" .IX Header "SEE ALSO" IO::Socket::Socks::Wrapper .SH "AUTHOR" .IX Header "AUTHOR" Original author is Ryan Eatmon .PP Now maintained by Oleg G .SH "COPYRIGHT" .IX Header "COPYRIGHT" This module is free software, you can redistribute it and/or modify it under the terms of \s-1LGPL.\s0