mirror of https://github.com/ospab/ostp.git
feat(gui): TTL-desync toggle in client settings
Adds a TTL Desync toggle to the obfuscation section of the desktop client settings, wired the same way as the Junk/TCP-fragmentation toggles: persisted in client settings, applied into transport.ttl_desync in the built config, included in the hot-reload fingerprint so flipping it while connected re-applies, and labelled in both EN and RU. ttl_desync_auto is passed true, so the engine measures the hop distance and aims the decoys itself — the user just flips it on.
This commit is contained in:
parent
1e9111ab9f
commit
bfd079ff48
|
|
@ -28,6 +28,8 @@ const translations = {
|
|||
label_kill_switch: 'Kill Switch',
|
||||
kill_switch_hint: 'Block non-VPN traffic when tunnel drops',
|
||||
label_transport: 'Transport Protocol',
|
||||
label_ttl_desync: 'TTL Desync',
|
||||
hint_ttl_desync: 'Decoy packets that die before the server (UDP, auto-tuned)',
|
||||
label_mtu: 'MTU Size',
|
||||
label_transport: 'Transport Protocol',
|
||||
label_sni: 'Stealth SNI (Fake Host)',
|
||||
|
|
@ -93,6 +95,8 @@ const translations = {
|
|||
label_kill_switch: 'Kill Switch',
|
||||
kill_switch_hint: 'Блокировать трафик вне VPN при обрыве связи',
|
||||
label_transport: 'Транспортный протокол',
|
||||
label_ttl_desync: 'TTL-десинхронизация',
|
||||
hint_ttl_desync: 'Пакеты-приманки, умирающие до сервера (UDP, авто-настройка)',
|
||||
label_mtu: 'Размер MTU',
|
||||
label_transport: 'Транспортный протокол',
|
||||
label_sni: 'Маскировочный SNI',
|
||||
|
|
|
|||
|
|
@ -336,6 +336,17 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toggle-row" style="border-top:none;">
|
||||
<div class="toggle-text">
|
||||
<span class="toggle-name" data-i18n="label_ttl_desync">TTL Desync</span>
|
||||
<span class="toggle-hint" data-i18n="hint_ttl_desync">Decoy packets that die before the server (UDP, auto-tuned)</span>
|
||||
</div>
|
||||
<label class="toggle">
|
||||
<input type="checkbox" id="cs-ttl-desync" />
|
||||
<span class="toggle-track"><span class="toggle-thumb"></span></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div> <!-- client-settings-card -->
|
||||
|
||||
<div class="app-version" id="app-version">OSTP GUI</div>
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ const btnJunkDone = $('btn-junk-done');
|
|||
|
||||
const inTcpFrag = $('cs-tcp-frag');
|
||||
const btnFragSettings = $('btn-frag-settings');
|
||||
const inTtlDesync = $('cs-ttl-desync');
|
||||
const fragModal = $('frag-modal');
|
||||
const inFragChunk = $('cs-frag-chunk');
|
||||
const inFragSleep = $('cs-frag-sleep');
|
||||
|
|
@ -318,7 +319,9 @@ function buildConfig() {
|
|||
frag_chunk: s.tcpFrag ? (s.fragChunk || 2) : (active.frag_chunk || 2),
|
||||
frag_sleep: s.tcpFrag ? (!isNaN(parseInt(s.fragSleep)) ? s.fragSleep : 2) : (active.frag_sleep !== undefined ? active.frag_sleep : 2),
|
||||
junk_pc: s.junkEnabled ? [s.junkPcMin || 2, s.junkPcMax || 5] : (active.junk_pc || [2, 5]),
|
||||
junk_ps: s.junkEnabled ? [s.junkPsMin || 100, s.junkPsMax || 1000] : (active.junk_ps || [100, 1000])
|
||||
junk_ps: s.junkEnabled ? [s.junkPsMin || 100, s.junkPsMax || 1000] : (active.junk_ps || [100, 1000]),
|
||||
ttl_desync: !!s.ttlDesync,
|
||||
ttl_desync_auto: true
|
||||
},
|
||||
tun: {
|
||||
enable: !!s.tun,
|
||||
|
|
@ -657,6 +660,7 @@ function loadSettingsIntoForm() {
|
|||
inTcpFrag.checked = !!s.tcpFrag;
|
||||
inFragChunk.value = s.fragChunk || 2;
|
||||
inFragSleep.value = !isNaN(parseInt(s.fragSleep)) ? s.fragSleep : 2;
|
||||
if (inTtlDesync) inTtlDesync.checked = !!s.ttlDesync;
|
||||
updateClientVisibility();
|
||||
}
|
||||
|
||||
|
|
@ -692,6 +696,7 @@ function collectAndSaveSettings() {
|
|||
tcpFrag: inTcpFrag.checked,
|
||||
fragChunk: parseInt(inFragChunk.value) || 2,
|
||||
fragSleep: !isNaN(parseInt(inFragSleep.value)) ? parseInt(inFragSleep.value) : 2,
|
||||
ttlDesync: inTtlDesync ? inTtlDesync.checked : false,
|
||||
};
|
||||
// Cheap and local: safe to run on every debounced keystroke.
|
||||
saveClientSettings(s);
|
||||
|
|
@ -715,7 +720,7 @@ function collectAndSaveSettings() {
|
|||
const tunnelRelevant = JSON.stringify([
|
||||
s.tun, s.killSwitch, s.mux, s.muxSessions, s.mtu, s.dns, s.socks,
|
||||
s.exDomains, s.exIps, s.exProcs, s.junkEnabled, s.junkPcMin, s.junkPcMax,
|
||||
s.junkPsMin, s.junkPsMax, s.tcpFrag, s.fragChunk, s.fragSleep,
|
||||
s.junkPsMin, s.junkPsMax, s.tcpFrag, s.fragChunk, s.fragSleep, s.ttlDesync,
|
||||
]);
|
||||
if (tunnelRelevant !== lastAppliedTunnelConfig) {
|
||||
clearTimeout(hotReloadTimer);
|
||||
|
|
@ -901,7 +906,8 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||
wintunModal.addEventListener('click', e => { if (e.target === wintunModal) wintunModal.classList.add('hidden'); });
|
||||
|
||||
// Client settings — wire all inputs
|
||||
[inTun, inKillSwitch, inMux, inAutoconnect, inLaunchStartup, inDebug, inShowRtt, inShowSpeed, inJunkEnabled, inTcpFrag]
|
||||
[inTun, inKillSwitch, inMux, inAutoconnect, inLaunchStartup, inDebug, inShowRtt, inShowSpeed, inJunkEnabled, inTcpFrag, inTtlDesync]
|
||||
.filter(Boolean)
|
||||
.forEach(el => el.addEventListener('change', collectAndSaveSettings));
|
||||
[inMuxSessions, inMtu, inDns, inSocks, inExDomains, inExIps, inExProcs, inJunkPcMin, inJunkPcMax, inJunkPsMin, inJunkPsMax, inFragChunk, inFragSleep]
|
||||
.forEach(el => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue