修正VMess 和 VLESS TLS配置问题,并且修改了切换节点的逻辑

(cherry picked from commit 8c34c2b0d31ee37a566de6dcb3ec62b7bb0a7222)
This commit is contained in:
2025-10-31 15:16:49 +08:00
committed by speakeloudest
parent b79ce2d15a
commit c5715f77e2
4 changed files with 232 additions and 29 deletions
+151 -11
View File
@@ -243,6 +243,111 @@ class KROutboundItem {
print(' - port: ${nodeListItem.port}');
print(' - uuid: ${nodeListItem.uuid}');
print(' - method: ${nodeListItem.method}');
print(' - config: ${nodeListItem.config}');
print(' - protocols: ${nodeListItem.protocols}');
// 🔧 尝试从 config 字段解析 transport 配置
Map<String, dynamic>? transportConfig;
Map<String, dynamic>? securityConfig;
// 🔧 关键修复:优先从 protocols 字段解析配置
if (nodeListItem.protocols.isNotEmpty) {
try {
final protocolsList = jsonDecode(nodeListItem.protocols) as List;
print('📄 解析到 protocols 数组,共 ${protocolsList.length} 个协议');
// 查找匹配当前协议类型的配置
Map<String, dynamic>? matchedProtocol;
for (var protocol in protocolsList) {
final protocolMap = protocol as Map<String, dynamic>;
final type = protocolMap['type']?.toString().toLowerCase() ?? '';
final enable = protocolMap['enable'] ?? true;
print(' 📋 协议: type=$type, enable=$enable');
// 匹配协议类型(注意 hysteria 和 hysteria2 都匹配 hysteria
if (type == nodeListItem.protocol.toLowerCase() ||
(nodeListItem.protocol == 'hysteria' && type == 'hysteria2') ||
(nodeListItem.protocol == 'hysteria2' && type == 'hysteria')) {
matchedProtocol = protocolMap;
print(' ✅ 找到匹配的协议配置: $type');
break;
}
}
if (matchedProtocol != null) {
// 提取 transport 配置
if (matchedProtocol['network'] != null || matchedProtocol['transport'] != null) {
final network = matchedProtocol['network'] ?? matchedProtocol['transport'];
print(' 📡 传输协议: $network');
if (network == 'ws' || network == 'websocket') {
transportConfig = {
'type': 'ws',
'path': matchedProtocol['ws_path'] ?? matchedProtocol['path'] ?? '/',
};
final host = matchedProtocol['ws_host'] ?? matchedProtocol['host'];
if (host != null && host.toString().isNotEmpty) {
transportConfig['headers'] = {'Host': host.toString()};
}
print(' ✅ WebSocket transport: $transportConfig');
} else if (network == 'grpc') {
transportConfig = {
'type': 'grpc',
'service_name': matchedProtocol['grpc_service_name'] ?? matchedProtocol['service_name'] ?? '',
};
print(' ✅ gRPC transport: $transportConfig');
} else if (network == 'http' || network == 'h2') {
transportConfig = {
'type': 'http',
'host': [matchedProtocol['http_host'] ?? matchedProtocol['host'] ?? ''],
'path': matchedProtocol['http_path'] ?? matchedProtocol['path'] ?? '/',
};
print(' ✅ HTTP transport: $transportConfig');
}
}
// 提取 security 配置
if (matchedProtocol['tls'] != null || matchedProtocol['security'] != null) {
// 🔧 关键修复:读取 security 字段判断是否启用 TLS
final security = matchedProtocol['security']?.toString().toLowerCase() ?? '';
final tlsEnabled = security == 'tls' || security == 'reality';
securityConfig = {
'tls_enabled': tlsEnabled, // ← 新增:记录 TLS 是否启用
'sni': matchedProtocol['sni'] ?? matchedProtocol['server_name'],
'allow_insecure': matchedProtocol['allow_insecure'] ?? matchedProtocol['insecure'] ?? true,
'fingerprint': matchedProtocol['fingerprint'] ?? 'chrome',
};
print(' ✅ Security config: security=$security, tls_enabled=$tlsEnabled, config=$securityConfig');
}
}
} catch (e) {
print('⚠️ 解析 protocols 字段失败: $e');
}
}
// 兜底:尝试从 config 字段解析(旧API格式)
if (transportConfig == null && nodeListItem.config.isNotEmpty) {
try {
final configJson = jsonDecode(nodeListItem.config) as Map<String, dynamic>;
print('📄 解析到 config JSON: $configJson');
// 提取 transport 配置
if (configJson['transport'] != null && configJson['transport'] != 'tcp') {
transportConfig = _buildTransport(configJson);
print('✅ 从 config 找到 transport 配置: $transportConfig');
}
// 提取 security_config
if (configJson['security_config'] != null) {
securityConfig = configJson['security_config'] as Map<String, dynamic>;
print('✅ 从 config 找到 security_config: $securityConfig');
}
} catch (e) {
print('⚠️ 解析 config 字段失败: $e');
}
}
switch (nodeListItem.protocol) {
case "shadowsocks":
@@ -268,19 +373,30 @@ class KROutboundItem {
final bool isDomain = !RegExp(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')
.hasMatch(nodeListItem.serverAddr);
// 🔧 优先使用 security_config 中的 SNI
String serverName = nodeListItem.serverAddr;
if (securityConfig != null && securityConfig['sni'] != null && securityConfig['sni'].toString().isNotEmpty) {
serverName = securityConfig['sni'].toString();
}
// 🔧 关键修复:根据 security_config 判断是否启用 TLS
final bool vlessTlsEnabled = securityConfig?['tls_enabled'] ?? false;
print('🔐 VLESS TLS 状态: enabled=$vlessTlsEnabled');
config = {
"type": "vless",
"tag": nodeListItem.name,
"server": nodeListItem.serverAddr,
"server_port": nodeListItem.port,
"uuid": nodeListItem.uuid,
"tls": {
if (transportConfig != null) "transport": transportConfig,
if (vlessTlsEnabled) "tls": {
"enabled": true,
if (isDomain) "server_name": nodeListItem.serverAddr,
"insecure": true,
if (isDomain) "server_name": serverName,
"insecure": securityConfig?['allow_insecure'] ?? true,
"utls": {
"enabled": true,
"fingerprint": "chrome"
"fingerprint": securityConfig?['fingerprint'] ?? "chrome"
}
}
};
@@ -292,6 +408,16 @@ class KROutboundItem {
final bool isDomain = !RegExp(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')
.hasMatch(nodeListItem.serverAddr);
// 🔧 优先使用 security_config 中的 SNI
String serverName = nodeListItem.serverAddr;
if (securityConfig != null && securityConfig['sni'] != null && securityConfig['sni'].toString().isNotEmpty) {
serverName = securityConfig['sni'].toString();
}
// 🔧 关键修复:根据 security_config 判断是否启用 TLS
final bool tlsEnabled = securityConfig?['tls_enabled'] ?? false;
print('🔐 TLS 状态: enabled=$tlsEnabled');
config = {
"type": "vmess",
"tag": nodeListItem.name,
@@ -300,11 +426,15 @@ class KROutboundItem {
"uuid": nodeListItem.uuid,
"alter_id": 0,
"security": "auto",
"tls": {
if (transportConfig != null) "transport": transportConfig,
if (tlsEnabled) "tls": {
"enabled": true,
if (isDomain) "server_name": nodeListItem.serverAddr,
"insecure": true,
"utls": {"enabled": true, "fingerprint": "chrome"}
if (isDomain) "server_name": serverName,
"insecure": securityConfig?['allow_insecure'] ?? true,
"utls": {
"enabled": true,
"fingerprint": securityConfig?['fingerprint'] ?? "chrome"
}
}
};
print('✅ VMess 节点配置构建成功: ${nodeListItem.name}');
@@ -315,17 +445,27 @@ class KROutboundItem {
final bool isDomain = !RegExp(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')
.hasMatch(nodeListItem.serverAddr);
// 🔧 优先使用 security_config 中的 SNI
String serverName = nodeListItem.serverAddr;
if (securityConfig != null && securityConfig['sni'] != null && securityConfig['sni'].toString().isNotEmpty) {
serverName = securityConfig['sni'].toString();
}
config = {
"type": "trojan",
"tag": nodeListItem.name,
"server": nodeListItem.serverAddr,
"server_port": nodeListItem.port,
"password": nodeListItem.uuid,
if (transportConfig != null) "transport": transportConfig,
"tls": {
"enabled": true,
if (isDomain) "server_name": nodeListItem.serverAddr,
"insecure": true,
"utls": {"enabled": true, "fingerprint": "chrome"}
if (isDomain) "server_name": serverName,
"insecure": securityConfig?['allow_insecure'] ?? true,
"utls": {
"enabled": true,
"fingerprint": securityConfig?['fingerprint'] ?? "chrome"
}
}
};
print('✅ Trojan 节点配置构建成功: ${nodeListItem.name}');