Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ba7ddedee | |||
| 19ef567873 | |||
| 4f4e36e1cb | |||
| 6267931475 | |||
| 7e2d90e7da | |||
| 28906176f5 | |||
| 968d72ce81 | |||
| 66e204e5ba | |||
| 36e8acd2aa | |||
| cdc20adccd | |||
| 8ad00bc47a | |||
| 4902eb53ce | |||
| 253cceb44c | |||
| 9d53f2896c | |||
| 550a8ad3b7 | |||
| e2f84b0ee7 | |||
| b394e769c6 | |||
| 7d8dc1dd2d | |||
| 34b1de5132 | |||
| 12b5d84afc | |||
| c3d90ada83 | |||
| dbe3f290ea | |||
| b56b48e080 | |||
| 21b7a4816f |
+4
-1
@@ -22,4 +22,7 @@ update/*
|
||||
override.env
|
||||
override.html
|
||||
override.php
|
||||
docker-compose.override.yml
|
||||
docker-compose.override.yml
|
||||
backup.json
|
||||
app/webapp/override/
|
||||
.rest
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/timezone.php';
|
||||
|
||||
require __DIR__ . '/bot.php';
|
||||
require __DIR__ . '/config.php';
|
||||
require __DIR__ . '/i18n.php';
|
||||
if ($c['debug']) {
|
||||
require __DIR__ . '/debug.php';
|
||||
}
|
||||
|
||||
$bot = new Bot($c['key'], $i);
|
||||
echo $bot->export();
|
||||
+418
-185
@@ -37,7 +37,7 @@ class Bot
|
||||
'xray',
|
||||
];
|
||||
$this->reg = '~' . implode('|', [
|
||||
'GET /ws(?:.+)? HTTP',
|
||||
'GET /ws HTTP',
|
||||
'GET /adguard/(?:.+)? HTTP',
|
||||
'GET /webapp(?:.+)? HTTP',
|
||||
'GET /pac(?:.+)? HTTP',
|
||||
@@ -163,6 +163,12 @@ class Bot
|
||||
case preg_match('~^/mirror$~', $this->input['message'], $m):
|
||||
$this->menu('mirror');
|
||||
break;
|
||||
case preg_match('~^/mainOutbound$~', $this->input['callback'], $m):
|
||||
$this->mainOutbound();
|
||||
break;
|
||||
case preg_match('~^/importIps (.+)$~', $this->input['callback'], $m):
|
||||
$this->importIps($m[1]);
|
||||
break;
|
||||
case preg_match('~^/switchBanIp$~', $this->input['callback'], $m):
|
||||
$this->switchBanIp();
|
||||
break;
|
||||
@@ -202,7 +208,7 @@ class Bot
|
||||
case preg_match('~^/cleanLogs (.+?)(?:\s(1))?$~', $this->input['callback'], $m):
|
||||
$this->cleanLogs($m[1], $m[2]);
|
||||
break;
|
||||
case preg_match('~^/allowIp (\d+\.\d+\.\d+\.\d+) (\d+)(?:\s(\d+))?$~', $this->input['callback'], $m):
|
||||
case preg_match('~^/allowIp (.+?) (\d+)(?:\s(\d+))?$~', $this->input['callback'], $m):
|
||||
$this->allowIp($m[1], $m[2], $m[3]);
|
||||
break;
|
||||
case preg_match('~^/searchIp (.+)$~', $this->input['callback'], $m):
|
||||
@@ -319,13 +325,13 @@ class Bot
|
||||
case preg_match('~^/defaultMTU (?P<arg>\d+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m):
|
||||
$this->defaultMTU(...explode('_', $m['arg']));
|
||||
break;
|
||||
case preg_match('~^/subnet (?P<arg>-?\d+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m):
|
||||
case preg_match('~^/subnet (?P<arg>-?\d+(?:_-?\d+)?(?:_\d)?)$~', $this->input['callback'], $m):
|
||||
$this->subnet(...explode('_', $m['arg']));
|
||||
break;
|
||||
case preg_match('~^/subnetAdd (?P<arg>-?\d+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m):
|
||||
case preg_match('~^/subnetAdd (?P<arg>-?\d+(?:_-?\d+)?(?:_-?\d+)?)$~', $this->input['callback'], $m):
|
||||
$this->subnetAdd(...explode('_', $m['arg']));
|
||||
break;
|
||||
case preg_match('~^/subnetDelete (?P<arg>-?\d+(?:_-?\d+)?(?:_-?\d+)?)$~', $this->input['callback'], $m):
|
||||
case preg_match('~^/subnetDelete (?P<arg>-?\d+(?:_-?\d+)?(?:_-?\d+)?(?:_-?\d+)?)$~', $this->input['callback'], $m):
|
||||
$this->subnetDelete(...explode('_', $m['arg']));
|
||||
break;
|
||||
case preg_match('~^/addSubnets (?P<arg>-?\d+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m):
|
||||
@@ -1186,10 +1192,10 @@ class Bot
|
||||
try {
|
||||
$pac = $this->getPacConf();
|
||||
if (!empty($pac['autoscan'])) {
|
||||
$r = $this->analysisIp(return: 1);
|
||||
require __DIR__ . '/config.php';
|
||||
if (!empty($c['admin']) && (empty($this->time3) || ((time() - $this->time3) > $pac['autoscan_timeout']))) {
|
||||
$this->time3 = time();
|
||||
$r = $this->analysisIp(return: 1);
|
||||
if (!empty($r)) {
|
||||
foreach ($r as $k => $v) {
|
||||
foreach ($v as $i) {
|
||||
@@ -1223,6 +1229,7 @@ class Bot
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
file_put_contents('/logs/php_error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3105,7 +3112,7 @@ DNS-over-HTTPS with IP:
|
||||
$this->menu('client', "{$client}_$page");
|
||||
}
|
||||
|
||||
public function subnetAdd($wgpage, $page)
|
||||
public function subnetAdd($wgpage, $page, $openconnect)
|
||||
{
|
||||
$r = $this->send(
|
||||
$this->input['chat'],
|
||||
@@ -3117,12 +3124,15 @@ DNS-over-HTTPS with IP:
|
||||
'start_message' => $this->input['message_id'],
|
||||
'start_callback' => $this->input['callback_id'],
|
||||
'callback' => 'subnetSave',
|
||||
'args' => [$wgpage, $page],
|
||||
'args' => [$wgpage, $page, $openconnect],
|
||||
];
|
||||
}
|
||||
|
||||
public function subnetSave($text, $wgpage, $page)
|
||||
public function subnetSave($text, $wgpage, $page, $openconnect)
|
||||
{
|
||||
if (!preg_match('~^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2}$~', $text)) {
|
||||
return $this->send($this->input['chat'], "wrong format: $text", $this->input['message_id']);
|
||||
}
|
||||
$c = $this->getPacConf();
|
||||
$subnets = explode(',', $text);
|
||||
if ($subnets) {
|
||||
@@ -3130,15 +3140,42 @@ DNS-over-HTTPS with IP:
|
||||
$this->setPacConf($c);
|
||||
$page = floor(count($c['subnets']) / $this->limit);
|
||||
}
|
||||
$this->subnet($wgpage, $page);
|
||||
if (!empty($openconnect)) {
|
||||
$this->ocservRoute();
|
||||
}
|
||||
$this->subnet($wgpage, $page, $openconnect);
|
||||
}
|
||||
|
||||
public function subnetDelete($wgpage, $k, $page = 0)
|
||||
public function subnetDelete($wgpage, $k, $page = 0, $openconnect = 0)
|
||||
{
|
||||
$c = $this->getPacConf();
|
||||
unset($c['subnets'][$k]);
|
||||
$this->setPacConf($c);
|
||||
$this->subnet($wgpage, $page);
|
||||
if (!empty($openconnect)) {
|
||||
$this->ocservRoute();
|
||||
}
|
||||
$this->subnet($wgpage, $page, $openconnect);
|
||||
}
|
||||
|
||||
public function ocservRoute()
|
||||
{
|
||||
$p = $this->getPacConf();
|
||||
$c = file_get_contents('/config/ocserv.conf');
|
||||
$t = preg_replace('~^route[^\n]+~sm', '', $c);
|
||||
if (!empty($p['subnets'])) {
|
||||
foreach ($p['subnets'] as $v) {
|
||||
if (preg_match('~^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2}~', $v)) {
|
||||
$t .= "route = $v";
|
||||
$flag = true;
|
||||
}
|
||||
}
|
||||
if (empty($flag)) {
|
||||
$t .= 'route = default';
|
||||
}
|
||||
} else {
|
||||
$t .= 'route = default';
|
||||
}
|
||||
$this->restartOcserv($t);
|
||||
}
|
||||
|
||||
public function calc()
|
||||
@@ -3194,10 +3231,10 @@ DNS-over-HTTPS with IP:
|
||||
}
|
||||
}
|
||||
|
||||
public function subnet($wgpage = 0, $page = 0, $count = 5)
|
||||
public function subnet($wgpage = 0, $page = 0, $openconnect = 0)
|
||||
{
|
||||
$count = $this->limit;
|
||||
$text = "Menu -> Wireguard -> " . $this->i18n('listSubnet') . "\n";
|
||||
$text = 'Menu -> ' . ($openconnect ? 'Openconnect' : 'Wireguard') . ' -> ' . $this->i18n('listSubnet') . "\n";
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('calc'),
|
||||
@@ -3207,7 +3244,7 @@ DNS-over-HTTPS with IP:
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('add'),
|
||||
'callback_data' => "/subnetAdd {$wgpage}_$page",
|
||||
'callback_data' => "/subnetAdd {$wgpage}_{$page}_$openconnect",
|
||||
],
|
||||
];
|
||||
$subnets = $this->getPacConf()['subnets'];
|
||||
@@ -3220,7 +3257,7 @@ DNS-over-HTTPS with IP:
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('delete') . " $v",
|
||||
'callback_data' => "/subnetDelete {$wgpage}_{$k}_$page",
|
||||
'callback_data' => "/subnetDelete {$wgpage}_{$k}_{$page}_$openconnect",
|
||||
],
|
||||
];
|
||||
}
|
||||
@@ -3228,11 +3265,11 @@ DNS-over-HTTPS with IP:
|
||||
$data[] = [
|
||||
[
|
||||
'text' => '<<',
|
||||
'callback_data' => "/subnet {$wgpage}_" . ($page - 1 >= 0 ? $page - 1 : $all - 1),
|
||||
'callback_data' => "/subnet {$wgpage}_" . ($page - 1 >= 0 ? $page - 1 : $all - 1) . ($openconnect ? '_1' : ''),
|
||||
],
|
||||
[
|
||||
'text' => '>>',
|
||||
'callback_data' => "/subnet {$wgpage}_" . ($page < $all - 1 ? $page + 1 : 0),
|
||||
'callback_data' => "/subnet {$wgpage}_" . ($page < $all - 1 ? $page + 1 : 0) . ($openconnect ? '_1' : ''),
|
||||
]
|
||||
];
|
||||
}
|
||||
@@ -3240,7 +3277,7 @@ DNS-over-HTTPS with IP:
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('back'),
|
||||
'callback_data' => "/menu wg $wgpage",
|
||||
'callback_data' => $openconnect ? '/menu oc' : "/menu wg $wgpage",
|
||||
],
|
||||
];
|
||||
$this->update(
|
||||
@@ -3791,12 +3828,6 @@ DNS-over-HTTPS with IP:
|
||||
$p = $this->getPacConf();
|
||||
$text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> proxy list';
|
||||
[$data] = $this->listPac('includelist', $page, 'xtlsproxy');
|
||||
$data[] = [
|
||||
[
|
||||
'text' => 'set to ' . ($p['domains_outbound'] ? 'proxy' : 'direct'),
|
||||
'callback_data' => "/domainsOutbound",
|
||||
],
|
||||
];
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('back'),
|
||||
@@ -3849,12 +3880,6 @@ DNS-over-HTTPS with IP:
|
||||
|
||||
[$data] = $this->listPac('packagelist', $page, 'xtlsapp');
|
||||
$p = $this->getPacConf();
|
||||
$data[] = [
|
||||
[
|
||||
'text' => 'set to ' . ($p['app_outbound'] ? 'proxy' : 'direct'),
|
||||
'callback_data' => "/appOutbound",
|
||||
],
|
||||
];
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('back'),
|
||||
@@ -3875,12 +3900,6 @@ DNS-over-HTTPS with IP:
|
||||
|
||||
[$data] = $this->listPac('processlist', $page, 'xtlsprocess');
|
||||
$p = $this->getPacConf();
|
||||
$data[] = [
|
||||
[
|
||||
'text' => 'set to ' . ($p['process_outbound'] ? 'proxy' : 'direct'),
|
||||
'callback_data' => "/processOutbound",
|
||||
],
|
||||
];
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('back'),
|
||||
@@ -4308,22 +4327,38 @@ DNS-over-HTTPS with IP:
|
||||
);
|
||||
}
|
||||
|
||||
public function suspicious($regexp, $file, $ip, $title, $reverse = false)
|
||||
public function ipInRange($ip, $range) {
|
||||
[$range, $netmask] = explode('/', $range, 2);
|
||||
$rangeDecimal = ip2long($range);
|
||||
$ipDecimal = ip2long($ip);
|
||||
$wildcardDecimal = pow(2, 32 - $netmask) - 1;
|
||||
$netmaskDecimal = ~$wildcardDecimal;
|
||||
return ($ipDecimal & $netmaskDecimal) == ($rangeDecimal & $netmaskDecimal);
|
||||
}
|
||||
|
||||
public function suspicious($regexp, $file, $ranges, $title, $reverse = false)
|
||||
{
|
||||
if ($r = fopen($file, 'r')) {
|
||||
while (feof($r) === false) {
|
||||
$l = fgets($r);
|
||||
if (preg_match('~(\d+\.\d+\.\d+\.\d+)~', $l, $m)) {
|
||||
if ($reverse xor preg_match($regexp, $l)) {
|
||||
if (is_array($ip)) {
|
||||
if (empty($ip[$m[1]])) {
|
||||
if (is_array($ranges)) {
|
||||
$flag = true;
|
||||
foreach ($ranges as $range) {
|
||||
if ($this->ipInRange($m[1], $range)) {
|
||||
$flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($flag) {
|
||||
$ret[$m[1]][] = [
|
||||
'title' => $title,
|
||||
'log' => $l,
|
||||
];
|
||||
}
|
||||
} else {
|
||||
if ($ip == $m[1]) {
|
||||
if ($this->ipInRange($m[1], $ranges)) {
|
||||
$ret[$m[1]][] = [
|
||||
'title' => $title,
|
||||
'log' => $l,
|
||||
@@ -4341,30 +4376,32 @@ DNS-over-HTTPS with IP:
|
||||
public function analysisIp(int $page = 0, $return = false)
|
||||
{
|
||||
$pac = $this->getPacConf();
|
||||
foreach (array_merge($pac['white'] ?: [], $pac['deny'] ?: [], [
|
||||
'10.10.0.1' ,'10.10.1.1' ,
|
||||
'10.10.0.2' ,'10.10.1.2' ,
|
||||
'10.10.0.3' ,'10.10.1.3' ,
|
||||
'10.10.0.4' ,'10.10.1.4' ,
|
||||
'10.10.0.5' ,'10.10.1.5' ,
|
||||
'10.10.0.6' ,'10.10.1.6' ,
|
||||
'10.10.0.7' ,'10.10.1.7' ,
|
||||
'10.10.0.8' ,'10.10.1.8' ,
|
||||
'10.10.0.9' ,'10.10.1.9' ,
|
||||
'10.10.0.10','10.10.1.10',
|
||||
'10.10.0.11','10.10.1.11',
|
||||
'10.10.0.12','10.10.1.12',
|
||||
'10.10.0.13','10.10.1.13',
|
||||
'10.10.0.14','10.10.1.14',
|
||||
'10.10.0.15','10.10.1.15',
|
||||
]) as $v) {
|
||||
$xr[$v] = true;
|
||||
$xr = [];
|
||||
foreach (array_merge($pac['white'] ?: [], $pac['deny'] ?: [], ['10.10.0.0/23']) as $v) {
|
||||
if (preg_match('~^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?:(/\d{1,2}))?$~', $v, $m)) {
|
||||
if (!in_array($m[1] . ($m[2] ?: '/32'), $xr)) {
|
||||
$xr[] = $m[1] . ($m[2] ?: '/32');
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($r = fopen('/logs/nginx_tlgrm_access', 'r')) {
|
||||
while (feof($r) === false) {
|
||||
$l = fgets($r);
|
||||
if (preg_match('~(\d+\.\d+\.\d+\.\d+)~', $l, $m)) {
|
||||
$xr[$m[1]] = true;
|
||||
if (!in_array("{$m[1]}/32", $xr)) {
|
||||
$xr[] = "{$m[1]}/32";
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose($r);
|
||||
}
|
||||
if ($r = fopen('/logs/nginx_doh_access', 'r')) {
|
||||
while (feof($r) === false) {
|
||||
$l = fgets($r);
|
||||
if (preg_match('~(\d+\.\d+\.\d+\.\d+)~', $l, $m)) {
|
||||
if (!in_array("{$m[1]}/32", $xr)) {
|
||||
$xr[] = "{$m[1]}/32";
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose($r);
|
||||
@@ -4373,7 +4410,9 @@ DNS-over-HTTPS with IP:
|
||||
while (feof($r) === false) {
|
||||
$l = fgets($r);
|
||||
if (preg_match('~(\d+\.\d+\.\d+\.\d+)(?=.+accepted)~', $l, $m)) {
|
||||
$xr[$m[1]] = true;
|
||||
if (!in_array("{$m[1]}/32", $xr)) {
|
||||
$xr[] = "{$m[1]}/32";
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose($r);
|
||||
@@ -4512,9 +4551,9 @@ DNS-over-HTTPS with IP:
|
||||
public function searchSuspiciousIp($ip)
|
||||
{
|
||||
$t = [
|
||||
$this->suspicious('~\d+\.\d+\.\d+\.\d+.+200\s\d+\s0$~', '/logs/upstream_access', $ip, 'possibly a Reality Degenerate'),
|
||||
$this->suspicious($this->reg, '/logs/nginx_default_access', $ip, 'possibly a scanner', true),
|
||||
$this->suspicious($this->reg, '/logs/nginx_domain_access', $ip, 'possibly a scanner', true),
|
||||
$this->suspicious('~\d+\.\d+\.\d+\.\d+.+200\s\d+\s0$~', '/logs/upstream_access', "$ip/32", 'possibly a Reality Degenerate'),
|
||||
$this->suspicious($this->reg, '/logs/nginx_default_access', "$ip/32", 'possibly a scanner', true),
|
||||
$this->suspicious($this->reg, '/logs/nginx_domain_access', "$ip/32", 'possibly a scanner', true),
|
||||
];
|
||||
foreach ($t as $r) {
|
||||
if (!empty($r)) {
|
||||
@@ -4543,6 +4582,33 @@ DNS-over-HTTPS with IP:
|
||||
}
|
||||
}
|
||||
|
||||
public function importIps($type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'telegram':
|
||||
$r = file_get_contents('https://core.telegram.org/resources/cidr.txt');
|
||||
if (!empty($r)) {
|
||||
$domains = explode("\n", $r);
|
||||
}
|
||||
break;
|
||||
case 'gcore':
|
||||
$r = json_decode(file_get_contents('https://api.gcore.com/cdn/public-ip-list'), true);
|
||||
if (!empty($r['addresses'])) {
|
||||
$domains = $r['addresses'];
|
||||
}
|
||||
break;
|
||||
case 'cloudflare':
|
||||
$r = json_decode(file_get_contents('https://api.cloudflare.com/client/v4/ips'), true);
|
||||
if (!empty($r['result']['ipv4_cidrs'])) {
|
||||
$domains = $r['result']['ipv4_cidrs'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!empty($domains = array_filter($domains ?: [], fn($e) => preg_match('~^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2}~', $e)))) {
|
||||
$this->addInclude(implode(',', $domains), 'white');
|
||||
}
|
||||
}
|
||||
|
||||
public function denyList($page = 0, $white = 0)
|
||||
{
|
||||
$text = 'Menu -> IP -> ' . ($white ? 'ignore' : 'block') . 'list';
|
||||
@@ -4551,6 +4617,26 @@ DNS-over-HTTPS with IP:
|
||||
$page = min($page, $all - 1);
|
||||
$page = $page < 0 ? $all - 1 : $page;
|
||||
|
||||
if (!empty($white)) {
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('telegram IPs'),
|
||||
'callback_data' => "/importIps telegram",
|
||||
],
|
||||
];
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('gcore IPs'),
|
||||
'callback_data' => "/importIps gcore",
|
||||
],
|
||||
];
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('cloudflare IPs'),
|
||||
'callback_data' => "/importIps cloudflare",
|
||||
],
|
||||
];
|
||||
}
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('add'),
|
||||
@@ -4696,8 +4782,10 @@ DNS-over-HTTPS with IP:
|
||||
}
|
||||
fclose($r);
|
||||
}
|
||||
foreach (array_keys($xr) as $v) {
|
||||
$text .= "allow $v;\n";
|
||||
if (!empty($xr)) {
|
||||
foreach (array_keys($xr) as $v) {
|
||||
$text .= "allow $v;\n";
|
||||
}
|
||||
}
|
||||
if (!empty($pac['white'])) {
|
||||
$pac['white'] = array_unique($pac['white']);
|
||||
@@ -4709,8 +4797,12 @@ DNS-over-HTTPS with IP:
|
||||
if (!empty($pac['deny'])) {
|
||||
$pac['deny'] = array_unique($pac['deny']);
|
||||
sort($pac['deny']);
|
||||
foreach ($pac['deny'] as $v) {
|
||||
$text .= "deny $v;\n";
|
||||
foreach ($pac['deny'] as $k => $v) {
|
||||
if (!in_array($v, $pac['white'] ?: []) && !in_array($v, array_keys($xr ?: []))) {
|
||||
$text .= "deny $v;\n";
|
||||
} else {
|
||||
unset($pac['deny'][$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->setPacConf($pac);
|
||||
@@ -4913,11 +5005,19 @@ DNS-over-HTTPS with IP:
|
||||
'text' => $this->i18n('change password'),
|
||||
'callback_data' => "/changeOcPass",
|
||||
],
|
||||
];
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('dns') . ": $dns",
|
||||
'callback_data' => "/changeOcDns",
|
||||
],
|
||||
];
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('listSubnet'),
|
||||
'callback_data' => "/subnet 0_0_1",
|
||||
],
|
||||
];
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('expose-iroutes') . ' ' . $this->i18n($expose ? 'on' : 'off'),
|
||||
@@ -5232,6 +5332,23 @@ DNS-over-HTTPS with IP:
|
||||
$domain = $this->getDomain();
|
||||
$hash = substr(md5($this->key), 0, 8);
|
||||
$text[] = "Menu -> " . $this->i18n('xray') . " -> $type templates";
|
||||
$text[] = <<<TEXT
|
||||
<code>~outbound~</code>
|
||||
<code>"~pac~"</code>
|
||||
<code>~package~</code>
|
||||
<code>~process~</code>
|
||||
<code>~block~</code>
|
||||
<code>~warp~</code>
|
||||
<code>~dns~</code>
|
||||
<code>~uid~</code>
|
||||
<code>~domain~</code>
|
||||
<code>~directdomain~</code>
|
||||
<code>~cdndomain~</code>
|
||||
<code>~short_id~</code>
|
||||
<code>~public_key~</code>
|
||||
<code>~server_name~</code>
|
||||
<code>~ip~</code>
|
||||
TEXT;
|
||||
$templates = $pac["{$type}templates"];
|
||||
|
||||
$data[] = [
|
||||
@@ -5293,6 +5410,34 @@ DNS-over-HTTPS with IP:
|
||||
);
|
||||
}
|
||||
|
||||
public function mainOutbound()
|
||||
{
|
||||
$r = $this->send(
|
||||
$this->input['chat'],
|
||||
"@{$this->input['username']} send name",
|
||||
$this->input['message_id'],
|
||||
reply: 'send name',
|
||||
);
|
||||
$_SESSION['reply'][$r['result']['message_id']] = [
|
||||
'start_message' => $this->input['message_id'],
|
||||
'start_callback' => $this->input['callback_id'],
|
||||
'callback' => 'setMainOutbound',
|
||||
'args' => [],
|
||||
];
|
||||
}
|
||||
|
||||
public function setMainOutbound($text)
|
||||
{
|
||||
$pac = $this->getPacConf();
|
||||
if (!empty($text)) {
|
||||
$pac['outbound'] = $text;
|
||||
} else {
|
||||
unset($pac['outbound']);
|
||||
}
|
||||
$this->setPacConf($pac);
|
||||
$this->xray();
|
||||
}
|
||||
|
||||
public function xray($page = 0)
|
||||
{
|
||||
if (!$this->ssh('pgrep xray', 'xr')) {
|
||||
@@ -5305,6 +5450,12 @@ DNS-over-HTTPS with IP:
|
||||
$text[] = "fake domain: <code>$fake</code>";
|
||||
}
|
||||
$text[] = 'transport: ' . ($p['transport'] ?: 'Reality');
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('main outbound name: ') . ($p['outbound'] ?: 'proxy'),
|
||||
'callback_data' => '/mainOutbound',
|
||||
],
|
||||
];
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $p['linkdomain'] ?: $this->i18n('cdn'),
|
||||
@@ -5342,6 +5493,10 @@ DNS-over-HTTPS with IP:
|
||||
'text' => $this->i18n('sing-box templates'),
|
||||
'callback_data' => "/templates sing",
|
||||
],
|
||||
[
|
||||
'text' => $this->i18n('clash templates'),
|
||||
'callback_data' => "/templates clash",
|
||||
],
|
||||
];
|
||||
$data[] = [
|
||||
[
|
||||
@@ -5431,24 +5586,20 @@ DNS-over-HTTPS with IP:
|
||||
'callback_data' => "/xtlswarp",
|
||||
]],
|
||||
[[
|
||||
'text' => $this->i18n('rulesset'),
|
||||
'callback_data' => "/xtlsrulesset",
|
||||
]],
|
||||
[[
|
||||
'text' => 'domains: ' . ($p['domains_outbound'] ? 'direct' : $outbound),
|
||||
'text' => 'domains',
|
||||
'callback_data' => "/xtlsproxy",
|
||||
]],
|
||||
[[
|
||||
'text' => 'process: ' . ($p['process_outbound'] ? 'direct' : $outbound),
|
||||
'text' => 'process',
|
||||
'callback_data' => "/xtlsprocess",
|
||||
]],
|
||||
[[
|
||||
'text' => 'package: ' . ($p['app_outbound'] ? 'direct' : $outbound),
|
||||
'text' => 'package',
|
||||
'callback_data' => "/xtlsapp",
|
||||
]],
|
||||
[[
|
||||
'text' => 'final: ' . ($p['final_outbound'] ? $outbound : 'direct'),
|
||||
'callback_data' => "/finalOutbound",
|
||||
'text' => $this->i18n('rulesset'),
|
||||
'callback_data' => "/xtlsrulesset",
|
||||
]],
|
||||
];
|
||||
$data[] = [
|
||||
@@ -5632,12 +5783,12 @@ DNS-over-HTTPS with IP:
|
||||
$text[] = "Menu -> " . $this->i18n('xray') . " -> {$c['email']}\n";
|
||||
$text[] = "<pre><code>{$this->linkXray($i)}</code></pre>\n";
|
||||
|
||||
$text[] = "import subscribe:";
|
||||
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=s&r=v&s={$c['id']}#{$c['email']}'>v2rayng</a>";
|
||||
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=si&r=si&s={$c['id']}#{$c['email']}'>sing-box</a>";
|
||||
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=s&r=st&s={$c['id']}#{$c['email']}'>streisand</a>";
|
||||
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=si&r=h&s={$c['id']}#{$c['email']}'>hiddify</a>";
|
||||
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=si&r=k&s={$c['id']}#{$c['email']}'>karing</a>";
|
||||
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=s&r=v&s={$c['id']}#{$c['email']}'>import://v2rayng</a>";
|
||||
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=si&r=si&s={$c['id']}#{$c['email']}'>import://sing-box</a>";
|
||||
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=s&r=st&s={$c['id']}#{$c['email']}'>import://streisand</a>";
|
||||
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=si&r=h&s={$c['id']}#{$c['email']}'>import://hiddify</a>";
|
||||
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=si&r=k&s={$c['id']}#{$c['email']}'>import://karing</a>";
|
||||
$text[] = "<a href='$scheme://{$domain}/pac?h=$hash&t=si&r=c&s={$c['id']}#{$c['email']}'>import://clash</a>";
|
||||
|
||||
$si = "$scheme://{$domain}/pac/" . base64_encode(serialize([
|
||||
'h' => $hash,
|
||||
@@ -5649,9 +5800,15 @@ DNS-over-HTTPS with IP:
|
||||
't' => 's',
|
||||
's' => $c['id'],
|
||||
]));
|
||||
$cl = "$scheme://{$domain}/pac/" . base64_encode(serialize([
|
||||
'h' => $hash,
|
||||
't' => 'cl',
|
||||
's' => $c['id'],
|
||||
]));
|
||||
|
||||
$text[] = "\nxray config: <pre><code>$xr</code></pre>";
|
||||
$text[] = "sing-box config: <pre><code>$si</code></pre>";
|
||||
$text[] = "clash config: <pre><code>$cl</code></pre>";
|
||||
|
||||
$text[] = "sing-box windows: <a href='$scheme://{$domain}/pac?h=$hash&t=si&r=w&s={$c['id']}'>windows service</a>";
|
||||
|
||||
@@ -5677,6 +5834,7 @@ DNS-over-HTTPS with IP:
|
||||
];
|
||||
$singtemplate = $c['singtemplate'] ? base64_decode($c['singtemplate']) : 'default(' . ($pac['defaultsingtemplate'] && !empty($pac['singtemplates'][base64_decode($pac['defaultsingtemplate'])]) ? base64_decode($pac['defaultsingtemplate']) : 'origin') . ')';
|
||||
$v2raytemplate = $c['v2raytemplate'] ? base64_decode($c['v2raytemplate']) : 'default(' . ($pac['defaultv2raytemplate'] && !empty($pac['v2raytemplates'][base64_decode($pac['defaultv2raytemplate'])]) ? base64_decode($pac['defaultv2raytemplate']) : 'origin') . ')';
|
||||
$clashtemplate = $c['clashtemplate'] ? base64_decode($c['clashtemplate']) : 'default(' . ($pac['defaultclashtemplate'] && !empty($pac['clashtemplates'][base64_decode($pac['defaultclashtemplate'])]) ? base64_decode($pac['defaultclashtemplate']) : 'origin') . ')';
|
||||
$data[] = [
|
||||
[
|
||||
'text' => $this->i18n('v2ray') . ": $v2raytemplate",
|
||||
@@ -5686,6 +5844,10 @@ DNS-over-HTTPS with IP:
|
||||
'text' => $this->i18n('singbox') . ": $singtemplate",
|
||||
'callback_data' => "/templateUser sing $i",
|
||||
],
|
||||
[
|
||||
'text' => $this->i18n('clash') . ": $clashtemplate",
|
||||
'callback_data' => "/templateUser clash $i",
|
||||
],
|
||||
];
|
||||
$data[] = [
|
||||
[
|
||||
@@ -5736,7 +5898,17 @@ DNS-over-HTTPS with IP:
|
||||
|
||||
public function subscription()
|
||||
{
|
||||
$type = $_GET['t'] == 's' ? 'v2ray' : 'sing';
|
||||
switch ($_GET['t']) {
|
||||
case 's':
|
||||
$type = 'v2ray';
|
||||
break;
|
||||
case 'si':
|
||||
$type = 'sing';
|
||||
break;
|
||||
case 'cl':
|
||||
$type = 'clash';
|
||||
break;
|
||||
}
|
||||
$pac = $this->getPacConf();
|
||||
$domain = $_GET['cdn'] ?: ($_SERVER['SERVER_NAME'] ?: $this->getDomain($pac['transport'] == 'Websocket'));
|
||||
$xr = $this->getXray();
|
||||
@@ -5770,6 +5942,11 @@ DNS-over-HTTPS with IP:
|
||||
't' => 's',
|
||||
's' => $uid,
|
||||
]));
|
||||
$cl = "$scheme://{$domain}/pac/" . base64_encode(serialize([
|
||||
'h' => $hash,
|
||||
't' => 'cl',
|
||||
's' => $uid,
|
||||
]));
|
||||
switch ($_GET['r']) {
|
||||
case 'si':
|
||||
header("Location: sing-box://import-remote-profile/?url=$si");
|
||||
@@ -5786,6 +5963,9 @@ DNS-over-HTTPS with IP:
|
||||
case 'h':
|
||||
header("Location: hiddify://install-config/?url=$si");
|
||||
exit;
|
||||
case 'c':
|
||||
header("Location: clash://install-config/?url=$cl&name=$email");
|
||||
exit;
|
||||
case 'w':
|
||||
$link = htmlspecialchars($si, ENT_XML1, 'UTF-8');
|
||||
$n = "singbox_$uid.zip";
|
||||
@@ -5826,6 +6006,14 @@ DNS-over-HTTPS with IP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isset($index)) {
|
||||
foreach ($c['proxies'] as $k => $v) {
|
||||
if ($v['name'] == $outbound) {
|
||||
$index = $k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch ($_GET['t']) {
|
||||
case 's':
|
||||
@@ -5884,30 +6072,101 @@ DNS-over-HTTPS with IP:
|
||||
$c['outbounds'][$index]['tls']['server_name'] = '~server_name~';
|
||||
$c['outbounds'][$index]['tls']['reality']['short_id'] = '~short_id~';
|
||||
}
|
||||
break;
|
||||
case 'cl':
|
||||
$c['proxies'][$index]['server'] = '~domain~';
|
||||
$c['proxies'][$index]['uuid'] = '~uid~';
|
||||
if ($pac['transport'] == 'Websocket') {
|
||||
unset($c['proxies'][$index]['flow']);
|
||||
unset($c['proxies'][$index]['reality-opts']);
|
||||
$c['proxies'][$index]["network"] = "ws";
|
||||
$c['proxies'][$index]["ws-opts"]['path'] = '/ws';
|
||||
$c['proxies'][$index]["skip-cert-verify"] = false;
|
||||
$c['proxies'][$index]['servername'] = '~domain~';
|
||||
} else {
|
||||
unset($c['proxies'][$index]["ws-opts"]);
|
||||
unset($c['proxies'][$index]["skip-cert-verify"]);
|
||||
$c['proxies'][$index]["network"] = "tcp";
|
||||
$c['proxies'][$index]['flow'] = 'xtls-rprx-vision';
|
||||
$c['proxies'][$index]['servername'] = '~server_name~';
|
||||
$c['proxies'][$index]['reality-opts'] = [
|
||||
'public-key' => '~public_key~',
|
||||
'short-id' => '~short_id~',
|
||||
];
|
||||
}
|
||||
break;
|
||||
}
|
||||
$c = json_decode($this->replaceTags(json_encode($c), [
|
||||
'"~pac~"' => json_encode(array_keys(array_filter($pac['includelist'] ?: []))),
|
||||
'"~block~"' => json_encode(array_keys(array_filter($pac['blocklist'] ?: []))),
|
||||
'"~warp~"' => json_encode(array_keys(array_filter($pac['warplist'] ?: []))),
|
||||
'"~process~"' => json_encode(array_keys(array_filter($pac['processlist'] ?: []))),
|
||||
'"~package~"' => json_encode(array_keys(array_filter($pac['packagelist'] ?: []))),
|
||||
'~dns~' => "https://$domain/dns-query/$uid",
|
||||
'~uid~' => $uid,
|
||||
'~domain~' => $domain,
|
||||
'~directdomain~' => $pac['domain'],
|
||||
'~cdndomain~' => $pac['linkdomain'],
|
||||
'~short_id~' => $xr['inbounds'][0]['streamSettings']['realitySettings']['shortIds'][0],
|
||||
'~public_key~' => $pac['xray'],
|
||||
'~server_name~' => $xr['inbounds'][0]['streamSettings']['realitySettings']['serverNames'][0],
|
||||
'~ip~' => $this->ip,
|
||||
]), true);
|
||||
|
||||
switch ($_GET['t']) {
|
||||
case 's':
|
||||
if (!empty($c['routing']['rules'])) {
|
||||
foreach ($c['routing']['rules'] as $k => $v) {
|
||||
if (array_key_exists('domain', $v) && empty($v['domain'])) {
|
||||
unset($c['routing']['rules'][$k]);
|
||||
}
|
||||
}
|
||||
$c['routing']['rules'] = array_values($c['routing']['rules']);
|
||||
}
|
||||
break;
|
||||
case 'si':
|
||||
$c['route'] = $this->addRuleSet($c['route']);
|
||||
$c['route'] = $this->createRuleSet($c['route'], $uid, $domain);
|
||||
if (!empty($c['route']['rules'])) {
|
||||
foreach ($c['route']['rules'] as $k => $v) {
|
||||
if (count($v) < 2) {
|
||||
unset($c['route']['rules'][$k]);
|
||||
}
|
||||
}
|
||||
$c['route']['rules'] = array_values($c['route']['rules']);
|
||||
}
|
||||
break;
|
||||
case 'cl':
|
||||
if (!empty($c['rules'])) {
|
||||
$c['rules'] = $this->clashRules($c['rules']);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$json = $this->replaceTags(json_encode($c), [
|
||||
'"~pac~"' => json_encode(array_keys(array_filter($pac['includelist'] ?: []))),
|
||||
'~dns~' => "https://$domain/dns-query/$uid",
|
||||
'~uid~' => $uid,
|
||||
'~domain~' => $domain,
|
||||
'~short_id~' => $xr['inbounds'][0]['streamSettings']['realitySettings']['shortIds'][0],
|
||||
'~public_key~' => $pac['xray'],
|
||||
'~server_name~' => $xr['inbounds'][0]['streamSettings']['realitySettings']['serverNames'][0],
|
||||
'~app_outbound~' => $pac['app_outbound'] ? 'direct' : $outbound,
|
||||
'~process_outbound~' => $pac['process_outbound'] ? 'direct' : $outbound,
|
||||
'~domains_outbound~' => $pac['domains_outbound'] ? 'direct' : $outbound,
|
||||
'~final_outbound~' => $pac['final_outbound'] ? $outbound : 'direct',
|
||||
'~ip~' => $this->ip,
|
||||
]);
|
||||
$json = $this->clearEmptyRules($json);
|
||||
if ($_GET['t'] == 'cl') {
|
||||
header('Content-type: text/yaml');
|
||||
echo yaml_emit($c);
|
||||
return;
|
||||
}
|
||||
|
||||
header('Content-type: application/json');
|
||||
echo $json;
|
||||
echo json_encode($c);
|
||||
}
|
||||
|
||||
public function clashRules($rules)
|
||||
{
|
||||
foreach ($rules as $v) {
|
||||
if (isset($v['list'])) {
|
||||
if (!empty($v['list'])) {
|
||||
foreach ($v['list'] as $j) {
|
||||
$tmp[] = "{$v['type']}, $j, {$v['action']}";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$tmp[] = "{$v['type']}, {$v['action']}";
|
||||
}
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
public function replaceTags($subject, $tags)
|
||||
@@ -5915,108 +6174,82 @@ DNS-over-HTTPS with IP:
|
||||
return str_replace(array_keys($tags), array_values($tags), $subject);
|
||||
}
|
||||
|
||||
public function clearEmptyRules($json)
|
||||
{
|
||||
$json = json_decode($json, 1);
|
||||
if (!empty($json['routing']['rules'])) {
|
||||
foreach ($json['routing']['rules'] as $k => $v) {
|
||||
if (array_key_exists('domain', $v) && empty($v['domain'])) {
|
||||
unset($json['routing']['rules'][$k]);
|
||||
}
|
||||
}
|
||||
$json['routing']['rules'] = array_values($json['routing']['rules']);
|
||||
}
|
||||
if (!empty($json['route']['rules'])) {
|
||||
foreach ($json['route']['rules'] as $k => $v) {
|
||||
if (count($v) < 2) {
|
||||
unset($json['route']['rules'][$k]);
|
||||
}
|
||||
}
|
||||
$json['route']['rules'] = array_values($json['route']['rules']);
|
||||
}
|
||||
return json_encode($json);
|
||||
}
|
||||
|
||||
public function addRuleSet($route)
|
||||
{
|
||||
foreach ($route['rules'] as $k => $v) {
|
||||
$t[$v['outbound']] = $k;
|
||||
}
|
||||
$p = $this->getPacConf();
|
||||
if (!empty($p['rulessetlist'])) {
|
||||
foreach ($p['rulessetlist'] as $k => $v) {
|
||||
if (!empty($v)) {
|
||||
[$type, $time, $url] = explode(':', $k, 3);
|
||||
$route['rule_set'][] = [
|
||||
"tag" => $k,
|
||||
"type" => "remote",
|
||||
"format" => "binary",
|
||||
"url" => $url,
|
||||
"download_detour" => "direct",
|
||||
"update_interval" => $time
|
||||
];
|
||||
$route['rules'][$t[$type]]['rule_set'][] = $k;
|
||||
if (!empty($route['rules'])) {
|
||||
foreach ($route['rules'] as $k => $v) {
|
||||
if (!empty($v['addruleset'])) {
|
||||
$t[$v['outbound']] = $k;
|
||||
}
|
||||
}
|
||||
$p = $this->getPacConf();
|
||||
if (!empty($p['rulessetlist'])) {
|
||||
foreach ($p['rulessetlist'] as $k => $v) {
|
||||
if (!empty($v)) {
|
||||
[$type, $time, $url] = explode(':', $k, 3);
|
||||
if (!empty($route['rules'][$t[$type]])) {
|
||||
$route['rule_set'][] = [
|
||||
"tag" => $k,
|
||||
"type" => "remote",
|
||||
"format" => "binary",
|
||||
"url" => $url,
|
||||
"download_detour" => "direct",
|
||||
"update_interval" => $time
|
||||
];
|
||||
$route['rules'][$t[$type]]['rule_set'][] = $k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($route['rules'] as $k => $v) {
|
||||
unset($route['rules'][$k]['addruleset']);
|
||||
}
|
||||
}
|
||||
return $route;
|
||||
}
|
||||
|
||||
public function cleanEmptyKeys(array $arr)
|
||||
{
|
||||
foreach ($arr as $k => $v) {
|
||||
if (empty($v)) {
|
||||
unset($arr[$k]);
|
||||
} elseif (is_array($v)) {
|
||||
$arr[$k] = $this->cleanEmptyKeys($v);
|
||||
if (empty($arr[$k])) {
|
||||
unset($arr[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
|
||||
public function createSrs(string $name, array $rules)
|
||||
{
|
||||
$rules = $this->cleanEmptyKeys($rules);
|
||||
header("Content-Disposition: attachment; filename=$name.srs");
|
||||
header('Content-Type: application/binary');
|
||||
$f = "/tmp/$name" . time() . rand(1, 100);
|
||||
file_put_contents($f, json_encode([
|
||||
'version' => 1,
|
||||
'rules' => $rules ?: [],
|
||||
]));
|
||||
exec("sing-box rule-set compile $f");
|
||||
echo file_get_contents("$f.srs");
|
||||
unlink($f);
|
||||
unlink("$f.srs");
|
||||
exit;
|
||||
}
|
||||
|
||||
public function createRuleSet($route, $uid, $domain)
|
||||
{
|
||||
$pac = $this->getPacConf();
|
||||
$scheme = empty($this->nginxGetTypeCert()) ? 'http' : 'https';
|
||||
$hash = substr(md5($this->key), 0, 8);
|
||||
|
||||
foreach ($route['rules'] as $k => $v) {
|
||||
if (!empty($v['createruleset'])) {
|
||||
foreach ($v['createruleset'] as $r) {
|
||||
foreach ($r['rules'] as $l => $n) {
|
||||
switch (true) {
|
||||
case array_key_exists('domain_suffix', $n):
|
||||
switch ($n['domain_suffix']) {
|
||||
case '~pac~':
|
||||
$t = 'includelist';
|
||||
break;
|
||||
case '~warp~':
|
||||
$t = 'warplist';
|
||||
break;
|
||||
case '~block~':
|
||||
$t = 'blocklist';
|
||||
break;
|
||||
}
|
||||
$r['rules'][$l]['domain_suffix'] = array_keys(array_filter($pac[$t] ?: []));
|
||||
if (empty($r['rules'][$l]['domain_suffix'])) {
|
||||
unset($r['rules'][$l]);
|
||||
}
|
||||
break;
|
||||
case array_key_exists('package_name', $n):
|
||||
$r['rules'][$l]['package_name'] = array_keys(array_filter($pac['packagelist'] ?: []));
|
||||
if (empty($r['rules'][$l]['package_name'])) {
|
||||
unset($r['rules'][$l]);
|
||||
}
|
||||
break;
|
||||
case array_key_exists('process_name', $n):
|
||||
$r['rules'][$l]['process_name'] = array_keys(array_filter($pac['processlist'] ?: []));
|
||||
if (empty($r['rules'][$l]['process_name'])) {
|
||||
unset($r['rules'][$l]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!empty($_GET['r']) && $r['name'] == $_GET['r']) {
|
||||
header("Content-Disposition: attachment; filename={$r['name']}.srs");
|
||||
header('Content-Type: application/binary');
|
||||
$f = "/tmp/{$r['name']}" . time() . rand(1, 100);
|
||||
file_put_contents($f, json_encode([
|
||||
'version' => 1,
|
||||
'rules' => $r['rules'] ?: [],
|
||||
]));
|
||||
exec("sing-box rule-set compile $f");
|
||||
echo file_get_contents("$f.srs");
|
||||
unlink($f);
|
||||
unlink("$f.srs");
|
||||
exit;
|
||||
$this->createSrs($r['name'], $r['rules']);
|
||||
}
|
||||
$ruleset[] = [
|
||||
"tag" => $r['name'],
|
||||
|
||||
@@ -37,6 +37,7 @@ if ($hash == substr(md5($c['key']), 0, 8)) {
|
||||
break;
|
||||
case 's':
|
||||
case 'si':
|
||||
case 'cl':
|
||||
$bot->subscription();
|
||||
exit;
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
{
|
||||
"mixed-port": 2080,
|
||||
"allow-lan": true,
|
||||
"tcp-concurrent": true,
|
||||
"enable-process": true,
|
||||
"find-process-mode": "strict",
|
||||
"global-client-fingerprint": "chrome",
|
||||
"mode": "rule",
|
||||
"log-level": "debug",
|
||||
"ipv6": false,
|
||||
"keep-alive-interval": 30,
|
||||
"unified-delay": false,
|
||||
"profile": {
|
||||
"store-selected": true,
|
||||
"store-fake-ip": true
|
||||
},
|
||||
"sniffer": {
|
||||
"enable": true,
|
||||
"sniff": {
|
||||
"HTTP": {
|
||||
"ports": [
|
||||
80,
|
||||
"8080-8880"
|
||||
],
|
||||
"override-destination": true
|
||||
},
|
||||
"TLS": {
|
||||
"ports": [
|
||||
443,
|
||||
8443
|
||||
]
|
||||
},
|
||||
"QUIC": {
|
||||
"ports": [
|
||||
443,
|
||||
8443
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"tun": {
|
||||
"enable": true,
|
||||
"stack": "mixed",
|
||||
"dns-hijack": [
|
||||
"any:53"
|
||||
],
|
||||
"auto-route": true,
|
||||
"auto-detect-interface": true,
|
||||
"strict-route": true
|
||||
},
|
||||
"dns": {
|
||||
"enable": true,
|
||||
"listen": ":1053",
|
||||
"prefer-h3": false,
|
||||
"ipv6": false,
|
||||
"enhanced-mode": "fake-ip",
|
||||
"fake-ip-filter": [
|
||||
"~domain~",
|
||||
"+.lan",
|
||||
"+.local"
|
||||
],
|
||||
"nameserver": [
|
||||
"~dns~"
|
||||
]
|
||||
},
|
||||
"proxies": [
|
||||
{
|
||||
"name": "~outbound~",
|
||||
"type": "vless",
|
||||
"server": "~domain~",
|
||||
"port": 443,
|
||||
"uuid": "~uid~",
|
||||
"network": "tcp",
|
||||
"flow": "xtls-rprx-vision",
|
||||
"tls": true,
|
||||
"reality-opts": {
|
||||
"public-key": "~public_key~",
|
||||
"short-id": "~short_id~"
|
||||
},
|
||||
"servername": "~server_name~",
|
||||
"client-fingerprint": "chrome"
|
||||
}
|
||||
],
|
||||
"proxy-groups": [
|
||||
{
|
||||
"name": "PROXY",
|
||||
"type": "select",
|
||||
"proxies": [
|
||||
"~outbound~"
|
||||
]
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"type": "DOMAIN-SUFFIX",
|
||||
"list": "~block~",
|
||||
"action": "REJECT"
|
||||
},
|
||||
{
|
||||
"type": "PROCESS-NAME",
|
||||
"list": "~process~",
|
||||
"action": "PROXY"
|
||||
},
|
||||
{
|
||||
"type": "PROCESS-NAME",
|
||||
"list": "~package~",
|
||||
"action": "PROXY"
|
||||
},
|
||||
{
|
||||
"type": "DOMAIN-SUFFIX",
|
||||
"list": "~warp~",
|
||||
"action": "PROXY"
|
||||
},
|
||||
{
|
||||
"type": "DOMAIN-SUFFIX",
|
||||
"list": "~pac~",
|
||||
"action": "PROXY"
|
||||
},
|
||||
{
|
||||
"type": "MATCH",
|
||||
"action": "DIRECT"
|
||||
}
|
||||
]
|
||||
}
|
||||
+1
-1
@@ -505,7 +505,7 @@ ipv4-netmask = 255.255.255.0
|
||||
|
||||
# Whether to tunnel all DNS queries via the VPN. This is the default
|
||||
# when a default route is set.
|
||||
#tunnel-all-dns = true
|
||||
tunnel-all-dns = true
|
||||
|
||||
# The advertised DNS server. Use multiple lines for
|
||||
# multiple servers.
|
||||
|
||||
+9
-7
@@ -111,6 +111,7 @@
|
||||
"outbound": "dns-out"
|
||||
},
|
||||
{
|
||||
"addruleset": true,
|
||||
"createruleset": [
|
||||
{
|
||||
"name": "pac",
|
||||
@@ -122,9 +123,10 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"outbound": "~domains_outbound~"
|
||||
"outbound": "~outbound~"
|
||||
},
|
||||
{
|
||||
"addruleset": true,
|
||||
"createruleset": [
|
||||
{
|
||||
"name": "package",
|
||||
@@ -136,9 +138,10 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"outbound": "~app_outbound~"
|
||||
"outbound": "~outbound~"
|
||||
},
|
||||
{
|
||||
"addruleset": true,
|
||||
"createruleset": [
|
||||
{
|
||||
"name": "process",
|
||||
@@ -150,9 +153,10 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"outbound": "~process_outbound~"
|
||||
"outbound": "~outbound~"
|
||||
},
|
||||
{
|
||||
"addruleset": true,
|
||||
"createruleset": [
|
||||
{
|
||||
"name": "block",
|
||||
@@ -167,6 +171,7 @@
|
||||
"outbound": "block"
|
||||
},
|
||||
{
|
||||
"addruleset": true,
|
||||
"createruleset": [
|
||||
{
|
||||
"name": "warp",
|
||||
@@ -179,11 +184,8 @@
|
||||
}
|
||||
],
|
||||
"outbound": "~outbound~"
|
||||
},
|
||||
{
|
||||
"outbound": "direct"
|
||||
}
|
||||
],
|
||||
"final": "~final_outbound~"
|
||||
"final": "direct"
|
||||
}
|
||||
}
|
||||
@@ -59,4 +59,12 @@ c:
|
||||
git checkout .
|
||||
git reset
|
||||
webhook:
|
||||
docker compose exec php php checkwebhook.php
|
||||
docker compose exec php php checkwebhook.php
|
||||
reset:
|
||||
make d
|
||||
git reset --hard
|
||||
git clean -fd
|
||||
docker volume rm vpnbot_adguard vpnbot_warp
|
||||
make u
|
||||
backup:
|
||||
docker compose exec php php backup.php > backup.json
|
||||
@@ -1,3 +1,23 @@
|
||||
28.11.2024 v1.109
|
||||
- фикс автоскана
|
||||
- добавление clash-шаблонов
|
||||
21.11.2024 v1.108
|
||||
- xray: addruleset для direct
|
||||
- openconnect:ограничение формата при добавлении подсети
|
||||
- новый механизм сверки ip для анализатора айпи
|
||||
- мелкие фиксы меню и текста
|
||||
21.11.2024 v1.107
|
||||
- xray: добавлены теги ~cdndomain~, ~directdomain~
|
||||
- xray: возможность менять имя главного аутбаунда(тот аутбаунд который заполняет бот, в шаблонах идет как ~outbound~) для клиентских конфигов
|
||||
- xray: в шаблонах теперь надо явно указывать ключ addruleset в route -> rules, чтобы бот заполнил их правилами из списка ruleset (см origin шаблон)
|
||||
- openconnect: добавлена маршрутизация (список подсетей общий с wireguard)
|
||||
- ip ban: фикс обработки подсетей в белом/черном списках
|
||||
- ip ban: в белый список можно импортировать адреса от telegram, gcore, cloudflare
|
||||
- добавлена в игнор папка app/webapp/override. она не будет перезатираться после обновления, туда можно положить ваши ресурсы к override.html
|
||||
- <code>make backup</code> - сохранит в корень backup.json
|
||||
- <code>make reset</code> - обнуляет все настройки
|
||||
18.11.2024 v1.106
|
||||
- фикс отвала бота при пустых логах телеги
|
||||
17.11.2024 v1.105
|
||||
- фикс установки домена при первом запуске
|
||||
16.11.2024 v1.104
|
||||
|
||||
Reference in New Issue
Block a user