clue/socks

异步 SOCKS 代理客户端和服务器(SOCKS4、SOCKS4a 和 SOCKS5)

v0.4.0 2013-05-24 09:36 UTC

This package is auto-updated.

Last update: 2024-09-06 09:14:11 UTC


README

该存储库目前正在被拆分为简单的阻塞客户端实现和异步非阻塞客户端和服务器实现。有关详细信息,请参阅 问题 #2

  • 如果您已经使用此库的旧版 v0.4,请考虑升级到 clue/socks-react。升级不应超过 10 分钟,有关详细信息,请参阅 CHANGELOG.md。

  • 如果您正在寻找异步非阻塞客户端和服务器实现,请访问 clue/socks-react

  • 如果您正在寻找简单的阻塞客户端实现,最好的选择是等待 问题 #2 完成。您愿意贡献吗? :)

以下说明适用于已迁移到 clue/socks-react 的旧版 v0.4。

clue/socks - SOCKS 客户端和服务器 Build Status

异步 SOCKS 客户端库,用于连接到 SOCKS4、SOCKS4a 和 SOCKS5 代理服务器,以及 SOCKS 服务器实现,能够以非阻塞方式处理多个并发连接。

描述

SOCKS 协议族可用于轻松地隧道 TCP 连接,而无需考虑实际的应用层协议,例如 HTTP、SMTP、IMAP、Telnet 等。

快速入门示例

安装后,初始化与远程 SOCKS 代理服务器的连接

<?php
include_once __DIR__.'/vendor/autoload.php';

$loop = React\EventLoop\Factory::create();

// use google's dns servers
$dnsResolverFactory = new React\Dns\Resolver\Factory();
$dns = $dnsResolverFactory->createCached('8.8.8.8', $loop);

// create SOCKS client which communicates with SOCKS server 127.0.0.1:9050
$factory = new Socks\Factory($loop, $dns);
$client = $factory->createClient('127.0.0.1', 9050);

// now work with your $client, see below

$loop->run();

隧道 TCP 连接

Socks/Client 使用基于 Promise 的接口,这使得异步函数的工作变得轻松。让我们打开一个 TCP Stream 连接并写入一些数据

$tcp = $client->createConnector();

$tcp->create('www.google.com',80)->then(function (React\Stream\Stream $stream) {
    echo 'connected to www.google.com:80';
    $stream->write("GET / HTTP/1.0\r\n\r\n");
    // ...
});

HTTP 请求

或者,如果您只想进行 HTTP 请求,Socks/Client 还提供了一个更简单的 HTTP 客户端 接口

$httpclient = $client->createHttpClient();

$request = $httpclient->request('GET', 'https://www.google.com/', array('user-agent'=>'Custom/1.0'));
$request->on('response', function (React\HttpClient\Response $response) {
    var_dump('Headers received:', $response->getHeaders());
    
    // dump whole response body
    $response->on('data', function ($data) {
        echo $data;
    });
});
$request->end();

是的,这适用于纯 HTTP 和 SSL 加密的 HTTPS 请求。

SSL/TLS 加密

如果您想连接到任意的 SSL/TLS 服务器,也有一个易于使用的 API 可用

$ssl = $client->createSecureConnector();

// now create an SSL encrypted connection (notice the $ssl instead of $tcp)
$ssl->create('www.google.com',443)->then(function (React\Stream\Stream $stream) {
    // proceed with just the plain text data and everything is encrypted/decrypted automatically
    echo 'connected to SSL encrypted www.google.com';
    $stream->write("GET / HTTP/1.0\r\n\r\n");
    // ...
});

SOCKS 协议版本及差异

虽然 SOCKS4 已经有了(有点有限)对 SOCKS BIND 请求的支持,而 SOCKS5 添加了通用 UDP 支持(SOCKS UDPASSOCIATE),但此库主要关注最常用的核心功能 SOCKS CONNECT。在这种模式下,SOCKS 服务器充当一个通用代理,允许更高级的应用层协议通过它工作。

注意,这不是完整的 SOCKS5 实现,因为缺少 GSSAPI 身份验证(但您可能根本不会注意到这一点)。

显式设置协议版本

本库支持 SOCKS4、SOCKS4a 和 SOCKS5 协议版本。通常情况下,无需担心使用的是哪个协议版本。根据您使用的功能(例如,远程 DNS 解析认证),Socks/Client会自动使用可用的最佳协议。通常情况下,此库在需要时会自动切换到更高版本的协议,但在可能的情况下会尽量保持简单,并坚持使用较低版本的协议。默认情况下,Socks/Server支持所有协议版本。

如果需要显式设置协议版本,请使用支持的值 44a5

// valid protocol versions:
$client->setProtocolVersion('4a');
$server->setProtocolVersion(5);

要将协议版本重置为其默认值(即自动检测),请使用 null 作为协议版本。

$client->setProtocolVersion(null);
$server->setProtocolVersion(null);

远程与本地 DNS 解析

默认情况下,Socks/Client使用本地 DNS 解析将目标主机名解析为 IP 地址,并将解析出的目标 IP 地址仅发送到 SOCKS 服务器。

本地解析通常会产生更好的性能,因为对于每个出站请求,同时解析主机名和初始化到 SOCKS 服务器的连接是可能的。因此,在建立 SOCKS 连接(需要每个连接的 TCP 握手)之前,目标主机名很可能已经被解析(通常已经缓存或需要通过 UDP 执行简单的 DNS 查询)。

如果您希望切换到远程 DNS 解析,那么您的本地 Socks/Client可能无法解析目标主机名,因为它无法直接访问互联网,或者它不应该解析目标主机名,因为其出站 DNS 流量可能会被拦截(尤其是在使用Tor 网络时)。

本地 DNS 解析在所有 SOCKS 协议版本中都可用。远程 DNS 解析仅适用于 SOCKS4a 和 SOCKS5(即它对于 SOCKS4 不可用)。

有效值为布尔值 true(默认值)或 false

$client->setResolveLocal(false);

用户名 / 密码认证

本库支持 SOCKS5 服务器上的用户名/密码认证,该认证由RFC 1929定义。

在客户端,只需设置用于认证的用户名和密码(见下文)。对于每个进一步的连接,客户端将仅向服务器发送一个标志,表示认证信息可用。只有当服务器在初始握手期间请求认证时,实际的认证凭据才会被发送到服务器。

请注意,密码会以明文形式发送到 SOCKS 代理服务器,因此此方法不应在您需要担心监听的网络中使用。认证仅由协议版本 5(SOCKS5)支持,因此设置 Socks/Client 上的认证强制与协议版本 5 进行通信,并在您明确设置了其他任何内容时提出抱怨。

$client->setAuth('username', 'password');

Socks/Server 上设置认证强制要求每个进一步连接的客户端使用协议版本 5。如果客户端尝试使用任何其他协议版本,未发送认证详细信息或如果无法验证认证详细信息,则连接将被拒绝。

由于您的认证机制可能需要一些时间来实际检查提供的认证凭据(例如查询远程数据库或 Web 服务),服务器端使用基于Promise的接口。虽然这看起来可能一开始就非常复杂,但它实际上提供了一种非常简单的方式来以非阻塞的方式处理并发连接,并提高了整体性能。

$server->setAuth(function ($username, $password) {
    // either return a boolean success value right away or use promises for delayed authentication
});

或者如果您只接受静态身份验证信息,可以使用基于简单数组的身份验证方法作为快捷方式

$server->setAuthArray(array(
    'tom' => 'password',
    'admin' => 'root'
));

如果您不想再使用身份验证

$client->unsetAuth();
$server->unsetAuth();

用法

将SSH用作SOCKS服务器

如果您已经设置好了SSH服务器,可以轻松将其用作SOCKS隧道端点。在您的客户端上,只需启动SSH客户端并使用-D [端口号]选项来启动本地SOCKS服务器(引用手册页:一个本地“动态”应用层端口转发

$ ssh -D 9050 ssh-server

$client = $factory->createClient('127.0.0.1', 9050);

使用Tor(匿名网络)隧道SOCKS连接

默认情况下,Tor匿名网络客户端软件旨在加密您的流量并将其通过多个节点的网络路由,以隐藏其来源。它通过TCP端口号9050提供了一个SOCKS4和SOCKS5接口,允许您将任何流量通过匿名网络进行隧道传输。在大多数场景中,您可能不希望您的客户端解析目标主机名,因为这会使您的DNS信息泄露给任何观察您本地流量的人。此外,Tor通过一个.onion伪顶级域名提供隐藏服务,这些服务必须由Tor解析。

$client = $factory->createClient('127.0.0.1', 9050);
$client->setResolveLocal(false);

安装

安装此库的推荐方式是通过composer。您是composer新手吗?了解composer?

{
    "require": {
        "clue/Socks": "0.4.*"
    }
}

许可证

MIT,请参阅license.txt