伦敦Perl和Raku研讨会将于2024年10月26日举行。如果您的公司依赖Perl,请考虑赞助和/或参加.

名称

IO::Socket::Socks-提供一种创建Socks客户端或服务器4和5版本的方法。

简介

顾客

使用IO::Socket::Socks;my$socks_client=IO::Socket::socks->new(ProxyAddr=>“代理主机”,ProxyPort=>“代理端口”,ConnectAddr=>“远程主机”,连接端口=>“远程端口”,)或死亡$SOCKS_ERROR;打印$socks_client“foo\n”;$socks_client->关闭();

服务器

使用IO::Socket::Socks“:constants”;my$socks_server=IO::Socket::socks->new(ProxyAddr=>“本地主机”,代理端口=>8000,听=>1,用户授权=>\&授权,要求授权=>1)或死亡$SOCKS_ERROR;而(1){我的$client=$socks_server->accept();除非($client){打印“ERROR:$SOCKS_ERROR\n”;下一步;}我的$command=$client->command();if($command->[0]==CMD_CONNECT){#处理CONNECT$client->command_reply(reply_SUCCESS,地址,端口);}...#从客户端读取并发送到CONNECT地址...$client->close();}子授权{my($user,$pass)=@_;如果$user-eq“foo”&&$pass-eq“bar”,则返回1;返回0;}

描述

IO::插槽::插槽连接到SOCKS代理,告诉它在创建对象时打开与远程主机/端口的连接。您收到的对象可以直接用作套接字(IO::插座接口)用于从远程主机发送和接收数据。除了创建socks客户端之外,该模块还可以用于创建socks服务器。请参见以下示例。

示例

有关socks 4/5客户端和服务器的完整示例,请参阅发行版中的“examples”子目录。

方法

Socks客户端

新(%cfg)

new_from_socket($socket,%cfg)

new_from_fd($socket,%cfg)

创建新的IO::Socket::Socks客户端对象。new_from_socket()与new()相同,但允许从现有且未连接的套接字创建对象(new_from _fd是new_frrom_socket别名)。要从连接的套接字生成IO::Socket::Socks对象,请参见启动_锁定

两者都采用以下配置哈希:

SocksVersion=>4或5。默认值为5超时=>连接/接受超时阻塞=>由于IO::Socket::Socks版本0.5,您可以通过以下方式执行非阻塞连接/绑定为此选项传递false值。默认值为true-blocking。请参阅ready()详情请参见下文。SocksResolve=>通过代理服务器或不(将由客户端解决)。这个覆盖$SOCKS4_RESOLVE或$SOCKS5_RESOLEVE的值变量。布尔值。SocksDebug=>这将导致所有SOCKS流量以表格形式显示在命令行上类似于RFC中的表。此覆盖值$SOCKS_DEBUG变量的。布尔值。ProxyAddr=>代理的主机名ProxyPort=>代理的端口ConnectAddr=>远程计算机的主机名ConnectPort=>远程机器的端口BindAddr=>将绑定请求后连接到代理服务器BindPort=>将绑定请求后连接到代理服务器UdpAddr=>预期的数据报发送地址。填写地址如果此时地址未知,则返回所有零。代理服务器可以使用此信息来限制对关联的访问。UdpPort=>将发送数据报的预期端口。使用零端口如果此时端口未知。代理服务器可以使用此限制访问关联的信息。AuthType=>支持哪种身份验证:无-无身份验证(默认)userpass—用户名/密码。对于袜子5仅代理。RequireAuth=>不要将ANON作为有效的身份验证机制发送。仅适用于socks5代理Username=>对于socks5,如果AuthType设置为userpass,则您必须提供用户名。对于socks4代理这个选项可以指定userid。密码=>如果AuthType设置为userpass,则必须提供密码。仅适用于socks5代理。

应指定以下选项:

(ProxyAddr和ProxyPort)(ConnectAddr和ConnectPort)或(BindAddr和BindPort)或(UdpAddr和UdpPort)

其他选项是临时性的。

start_SOCKS($socket,%cfg)

这是一个在已连接的套接字上开始袜子握手的类方法。这将有助于将$socket传递给IO::socket::Socks类。%cfg就像构造函数中的散列。只有下列选项才有意义:

超时连接地址连接端口绑定地址绑定端口Udp地址Udp端口套接字版本套接字调试套接字解析身份验证类型需要身份验证用户名密码AuthMethods(作者方法)

成功时,此方法将返回相同的$socket,但作为IO::socket::Socks对象。失败时,它将返回undef(但套接字仍然适用于IO::socket::Socks类)。参见示例:

使用IO::套接字;使用IO::Socket::Socks;my$sock=IO::Socket::INET->new(“$proxy_host:$proxy_port”)或die$@;$sock=IO::Socket::Socks->start_Socks($sock,ConnectAddr=>“google.com”,ConnectPort=>80)或死$Socks_ERROR;

版本()

返回此套接字的袜子版本

就绪()

当套接字准备好传输数据时返回true(socks握手完成),否则返回false。这对于非阻塞连接/绑定非常有用。当此方法返回假值时,您可以使用$socks_ERROR变量确定握手所需的袜子。它可能需要读取,然后$SOCKS_ERROR将为SOCKS_WANT_read或需要写入,然后它将为SOCKS_WANT_write。

例子:

使用IO::Socket::Socks;使用IO::选择;my$sock=IO::Socket::Socks->新(ProxyAddr=>“localhost”,ProxyPort=>1080,ConnectAddr=>'mail.com',ConnectPort=>80,Blocking=>0)或死亡$SOCKS_ERROR;my$sel=IO::选择->新建($sock);直到($sock->准备好){如果($SOCKS_ERROR==SOCKS_WANT_READ){$sel->can_read();}elsif($SOCKS_ERROR==SOCKS_WANT_WRITE){$sel->can_write();}其他{模具$SOCKS_ERROR;}#注意:当基类($IO::Socket::Socks::Socket_class)为IO::套接字::IP时#您正在使用kqueue或epoll检查可读/可写套接字#每次调用ready()后,您都需要将$sock读到kqueue/epoll(实际上直到套接字连接到代理服务器),#因为IO::Socket::IP可能会更改多主机的$sock的内部套接字。#当您使用select/poll时,没有这样的问题}#您可能希望通过$sock->blocking(1)将套接字返回到阻塞状态$sock->syswrite(“我准备好了”);

接受()

在绑定请求后接受传入连接。失败时返回undef。成功时返回套接字。未创建新套接字,返回的套接字与调用此方法的套接符相同。因为客户端没有调用accept(2),所以socks服务器调用accept(2)并通过客户端绑定请求打开的套接字代理所有流量。您只能在IO::Socket::Socks客户端套接字上调用accept一次。

命令(%cfg)

允许用户在已打开的套接字上执行socks命令。这样就可以创建袜子链。例如,请参见“示例”第节。

%cfg就像构造函数中的散列。只有下列选项才有意义:

连接地址连接端口绑定地址绑定端口Udp地址Udp端口套接字版本套接字调试套接字解析身份验证类型需要身份验证用户名密码验证方法

从构造函数继承的其他选项(例如Timeout)的值。不包括ProxyAddr和ProxyPort等选项。

dst()

在connect/accept后返回远程主机的(host,port,address_type),在bind/udpassoc后返回socks服务器(host、port、address_type)。

Socks服务器

新(%cfg)

new_from_socket($socket,%cfg)

new_from_fd($socket,%cfg)

创建新的IO::Socket::Socks服务器对象。new_from_socket()与new()相同,但允许从现有套接字中创建对象(new_from _fd是new_frrom_socket别名)。两者都采用以下配置哈希:

SocksVersion=>4表示袜子4,5表示袜子5,或者[4,5]表示同时接受4和5。默认值为5超时=>各种操作的超时值阻塞=>由于IO::Socket::Socks版本0.6,您可以通过以下方式执行非阻塞接受为此选项传递false值。默认值为true-blocking。请参阅ready()详情请参见下文。SocksResolve=>对于socks v5:将目标地址返回给客户端如果为true,则以4字节的形式显示,否则以主机的形式显示长度和主机名。对于socks v4:允许使用socks4a协议扩展,如果是真的,而不是别的。这将覆盖$SOCKS4_RESOLVE或$SOCKS5_RESOLEVE的值。另请参见command_reply()。SocksDebug=>这将导致所有SOCKS流量以表格形式显示在命令行上类似于RFC中的表。此覆盖值$SOCKS_DEBUG变量的。布尔值。ProxyAddr=>本地主机绑定地址ProxyPort=>本地主机绑定端口UserAuth=>对一个函数的引用,如果客户端为1允许使用socks服务器,否则为0。对于socks5代理它接受登录名和密码论据。对于socks4,参数是userid。RequireAuth=>不允许对socks5代理进行匿名访问。侦听=>与IO::Socket::INET侦听选项相同。应该是指定为数字>0。

应指定以下选项:

代理地址代理端口

其他选项是临时性的。

接受()

接受传入连接并返回表示该连接的新IO::Socket::Socks对象。您必须对此调用command()以了解传入连接希望您执行的操作,然后调用command_reply()返回回复。

版本()

返回套接字的袜子版本。当服务器同时接受4和5版本时,它很有用。那么你应该知道袜子的版本以做出正确的反应。只要打电话版本()在之后接收的套接字上接受().

就绪()

在非阻塞接受之后,您将获得新的客户机套接字对象,该对象可能尚未准备好传输数据(如果尚未完成袜子握手)。当握手成功时,ready()将返回true值,否则返回false。注意,accept()调用返回的套接字将始终处于阻塞模式。因此,如果您的程序无法阻塞,则应在ready()调用之前为该套接字设置非阻塞模式:$socket->blocking(0)。当ready()返回假值时,您可以使用$socks_ERROR变量确定握手需要什么袜子。它可能需要读取,然后$SOCKS_ERROR将为SOCKS_WANT_read或需要写入,然后它将为SOCKS_WANT_write。

例子:

使用IO::Socket::Socks;使用IO::选择;my$server=IO::Socket::Socks->new(ProxyAddr=>'localhost',ProxyPort=>1080,Blocking=>0)或者死$@;my$select=IO::select->new($server);$select->can_read();#等待客户端我的$client=$server->accept()或死“accept():$!($SOCKS_ERROR)”;$client->阻塞(0);#!!!$select->add($client);$select->remove($server);#没有更多连接而(1){if($client->就绪){我的$command=$client->命令;…#do客户端命令$client->command_reply(IO::套接字::套接字::reply_SUCCESS,$command->[1],$command->[2]);…#传输流量最后;}elsif($SOCKS_ERROR==SOCKS_WANT_READ){$select->can_read();}elsif($SOCKS_ERROR==SOCKS_WANT_WRITE){$select->can_write();}其他{die“意外错误:$SOCKS_error”;}}

命令()

调用accept()后,客户机发送了希望您处理的命令。应该对accept()返回的套接字调用此函数。它以以下格式返回对数组的引用:

[命令、地址、端口、地址类型]

command_reply(应答代码、地址、端口)

调用command()后,需要告诉客户端结果是什么。REPLY CODE是以下常量之一(整数值):

袜子v4REQUEST_GRANTED(90):已批准请求REQUEST_FAILED(91):请求被拒绝或失败REQUEST_REJECTED_IDENTD(92):请求被拒绝,因为SOCKS服务器无法连接到客户端上的identREQUEST_REJECTED_USERID(93):请求被拒绝,因为客户端程序和标识报告的用户ID不同对于袜子v5REPLY_SUCCESS(0):成功REPLY_GENERAL_FAILURE(1):一般故障REPLY_CONN_NOT_ALLOWED(2):不允许连接REPLY_NETWORK_UNREACABLE(3):网络无法访问REPLY_HOST_UNREACABLE(4):主机无法访问REPLY_CONN_REFUSED(5):连接被拒绝REPLY_TTL_EXPIRED(6):TTL过期REPLY_CMD_NOT_SUPPORTED(7):不支持命令REPLY_ADDR_NOT_SUPPORTED(8):不支持地址

HOST和PORT是生成的主机和端口(其中服务器套接字负责此命令绑定)。

注:适用于5个版本命令_reply将尝试解析传递的地址,如果套接字解析具有true值,传递的地址是域名。为了避免这种情况,只需传递ip地址($socket->sockhost)而不是主机名或关闭袜子解决方案用于此服务器。对于版本4,传递的主机名将始终解析为ip地址,即使套接字解析具有假值。因为此版本不支持地址作为域名。

变量

$袜子_错误

此标量的行为类似于$!如果返回undef。$袜子_错误是具有一些重载运算符的IO::Socket::Socks::Error对象。在字符串上下文中,此变量应包含错误的字符串原因。在数字上下文中,它包含错误代码。

$SOCKS4_恢复

如果此变量具有真值,则主机名解析将由代理服务器完成,否则解析将在本地完成。通过socks代理版本4解析主机是协议(也称为socks4a)的扩展。因此,只有socks4a代理支持解析主机名。此变量的默认值为false。此变量不可导入。另请参见构造函数中的“SocksResolve”参数。

$SOCKS5_恢复

如果此变量具有真值,则主机名解析将由代理服务器完成,否则解析将在本地完成。注意:一些错误的socks5服务器不支持解析主机名。默认值为true。此变量不可导入。另请参见构造函数中的“SocksResolve”参数。

$袜子_DEBUG

默认值为$ENV{SOCKS_DEBUG}。如果此变量的值为true,并且指定的构造函数中没有SocksDebug选项,则SocksDebug的值为true。此变量不可导入。

$短袜类

使用此变量,您可以获取/设置IO::插槽::插槽。默认情况下,它尝试使用IO::套接字::IP0.36+作为插座等级。然后回到IO::插座::INET如果不可用。您可以设置$IO::套接字::套接字::Socket_CLASS加载之前IO::插槽::插槽然后它就不会尝试检测合适的基类本身。您也可以在加载IO::插槽::插槽这将自动更新@ISA公司,所以你不应该担心继承问题。

常量

可以手动导入或使用“:constants”标记导入以下常量:

袜子5_插座4_添加_IPV4地址域名添加_IPV6CMD_CONNECT(连接)CMD_绑定CMD_UDPASSOC公司授权_无授权机制用户通行证认证无效授权回复_成功授权回复_完成ISS_UNKNOWN_ADDRESS#I::S::S不支持客户端/服务器发送的地址类型ISS_BAD_VERSION#客户端/服务器发送的socks版本!=指定的版本ISS_CANT_RESOLVE#I::S::S无法解析某些主机回复_成功回复_通用_完整回复CONN_NOT_ALLOWED回复_网络工作_不可恢复回复_暂停_不可恢复回复CONN_REFUSED回复_TTL_EXPIRED回复CMD_NOT_SUPPORTED回复_ADDR_NOT_SUPPORTED请求_批准请求失败请求_拒绝_拒绝请求拒绝用户ID袜子_手_头袜子_手套_毛线伊萨克斯普罗托

默认情况下,将导入SOCKS_WANT_READ、SOCKS_HANT_WRITE和ESOCKSPROTO。

IPv6协议

自版本0.66起IO::插槽::插槽借助支持IPv6IO::套接字::IP0.36+. 并将使用IO::套接字::IP作为基类(如果可用)。然而,您可以强制设置$SOCKET_CLASS=“IO::套接字::INET”仅使用IPv4。另请参见“$SOCKET_CLASS”

常见问题解答

如何确定连接到socks服务器(客户端接受)失败或发生了一些协议错误?

您可以查看$!变量。如果$!==ESOCKSPROTO常数,则为协议中的错误。在$SOCKS_Error中可以找到错误描述。

如何确定协议中发生了哪些错误?

你应该比较一下$袜子_错误常数如下:

认证无效授权回复_完成ISS_UNKNOWN_ADDRESS系统ISS_BAD_版本回复_通用_完整回复CONN_NOT_ALLOWED回复_网络工作_不可恢复回复_暂停_不可恢复回复CONN_REFUSED回复_TTL_EXPIRED回复CMD_NOT_SUPPORTED回复_ADDR_NOT_SUPPORTED请求失败请求_拒绝_拒绝请求_拒绝_序列化

漏洞

未实施以下选项:

GSSAPI身份验证
UDP服务器端支持

欢迎使用补丁。

另请参阅

IO::插座::袜子::包装

作者

原作者是Ryan Eatmon

现在由Oleg G维护<oleg@cpan.org>

版权

此模块是自由软件,您可以根据LGPL条款重新发布和/或修改它。