mirror of https://github.com/ospab/ostp.git
feat(gui): add junk and tcp fragmentation global settings
This commit is contained in:
parent
b89c6b0950
commit
2819e2b3c2
|
|
@ -302,6 +302,40 @@
|
|||
</label>
|
||||
</div>
|
||||
|
||||
<div class="section-divider-mini"><span>Obfuscation</span></div>
|
||||
|
||||
<div class="toggle-row" style="border-top:none;">
|
||||
<div class="toggle-text">
|
||||
<span class="toggle-name">Junk Packets</span>
|
||||
<span class="toggle-hint">Random noise before connection (UoT only)</span>
|
||||
</div>
|
||||
<div class="toggle-with-gear">
|
||||
<label class="toggle">
|
||||
<input type="checkbox" id="cs-junk-enabled" />
|
||||
<span class="toggle-track"><span class="toggle-thumb"></span></span>
|
||||
</label>
|
||||
<button id="btn-junk-settings" class="gear-btn" title="Configure junk packets">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toggle-row" style="border-top:none;">
|
||||
<div class="toggle-text">
|
||||
<span class="toggle-name">TCP Fragmentation</span>
|
||||
<span class="toggle-hint">Split handshake into segments (UoT only)</span>
|
||||
</div>
|
||||
<div class="toggle-with-gear">
|
||||
<label class="toggle">
|
||||
<input type="checkbox" id="cs-tcp-frag" />
|
||||
<span class="toggle-track"><span class="toggle-thumb"></span></span>
|
||||
</label>
|
||||
<button id="btn-frag-settings" class="gear-btn" title="Configure fragmentation">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div> <!-- client-settings-card -->
|
||||
|
||||
<div class="app-version" id="app-version">OSTP GUI</div>
|
||||
|
|
@ -457,6 +491,58 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── JUNK PACKETS MODAL ──────────────────────────────────── -->
|
||||
<div id="junk-modal" class="modal-overlay hidden">
|
||||
<div class="modal-content compact">
|
||||
<h3 class="modal-title">Junk Packets</h3>
|
||||
<p class="modal-text">Sends random garbage frames before the Noise handshake to confuse DPI pattern matching. Active in UoT/TCP mode only.</p>
|
||||
<div class="modal-row-2">
|
||||
<div class="field-group">
|
||||
<label class="field-label" for="cs-junk-pc-min">Count min</label>
|
||||
<input id="cs-junk-pc-min" class="field-input" type="number" min="0" max="100" placeholder="2" />
|
||||
</div>
|
||||
<div class="field-group">
|
||||
<label class="field-label" for="cs-junk-pc-max">Count max</label>
|
||||
<input id="cs-junk-pc-max" class="field-input" type="number" min="0" max="100" placeholder="5" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-row-2">
|
||||
<div class="field-group">
|
||||
<label class="field-label" for="cs-junk-ps-min">Size min (bytes)</label>
|
||||
<input id="cs-junk-ps-min" class="field-input" type="number" min="1" placeholder="100" />
|
||||
</div>
|
||||
<div class="field-group">
|
||||
<label class="field-label" for="cs-junk-ps-max">Size max (bytes)</label>
|
||||
<input id="cs-junk-ps-max" class="field-input" type="number" min="1" placeholder="1000" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button id="btn-junk-done" class="btn primary">Done</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── TCP FRAGMENTATION MODAL ──────────────────────────────── -->
|
||||
<div id="frag-modal" class="modal-overlay hidden">
|
||||
<div class="modal-content compact">
|
||||
<h3 class="modal-title">TCP Fragmentation</h3>
|
||||
<p class="modal-text">Splits the initial handshake into tiny TCP segments with delays between them. Prevents DPI from reading the full handshake signature. Active in UoT/TCP mode only.</p>
|
||||
<div class="modal-row-2">
|
||||
<div class="field-group">
|
||||
<label class="field-label" for="cs-frag-chunk">Chunk size (bytes)</label>
|
||||
<input id="cs-frag-chunk" class="field-input" type="number" min="1" placeholder="2" />
|
||||
</div>
|
||||
<div class="field-group">
|
||||
<label class="field-label" for="cs-frag-sleep">Delay (ms)</label>
|
||||
<input id="cs-frag-sleep" class="field-input" type="number" min="0" placeholder="2" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button id="btn-frag-done" class="btn primary">Done</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast notification -->
|
||||
<div id="toast" class="toast" role="status" aria-live="polite"></div>
|
||||
|
||||
|
|
|
|||
|
|
@ -159,6 +159,22 @@ const inShowSpeed = $('in-show-speed');
|
|||
const groupKillSwitch = $('group-kill-switch');
|
||||
const groupMuxSessions = $('group-mux-sessions');
|
||||
|
||||
const inJunkEnabled = $('cs-junk-enabled');
|
||||
const btnJunkSettings = $('btn-junk-settings');
|
||||
const junkModal = $('junk-modal');
|
||||
const inJunkPcMin = $('cs-junk-pc-min');
|
||||
const inJunkPcMax = $('cs-junk-pc-max');
|
||||
const inJunkPsMin = $('cs-junk-ps-min');
|
||||
const inJunkPsMax = $('cs-junk-ps-max');
|
||||
const btnJunkDone = $('btn-junk-done');
|
||||
|
||||
const inTcpFrag = $('cs-tcp-frag');
|
||||
const btnFragSettings = $('btn-frag-settings');
|
||||
const fragModal = $('frag-modal');
|
||||
const inFragChunk = $('cs-frag-chunk');
|
||||
const inFragSleep = $('cs-frag-sleep');
|
||||
const btnFragDone = $('btn-frag-done');
|
||||
|
||||
// ── UTILITIES ─────────────────────────────────────────────────────────
|
||||
function fmtBytes(b) {
|
||||
if (!b || b === 0) return '0 B';
|
||||
|
|
@ -307,11 +323,11 @@ function buildConfig() {
|
|||
debug: !!s.debug,
|
||||
transport: {
|
||||
mode: active.transport || 'udp',
|
||||
tcp_fragmentation: !!active.tcp_fragmentation,
|
||||
frag_chunk: active.frag_chunk || 2,
|
||||
frag_sleep: active.frag_sleep || 2,
|
||||
junk_pc: active.junk_pc || [2, 5],
|
||||
junk_ps: active.junk_ps || [100, 1000]
|
||||
tcp_fragmentation: s.tcpFrag || !!active.tcp_fragmentation,
|
||||
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])
|
||||
},
|
||||
tun: {
|
||||
enable: !!s.tun,
|
||||
|
|
@ -668,6 +684,14 @@ function loadSettingsIntoForm() {
|
|||
inDebug.checked = !!s.debug;
|
||||
inShowRtt.checked = s.showRtt !== false;
|
||||
inShowSpeed.checked = s.showSpeed !== false;
|
||||
inJunkEnabled.checked = !!s.junkEnabled;
|
||||
inJunkPcMin.value = s.junkPcMin || 2;
|
||||
inJunkPcMax.value = s.junkPcMax || 5;
|
||||
inJunkPsMin.value = s.junkPsMin || 100;
|
||||
inJunkPsMax.value = s.junkPsMax || 1000;
|
||||
inTcpFrag.checked = !!s.tcpFrag;
|
||||
inFragChunk.value = s.fragChunk || 2;
|
||||
inFragSleep.value = !isNaN(parseInt(s.fragSleep)) ? s.fragSleep : 2;
|
||||
updateClientVisibility();
|
||||
}
|
||||
|
||||
|
|
@ -688,6 +712,14 @@ function collectAndSaveSettings() {
|
|||
debug: inDebug.checked,
|
||||
showRtt: inShowRtt.checked,
|
||||
showSpeed: inShowSpeed.checked,
|
||||
junkEnabled: inJunkEnabled.checked,
|
||||
junkPcMin: parseInt(inJunkPcMin.value) || 2,
|
||||
junkPcMax: parseInt(inJunkPcMax.value) || 5,
|
||||
junkPsMin: parseInt(inJunkPsMin.value) || 100,
|
||||
junkPsMax: parseInt(inJunkPsMax.value) || 1000,
|
||||
tcpFrag: inTcpFrag.checked,
|
||||
fragChunk: parseInt(inFragChunk.value) || 2,
|
||||
fragSleep: !isNaN(parseInt(inFragSleep.value)) ? parseInt(inFragSleep.value) : 2,
|
||||
};
|
||||
saveClientSettings(s);
|
||||
updateClientVisibility();
|
||||
|
|
@ -881,9 +913,9 @@ 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]
|
||||
[inTun, inKillSwitch, inMux, inAutoconnect, inLaunchStartup, inDebug, inShowRtt, inShowSpeed, inJunkEnabled, inTcpFrag]
|
||||
.forEach(el => el.addEventListener('change', collectAndSaveSettings));
|
||||
[inMuxSessions, inMtu, inDns, inSocks, inExDomains, inExIps, inExProcs]
|
||||
[inMuxSessions, inMtu, inDns, inSocks, inExDomains, inExIps, inExProcs, inJunkPcMin, inJunkPcMax, inJunkPsMin, inJunkPsMax, inFragChunk, inFragSleep]
|
||||
.forEach(el => {
|
||||
el.addEventListener('input', () => {
|
||||
clearTimeout(el._saveTimer);
|
||||
|
|
@ -891,6 +923,21 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||
});
|
||||
});
|
||||
|
||||
// Junk and Frag modals
|
||||
btnJunkSettings.addEventListener('click', () => junkModal.classList.remove('hidden'));
|
||||
btnJunkDone.addEventListener('click', () => {
|
||||
collectAndSaveSettings();
|
||||
junkModal.classList.add('hidden');
|
||||
});
|
||||
junkModal.addEventListener('click', e => { if (e.target === junkModal) junkModal.classList.add('hidden'); });
|
||||
|
||||
btnFragSettings.addEventListener('click', () => fragModal.classList.remove('hidden'));
|
||||
btnFragDone.addEventListener('click', () => {
|
||||
collectAndSaveSettings();
|
||||
fragModal.classList.add('hidden');
|
||||
});
|
||||
fragModal.addEventListener('click', e => { if (e.target === fragModal) fragModal.classList.add('hidden'); });
|
||||
|
||||
// ── Global Keyboard Shortcuts (TUI emulation) ─────────────────────
|
||||
window.addEventListener('keydown', async e => {
|
||||
// Ignore if typing in an input or textarea
|
||||
|
|
@ -922,6 +969,8 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||
!profileModal.classList.contains('hidden') ||
|
||||
!shareModal.classList.contains('hidden') ||
|
||||
!wintunModal.classList.contains('hidden') ||
|
||||
!junkModal.classList.contains('hidden') ||
|
||||
!fragModal.classList.contains('hidden') ||
|
||||
!addMenu.classList.contains('hidden')) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -604,6 +604,22 @@ a { text-decoration: none; }
|
|||
background: var(--c-accent);
|
||||
}
|
||||
|
||||
.toggle-with-gear {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.gear-btn {
|
||||
width: 26px; height: 26px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
border-radius: var(--r-xs);
|
||||
color: var(--c-txt-2);
|
||||
transition: all var(--t-fast);
|
||||
background: transparent;
|
||||
}
|
||||
.gear-btn:hover { color: var(--c-txt-1); background: rgba(255,255,255,0.07); }
|
||||
:root.light .gear-btn:hover { background: rgba(0,0,0,0.05); }
|
||||
|
||||
/* ── Inline field (label + input on one line) ────────────────────────── */
|
||||
.inline-field {
|
||||
display: flex;
|
||||
|
|
|
|||
Loading…
Reference in New Issue