怎么用PHP实现简单的Socks5 Server
发表于:2024-11-14 作者:千家信息网编辑
千家信息网最后更新 2024年11月14日,本篇内容主要讲解"怎么用PHP实现简单的Socks5 Server",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么用PHP实现简单的Socks5 Ser
千家信息网最后更新 2024年11月14日怎么用PHP实现简单的Socks5 Server
本篇内容主要讲解"怎么用PHP实现简单的Socks5 Server",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么用PHP实现简单的Socks5 Server"吧!
利用 Phalcon7 的异步功能实现,完整源码 https://github.com/dreamsxin/cphalcon7/blob/master/examples/async/Socks5Server.php。
concurrency = max(1, $concurrency); $this->channel = new \Phalcon\Async\Channel($capacity); $this->context = \Phalcon\Async\Context::background(); } public function close(?\Throwable $e = null): void { $this->count = \PHP_INT_MAX; $this->channel->close($e); } public function submit(callable $work, $socket, ...$args): \Phalcon\Async\Awaitable { if ($this->count < $this->concurrency) { $this->count++; Socks5Server::info('Pool count '.$this->count); \Phalcon\Async\Task::asyncWithContext($this->context, static function (iterable $it) { try { foreach ($it as list ($defer, $context, $work, $socket, $args)) { try { $defer->resolve($context->run($work, $socket, ...$args)); } catch (\Throwable $e) { Socks5Server::err($e->getMessage()); $defer->fail($e); } finally { } } } catch (\Throwable $e) { Socks5Server::err($e->getMessage()); } finally { --$this->count; } }, $this->channel->getIterator()); } $this->channel->send([ $defer = new \Phalcon\Async\Deferred(), \Phalcon\Async\Context::current(), $work, $socket, $args ]); return $defer->awaitable(); }}class Socks5Server{ static public $debug = false; private $server; private $host; private $port; private $clients; public function __construct($host, $port, callable $callback = NULL, int $concurrency = 1, int $capacity = 0) { $this->host = $host; $this->port = $port; $this->callback = $callback; $this->pool = new Pool($concurrency, $capacity); } public function start() { $callback = $this->callback; $ws = $this; $worker = static function ($socket) use ($ws, $callback) { $socket->status = Socks5::STATUS_INIT; $socket->is_closing = false; try { $buffer = ''; while (!$socket->is_closing && null !== ($chunk = $socket->read())) { $buffer .= $chunk; switch ($socket->status) { case Socks5::STATUS_INIT: /** * 协商版本以及验证方式 * +---------+-----------------+------------------+ * |协议版本 |支持的验证式数量 |验证方式 | * +---------+-----------------+------------------+ * |1个字节 |1个字节 |1种式占一个字节 | * +---------+-----------------+------------------+ * |0x05 |0x02 |0x00,0x02 | * +---------+-----------------+------------------+ */ /** * 0x00 无验证需求 * 0x01 通用安全服务应用程序接口(GSSAPI) * 0x02 用户名/密码(USERNAME/PASSWORD) * 0x03 至 X'7F' IANA 分配(IANA ASSIGNED) * 0x80 至 X'FE' 私人方法保留(RESERVED FOR PRIVATE METHODS) * 0xFF 无可接受方法(NO ACCEPTABLE METHODS) */ $authtypes = Socks5::parseAuth($buffer); if ($authtypes === false) { $socket->is_closing = true; break; } if ($authtypes === true) { // continue break; } $socket->status = Socks5::STATUS_ADDR; $socket->write("\x05\x00"); // TODO: 暂时 $buffer = ''; break; case Socks5::STATUS_AUTH: if ($callback && \is_callable($callback)) { // TODO } break; case Socks5::STATUS_ADDR: self::info('Socks5::STATUS_ADDR'); /** * 建立代理连接 * +----------+------------+---------+-----------+-----------------------+------------+ * |协议版本 |请求的类型 |保留字段 |地址类型 |地址数据 |地址端口 | * +----------+------------+---------+-----------+-----------------------+------------+ * |1个字节 |1个字节 |1个字节 |1个字节 |变长 |2个字节 | * +----------+------------+---------+-----------+-----------------------+------------+ * |0x05 |0x01 |0x00 |0x01 |0x0a,0x00,0x01,0x0a |0x00,0x50 | * +----------+------------+---------+-----------+-----------------------+------------+ */ /** * 请求类型 * CONNECT : 0x01, 建立代理连接 * BIND : 0x02,告诉代理服务器监听目标机器的连接,也就是让代理服务器创建socket监听来自目标机器的连接。FTP这类需要服务端主动联接客户端的的应用场景。 * 1. 只有在完成了connnect操作之后才能进行bind操作 * 2. bind操作之后,代理服务器会有两次响应, 第一次响应是在创建socket监听完成之后,第二次是在目标机器连接到代理服务器上之后。 * UDP ASSOCIATE : 0x03, udp 协议请求代理。 */ if (strlen($buffer) < 2) { break; } $cmd = ord($buffer[1]); if ($cmd != Socks5::CMD_CONNECT) { self::err("Bad command ".$cmd); $socket->is_closing = true; break; } $headers = Socks5::parseAddr($buffer); if (!$headers) { self::err('Error header'); $socket->is_closing = true; break; } if ($headers === true) { // continue break; } /** * 数据包转发 * +----+------+------+----------+----------+----------+ * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | * +----+------+------+----------+----------+----------+ * | 2 | 1 | 1 | Variable | 2 | Variable | * +----+------+------+----------+----------+----------+ */ $buffer = substr($buffer, $headers[3]); $socket->status = Socks5::STATUS_CONNECTING; if (!in_array($headers[0], [Socks5::TYPE_IPV4, Socks5::TYPE_HOST, Socks5::TYPE_IPV6])) { self::err('Addr type error'); $socket->is_closing = true; break; } $tls = NULL; if ($headers[2] == 443) { $tls = new \Phalcon\Async\Network\TlsClientEncryption(); $tls = $tls->withAllowSelfSigned(true); } $socket->client = \Phalcon\Async\Network\TcpSocket::connect($headers[1], $headers[2], $tls); $socket->write(Socks5::REPLY_ADDR); $socket->status = Socks5::STATUS_STREAM; \Phalcon\Async\Task::async(function ($client) use ($socket) { while (!$socket->is_closing && null !== ($chunk = $client->read())) { $socket->write($chunk); } }, $socket->client); break; case Socks5::STATUS_STREAM: self::info('Socks5::STATUS_STREAM'); $socket->client->write($buffer); $buffer = ''; break; } } } catch (\Throwable $e) { self::err($e->getMessage()); } finally { $socket->close(); } }; try { $this->server = \Phalcon\Async\Network\TcpServer::listen($this->host, $this->port); echo Phalcon\Cli\Color::info('start server listen:'.$this->host.':'.$this->port).PHP_EOL; while (true) { $socket = $this->server->accept(); if ($socket === false) { continue; } $this->pool->submit($worker, $socket); } } catch (\Throwable $e) { self::err($e->getMessage()); } finally { if ($this->server) { $this->server->close(); } } } static public function info($message) { if (self::$debug) { echo Phalcon\Cli\Color::info($message).PHP_EOL; } } static public function err($message) { echo Phalcon\Cli\Color::error($message).PHP_EOL; }}$opts = new \Phalcon\Cli\Options('Websocket CLI');$opts->add([ 'type' => \Phalcon\Cli\Options::TYPE_STRING, 'name' => 'server', 'shortName' => 's', 'required' => false, // 可选,需要用=号赋值 'help' => "address"]);$opts->add([ 'type' => \Phalcon\Cli\Options::TYPE_INT, 'name' => 'port', 'shortName' => 'p', 'required' => false, 'help' => "port"]);$opts->add([ 'type' => \Phalcon\Cli\Options::TYPE_BOOLEAN, 'name' => 'concurrency', 'shortName' => 'c', 'required' => false]);$opts->add([ 'type' => \Phalcon\Cli\Options::TYPE_BOOLEAN, 'name' => 'capacity', 'shortName' => 'C', 'required' => false]);$opts->add([ 'type' => \Phalcon\Cli\Options::TYPE_BOOLEAN, 'name' => 'debug', 'shortName' => 'v', 'required' => false, 'help' => "enable debug"]);$vals = $opts->parse();if ($vals === false ) { exit;}/** * 运行 php websocket-server.php */if (isset($vals['debug'])) { Socks5Server::$debug = true; echo Phalcon\Cli\Color::info('Use debug mode').PHP_EOL;}$sserver = new Socks5Server(\Phalcon\Arr::get($vals, 'server', '0.0.0.0'), \Phalcon\Arr::get($vals, 'port', 10002), function($socket, $status, $data) { // TODO}, \Phalcon\Arr::get($vals, 'concurrency', 500), \Phalcon\Arr::get($vals, 'capacity', 1));$sserver->start();
到此,相信大家对"怎么用PHP实现简单的Socks5 Server"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
字节
代理
服务
服务器
验证
地址
方法
机器
版本
目标
类型
监听
内容
数据
方式
是在
学习
应用
实用
更深
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
西北大学数据库从哪里进
数据库技术与应用常考的概念
亲爱的亲爱的网络安全
网络安全风险防范不到位
云南特种网络技术服务代理商
sql数据库怎么建立
少年儿童网络安全九规则
为了软件开发效率
图书馆特色数据库购买制度
文件打包成压缩包后保存到服务器
软件开发人员为啥不参评职称
dell存储服务器管理软件
服务器多个ip是什么
烟草网络安全的文章
哪个数据库收录增刊的论文
厦门博颖网络技术
广播站网络技术问题
数据库被黑 快照
数据库建立前问卷调查
电视墙服务器特点
数据库做好怎么保存到桌面文件夹
飞行管理仿真软件开发
宿迁网络安全准入控制价格
海淀区咨询软件开发服务电话
硚口区电商网络安全维护怎么样
四大行软件开发
网络安全知识故事
数据库和大数据有关系吗
网络安全防护公司如何开展业务
静安区金融行业解决方案软件开发