Compare commits

...

12 Commits

Author SHA1 Message Date
mercury 49d0827b9e update version 2025-01-18 23:39:39 +04:00
mercury 07e04c384a Merge branch 'dev' of github.com:mercurykd/vpnbot into dev 2025-01-18 23:33:29 +04:00
mercury 579457b4f4 show xray stats 2025-01-18 23:33:00 +04:00
mercury 3dac9416ca fix download mihomo template 2025-01-18 23:32:31 +04:00
mercury 5b4d3b5627 reality degenerate pattern improve 2025-01-18 23:31:58 +04:00
mercury 658e125cd8 show group id 2025-01-18 23:31:01 +04:00
Konstantin 1840555573 Merge pull request #33 from legiz-ru/dev
update singbox 1.10.7 windows x64
2025-01-18 18:23:20 +04:00
legiz-ru ecdc028226 update singbox 1.10.7 windows x64 2025-01-18 16:57:39 +03:00
mercury d432bf82f2 force inclusion of xray statistics 2025-01-16 01:04:33 +04:00
mercury 211e2c079d collect xray metrics 2025-01-13 15:32:54 +04:00
Konstantin 1696c4da7b Merge pull request #32 from legiz-ru/dev
v2ray(xray) client templates update
2025-01-12 02:23:56 +04:00
legiz-ru b8d5700eba v2ray(xray) client update
return warp+block domain routes
replace rule for directing
2025-01-12 01:17:23 +03:00
5 changed files with 291 additions and 105 deletions
+141 -23
View File
@@ -238,6 +238,7 @@ class Bot
break;
case preg_match('~^/id$~', $this->input['message'], $m):
$this->send($this->input['chat'], $this->input['from'], $this->input['message_id']);
$this->send($this->input['chat'], $this->input['chat'], $this->input['message_id']);
break;
case preg_match('~^/adguardChBr$~', $this->input['callback'], $m):
$this->adguardChBr();
@@ -296,7 +297,7 @@ class Bot
case preg_match('~^/delLog (?P<arg>\d+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m):
$this->delLog(...explode('_', $m['arg']));
break;
case preg_match('~^/debug$~', $this->input['callback'], $m):
case preg_match('~^/debug$~', $this->input['message'], $m):
$this->debug();
break;
case preg_match('~^/backup$~', $this->input['callback'], $m):
@@ -667,13 +668,73 @@ class Bot
}
}
public function restartXray($c)
public function restartXray($c, $norestart = false)
{
$c['inbounds'][0]['settings']['clients'] = array_values($c['inbounds'][0]['settings']['clients']);
$c['log']['access'] = '/logs/xray';
$this->ssh('pkill xray', 'xr');
file_put_contents('/config/xray.json', json_encode($c, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$this->ssh('xray run -config /xray.json > /dev/null 2>&1 &', 'xr');
foreach ($c['inbounds'] as $v) {
if ($v['tag'] == 'api') {
$inbound = true;
break;
}
}
if (empty($inbound)) {
$c['inbounds'][] = [
"listen" => "127.0.0.1",
"port" => 8080,
"protocol" => "dokodemo-door",
"settings" => [
"address" => "127.0.0.1"
],
"tag" => "api"
];
}
foreach ($c['routing']['rules'] as $v) {
if ($v['outboundTag'] == 'api') {
$rule = true;
break;
}
}
if (empty($rule)) {
$c['routing']['rules'][] = [
"inboundTag" => ["api"],
"outboundTag" => "api",
"type" => "field"
];
}
$c['stats'] = new stdClass();
$c['api'] = [
'services' => ['StatsService'],
'tag' => 'api'
];
$l = new stdClass();
$l->{'0'} = [
"statsUserUplink" => true,
"statsUserDownlink" => true
];
$c['policy']['levels'] = $l;
$c['policy']['system'] = [
"statsInboundUplink" => true,
"statsInboundDownlink" => true,
"statsOutboundUplink" => true,
"statsOutboundDownlink" => true
];
if (empty($norestart)) {
$c = $this->collectSession($c);
file_put_contents('/config/xray.json', json_encode($c, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$this->ssh('pkill xray', 'xr');
$this->ssh('xray run -config /xray.json > /dev/null 2>&1 &', 'xr');
} else {
file_put_contents('/config/xray.json', json_encode($c, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
}
}
public function collectSession($c) {
foreach ($c['inbounds'][0]['settings']['clients'] as $k => $v) {
$c['inbounds'][0]['settings']['clients'][$k]['global']['download'] += $v['session']['download'];
$c['inbounds'][0]['settings']['clients'][$k]['global']['upload'] += $v['session']['upload'];
}
return $c;
}
public function linkMtproto()
@@ -1251,10 +1312,30 @@ class Bot
$this->checkBackup($period);
$this->checkCert();
$this->autoAnalyzeLogs();
$this->xrayStatsUser();
sleep($period);
}
}
public function xrayStatsUser()
{
try {
$x = $this->getXray();
if (!empty($users = $x['inbounds'][0]['settings']['clients'])) {
foreach ($users as $k => $v) {
$d = json_decode($this->ssh('xray api stats --server=127.0.0.1:8080 -name "user>>>' . $v['email'] . '>>>traffic>>>downlink" 2>&1', 'xr'), true)['stat']['value'] ?: 0;
$u = json_decode($this->ssh('xray api stats --server=127.0.0.1:8080 -name "user>>>' . $v['email'] . '>>>traffic>>>uplink" 2>&1', 'xr'), true)['stat']['value'] ?: 0;
$x['inbounds'][0]['settings']['clients'][$k]['session'] = [
'download' => $d,
'upload' => $u,
];
}
$this->restartXray($x, norestart: 1);
}
} catch (\Throwable $th) {
}
}
public function autoAnalyzeLogs()
{
try {
@@ -4426,7 +4507,6 @@ DNS-over-HTTPS with IP:
}
$t = [
$this->suspicious('~\d+\.\d+\.\d+\.\d+.+200\s\d+\s0$~', '/logs/upstream_access', $xr, 'possibly a Reality Degenerate'),
$this->suspicious($this->reg, '/logs/nginx_default_access', $xr, 'possibly a scanner', true),
$this->suspicious($this->reg, '/logs/nginx_domain_access', $xr, 'possibly a scanner', true),
];
@@ -4438,6 +4518,15 @@ DNS-over-HTTPS with IP:
}
}
$r = $this->suspicious('~\d+\.\d+\.\d+\.\d+.+200\s\d+\s0$~', '/logs/upstream_access', $xr, 'possibly a Reality Degenerate');
if (!empty($r)) {
foreach ($r as $k => $v) {
if (count($v) > 30) {
$ip[$k] = $v;
}
}
}
if (!empty($return)) {
return $ip;
}
@@ -5137,15 +5226,15 @@ DNS-over-HTTPS with IP:
public function setTimerXr($time, $i)
{
$time = strtotime($time);
if ($time === false) {
$this->send($this->input['chat'], 'wrong format');
return;
}
$c = $this->getXray();
if (empty($time)) {
unset($c['inbounds'][0]['settings']['clients'][$i]['time']);
} else {
$time = strtotime($time);
if ($time === false) {
$this->send($this->input['chat'], 'wrong format');
return;
}
if (!empty($c['inbounds'][0]['settings']['clients'][$i]['off'])) {
$this->switchXr($i, 1);
$c = $this->getXray();
@@ -5314,14 +5403,7 @@ DNS-over-HTTPS with IP:
public function downloadOrigin($type)
{
switch ($type) {
case 'sing':
$f = new \CURLFile('/config/sing.json', 'application/json', 'origin.json');
break;
case 'v2ray':
$f = new \CURLFile('/config/v2ray.json', 'application/json', 'origin.json');
break;
}
$f = new \CURLFile("/config/$type.json", 'application/json', 'origin.json');
$this->sendFile($this->input['chat'], $f);
}
@@ -5456,6 +5538,25 @@ DNS-over-HTTPS with IP:
$this->xray();
}
public function getBytes($bytes)
{
$t = [
'B',
'KB',
'MB',
'GB',
'TB',
];
foreach ($t as $k => $v) {
if ($k == 0) {
continue;
}
if ($bytes / (1024 ** $k) < 1) {
return round($bytes / (1024 ** ($k - 1)), 2) . " {$t[$k - 1]}";
}
}
}
public function xray($page = 0)
{
if (!$this->ssh('pgrep xray', 'xr')) {
@@ -5538,10 +5639,12 @@ DNS-over-HTTPS with IP:
$page = $page == -2 ? $all - 1 : $page;
$clients = $page != -1 ? array_slice($clients, $page * $this->limit, $this->limit, true) : $clients;
foreach ($clients as $k => $v) {
$time = $v['time'] ? $this->getTime($v['time']) : '';
$data[] = [
$download = $this->getBytes($v['global']['download'] + $v['session']['download']);
$upload = $this->getBytes($v['global']['upload'] + $v['session']['upload']);
$time = $v['time'] ? $this->getTime($v['time']) : '';
$data[] = [
[
'text' => "{$v['email']}" . ($time ? ": $time" : ''),
'text' => "{$v['email']}" . ($time ? ": $time" : '') . " (↓$download$upload)",
'callback_data' => "/userXr $k",
],
];
@@ -6919,6 +7022,7 @@ DNS-over-HTTPS with IP:
$text[] = 'Settings -> Ports';
$f = '/docker/compose';
$c = yaml_parse_file($f)['services'];
$pac = $this->getPacConf();
$data = [
[[
'text' => $this->i18n($c['wg'] ? 'on' : 'off') . ' ' . getenv('WGPORT') . ' Wireguard',
@@ -6941,6 +7045,14 @@ DNS-over-HTTPS with IP:
'callback_data' => "/hidePort ss",
]],
];
if (!empty($pac['restart'])) {
$data[] = [
[
'text' => $this->i18n('restart'),
'callback_data' => "/restart",
],
];
}
$data[] = [
[
'text' => $this->i18n('back'),
@@ -6976,7 +7088,10 @@ DNS-over-HTTPS with IP:
} else {
yaml_emit_file($f, $c);
}
$this->restart();
$pac = $this->getPacConf();
$pac['restart'] = 1;
$this->setPacConf($pac);
$this->ports();
}
public function branches()
@@ -7113,6 +7228,9 @@ DNS-over-HTTPS with IP:
}
file_put_contents('/update/message', '');
file_put_contents('/update/reload_message', '');
$pac = $this->getPacConf();
unset($pac['restart']);
$this->setPacConf($pac);
}
public function backup()
+106 -81
View File
@@ -4,92 +4,117 @@
"error": "",
"loglevel": "warning"
},
"inbounds": [{
"tag": "socks",
"port": 10808,
"listen": "127.0.0.1",
"protocol": "socks",
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"],
"routeOnly": false
},
"settings": {
"auth": "noauth",
"udp": true,
"allowTransparent": false
}
}, {
"tag": "http",
"port": 10809,
"listen": "127.0.0.1",
"protocol": "http",
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"],
"routeOnly": false
},
"settings": {
"auth": "noauth",
"udp": true,
"allowTransparent": false
}
}],
"outbounds": [{
"tag": "~outbound~",
"protocol": "vless",
"settings": {
"vnext": [{
"address": "~domain~",
"port": 443,
"users": [{
"id": "~uid~",
"alterId": 0,
"email": "t@t.tt",
"security": "auto",
"encryption": "none",
"flow": "xtls-rprx-vision"
}]
}]
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"serverName": "~server_name~",
"fingerprint": "chrome",
"show": false,
"publicKey": "~public_key~",
"shortId": "~short_id~",
"spiderX": ""
"inbounds": [
{
"tag": "socks",
"port": 10808,
"listen": "127.0.0.1",
"protocol": "socks",
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
],
"routeOnly": false
},
"settings": {
"auth": "noauth",
"udp": true,
"allowTransparent": false
}
},
"mux": {
"enabled": false,
"concurrency": -1
}
}, {
"tag": "direct",
"protocol": "freedom"
}, {
"tag": "block",
"protocol": "blackhole",
"settings": {
"response": {
"type": "http"
{
"tag": "http",
"port": 10809,
"listen": "127.0.0.1",
"protocol": "http",
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
],
"routeOnly": false
},
"settings": {
"auth": "noauth",
"udp": true,
"allowTransparent": false
}
}
}],
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "~outbound~",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "~domain~",
"port": 443,
"users": [
{
"id": "~uid~",
"alterId": 0,
"email": "t@t.tt",
"security": "auto",
"encryption": "none",
"flow": "xtls-rprx-vision"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"serverName": "~server_name~",
"fingerprint": "chrome",
"show": false,
"publicKey": "~public_key~",
"shortId": "~short_id~",
"spiderX": ""
}
},
"mux": {
"enabled": false,
"concurrency": -1
}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {
"response": {
"type": "http"
}
}
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [{
"type": "field",
"outboundTag": "~outbound~",
"domain": "~pac~"
}, {
"type": "field",
"port": "0-65535",
"outboundTag": "direct"
}]
"rules": [
{
"type": "field",
"outboundTag": "block",
"domain": "~block~"
},
{
"type": "field",
"outboundTag": "~outbound~",
"domain": "~pac~"
},
{
"type": "field",
"outboundTag": "~outbound~",
"domain": "~warp~"
}
]
}
}
+39 -1
View File
@@ -22,6 +22,15 @@
}
},
"tag": "vless_tls"
},
{
"listen": "127.0.0.1",
"port": 8080,
"protocol": "dokodemo-door",
"settings": {
"address": "127.0.0.1"
},
"tag": "api"
}
],
"log": {
@@ -40,6 +49,35 @@
],
"routing": {
"domainStrategy": "AsIs",
"rules": []
"rules": [
{
"inboundTag": [
"api"
],
"outboundTag": "api",
"type": "field"
}
]
},
"stats": {},
"api": {
"services": [
"StatsService"
],
"tag": "api"
},
"policy": {
"levels": {
"0": {
"statsUserUplink": true,
"statsUserDownlink": true
}
},
"system": {
"statsInboundUplink": true,
"statsInboundDownlink": true,
"statsOutboundUplink": true,
"statsOutboundDownlink": true
}
}
}
Binary file not shown.
+5
View File
@@ -1,3 +1,8 @@
18.01.2025 v2.5
- фикс скачивания шаблона михомо
- обновлен singbox.exe
- вывод статистики vless пользователей
- смягчил паттерн поиска reality degenerate в логах
07.01.2025 v2.4
- вернул shadowsocks (спасибо за донат)
04.01.2025