diff --git a/app/Protocols/ClashMeta.php b/app/Protocols/ClashMeta.php index daa46ce..4d0cb5b 100644 --- a/app/Protocols/ClashMeta.php +++ b/app/Protocols/ClashMeta.php @@ -311,6 +311,7 @@ class ClashMeta extends AbstractProtocol if ($serverName = data_get($protocol_settings, 'tls_settings.server_name')) { $array['servername'] = $serverName; } + $array['client-fingerprint'] = Helper::getRandFingerprint(); break; case 2: $array['tls'] = true; diff --git a/app/Protocols/General.php b/app/Protocols/General.php index 07a35d3..c57171c 100644 --- a/app/Protocols/General.php +++ b/app/Protocols/General.php @@ -19,6 +19,7 @@ class General extends AbstractProtocol Server::TYPE_HYSTERIA, Server::TYPE_ANYTLS, Server::TYPE_SOCKS, + Server::TYPE_TUIC, ]; protected $protocolRequirements = [ @@ -41,6 +42,7 @@ class General extends AbstractProtocol Server::TYPE_HYSTERIA => self::buildHysteria($item['password'], $item), Server::TYPE_ANYTLS => self::buildAnyTLS($item['password'], $item), Server::TYPE_SOCKS => self::buildSocks($item['password'], $item), + Server::TYPE_TUIC => self::buildTuic($item['password'], $item), default => '', }; } @@ -137,6 +139,7 @@ class General extends AbstractProtocol $config['security'] = "tls"; if ($serverName = data_get($protocol_settings, 'tls_settings.server_name')) { $config['sni'] = $serverName; + $config['fp'] = Helper::getRandFingerprint(); } break; case 2: //reality @@ -256,6 +259,59 @@ class General extends AbstractProtocol return $uri; } + + + public static function buildTuic($password, $server) + { + $protocol_settings = data_get($server, 'protocol_settings', []); + $name = rawurlencode($server['name']); + $addr = Helper::wrapIPv6($server['host']); + $port = $server['port']; + $uuid = $password; // v2rayN格式里,uuid和password都是密码部分 + $pass = $password; + + $queryParams = []; + + // 填充sni参数 + if ($sni = data_get($protocol_settings, 'tls.server_name')) { + $queryParams['sni'] = $sni; + } + + // alpn参数,支持多值时用逗号连接 + if ($alpn = data_get($protocol_settings, 'alpn')) { + if (is_array($alpn)) { + $queryParams['alpn'] = implode(',', $alpn); + } else { + $queryParams['alpn'] = $alpn; + } + } + + // congestion_controller参数,默认cubic + $congestion = data_get($protocol_settings, 'congestion_control', 'cubic'); + $queryParams['congestion_control'] = $congestion; + + // udp_relay_mode参数,默认native + $udpRelay = data_get($protocol_settings, 'udp_relay_mode', 'native'); + $queryParams['udp-relay-mode'] = $udpRelay; + + $query = http_build_query($queryParams); + + // 构造完整URI,格式: + // Tuic://uuid:password@host:port?sni=xxx&alpn=xxx&congestion_controller=xxx&udp_relay_mode=xxx#别名 + $uri = "tuic://{$uuid}:{$pass}@{$addr}:{$port}"; + + if (!empty($query)) { + $uri .= "?{$query}"; + } + + $uri .= "#{$name}\r\n"; + + return $uri; + } + + + + public static function buildAnyTLS($password, $server) { diff --git a/app/Protocols/Shadowrocket.php b/app/Protocols/Shadowrocket.php index 40dbcf9..9aaac5b 100644 --- a/app/Protocols/Shadowrocket.php +++ b/app/Protocols/Shadowrocket.php @@ -165,6 +165,7 @@ class Shadowrocket extends AbstractProtocol if ($serverName = data_get($protocol_settings, 'tls_settings.server_name')) { $config['peer'] = $serverName; } + $config['fp'] = Helper::getRandFingerprint(); break; case 2: $config['tls'] = 1;