Merge remote-tracking branch 'upstream/master'

# Conflicts:
#	public/assets/admin
This commit is contained in:
yinjianm
2026-04-18 00:35:04 +08:00
27 changed files with 1604 additions and 354 deletions
+66 -2
View File
@@ -58,6 +58,66 @@ class ClashMeta extends AbstractProtocol
'flclash.hysteria.protocol_settings.version' => [
2 => '0.8.0',
],
'meta.vmess.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'meta.vless.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'meta.trojan.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'meta.anytls.protocol_settings.tls.ech.enabled' => [
1 => '1.19.9',
],
'verge.vmess.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'verge.vless.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'verge.trojan.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'verge.anytls.protocol_settings.tls.ech.enabled' => [
1 => '1.19.9',
],
'flclash.vmess.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'flclash.vless.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'flclash.trojan.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'flclash.anytls.protocol_settings.tls.ech.enabled' => [
1 => '1.19.9',
],
'nekobox.vmess.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'nekobox.vless.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'nekobox.trojan.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'nekobox.anytls.protocol_settings.tls.ech.enabled' => [
1 => '1.19.9',
],
'clashmetaforandroid.vmess.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'clashmetaforandroid.vless.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'clashmetaforandroid.trojan.protocol_settings.tls_settings.ech.enabled' => [
1 => '1.19.9',
],
'clashmetaforandroid.anytls.protocol_settings.tls.ech.enabled' => [
1 => '1.19.9',
],
];
public function handle()
@@ -266,6 +326,7 @@ class ClashMeta extends AbstractProtocol
$array['tls'] = (bool) data_get($protocol_settings, 'tls');
$array['skip-cert-verify'] = (bool) data_get($protocol_settings, 'tls_settings.allow_insecure', false);
$array['servername'] = data_get($protocol_settings, 'tls_settings.server_name');
self::appendEch($array, data_get($protocol_settings, 'tls_settings.ech'));
}
self::appendUtls($array, $protocol_settings);
@@ -348,6 +409,7 @@ class ClashMeta extends AbstractProtocol
if ($serverName = data_get($protocol_settings, 'tls_settings.server_name')) {
$array['servername'] = $serverName;
}
self::appendEch($array, data_get($protocol_settings, 'tls_settings.ech'));
self::appendUtls($array, $protocol_settings);
break;
case 2:
@@ -442,10 +504,11 @@ class ClashMeta extends AbstractProtocol
];
break;
default: // Standard TLS
$array['skip-cert-verify'] = (bool) data_get($protocol_settings, 'allow_insecure', false);
if ($serverName = data_get($protocol_settings, 'server_name')) {
$array['skip-cert-verify'] = (bool) data_get($protocol_settings, 'tls_settings.allow_insecure', data_get($protocol_settings, 'allow_insecure', false));
if ($serverName = data_get($protocol_settings, 'tls_settings.server_name', data_get($protocol_settings, 'server_name'))) {
$array['sni'] = $serverName;
}
self::appendEch($array, data_get($protocol_settings, 'tls_settings.ech'));
break;
}
@@ -586,6 +649,7 @@ class ClashMeta extends AbstractProtocol
if ($allowInsecure = data_get($protocol_settings, 'tls.allow_insecure')) {
$array['skip-cert-verify'] = (bool) $allowInsecure;
}
self::appendEch($array, data_get($protocol_settings, 'tls.ech'));
return $array;
}
+28
View File
@@ -14,6 +14,7 @@ class QuantumultX extends AbstractProtocol
Server::TYPE_VMESS,
Server::TYPE_VLESS,
Server::TYPE_TROJAN,
Server::TYPE_ANYTLS,
Server::TYPE_SOCKS,
Server::TYPE_HTTP,
];
@@ -29,6 +30,7 @@ class QuantumultX extends AbstractProtocol
Server::TYPE_VMESS => self::buildVmess($item['password'], $item),
Server::TYPE_VLESS => self::buildVless($item['password'], $item),
Server::TYPE_TROJAN => self::buildTrojan($item['password'], $item),
Server::TYPE_ANYTLS => self::buildAnyTLS($item['password'], $item),
Server::TYPE_SOCKS => self::buildSocks5($item['password'], $item),
Server::TYPE_HTTP => self::buildHttp($item['password'], $item),
default => ''
@@ -198,6 +200,32 @@ class QuantumultX extends AbstractProtocol
return implode(',', array_filter($config)) . "\r\n";
}
public static function buildAnyTLS($password, $server)
{
$protocol_settings = data_get($server, 'protocol_settings', []);
$addr = Helper::wrapIPv6($server['host']);
$config = [
"anytls={$addr}:{$server['port']}",
"password={$password}",
'udp-relay=true',
"tag={$server['name']}",
"over-tls=true",
];
// allow_insecure=false => tls-verification=true
// allow_insecure=true 时不写,沿用 QX 默认 false
$allowInsecure = (bool) data_get($protocol_settings, 'tls.allow_insecure', false);
if (!$allowInsecure) {
$config[] = 'tls-verification=true';
}
if ($serverName = data_get($protocol_settings, 'tls.server_name')) {
$config[] = "tls-host=$serverName";
}
return implode(',', array_filter($config)) . "\r\n";
}
public static function buildSocks5($password, $server)
{
$protocol_settings = $server['protocol_settings'];
+60 -4
View File
@@ -37,16 +37,35 @@ class SingBox extends AbstractProtocol
],
'protocol_settings.tls' => [
'2' => '1.6.0' // Reality
],
'protocol_settings.tls_settings.ech.enabled' => [
1 => '1.5.0'
]
],
'vmess' => [
'protocol_settings.tls_settings.ech.enabled' => [
1 => '1.5.0'
]
],
'trojan' => [
'protocol_settings.tls_settings.ech.enabled' => [
1 => '1.5.0'
]
],
'hysteria' => [
'base_version' => '1.5.0',
'protocol_settings.version' => [
'2' => '1.5.0' // Hysteria 2
],
'protocol_settings.tls.ech.enabled' => [
1 => '1.5.0'
]
],
'tuic' => [
'base_version' => '1.5.0'
'base_version' => '1.5.0',
'protocol_settings.tls.ech.enabled' => [
1 => '1.5.0'
]
],
'ssh' => [
'base_version' => '1.8.0'
@@ -58,7 +77,25 @@ class SingBox extends AbstractProtocol
'base_version' => '1.5.0'
],
'anytls' => [
'base_version' => '1.12.0'
'base_version' => '1.12.0',
'protocol_settings.tls.ech.enabled' => [
1 => '1.12.0'
]
],
'socks' => [
'protocol_settings.tls_settings.ech.enabled' => [
1 => '1.5.0'
]
],
'naive' => [
'protocol_settings.tls_settings.ech.enabled' => [
1 => '1.5.0'
]
],
'http' => [
'protocol_settings.tls_settings.ech.enabled' => [
1 => '1.5.0'
]
],
]
];
@@ -405,6 +442,7 @@ class SingBox extends AbstractProtocol
];
$this->appendUtls($array['tls'], $protocol_settings);
$this->appendEch($array['tls'], data_get($protocol_settings, 'tls_settings.ech'));
if ($serverName = data_get($protocol_settings, 'tls_settings.server_name')) {
$array['tls']['server_name'] = $serverName;
@@ -447,6 +485,7 @@ class SingBox extends AbstractProtocol
switch ($tlsMode) {
case 1:
$this->appendEch($tlsConfig, data_get($protocol_settings, 'tls_settings.ech'));
if ($serverName = data_get($protocol_settings, 'tls_settings.server_name')) {
$tlsConfig['server_name'] = $serverName;
}
@@ -498,8 +537,9 @@ class SingBox extends AbstractProtocol
];
break;
default: // Standard TLS
$tlsConfig['insecure'] = (bool) data_get($protocol_settings, 'allow_insecure', false);
if ($serverName = data_get($protocol_settings, 'server_name')) {
$tlsConfig['insecure'] = (bool) data_get($protocol_settings, 'tls_settings.allow_insecure', data_get($protocol_settings, 'allow_insecure', false));
$this->appendEch($tlsConfig, data_get($protocol_settings, 'tls_settings.ech'));
if ($serverName = data_get($protocol_settings, 'tls_settings.server_name', data_get($protocol_settings, 'server_name'))) {
$tlsConfig['server_name'] = $serverName;
}
break;
@@ -541,6 +581,7 @@ class SingBox extends AbstractProtocol
if ($serverName = data_get($protocol_settings, 'tls.server_name')) {
$baseConfig['tls']['server_name'] = $serverName;
}
$this->appendEch($baseConfig['tls'], data_get($protocol_settings, 'tls.ech'));
$speedConfig = [
'up_mbps' => data_get($protocol_settings, 'bandwidth.up'),
'down_mbps' => data_get($protocol_settings, 'bandwidth.down'),
@@ -590,6 +631,7 @@ class SingBox extends AbstractProtocol
if ($serverName = data_get($protocol_settings, 'tls.server_name')) {
$array['tls']['server_name'] = $serverName;
}
$this->appendEch($array['tls'], data_get($protocol_settings, 'tls.ech'));
if (data_get($protocol_settings, 'version') === 4) {
$array['token'] = $password;
@@ -620,6 +662,7 @@ class SingBox extends AbstractProtocol
if ($serverName = data_get($protocol_settings, 'tls.server_name')) {
$array['tls']['server_name'] = $serverName;
}
$this->appendEch($array['tls'], data_get($protocol_settings, 'tls.ech'));
return $array;
}
@@ -673,6 +716,7 @@ class SingBox extends AbstractProtocol
if ($serverName = data_get($protocol_settings, 'tls_settings.server_name')) {
$array['tls']['server_name'] = $serverName;
}
$this->appendEch($array['tls'], data_get($protocol_settings, 'tls_settings.ech'));
}
return $array;
@@ -754,4 +798,16 @@ class SingBox extends AbstractProtocol
}
}
}
protected function appendEch(&$tlsConfig, $ech): void
{
if ($normalized = Helper::normalizeEchSettings($ech)) {
// Client outbound only needs the public ECH config, not the server's private key
$tlsConfig['ech'] = array_filter([
'enabled' => true,
'config' => data_get($normalized, 'config') ? [data_get($normalized, 'config')] : null,
'query_server_name' => data_get($normalized, 'query_server_name'),
], fn($value) => $value !== null);
}
}
}