mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-05 20:54:14 +00:00
fix(outbounds): preserve SNI/TLS settings on transport change
Changing the transport in the outbound edit modal rebuilt streamSettings from scratch, dropping tlsSettings (and its serverName) while keeping security: 'tls'. On save xray received TLS with an empty SNI, so SNI-spoof tunnels connected but passed no traffic. Carry over tlsSettings/ realitySettings when the new network still supports the security mode, via a new applyNetworkChange helper. Fixes #4791.
This commit is contained in:
parent
039d05a743
commit
5fb18b8819
2 changed files with 31 additions and 14 deletions
|
|
@ -42,6 +42,7 @@ import {
|
||||||
SERVER_PROTOCOLS,
|
SERVER_PROTOCOLS,
|
||||||
} from './outbound-form-constants';
|
} from './outbound-form-constants';
|
||||||
import {
|
import {
|
||||||
|
applyNetworkChange,
|
||||||
buildAddModeValues,
|
buildAddModeValues,
|
||||||
hysteriaStreamSlice,
|
hysteriaStreamSlice,
|
||||||
newStreamSlice,
|
newStreamSlice,
|
||||||
|
|
@ -231,20 +232,8 @@ export default function OutboundFormModal({
|
||||||
// wsSettings, etc.) so the DU branch matches. Preserve security if
|
// wsSettings, etc.) so the DU branch matches. Preserve security if
|
||||||
// the new network supports it, otherwise force back to 'none'.
|
// the new network supports it, otherwise force back to 'none'.
|
||||||
function onNetworkChange(next: string) {
|
function onNetworkChange(next: string) {
|
||||||
if (next === 'hysteria') {
|
const stream = (form.getFieldValue('streamSettings') ?? {}) as Record<string, unknown>;
|
||||||
form.setFieldValue('streamSettings', hysteriaStreamSlice());
|
form.setFieldValue('streamSettings', applyNetworkChange(protocol, stream, next));
|
||||||
return;
|
|
||||||
}
|
|
||||||
const currentSecurity = form.getFieldValue(['streamSettings', 'security']) ?? 'none';
|
|
||||||
const stillAllowed = canEnableTls({ protocol, streamSettings: { network: next, security: currentSecurity } });
|
|
||||||
const stillReality = canEnableReality({ protocol, streamSettings: { network: next, security: currentSecurity } });
|
|
||||||
const newSecurity =
|
|
||||||
currentSecurity === 'tls' && !stillAllowed
|
|
||||||
? 'none'
|
|
||||||
: currentSecurity === 'reality' && !stillReality
|
|
||||||
? 'none'
|
|
||||||
: currentSecurity;
|
|
||||||
form.setFieldValue('streamSettings', { ...newStreamSlice(next), security: newSecurity });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onXmuxToggle(checked: boolean) {
|
function onXmuxToggle(checked: boolean) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { rawOutboundToFormValues } from '@/lib/xray/outbound-form-adapter';
|
import { rawOutboundToFormValues } from '@/lib/xray/outbound-form-adapter';
|
||||||
|
import { canEnableReality, canEnableTls } from '@/lib/xray/protocol-capabilities';
|
||||||
import type { OutboundFormValues } from '@/schemas/forms/outbound-form';
|
import type { OutboundFormValues } from '@/schemas/forms/outbound-form';
|
||||||
|
|
||||||
import { MUX_PROTOCOLS } from './outbound-form-constants';
|
import { MUX_PROTOCOLS } from './outbound-form-constants';
|
||||||
|
|
@ -74,6 +75,33 @@ export function hysteriaStreamSlice(): Record<string, unknown> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Network change cascade: swap the per-network sub-key (tcpSettings,
|
||||||
|
// wsSettings, etc.) so the DU branch matches. Carry over the security mode
|
||||||
|
// and its settings (tlsSettings/realitySettings, including SNI serverName)
|
||||||
|
// when the new network still supports it; otherwise fall back to 'none'.
|
||||||
|
// Dropping tlsSettings here silently wiped the spoofed SNI on save (#4791).
|
||||||
|
export function applyNetworkChange(
|
||||||
|
protocol: string,
|
||||||
|
prevStream: Record<string, unknown> | undefined,
|
||||||
|
next: string,
|
||||||
|
): Record<string, unknown> {
|
||||||
|
if (next === 'hysteria') return hysteriaStreamSlice();
|
||||||
|
const stream = prevStream ?? {};
|
||||||
|
const currentSecurity = (stream.security as string) ?? 'none';
|
||||||
|
const stillTls = canEnableTls({ protocol, streamSettings: { network: next, security: currentSecurity } });
|
||||||
|
const stillReality = canEnableReality({ protocol, streamSettings: { network: next, security: currentSecurity } });
|
||||||
|
const newSecurity =
|
||||||
|
currentSecurity === 'tls' && !stillTls
|
||||||
|
? 'none'
|
||||||
|
: currentSecurity === 'reality' && !stillReality
|
||||||
|
? 'none'
|
||||||
|
: currentSecurity;
|
||||||
|
const newStream: Record<string, unknown> = { ...newStreamSlice(next), security: newSecurity };
|
||||||
|
if (newSecurity === 'tls' && stream.tlsSettings) newStream.tlsSettings = stream.tlsSettings;
|
||||||
|
else if (newSecurity === 'reality' && stream.realitySettings) newStream.realitySettings = stream.realitySettings;
|
||||||
|
return newStream;
|
||||||
|
}
|
||||||
|
|
||||||
export function buildAddModeValues(): OutboundFormValues {
|
export function buildAddModeValues(): OutboundFormValues {
|
||||||
return rawOutboundToFormValues({});
|
return rawOutboundToFormValues({});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue