TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
79 lines
2.5 KiB
79 lines
2.5 KiB
<?php
|
|
|
|
/**
|
|
* Converts OpenSSH's channel-oriented SOCKS diagnostics into messages that
|
|
* identify the destination requested by the local SOCKS client.
|
|
*/
|
|
class SshOutputParser
|
|
{
|
|
/** @var array<string, array<string, string>> */
|
|
private array $socksTargets = [];
|
|
|
|
public function parse(
|
|
string $tunnelId,
|
|
string $line,
|
|
bool $isSocks5,
|
|
bool $showDebug = false
|
|
): ?string
|
|
{
|
|
$line = trim($line);
|
|
if ($line === '' || !$isSocks5) {
|
|
return $line === '' ? null : $line;
|
|
}
|
|
|
|
$matches = [];
|
|
if (preg_match(
|
|
'/^(?:debug\d+: )?channel (\d+): dynamic request: socks[45] host (.+) port (\d+) command \d+$/',
|
|
$line,
|
|
$matches
|
|
) === 1) {
|
|
$channel = (string) $matches[1];
|
|
$host = (string) $matches[2];
|
|
$port = (string) $matches[3];
|
|
$this->socksTargets[$tunnelId][$channel] = $this->formatEndpoint($host, $port);
|
|
return $showDebug ? $line : null;
|
|
}
|
|
|
|
if (preg_match(
|
|
'/^(?:debug\d+: )?channel (\d+): open failed: (.+)$/',
|
|
$line,
|
|
$matches
|
|
) === 1) {
|
|
$channel = (string) $matches[1];
|
|
$reason = (string) $matches[2];
|
|
$target = (string) ($this->socksTargets[$tunnelId][$channel] ?? '');
|
|
unset($this->socksTargets[$tunnelId][$channel]);
|
|
if ($target !== '') {
|
|
return 'SOCKS5 连接失败:' . $target . '(' . $reason . ')';
|
|
}
|
|
return $line;
|
|
}
|
|
|
|
if (preg_match('/^debug\d+: channel (\d+): free:/', $line, $matches) === 1) {
|
|
unset($this->socksTargets[$tunnelId][(string) $matches[1]]);
|
|
return $showDebug ? $line : null;
|
|
}
|
|
|
|
// -vv is enabled only to obtain the SOCKS destination. Do not expose
|
|
// unrelated OpenSSH handshake/channel diagnostics in the UI.
|
|
if (preg_match('/^debug\d+:/', $line) === 1) {
|
|
return $showDebug ? $line : null;
|
|
}
|
|
return $line;
|
|
}
|
|
|
|
public function clear(string $tunnelId): void
|
|
{
|
|
unset($this->socksTargets[$tunnelId]);
|
|
}
|
|
|
|
private function formatEndpoint(string $host, string $port): string
|
|
{
|
|
if (str_contains($host, ':')
|
|
&& !str_starts_with($host, '[')
|
|
&& !str_ends_with($host, ']')) {
|
|
return '[' . $host . ']:' . $port;
|
|
}
|
|
return $host . ':' . $port;
|
|
}
|
|
}
|
|
|