Compare commits

...

7 Commits

Author SHA1 Message Date
mercury 8effb72cdc update version 2026-03-10 10:05:12 +04:00
mercury bec8f5488e reset amnezia keys fix 2026-03-08 01:23:12 +04:00
mercury f97b0f9228 amneziawg2.0 2026-03-08 01:12:09 +04:00
mercury 8e8babe1a6 update version 2025-12-16 00:58:02 +04:00
mercury 238c380f23 fix clash template rules behavior 2025-12-16 00:55:44 +04:00
mercury abc2e7c587 setting up dnstt display in menu 2025-12-16 00:38:34 +04:00
mercury 3f99d9fbf0 hide dnstt 2025-12-15 17:06:19 +04:00
4 changed files with 252 additions and 177 deletions
+243 -172
View File
@@ -320,8 +320,11 @@ class Bot
case preg_match('~^/logs$~', $this->input['callback'], $m): case preg_match('~^/logs$~', $this->input['callback'], $m):
$this->logs(); $this->logs();
break; break;
case preg_match('~^/dnstt$~', $this->input['callback'], $m): case preg_match('~^/dnstt$~', $this->input['callback'] ?: $this->input['message'], $m):
$this->dnstt(); $this->dnstt(!empty($this->input['callback']));
break;
case preg_match('~^/showdnstt$~', $this->input['callback'], $m):
$this->showdnstt();
break; break;
case preg_match('~^/dnsttDownload$~', $this->input['callback'], $m): case preg_match('~^/dnsttDownload$~', $this->input['callback'], $m):
$this->dnsttDownload(); $this->dnsttDownload();
@@ -458,9 +461,6 @@ class Bot
case preg_match('~^/enterPage$~', $this->input['callback'], $m): case preg_match('~^/enterPage$~', $this->input['callback'], $m):
$this->enterPage(); $this->enterPage();
break; break;
case preg_match('~^/geodb$~', $this->input['callback'], $m):
$this->geodb();
break;
case preg_match('~^/adguardreset$~', $this->input['callback'], $m): case preg_match('~^/adguardreset$~', $this->input['callback'], $m):
$this->adguardreset(); $this->adguardreset();
break; break;
@@ -518,6 +518,9 @@ class Bot
case preg_match('~^/switchAmnezia (-?\d+)$~', $this->input['callback'], $m): case preg_match('~^/switchAmnezia (-?\d+)$~', $this->input['callback'], $m):
$this->switchAmnezia($m[1]); $this->switchAmnezia($m[1]);
break; break;
case preg_match('~^/resetAmnezia (-?\d+)$~', $this->input['callback'], $m):
$this->resetAmnezia($m[1]);
break;
case preg_match('~^/switchExchange (\d+)$~', $this->input['callback'], $m): case preg_match('~^/switchExchange (\d+)$~', $this->input['callback'], $m):
$this->switchExchange($m[1]); $this->switchExchange($m[1]);
break; break;
@@ -1236,7 +1239,11 @@ class Bot
public function chhypass($pass) public function chhypass($pass)
{ {
$pac = $this->getPacConf(); $pac = $this->getPacConf();
$pac['hysteria_pass'] = $pass; if (!empty($pass)) {
$pac['hysteria_pass'] = $pass;
} else {
unset($pac['hysteria_pass']);
}
$this->setPacConf($pac); $this->setPacConf($pac);
$this->restartHysteria(); $this->restartHysteria();
$this->menu('hy'); $this->menu('hy');
@@ -2066,63 +2073,65 @@ class Bot
$this->restartWG($this->createConfig($server)); $this->restartWG($this->createConfig($server));
} }
public function switchAmnezia($page = 0) public function resetAmnezia($page = 0) {
$this->switchAmnezia($page, 1);
}
public function switchAmnezia($page = 0, $reset = false)
{ {
$c = $this->getPacConf(); $c = $this->getPacConf();
$amnezia = $c[$this->getInstanceWG(1) . 'amnezia'] = $c[$this->getInstanceWG(1) . 'amnezia'] ? 0 : 1; if (empty($reset)) {
$amnezia = $c[$this->getInstanceWG(1) . 'amnezia'] = $c[$this->getInstanceWG(1) . 'amnezia'] ? 0 : 1;
} else {
$amnezia = 1;
unset($c[$this->getInstanceWG(1) . 'amnezia_keys']);
unset($c[$this->getInstanceWG(1) . 'presharedkey']);
}
$this->setPacConf($c); $this->setPacConf($c);
$pk = $this->presharedKey(); $pk = $this->presharedKey();
$ak = $this->amneziaKeys(); $ak = $this->amneziaKeys();
$clients = $this->readClients(); $clients = $this->readClients();
foreach ($clients as $k => $v) { foreach ($clients as $k => $v) {
unset($clients[$k]['peers'][0]['PresharedKey']);
unset($clients[$k]['interface']['Jc']);
unset($clients[$k]['interface']['Jmin']);
unset($clients[$k]['interface']['Jmax']);
unset($clients[$k]['interface']['S1']);
unset($clients[$k]['interface']['S2']);
unset($clients[$k]['interface']['S3']);
unset($clients[$k]['interface']['S4']);
unset($clients[$k]['interface']['H1']);
unset($clients[$k]['interface']['H2']);
unset($clients[$k]['interface']['H3']);
unset($clients[$k]['interface']['H4']);
unset($clients[$k]['interface']['I1']);
if (!empty($amnezia)) { if (!empty($amnezia)) {
$clients[$k]['peers'][0]['PresharedKey'] = $pk; $clients[$k]['peers'][0]['PresharedKey'] = $pk;
$clients[$k]['interface']['Jc'] = $ak['Jc']; foreach ($ak as $j => $i) {
$clients[$k]['interface']['Jmin'] = $ak['Jmin']; $clients[$k]['interface'][$j] = $i;
$clients[$k]['interface']['Jmax'] = $ak['Jmax']; }
$clients[$k]['interface']['S1'] = $ak['S1'];
$clients[$k]['interface']['S2'] = $ak['S2'];
$clients[$k]['interface']['H1'] = $ak['H1'];
$clients[$k]['interface']['H2'] = $ak['H2'];
$clients[$k]['interface']['H3'] = $ak['H3'];
$clients[$k]['interface']['H4'] = $ak['H4'];
} else {
unset($clients[$k]['peers'][0]['PresharedKey']);
unset($clients[$k]['interface']['Jc']);
unset($clients[$k]['interface']['Jmin']);
unset($clients[$k]['interface']['Jmax']);
unset($clients[$k]['interface']['S1']);
unset($clients[$k]['interface']['S2']);
unset($clients[$k]['interface']['H1']);
unset($clients[$k]['interface']['H2']);
unset($clients[$k]['interface']['H3']);
unset($clients[$k]['interface']['H4']);
} }
} }
$this->saveClients($clients); $this->saveClients($clients);
$wg = $this->readConfig(); $wg = $this->readConfig();
unset($wg['interface']['Jc']);
unset($wg['interface']['Jmin']);
unset($wg['interface']['Jmax']);
unset($wg['interface']['S1']);
unset($wg['interface']['S2']);
unset($wg['interface']['S3']);
unset($wg['interface']['S4']);
unset($wg['interface']['H1']);
unset($wg['interface']['H2']);
unset($wg['interface']['H3']);
unset($wg['interface']['H4']);
unset($wg['interface']['I1']);
if (!empty($amnezia)) { if (!empty($amnezia)) {
$wg['interface']['Jc'] = $ak['Jc']; foreach ($ak as $j => $i) {
$wg['interface']['Jmin'] = $ak['Jmin']; $wg['interface'][$j] = $i;
$wg['interface']['Jmax'] = $ak['Jmax']; }
$wg['interface']['S1'] = $ak['S1'];
$wg['interface']['S2'] = $ak['S2'];
$wg['interface']['H1'] = $ak['H1'];
$wg['interface']['H2'] = $ak['H2'];
$wg['interface']['H3'] = $ak['H3'];
$wg['interface']['H4'] = $ak['H4'];
} else {
unset($wg['interface']['Jc']);
unset($wg['interface']['Jmin']);
unset($wg['interface']['Jmax']);
unset($wg['interface']['S1']);
unset($wg['interface']['S2']);
unset($wg['interface']['H1']);
unset($wg['interface']['H2']);
unset($wg['interface']['H3']);
unset($wg['interface']['H4']);
} }
foreach ($wg['peers'] as $k => $v) { foreach ($wg['peers'] as $k => $v) {
@@ -3352,12 +3361,6 @@ DNS-over-HTTPS with IP:
$am = $c[$this->getInstanceWG(1) . 'amnezia']; $am = $c[$this->getInstanceWG(1) . 'amnezia'];
$end = $c[$this->getInstanceWG(1) . 'endpoint']; $end = $c[$this->getInstanceWG(1) . 'endpoint'];
$data = [ $data = [
[
[
'text' => $this->i18n($am ? 'on' : 'off') . " amnezia",
'callback_data' => "/switchAmnezia $page",
],
],
[ [
[ [
'text' => $this->i18n(!$bt ? 'on' : 'off') . " {$this->i18n('torrent')} ", 'text' => $this->i18n(!$bt ? 'on' : 'off') . " {$this->i18n('torrent')} ",
@@ -3395,6 +3398,20 @@ DNS-over-HTTPS with IP:
], ],
], ],
]; ];
if (!empty($am)) {
array_unshift($data, [
[
'text' => "reset obf-keys",
'callback_data' => "/resetAmnezia $page",
],
]);
}
array_unshift($data, [
[
'text' => $this->i18n($am ? 'on' : 'off') . " amnezia",
'callback_data' => "/switchAmnezia $page",
],
]);
if ($clients) { if ($clients) {
$data = array_merge($data, $clients); $data = array_merge($data, $clients);
} }
@@ -3802,46 +3819,51 @@ DNS-over-HTTPS with IP:
public function getAmneziaShortLink($client) public function getAmneziaShortLink($client)
{ {
$domain = $this->getDomain(); $domain = $this->getDomain();
$dns = explode(',', $client['interface']['DNS']); $pac = $this->getPacConf();
$c = json_encode([ $dnsRaw = $client['interface']['DNS'] ?: $pac[$this->getInstanceWG(1) . 'dns'] ?: $this->dns;
$dns = array_map('trim', explode(',', $dnsRaw));
$wgPort = (int) getenv($this->getInstanceWG() == 'wg1' ? 'WG1PORT' : 'WGPORT');
$c = [
"containers" => [ "containers" => [
[ [
"awg" => [ "awg" => [
"isThirdPartyConfig" => True, "isThirdPartyConfig" => true,
"last_config" => json_encode([ "last_config" => json_encode(array_merge(array_map('strval', $this->amneziaKeys()), [
"H1" => "{$client['interface']['H1']}", "protocol_version" => "2",
"H2" => "{$client['interface']['H2']}", "client_ip" => $client['interface']['Address'],
"H3" => "{$client['interface']['H3']}", "client_priv_key" => $client['interface']['PrivateKey'],
"H4" => "{$client['interface']['H4']}", "client_pub_key" => "0",
"Jc" => "{$client['interface']['Jc']}", "config" => $this->createConfig($client),
"Jmax" => "{$client['interface']['Jmax']}", "hostName" => $domain,
"Jmin" => "{$client['interface']['Jmin']}", "port" => $wgPort,
"S1" => "{$client['interface']['S1']}", "psk_key" => $client['peers'][0]['PresharedKey'],
"S2" => "{$client['interface']['S2']}", "server_pub_key" => $client['peers'][0]['PublicKey'],
"client_ip" => explode('/', $client['interface']['Address'])[0], "allowed_ips" => array_map('trim', explode(',', $client['peers'][0]['AllowedIPs'])),
"client_priv_key" => $client['interface']['PrivateKey'], "persistent_keep_alive" => "25"
"client_pub_key" => "0", ])),
"config" => $this->createConfig($client), "port" => $wgPort,
"hostName" => $domain, "transport_proto" => "udp",
"port" => (int) getenv($this->getInstanceWG() == 'wg1' ? 'WG1PORT' : 'WGPORT'), "protocol_version" => "2"
"psk_key" => $client['peers'][0]['PresharedKey'],
"server_pub_key" => $client['peers'][0]['PublicKey']
]),
"port" => (int) getenv('WG1PORT'),
"transport_proto" => "udp"
], ],
"container" => "amnezia-awg" "container" => "amnezia-awg2"
] ]
], ],
"defaultContainer" => "amnezia-awg", "defaultContainer" => "amnezia-awg2",
"description" => $client['interface']['## name'], "description" => $client['interface']['## name'],
"dns1" => $dns[0], "dns1" => $dns[0] ?? '',
"dns2" => $dns[1] ?: '', "dns2" => $dns[1] ?? '',
"hostName" => $domain "hostName" => $domain,
]); "isThirdPartyConfig" => true
exec("echo '$c' | python amnezia.py", $o); ];
return $o[0]; $json = json_encode($c);
$proc = proc_open('python amnezia.py', [0 => ['pipe', 'r'], 1 => ['pipe', 'w']], $pipes);
fwrite($pipes[0], $json);
fclose($pipes[0]);
$result = trim(stream_get_contents($pipes[1]));
fclose($pipes[1]);
proc_close($proc);
return $result;
} }
public function getClient($client, $page) public function getClient($client, $page)
@@ -3849,7 +3871,7 @@ DNS-over-HTTPS with IP:
$clients = $this->readClients(); $clients = $this->readClients();
if ($clients) { if ($clients) {
$name = $this->getName($clients[$client]['interface']); $name = $this->getName($clients[$client]['interface']);
$conf = $this->createConfig($clients[$client]); $conf = htmlspecialchars($this->createConfig($clients[$client]));
if ($this->getWGType() == 'awg') { if ($this->getWGType() == 'awg') {
$sl = $this->getAmneziaShortLink($clients[$client]); $sl = $this->getAmneziaShortLink($clients[$client]);
} }
@@ -4696,11 +4718,25 @@ DNS-over-HTTPS with IP:
$this->sendFile($this->input['from'], curl_file_create('/config/dnstt/server.pub')); $this->sendFile($this->input['from'], curl_file_create('/config/dnstt/server.pub'));
} }
public function dnstt() public function showdnstt()
{
$c = $this->getPacConf();
$c['showdnstt'] = empty($c['showdnstt']);
$this->setPacConf($c);
$this->dnstt(1);
}
public function dnstt($update = false)
{ {
$c = $this->getPacConf(); $c = $this->getPacConf();
$pubkey = file_get_contents('/config/dnstt/server.pub'); $pubkey = file_get_contents('/config/dnstt/server.pub');
$text[] = "dnstt"; $text[] = "dnstt";
$data[] = [
[
'text' => $this->i18n('show in menu ') . $this->i18n($c['showdnstt'] ? 'on' : 'off'),
'callback_data' => "/showdnstt",
],
];
if (!empty($c['dnsttDomain']) && !empty($c['dnsttPassword'])) { if (!empty($c['dnsttDomain']) && !empty($c['dnsttPassword'])) {
$text[] = "<pre>set the NS record for {$c['dnsttDomain']}: tns.{$c['domain']}\nset A record for tns.{$c['domain']}: {$this->ip}</pre>"; $text[] = "<pre>set the NS record for {$c['dnsttDomain']}: tns.{$c['domain']}\nset A record for tns.{$c['domain']}: {$this->ip}</pre>";
$text[] = "account: <code>vpnbot:{$c['dnsttPassword']}</code>"; $text[] = "account: <code>vpnbot:{$c['dnsttPassword']}</code>";
@@ -4734,12 +4770,21 @@ DNS-over-HTTPS with IP:
'callback_data' => "/menu", 'callback_data' => "/menu",
], ],
]; ];
$this->update( if ($update) {
$this->input['chat'], $this->update(
$this->input['message_id'], $this->input['chat'],
implode("\n", $text), $this->input['message_id'],
$data ?: false, implode("\n", $text),
); $data ?: false,
);
} else {
$this->send(
$this->input['chat'],
implode("\n", $text),
$this->input['message_id'],
$data ?: false,
);
}
} }
public function menu($type = false, $arg = false, $return = false) public function menu($type = false, $arg = false, $return = false)
@@ -4842,86 +4887,94 @@ DNS-over-HTTPS with IP:
$menu = [ $menu = [
'main' => [ 'main' => [
'text' => implode("\n", $main ?: []), 'text' => implode("\n", $main ?: []),
'data' => [ 'data' => array_merge(
[ [
[ [
'text' => $this->i18n($this->getPacConf()['amnezia'] ? 'amnezia' : 'wg_title'), [
'callback_data' => "/changeWG 0", 'text' => $this->i18n($this->getPacConf()['amnezia'] ? 'amnezia' : 'wg_title'),
'callback_data' => "/changeWG 0",
],
[
'text' => $this->i18n($this->getPacConf()['wg1_amnezia'] ? 'amnezia' : 'wg_title'),
'callback_data' => "/changeWG 1",
],
], ],
[ [
'text' => $this->i18n($this->getPacConf()['wg1_amnezia'] ? 'amnezia' : 'wg_title'), [
'callback_data' => "/changeWG 1", 'text' => $this->i18n('xray'),
'callback_data' => "/xray",
],
[
'text' => $this->i18n('naive'),
'callback_data' => "/menu naive",
],
],
[
[
'text' => $this->i18n('ocserv'),
'callback_data' => "/menu oc",
],
[
'text' => $this->i18n('mtproto'),
'callback_data' => "/mtproto",
],
],
[
[
'text' => $this->i18n('ad_title'),
'callback_data' => "/menu adguard",
],
[
'text' => $this->i18n('warp'),
'callback_data' => "/warp",
],
],
[
[
'text' => $this->i18n('sh_title'),
'callback_data' => "/menu ss",
],
[
'text' => $this->i18n('pac'),
'callback_data' => "/pacMenu 0",
],
], ],
], ],
[array_merge(
[
[
'text' => $this->i18n('Hysteria'),
'callback_data' => "/menu hy",
],
],
$conf['showdnstt'] ? [
[
'text' => $this->i18n('DNSTT'),
'callback_data' => "/dnstt",
],
] : [],
)],
[ [
[ [
'text' => $this->i18n('xray'), [
'callback_data' => "/xray", 'text' => $this->i18n('config'),
'callback_data' => "/menu config",
],
], ],
[ [
'text' => $this->i18n('naive'), [
'callback_data' => "/menu naive", 'text' => $this->i18n('chat'),
'url' => base64_decode('aHR0cHM6Ly90Lm1lLys0RzMtUTRkX3ZGRXhPRGN5'),
],
[
'text' => $this->i18n('donate'),
'web_app' => [
'url' => "https://$domain/webapp$hash/donate.html",
]
],
], ],
], ],
[ )
[
'text' => $this->i18n('ocserv'),
'callback_data' => "/menu oc",
],
[
'text' => $this->i18n('mtproto'),
'callback_data' => "/mtproto",
],
],
[
[
'text' => $this->i18n('ad_title'),
'callback_data' => "/menu adguard",
],
[
'text' => $this->i18n('warp'),
'callback_data' => "/warp",
],
],
[
[
'text' => $this->i18n('sh_title'),
'callback_data' => "/menu ss",
],
[
'text' => $this->i18n('pac'),
'callback_data' => "/pacMenu 0",
],
],
[
[
'text' => $this->i18n('Hysteria'),
'callback_data' => "/menu hy",
],
[
'text' => $this->i18n('DNSTT'),
'callback_data' => "/dnstt",
],
],
[
[
'text' => $this->i18n('config'),
'callback_data' => "/menu config",
],
],
[
[
'text' => $this->i18n('chat'),
'url' => base64_decode('aHR0cHM6Ly90Lm1lLys0RzMtUTRkX3ZGRXhPRGN5'),
],
[
'text' => $this->i18n('donate'),
'web_app' => [
'url' => "https://$domain/webapp$hash/donate.html",
]
],
],
],
], ],
'wg' => $type == 'wg' ? $this->statusWg($arg) : false, 'wg' => $type == 'wg' ? $this->statusWg($arg) : false,
'client' => $type == 'client' ? $this->getClient(...explode('_', $arg)) : false, 'client' => $type == 'client' ? $this->getClient(...explode('_', $arg)) : false,
@@ -8909,7 +8962,7 @@ DNS-over-HTTPS with IP:
$this->update( $this->update(
$this->input['chat'], $this->input['chat'],
$this->input['message_id'], $this->input['message_id'],
implode("\n", $text ?: ['...']), implode("\n", ['...']),
$data ?: false, $data ?: false,
); );
} }
@@ -9360,16 +9413,34 @@ DNS-over-HTTPS with IP:
{ {
$c = $this->getPacConf(); $c = $this->getPacConf();
if (empty($c[$this->getInstanceWG(1) . 'amnezia_keys'])) { if (empty($c[$this->getInstanceWG(1) . 'amnezia_keys'])) {
// S1 and S2: 064 bytes; constraint: S1 + 56 ≠ S2
$s1 = random_int(15, 64);
do {
$s2 = random_int(15, 64);
} while ($s1 + 56 === $s2);
// H1H4: distinct 32-bit values (must not overlap)
$h = [];
while (count($h) < 4) {
$v = random_int(1, 4_294_967_295);
if (!in_array($v, $h)) {
$h[] = $v;
}
}
$c[$this->getInstanceWG(1) . 'amnezia_keys'] = [ $c[$this->getInstanceWG(1) . 'amnezia_keys'] = [
'Jc' => rand(3, 10), 'Jc' => random_int(3, 10),
'Jmin' => 50, 'Jmin' => 64,
'Jmax' => 1000, 'Jmax' => 1000,
'S1' => rand(15, 150), 'S1' => $s1,
'S2' => rand(15, 150), 'S2' => $s2,
'H1' => rand(1, 2_147_483_647), 'S3' => random_int(0, 64),
'H2' => rand(1, 2_147_483_647), 'S4' => random_int(0, 32),
'H3' => rand(1, 2_147_483_647), 'H1' => $h[0],
'H4' => rand(1, 2_147_483_647), 'H2' => $h[1],
'H3' => $h[2],
'H4' => $h[3],
'I1' => '<b 0xc000000001><r 100>',
]; ];
$this->setPacConf($c); $this->setPacConf($c);
} }
+3 -3
View File
@@ -99,7 +99,7 @@
"list": "~block~", "list": "~block~",
"action": "REJECT", "action": "REJECT",
"interval": 60, "interval": 60,
"behavior": "domain", "behavior": "classical",
"name": "block" "name": "block"
}, },
{ {
@@ -131,7 +131,7 @@
"list": "~pac~", "list": "~pac~",
"action": "PROXY", "action": "PROXY",
"interval": 60, "interval": 60,
"behavior": "domain", "behavior": "classical",
"name": "pac" "name": "pac"
}, },
{ {
@@ -139,7 +139,7 @@
"list": "~subnet~", "list": "~subnet~",
"action": "PROXY", "action": "PROXY",
"interval": 60, "interval": 60,
"behavior": "ipcidr", "behavior": "classical",
"name": "subnet" "name": "subnet"
}, },
{ {
+2 -2
View File
@@ -214,7 +214,7 @@ services:
- dnstt - dnstt
- hy - hy
wg: wg:
image: mercurykd/vpnbot-wg:1.1 image: mercurykd/vpnbot-wg:1.2
build: build:
dockerfile: dockerfile/wireguard.dockerfile dockerfile: dockerfile/wireguard.dockerfile
args: args:
@@ -252,7 +252,7 @@ services:
ipv4_address: 10.10.0.4 ipv4_address: 10.10.0.4
logging: *default-logging logging: *default-logging
wg1: wg1:
image: mercurykd/vpnbot-wg:1.1 image: mercurykd/vpnbot-wg:1.2
build: build:
dockerfile: dockerfile/wireguard.dockerfile dockerfile: dockerfile/wireguard.dockerfile
args: args:
+4
View File
@@ -1,3 +1,7 @@
10.03.2026 v2.29
- amnezia 2.0
16.12.2025 v2.28.1
- фикс шаблона mihomo
15.12.2025 v2.28 15.12.2025 v2.28
- новый MTProto - новый MTProto
- hysteria - hysteria