34 Xray Beta

This commit is contained in:
2025-11-26 14:15:36 -03:00
parent d604c1e8ab
commit 6f81d9f9cf
4 changed files with 662 additions and 9 deletions

101
menu
View File

@@ -189,18 +189,103 @@ fi
#menuv2
#--------------------
elif [ "$cake" == "4" ]; then
clear
echo "Portas Ativas"
echo ""
php /opt/DragonCore/menu.php infoport
echo ""
echo -ne "Pressione enter para continuar"; read enter
menucon
# Xray Core management
clear
menuxray
elif [ "$cake" == "5" ]; then
clear
echo "Portas Ativas"
echo ""
php /opt/DragonCore/menu.php infoport
echo ""
echo -ne "Pressione enter para continuar"; read enter
menucon
else
menucon
menucon
fi
}
menuxray(){
clear
php /opt/DragonCore/menu.php menuxray
echo -ne "> "; read option
if [ -z "$option" ]; then
menuxray
elif [ "$option" == "0" ]; then
menucon
elif [ "$option" == "1" ]; then
clear
echo -ne "Nome do usuario > "; read usr
if [ -z "$usr" ]; then
menuxray
else
echo -ne "Protocolo (ws/xhttp/grpc/tcp) [ws] > "; read proto
[ -z "$proto" ] && proto="ws"
php /opt/DragonCore/menu.php xrayAddUser "$usr" "$proto"
echo ""
echo -ne "Pressione enter para continuar"; read enter
menuxray
fi
elif [ "$option" == "2" ]; then
clear
php /opt/DragonCore/menu.php xrayListUsers
echo ""
echo -ne "ID ou UUID para remover > "; read ident
if [ -n "$ident" ]; then
php /opt/DragonCore/menu.php xrayRemoveUser "$ident"
echo ""
echo -ne "Pressione enter para continuar"; read enter
fi
menuxray
elif [ "$option" == "3" ]; then
clear
php /opt/DragonCore/menu.php xrayListUsers
echo ""
echo -ne "Pressione enter para continuar"; read enter
menuxray
elif [ "$option" == "4" ]; then
clear
php /opt/DragonCore/menu.php xrayInfo
echo ""
echo -ne "Pressione enter para continuar"; read enter
menuxray
elif [ "$option" == "5" ]; then
clear
echo -ne "Dominio (ex: vpn.seudominio.com) > "; read dominio
if [ -n "$dominio" ]; then
php /opt/DragonCore/menu.php xrayCert "$dominio"
echo ""
chmod 777 -R /opt/DragonCore/ssl
echo -ne "Pressione enter para continuar"; read enter
fi
menuxray
elif [ "$option" == "6" ]; then
clear
echo -ne "Porta do inbound [443] > "; read p
[ -z "$p" ] && p=443
echo -ne "Protocolo (ws/xhttp/grpc/tcp) [ws] > "; read pr
[ -z "$pr" ] && pr="ws"
bash <(php /opt/DragonCore/menu.php xrayInstall)
php /opt/DragonCore/menu.php xrayGenerateConfig "$p" "$pr"
echo ""
chmod 777 /usr/local/etc/xray/config.json
echo -ne "Pressione enter para continuar"; read enter
menuxray
elif [ "$option" == "7" ]; then
clear
echo -ne "Deseja remover o Xray Core? S/n > "; read sn
lower=$(echo "$sn" | tr '[:upper:]' '[:lower:]')
if [[ "$lower" == "s" || "$lower" == "y" ]]; then
bash <(php /opt/DragonCore/menu.php xrayRemove)
echo ""
echo -ne "Pressione enter para continuar"; read enter
fi
menuxray
else
menuxray
fi
}
menuferrament(){
clear
php /opt/DragonCore/menu.php menuferramenta

View File

@@ -31,6 +31,7 @@ require "/opt/DragonCore/speedtest.php";
require "/opt/DragonCore/limiterstart.php";
require "/opt/DragonCore/statusvps.php";
require "/opt/DragonCore/bottg.php";
require "/opt/DragonCore/xray.php";
function clearScreen()
@@ -91,6 +92,7 @@ function menuconnect()
"Dragon X Go" => "",
"Stunnel4" => "",
"OpenVPN" => "",
"Xray Core" => "",
"Portas Ativas" => "",
];
@@ -222,6 +224,37 @@ function menuv2()
echo "------------\n";
}
function menuxray()
{
// Build a static set of management options for Xray. Users can install, configure or
// remove Xray regardless of its current state. This avoids confusing toggles and allows
// explicit selection of actions.
$menuItems = [
'Criar Usuario Xray' => '',
'Remover Usuario Xray' => '',
'Listar Usuarios Xray' => '',
'Informacao Xray' => '',
'Gerar Certificado TLS' => '',
'Instalar/Configurar Xray Core' => '',
'Remover Xray Core' => '',
];
$maxDigits = strlen(count($menuItems));
echo "Gerenciamento Xray\n";
echo "------------\n";
$i = 1;
foreach ($menuItems as $item => $description) {
$number = str_pad($i, $maxDigits, " ", STR_PAD_LEFT);
echo "$number. $item";
if (!empty($description)) {
echo " $description";
}
echo "\n";
$i++;
}
echo "0. Voltar para o menu\n";
echo "------------\n";
}
if ($argc < 2) {
die("Use o MENU!\n");

View File

@@ -1 +1 @@
33 Year Of the Tubular Dragon
34 Year Of the Tubular Dragon

535
xray.php Normal file
View File

@@ -0,0 +1,535 @@
<?php
require_once '/opt/DragonCore/config.php';
function createXrayTable()
{
global $db_user, $db_pass;
$conn = pg_connect("host=localhost dbname=dragoncore user={$db_user} password={$db_pass}");
if (!$conn) {
echo "Failed to connect to PostgreSQL\n";
return;
}
$query = "CREATE TABLE IF NOT EXISTS xray (
id SERIAL PRIMARY KEY,
uuid TEXT,
nick TEXT,
expiry DATE,
protocol TEXT
);";
$result = pg_query($conn, $query);
if (!$result) {
echo "Error creating Xray table: " . pg_last_error($conn) . "\n";
}
pg_close($conn);
}
function xrayConfigPath(): string
{
return '/usr/local/etc/xray/config.json';
}
function xrayEnsureConfigDir(): void
{
$dir = dirname(xrayConfigPath());
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
}
function isXrayInstalled(): bool
{
$paths = [
'/usr/local/bin/xray',
'/usr/bin/xray'
];
foreach ($paths as $p) {
if (file_exists($p)) {
return true;
}
}
return false;
}
function xrayInstall()
{
if (isXrayInstalled()) {
echo "echo 'Xray ja esta instalado';\n";
return;
}
echo 'bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install' . "\n";
}
function xrayRemove()
{
if (!isXrayInstalled()) {
echo "echo 'Xray nao esta instalado';\n";
return;
}
echo 'bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove' . "\n";
}
function xrayGetProtocols()
{
global $db_user, $db_pass;
$protocols = [];
$conn = pg_connect("host=localhost dbname=dragoncore user={$db_user} password={$db_pass}");
if ($conn) {
$res = pg_query($conn, 'SELECT DISTINCT protocol FROM xray ORDER BY protocol');
while ($row = pg_fetch_assoc($res)) {
$protocols[] = $row['protocol'];
}
pg_close($conn);
}
echo implode(', ', $protocols);
}
function xrayListSimple()
{
global $db_user, $db_pass;
$conn = pg_connect("host=localhost dbname=dragoncore user={$db_user} password={$db_pass}");
if ($conn) {
$res = pg_query($conn, 'SELECT uuid, expiry FROM xray ORDER BY id');
while ($row = pg_fetch_assoc($res)) {
echo $row['uuid'] . ' ' . $row['expiry'] . "\n";
}
pg_close($conn);
}
}
function xrayChoice(): string
{
return isXrayInstalled() ? 'Remover' : 'Instalar';
}
function xrayUuid(): string
{
$uuid = trim((string)@shell_exec('uuidgen'));
if ($uuid !== '') {
return $uuid;
}
if (function_exists('random_bytes')) {
$data = random_bytes(16);
$data[6] = chr((ord($data[6]) & 0x0f) | 0x40);
$data[8] = chr((ord($data[8]) & 0x3f) | 0x80);
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
return md5(uniqid((string)mt_rand(), true));
}
function xrayGenerateConfig($port, string $network = 'xhttp')
{
$configPath = xrayConfigPath();
xrayEnsureConfigDir();
$port = (int)$port;
if ($port <= 0 || $port > 65535) {
$port = 443;
}
$network = strtolower($network);
if (!in_array($network, ['xhttp', 'ws', 'grpc', 'tcp'], true)) {
$network = 'xhttp';
}
$apiInbound = [
'tag' => 'api',
'port' => 1080,
'protocol' => 'dokodemo-door',
'settings' => [
'address' => '127.0.0.1',
],
'listen' => '127.0.0.1',
];
$streamSettings = [
'network' => $network,
];
if ($network === 'xhttp') {
$streamSettings['security'] = 'tls';
$streamSettings['tlsSettings'] = [
'certificates' => [[
'certificateFile' => '/opt/DragonCore/ssl/fullchain.pem',
'keyFile' => '/opt/DragonCore/ssl/privkey.pem',
]],
'alpn' => ['http/1.1'],
];
$streamSettings['xhttpSettings'] = [
'headers' => null,
'host' => '',
'mode' => '',
'noSSEHeader' => false,
'path' => '/',
'scMaxBufferedPosts' => 30,
'scMaxEachPostBytes' => '1000000',
'scStreamUpServerSecs' => '20-80',
'xPaddingBytes' => '100-1000',
];
} elseif ($network === 'ws') {
$streamSettings['security'] = 'none';
$streamSettings['wsSettings'] = [
'acceptProxyProtocol' => false,
'headers' => (object)[],
'heartbeatPeriod' => 0,
'host' => '',
'path' => '/',
];
} elseif ($network === 'grpc') {
$streamSettings['security'] = 'none';
$streamSettings['grpcSettings'] = [
'serviceName' => 'vlessgrpc',
'multiMode' => false,
'idle_timeout' => 60,
'permit_without_stream' => false,
];
} else {
$streamSettings['security'] = 'none';
}
$dragonInbound = [
'tag' => 'inbound-dragoncore',
'port' => $port,
'protocol' => 'vless',
'settings' => [
'clients' => [],
'decryption' => 'none',
'fallbacks' => [],
],
'streamSettings' => $streamSettings,
];
$config = [
'api' => [
'services' => [
'HandlerService',
'LoggerService',
'StatsService',
],
'tag' => 'api',
],
'burstObservatory' => null,
'dns' => null,
'fakedns' => null,
'inbounds' => [
$apiInbound,
$dragonInbound,
],
'log' => [
'access' => '/var/log/v2ray/access.log',
'dnsLog' => false,
'error' => '',
'loglevel' => 'info',
'maskAddress' => '',
],
'observatory' => null,
'outbounds' => [
[
'protocol' => 'freedom',
'settings' => (object)[],
'tag' => 'direct',
],
[
'protocol' => 'blackhole',
'settings' => (object)[],
'tag' => 'blocked',
],
],
'policy' => [
'levels' => [
'0' => [
'statsUserDownlink' => true,
'statsUserUplink' => true,
],
],
'system' => [
'statsInboundDownlink' => true,
'statsInboundUplink' => true,
'statsOutboundDownlink' => false,
'statsOutboundUplink' => false,
],
],
'reverse' => null,
'routing' => [
'domainStrategy' => 'AsIs',
'rules' => [
[
'inboundTag' => ['api'],
'outboundTag' => 'api',
'type' => 'field',
],
[
'ip' => ['geoip:private'],
'outboundTag' => 'blocked',
'type' => 'field',
],
[
'outboundTag' => 'blocked',
'protocol' => ['bittorrent'],
'type' => 'field',
],
],
],
'stats' => (object)[],
'transport' => null,
];
file_put_contents(
$configPath,
json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
);
@shell_exec('systemctl restart xray');
echo "Config Xray gerado em {$configPath} (porta {$port}, protocolo {$network})\n";
}
function xrayFixEmptyObjects(array &$config): void
{
if (isset($config['stats']) && is_array($config['stats']) && empty($config['stats'])) {
$config['stats'] = (object)[];
}
if (isset($config['outbounds']) && is_array($config['outbounds'])) {
foreach ($config['outbounds'] as &$out) {
if (isset($out['settings']) && is_array($out['settings']) && empty($out['settings'])) {
$out['settings'] = (object)[];
}
}
unset($out);
}
}
function xrayAddUser(string $nick, string $protocol = 'xhttp')
{
global $db_user, $db_pass;
$uuid = xrayUuid();
$expiry = date('Y-m-d', strtotime('+30 days'));
$configPath = xrayConfigPath();
if (!file_exists($configPath)) {
echo "Arquivo de configuracao {$configPath} nao encontrado. Gere o config Xray primeiro.\n";
return;
}
$config = json_decode(file_get_contents($configPath), true);
if (!is_array($config)) {
echo "Falha ao ler/decodificar {$configPath}.\n";
return;
}
$inboundIndex = null;
if (isset($config['inbounds']) && is_array($config['inbounds'])) {
foreach ($config['inbounds'] as $idx => $in) {
if (isset($in['tag']) && $in['tag'] === 'inbound-dragoncore') {
$inboundIndex = $idx;
break;
}
}
}
if ($inboundIndex === null) {
echo "Inbound 'inbound-dragoncore' nao encontrado no config Xray.\n";
return;
}
if (
!isset($config['inbounds'][$inboundIndex]['settings']['clients']) ||
!is_array($config['inbounds'][$inboundIndex]['settings']['clients'])
) {
$config['inbounds'][$inboundIndex]['settings']['clients'] = [];
}
$client = [
'id' => $uuid,
'email' => $nick,
'level' => 0,
];
$config['inbounds'][$inboundIndex]['settings']['clients'][] = $client;
xrayFixEmptyObjects($config);
file_put_contents(
$configPath,
json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
);
$conn = pg_connect("host=localhost dbname=dragoncore user={$db_user} password={$db_pass}");
if ($conn) {
$query = "INSERT INTO xray (uuid, nick, expiry, protocol) VALUES ($1,$2,$3,$4)";
$stmt = pg_prepare($conn, '', $query);
pg_execute($conn, '', [$uuid, $nick, $expiry, $protocol]);
pg_close($conn);
}
@shell_exec('systemctl restart xray');
$domain = trim((string)shell_exec('hostname -I | awk "{print $1}"'));
if ($domain === '') {
$domain = '127.0.0.1';
}
$port = $config['inbounds'][$inboundIndex]['port'];
$uri = "vless://{$uuid}@{$domain}:{$port}#{$nick}";
echo "UUID Criado: {$uuid}\n{$uri}\n";
}
function xrayRemoveUser($identifier)
{
global $db_user, $db_pass;
$uuid = null;
if (is_numeric($identifier)) {
$conn = pg_connect("host=localhost dbname=dragoncore user={$db_user} password={$db_pass}");
if ($conn) {
$res = pg_query_params($conn, 'SELECT uuid FROM xray WHERE id = $1', [$identifier]);
if ($res && ($row = pg_fetch_assoc($res))) {
$uuid = $row['uuid'];
}
pg_close($conn);
}
} else {
$uuid = $identifier;
}
if (!$uuid) {
echo "UUID nao encontrado\n";
return;
}
$configPath = xrayConfigPath();
if (file_exists($configPath)) {
$config = json_decode(file_get_contents($configPath), true);
if (isset($config['inbounds']) && is_array($config['inbounds'])) {
$inboundIndex = null;
foreach ($config['inbounds'] as $idx => $in) {
if (isset($in['tag']) && $in['tag'] === 'inbound-dragoncore') {
$inboundIndex = $idx;
break;
}
}
if (
$inboundIndex !== null &&
isset($config['inbounds'][$inboundIndex]['settings']['clients']) &&
is_array($config['inbounds'][$inboundIndex]['settings']['clients'])
) {
$clients = &$config['inbounds'][$inboundIndex]['settings']['clients'];
foreach ($clients as $index => $cli) {
if (isset($cli['id']) && $cli['id'] === $uuid) {
array_splice($clients, $index, 1);
break;
}
}
xrayFixEmptyObjects($config);
file_put_contents(
$configPath,
json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
);
}
}
}
$conn = pg_connect("host=localhost dbname=dragoncore user={$db_user} password={$db_pass}");
if ($conn) {
pg_query_params($conn, 'DELETE FROM xray WHERE uuid = $1', [$uuid]);
pg_close($conn);
}
@shell_exec('systemctl restart xray');
echo "Usuario removido: {$uuid}\n";
}
function xrayListUsers()
{
global $db_user, $db_pass;
$conn = pg_connect("host=localhost dbname=dragoncore user={$db_user} password={$db_pass}");
if (!$conn) {
echo "Falha ao conectar ao banco de dados\n";
return;
}
$res = pg_query($conn, 'SELECT id, uuid, nick, expiry, protocol FROM xray ORDER BY id');
while ($row = pg_fetch_assoc($res)) {
echo "ID: {$row['id']} | NICK: {$row['nick']} | UUID: {$row['uuid']} | EXPIRA: {$row['expiry']} | PROTO: {$row['protocol']}\n";
}
pg_close($conn);
}
function xrayCert(string $domain)
{
$sslDir = '/opt/DragonCore/ssl';
$keyFile = $sslDir . '/privkey.pem';
$crtFile = $sslDir . '/fullchain.pem';
if (!is_dir($sslDir)) {
mkdir($sslDir, 0700, true);
}
$subject = '/C=BR/ST=SP/L=SaoPaulo/O=DragonCore/OU=VPN/CN=' . $domain;
$cmd = 'openssl req -x509 -nodes -newkey rsa:2048 '
. '-days 9999 '
. '-subj ' . escapeshellarg($subject) . ' '
. '-keyout ' . escapeshellarg($keyFile) . ' '
. '-out ' . escapeshellarg($crtFile) . ' 2>/dev/null';
@shell_exec($cmd);
if (file_exists($keyFile) && file_exists($crtFile)) {
echo "Certificado TLS autoassinado (9999 dias) gerado para {$domain}\n";
} else {
echo "Falha ao gerar certificado autoassinado para {$domain}\n";
}
}
function xrayPurgeExpired()
{
global $db_user, $db_pass;
$today = date('Y-m-d');
$conn = pg_connect("host=localhost dbname=dragoncore user={$db_user} password={$db_pass}");
if ($conn) {
$res = pg_query_params($conn, 'SELECT uuid FROM xray WHERE expiry < $1', [$today]);
while ($row = pg_fetch_assoc($res)) {
xrayRemoveUser($row['uuid']);
}
pg_close($conn);
}
}
function xrayInfo()
{
$binary = isXrayInstalled() ? '/usr/local/bin/xray' : 'xray';
$version = trim((string)shell_exec($binary . ' -version 2>&1'));
global $db_user, $db_pass;
$conn = pg_connect("host=localhost dbname=dragoncore user={$db_user} password={$db_pass}");
$count = 0;
$protocols = [];
if ($conn) {
$res = pg_query($conn, 'SELECT COUNT(*) AS c FROM xray');
if ($row = pg_fetch_assoc($res)) {
$count = $row['c'];
}
$res2 = pg_query($conn, 'SELECT DISTINCT protocol FROM xray');
while ($r = pg_fetch_assoc($res2)) {
$protocols[] = $r['protocol'];
}
pg_close($conn);
}
echo "Xray Versao: {$version}\n";
echo "Usuarios cadastrados: {$count}\n";
echo "Protocolos em uso: " . implode(', ', $protocols) . "\n";
}