Skip to content

twomiao/Socks5-Proxy

Repository files navigation

Swoman Socks5

Workerman 设计思想,使用Swoole 扩展实现,命名为“Swoman”;
采用SOCKS5 协议实现代理服务器,故“Swoman Socks5”。

源于好奇:

  • 为了探索Workerman 实现原理,使用Swoole4 + Pcntl 实现核心功能。
  • 为了更方便掌握原理,实现的单实例单端口多进程高性能服务器、不支持单进程多端口,当然这并不影响,掌握它的原理。
  • 为了更方便解决实际遇见的问题,拥有改造Workerman的能力。

Socks5 协议

SOCKS5支持TCP和UDP应用。
SOCKS是一种网络传输协议,主要用于客户端与外网服务器之间通讯的中间传递。
当客户端要访问外部的服务器时,就跟SOCKS代理服务器连接。这个代理服务器控制客户端访问外网的资格。
SOCKS5还支持各种认证机制和域名解析(DNS)。

安装使用?

  1. 安装扩展 linux + pcntl + swoole
  2. 个人电脑安装SOCKS5客户端, “Proxifier”即可,将全部流量转发给服务器。
  3. php start_socks5.php start 启动代理服务

Socks5 Server:

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

use Socks5\Protocols\Command\Command;
use Socks5\Protocols\Socks5;
use Socks5\Worker;
use Socks5\TcpConnection;
use Socks5\Protocols\Command\InitCommand;
use Socks5\Protocols\Command\Message\MessageClosed;
use Socks5\Protocols\Command\Message\MessageSock;
use Socks5\Connection\AsyncTcpConnection;

Worker::$onMasterStart = function () {
    echo " ____                                       ____             _          ____
/ ___|_      _____  _ __ ___   __ _ _ __   / ___|  ___   ___| | _____  | ___|
\___ \ \ /\ / / _ \| '_ ` _ \ / _` | '_ \  \___ \ / _ \ / __| |/ / __| |___ \
 ___) \ V  V / (_) | | | | | | (_| | | | |  ___) | (_) | (__|   <\__ \  ___) |
|____/ \_/\_/ \___/|_| |_| |_|\__,_|_| |_| |____/ \___/ \___|_|\_\___/ |____/
\n{ Socks5 } 多进程、高性能Socks5代理服务器\n";
    Worker::debug('Master started success.');
};

Worker::$processTitle = 'Socks5-Server';
$worker = new Worker('tcp://0.0.0.0:1090');
$worker->layerProtocol = Socks5::class;
$worker->user = 'meows';
$worker->group = 'meows';
$worker->count = 16;

$worker->onWorkerStart = function () {
    Worker::debug('Worker started success.');
};

$worker->onConnect = function (TcpConnection $connection) {
    if (!isset($connection->state)) {
        $connection->state = InitCommand::COMMAND;
    }
    $connection->onSocks5Auth = function ($username, $password) {
        return $password === 'pass';
    };
};

$worker->onMessage = function (TcpConnection $connection, $message) {
//    Worker::debug($connection->getClientIP() . ":" . $connection->getClientPort() . " 客户端代理数据 " . $message);
    $message = json_decode($message, true);
    if (!$message) {
        $connection->close(
            new MessageClosed(Command::COMMAND_SERVER_ERROR, '0.0.0.0', '0')
        );
        return;
    }
    var_dump($message);

    switch ($command = $message['command']) {
        case 'CONNECT':
            $proxyClient = new AsyncTcpConnection(
                "tcp://" . $message["dest_address"] . ":" . $message["port"]
            );
            $proxyClient->onConnect = function (AsyncTcpConnection $proxyClient) use ($connection, $message) {
                $connection->send(
                    new MessageSock(
                        Command::COMMAND_CONNECT_SUCCESS,
                        $connection->getClientIP(),
                        $connection->getClientPort(),
                        (int)$message['addr_type'],
                    )
                );

                $proxyClient->onMessage = function (AsyncTcpConnection $proxyClient, $data) use ($connection) {
                    $connection->send($data);
                };

                $proxyClient->onBufferFull = function (AsyncTcpConnection $proxyClient) {
                    $proxyClient->pauseRecv();
                };

                $proxyClient->onBufferDrain = function (AsyncTcpConnection $proxyClient) {
                    $proxyClient->resumeRecv();
                };

                $connection->onMessage = function (TcpConnection $connection, $data) use ($proxyClient) {
                    $proxyClient->send($data);
                };
                $connection->onBufferFull = function (TcpConnection $connection) {
                    $connection->pauseRecv();
                };
                $connection->onBufferDrain = function (TcpConnection $connection) {
                    $connection->resumeRecv();
                };

                $connection->onClose = function ($connection) use ($proxyClient) {
                    $proxyClient->close();
                };

                $proxyClient->onClose = function ($proxyClient) use ($connection) {
                    $connection->close();
                };
            };

            $proxyClient->connect();
            break;
        default:
            Worker::debug("[ {$command} ] 未知命令.");
            $connection->close(
                new MessageClosed(Command::COMMAND_UNKNOWN, '0.0.0.0', '0')
            );
            break;
    }
};

$worker->onClose = function () {
    var_dump('关闭连接.');
};

$worker->start();

License

Apache License Version 2.0, http://www.apache.org/licenses/

About

探索 Workerman 工作原理

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages