fix(fuzzer): eliminate nfq_create_queue race conditions, rogue daemon leaks and fix modal badge rendering

This commit is contained in:
Dushnilin
2026-09-02 21:58:43 +03:00
parent 13bd69cef9
commit cce9e026a2
5 changed files with 437 additions and 133 deletions
@@ -252,4 +252,23 @@ describe('TachyonShellMethods Fuzzer Actions', () => {
expect(res.data.message).toBe('Patterns reset to factory defaults');
}
});
it('stops running fuzzer', async () => {
mocks.executeShellCommand.mockResolvedValueOnce({
stdout: JSON.stringify({
success: true,
message: 'Fuzzer stopped',
}),
stderr: '',
code: 0,
});
const res = await TachyonShellMethods.stopFuzzer();
expect(res.success).toBe(true);
expect(mocks.executeShellCommand).toHaveBeenCalledWith(
expect.objectContaining({
args: ['fuzzer_stop'],
}),
);
});
});
@@ -1282,24 +1282,59 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
list.forEach((item, idx) => {
const isBest = state.best_strategy && state.best_strategy.id === item.id;
const statusBadge = `<span class="label ${item.success ? 'badge-success' : 'badge-danger'}" style="font-size: 10px; padding: 2px 6px; border-radius: 3px;">${item.success ? `HTTP ${item.http_code}` : 'DROP'}</span>`;
const nameChildren: (HTMLElement | string)[] = [
E('span', {}, item.name),
];
if (item.badge) {
nameChildren.push(
E(
'span',
{
style: `font-size: 10px; margin-left: 6px; font-weight: bold; color: ${
isBest ? '#28a745' : '#17a2b8'
};`,
},
item.badge,
),
);
}
const statusChildren: (HTMLElement | string)[] = [
E(
'span',
{
class: `label ${item.success ? 'badge-success' : 'badge-danger'}`,
style:
'font-size: 10px; padding: 2px 6px; border-radius: 3px; display: inline-block;',
},
item.success ? `HTTP ${item.http_code}` : 'DROP',
),
];
// If suite sub-probes exist, render multi-endpoint summary
let subProbesHtml = '';
if (item.sub_probes && item.sub_probes.length > 1) {
const passedSub = item.sub_probes.filter((p) => p.success).length;
const totalSub = item.sub_probes.length;
subProbesHtml = `<div style="font-size: 10px; opacity: 0.75; margin-top: 2px;">${passedSub}/${totalSub} endpoints OK</div>`;
statusChildren.push(
E(
'div',
{ style: 'font-size: 10px; opacity: 0.75; margin-top: 2px;' },
`${passedSub}/${totalSub} endpoints OK`,
),
);
}
let errorHtml = '';
if (!item.success && item.error) {
errorHtml = `<div style="font-size: 10px; color: #dc3545; opacity: 0.85; margin-top: 2px; max-width: 140px; word-break: break-word;" title="${item.error}">${item.error}</div>`;
}
let badgeHtml = '';
if (item.badge) {
badgeHtml = `<span style="font-size: 10px; margin-left: 6px; font-weight: bold; color: ${isBest ? '#28a745' : '#17a2b8'};">${item.badge}</span>`;
statusChildren.push(
E(
'div',
{
style:
'font-size: 10px; color: #dc3545; opacity: 0.85; margin-top: 2px; max-width: 140px; word-break: break-word;',
title: item.error,
},
item.error,
),
);
}
const tr = E(
@@ -1320,10 +1355,7 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
item.engine,
),
E('td', { style: 'padding: 8px 10px;' }, [
E('div', { style: 'font-weight: 600;' }, [
E('span', {}, item.name),
E('span', { innerHTML: badgeHtml }),
]),
E('div', { style: 'font-weight: 600;' }, nameChildren),
E(
'div',
{
@@ -1336,7 +1368,7 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
E(
'td',
{ style: 'padding: 8px 10px;' },
E('div', { innerHTML: statusBadge + subProbesHtml + errorHtml }),
E('div', {}, statusChildren),
),
E(
'td',
@@ -1395,26 +1427,41 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
if (pctText) pctText.innerText = `${state.progress_pct}%`;
if (progressBar) progressBar.style.width = `${state.progress_pct}%`;
const workingResults = state.results?.filter((r) => r.success) || [];
const bestStrategy = state.best_strategy || workingResults[0] || null;
if (statusText) {
if (state.running) {
statusText.innerText = `${_('Testing strategy')} ${state.current_index} / ${state.total_strategies}...`;
} else if (state.finished_at > 0) {
statusText.innerText = state.best_strategy
? _('✅ Benchmark completed! Optimal strategy identified.')
: _(
'⚠️ Benchmark completed. No working bypass found for this target.',
} else if (state.finished_at > 0 || state.results?.length) {
if (bestStrategy || workingResults.length > 0) {
if (state.error) {
statusText.innerText = `${_('🛑 Benchmark stopped')}. ${_('Found')} ${workingResults.length} ${_('working strategies')}.`;
} else {
statusText.innerText = _(
'✅ Benchmark completed! Optimal strategy identified.',
);
}
} else {
statusText.innerText = state.error
? `${_('⚠️ Benchmark stopped')}: ${state.error}`
: _(
'⚠️ Benchmark completed. No working bypass found for this target.',
);
}
}
}
if (currentStratEl && state.current_strategy) {
currentStratEl.innerText = `Testing: [${state.current_strategy.name}] -> ${state.current_strategy.args}`;
} else if (currentStratEl && !state.running) {
currentStratEl.innerText = '';
if (currentStratEl) {
if (state.running && state.current_strategy) {
currentStratEl.innerText = `Testing: [${state.current_strategy.name}] -> ${state.current_strategy.args}`;
} else {
currentStratEl.innerText = '';
}
}
if (state.best_strategy && applyBestBtn) {
(applyBestBtn as HTMLButtonElement).disabled = false;
if (applyBestBtn) {
(applyBestBtn as HTMLButtonElement).disabled = !bestStrategy;
}
};
@@ -1431,6 +1478,16 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
currentState = res.data;
isRunning = res.data.running;
if (isRunning) {
startBtn.innerText = _('🛑 Stop Benchmark');
(startBtn as HTMLButtonElement).disabled = false;
startPolling();
} else {
stopPolling();
startBtn.innerText = _('🚀 Start Benchmark');
(startBtn as HTMLButtonElement).disabled = false;
}
updateProgressUI(res.data);
// Only re-render results when new results arrive or benchmark finishes
@@ -1446,10 +1503,6 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
}
if (!isRunning) {
stopPolling();
startBtn.innerText = _('🚀 Start Benchmark');
(startBtn as HTMLButtonElement).disabled = false;
// Auto-apply best strategy if enabled
if (autoApplyEnabled && currentState?.best_strategy) {
try {
@@ -1557,10 +1610,13 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
const handleToggleRun = async () => {
if (isRunning) {
(startBtn as HTMLButtonElement).disabled = true;
startBtn.innerText = _('⏳ Stopping...');
await TachyonShellMethods.stopFuzzer();
showToast(_('Benchmark stopped'), 'success');
isRunning = false;
stopPolling();
pollStatus();
await pollStatus();
return;
}
@@ -1726,8 +1782,14 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
};
const handleApplyBest = async () => {
if (!currentState?.best_strategy) return;
await handleApplySingle(currentState.best_strategy);
const best =
currentState?.best_strategy ||
currentState?.results?.find((r) => r.success);
if (!best) {
showToast(_('No working strategy to apply'), 'error');
return;
}
await handleApplySingle(best);
};
// Initial Data Fetch: available engines & custom patterns
@@ -109,18 +109,17 @@ vi.mock('../../../../helpers', async (importOriginal) => ({
}));
import { renderStrategyFuzzerModal } from '../partials/renderStrategyFuzzerModal';
import { TachyonShellMethods } from '../../../methods/shell';
describe('renderStrategyFuzzerModal', () => {
beforeEach(() => {
mocks.showModal.mockReset();
mocks.executeShellCommand.mockReset();
mocks.executeShellCommand.mockResolvedValue({
stdout: JSON.stringify({
vi.spyOn(TachyonShellMethods, 'getFuzzerStatus').mockResolvedValue({
success: true,
data: {
running: false,
results: [],
}),
stderr: '',
code: 0,
} as any,
});
});
@@ -133,4 +132,41 @@ describe('renderStrategyFuzzerModal', () => {
expect.anything(),
);
});
it('handles fuzzer status with successful probe results and best badge', async () => {
vi.spyOn(TachyonShellMethods, 'getFuzzerStatus').mockResolvedValue({
success: true,
data: {
running: false,
progress_pct: 100,
results: [
{
id: 'z2_fake_repeats8_multisplit',
name: 'Burst Fake + Multisplit',
engine: 'zapret2',
args: '--lua-desync=fake:repeats=8',
description: 'PAWS spoofing',
success: true,
http_code: 204,
handshake_ms: 225,
ttfb_ms: 271,
speed_kbps: 2005,
score: 1029,
error: '',
badge: '🏆 Best Match',
},
],
best_strategy: {
id: 'z2_fake_repeats8_multisplit',
score: 1029,
},
} as any,
});
renderStrategyFuzzerModal(['youtube_rule']);
expect(mocks.showModal).toHaveBeenCalledTimes(1);
await new Promise((resolve) => setTimeout(resolve, 20));
expect(TachyonShellMethods.getFuzzerStatus).toHaveBeenCalled();
});
});
@@ -13217,20 +13217,52 @@ function renderStrategyFuzzerModal(ruleNames = []) {
}
list.forEach((item, idx) => {
const isBest = state.best_strategy && state.best_strategy.id === item.id;
const statusBadge = `<span class="label ${item.success ? "badge-success" : "badge-danger"}" style="font-size: 10px; padding: 2px 6px; border-radius: 3px;">${item.success ? `HTTP ${item.http_code}` : "DROP"}</span>`;
let subProbesHtml = "";
const nameChildren = [
E("span", {}, item.name)
];
if (item.badge) {
nameChildren.push(
E(
"span",
{
style: `font-size: 10px; margin-left: 6px; font-weight: bold; color: ${isBest ? "#28a745" : "#17a2b8"};`
},
item.badge
)
);
}
const statusChildren = [
E(
"span",
{
class: `label ${item.success ? "badge-success" : "badge-danger"}`,
style: "font-size: 10px; padding: 2px 6px; border-radius: 3px; display: inline-block;"
},
item.success ? `HTTP ${item.http_code}` : "DROP"
)
];
if (item.sub_probes && item.sub_probes.length > 1) {
const passedSub = item.sub_probes.filter((p) => p.success).length;
const totalSub = item.sub_probes.length;
subProbesHtml = `<div style="font-size: 10px; opacity: 0.75; margin-top: 2px;">${passedSub}/${totalSub} endpoints OK</div>`;
statusChildren.push(
E(
"div",
{ style: "font-size: 10px; opacity: 0.75; margin-top: 2px;" },
`${passedSub}/${totalSub} endpoints OK`
)
);
}
let errorHtml = "";
if (!item.success && item.error) {
errorHtml = `<div style="font-size: 10px; color: #dc3545; opacity: 0.85; margin-top: 2px; max-width: 140px; word-break: break-word;" title="${item.error}">${item.error}</div>`;
}
let badgeHtml = "";
if (item.badge) {
badgeHtml = `<span style="font-size: 10px; margin-left: 6px; font-weight: bold; color: ${isBest ? "#28a745" : "#17a2b8"};">${item.badge}</span>`;
statusChildren.push(
E(
"div",
{
style: "font-size: 10px; color: #dc3545; opacity: 0.85; margin-top: 2px; max-width: 140px; word-break: break-word;",
title: item.error
},
item.error
)
);
}
const tr = E(
"tr",
@@ -13247,10 +13279,7 @@ function renderStrategyFuzzerModal(ruleNames = []) {
item.engine
),
E("td", { style: "padding: 8px 10px;" }, [
E("div", { style: "font-weight: 600;" }, [
E("span", {}, item.name),
E("span", { innerHTML: badgeHtml })
]),
E("div", { style: "font-weight: 600;" }, nameChildren),
E(
"div",
{
@@ -13262,7 +13291,7 @@ function renderStrategyFuzzerModal(ruleNames = []) {
E(
"td",
{ style: "padding: 8px 10px;" },
E("div", { innerHTML: statusBadge + subProbesHtml + errorHtml })
E("div", {}, statusChildren)
),
E(
"td",
@@ -13315,22 +13344,36 @@ function renderStrategyFuzzerModal(ruleNames = []) {
}
if (pctText) pctText.innerText = `${state.progress_pct}%`;
if (progressBar) progressBar.style.width = `${state.progress_pct}%`;
const workingResults = state.results?.filter((r) => r.success) || [];
const bestStrategy = state.best_strategy || workingResults[0] || null;
if (statusText) {
if (state.running) {
statusText.innerText = `${_("Testing strategy")} ${state.current_index} / ${state.total_strategies}...`;
} else if (state.finished_at > 0) {
statusText.innerText = state.best_strategy ? _("\u2705 Benchmark completed! Optimal strategy identified.") : _(
"\u26A0\uFE0F Benchmark completed. No working bypass found for this target."
);
} else if (state.finished_at > 0 || state.results?.length) {
if (bestStrategy || workingResults.length > 0) {
if (state.error) {
statusText.innerText = `${_("\u{1F6D1} Benchmark stopped")}. ${_("Found")} ${workingResults.length} ${_("working strategies")}.`;
} else {
statusText.innerText = _(
"\u2705 Benchmark completed! Optimal strategy identified."
);
}
} else {
statusText.innerText = state.error ? `${_("\u26A0\uFE0F Benchmark stopped")}: ${state.error}` : _(
"\u26A0\uFE0F Benchmark completed. No working bypass found for this target."
);
}
}
}
if (currentStratEl && state.current_strategy) {
currentStratEl.innerText = `Testing: [${state.current_strategy.name}] -> ${state.current_strategy.args}`;
} else if (currentStratEl && !state.running) {
currentStratEl.innerText = "";
if (currentStratEl) {
if (state.running && state.current_strategy) {
currentStratEl.innerText = `Testing: [${state.current_strategy.name}] -> ${state.current_strategy.args}`;
} else {
currentStratEl.innerText = "";
}
}
if (state.best_strategy && applyBestBtn2) {
applyBestBtn2.disabled = false;
if (applyBestBtn2) {
applyBestBtn2.disabled = !bestStrategy;
}
};
let lastRenderedCount = 0;
@@ -13343,6 +13386,15 @@ function renderStrategyFuzzerModal(ruleNames = []) {
if (res.success && res.data) {
currentState = res.data;
isRunning = res.data.running;
if (isRunning) {
startBtn.innerText = _("\u{1F6D1} Stop Benchmark");
startBtn.disabled = false;
startPolling();
} else {
stopPolling();
startBtn.innerText = _("\u{1F680} Start Benchmark");
startBtn.disabled = false;
}
updateProgressUI(res.data);
const resultCount = res.data.results?.length || 0;
const finishedAt = res.data.finished_at || 0;
@@ -13352,9 +13404,6 @@ function renderStrategyFuzzerModal(ruleNames = []) {
lastRenderedFinishedAt = finishedAt;
}
if (!isRunning) {
stopPolling();
startBtn.innerText = _("\u{1F680} Start Benchmark");
startBtn.disabled = false;
if (autoApplyEnabled && currentState?.best_strategy) {
try {
const applyRes = await TachyonShellMethods.autoApplyFuzzerStrategy(
@@ -13448,10 +13497,13 @@ function renderStrategyFuzzerModal(ruleNames = []) {
};
const handleToggleRun = async () => {
if (isRunning) {
startBtn.disabled = true;
startBtn.innerText = _("\u23F3 Stopping...");
await TachyonShellMethods.stopFuzzer();
showToast(_("Benchmark stopped"), "success");
isRunning = false;
stopPolling();
pollStatus();
await pollStatus();
return;
}
startBtn.disabled = true;
@@ -13596,8 +13648,12 @@ function renderStrategyFuzzerModal(ruleNames = []) {
}
};
const handleApplyBest = async () => {
if (!currentState?.best_strategy) return;
await handleApplySingle(currentState.best_strategy);
const best = currentState?.best_strategy || currentState?.results?.find((r) => r.success);
if (!best) {
showToast(_("No working strategy to apply"), "error");
return;
}
await handleApplySingle(best);
};
TachyonShellMethods.getFuzzerStrategies().then((res) => {
if (res.success && res.data?.available_engines) {
+194 -63
View File
@@ -1406,8 +1406,12 @@ function kill_pid_file(path) {
let pid_str = fs.readfile(path);
if (pid_str) {
let pid = trim(as_string(pid_str));
if (pid != "") {
if (pid != "" && match(pid, /^[0-9]+$/) != null) {
system(sprintf("kill %s >/dev/null 2>&1 || kill -9 %s >/dev/null 2>&1", pid, pid));
for (let k = 0; k < 3; k++) {
if (system(sprintf("kill -0 %s >/dev/null 2>&1", pid)) != 0) break;
system("sleep 0.1");
}
}
try { fs.unlink(path); } catch (e) {}
}
@@ -1417,7 +1421,50 @@ function cleanup_temp_daemons() {
kill_pid_file(STATE_DIR + "/fuzzer_byedpi.pid");
kill_pid_file(STATE_DIR + "/fuzzer_zapret.pid");
kill_pid_file(STATE_DIR + "/fuzzer_zapret2.pid");
system("nft delete table inet tachyon_fuzzer 2>/dev/null");
// Directly parse /proc/net/netfilter/nfnetlink_queue to terminate any process bound to fuzzer queues
for (let w = 0; w < 5; w++) {
let nfq = fs.readfile("/proc/net/netfilter/nfnetlink_queue");
let found = false;
if (nfq) {
let lines = split(trim(nfq), "\n");
for (let line in lines) {
let cols = split(trim(line), /[ \t]+/);
if (length(cols) >= 2) {
let q = int(cols[0]);
let p = int(cols[1]);
if ((q == NFQUEUE_QNUM_ZAPRET || q == NFQUEUE_QNUM_ZAPRET2) && p > 0) {
found = true;
system(sprintf("kill -9 %d >/dev/null 2>&1", p));
}
}
}
}
if (!found) break;
system("sleep 0.1");
}
// Terminate any stray nfqws / nfqws2 / ciadpi fuzzer daemons
let self_pid = fs.readlink("/proc/self");
let procs = fs.glob("/proc/[0-9]*");
if (procs) {
for (let p_dir in procs) {
let p_id = replace(p_dir, "/proc/", "");
if (p_id != self_pid) {
let cmdline = fs.readfile(p_dir + "/cmdline");
if (cmdline && (index(cmdline, "nfqws") >= 0 || index(cmdline, "ciadpi") >= 0)) {
if (index(cmdline, "qnum=298") >= 0 || index(cmdline, "qnum=299") >= 0 || index(cmdline, "11089") >= 0) {
system(sprintf("kill -9 %s >/dev/null 2>&1", p_id));
}
}
}
}
}
// Ensure ByeDPI port is released
system(sprintf("fuser -k %d/tcp >/dev/null 2>&1", BYEDPI_PORT));
system("nft delete table inet tachyon_fuzzer >/dev/null 2>&1");
try { fs.unlink(STATE_DIR + "/fuzzer_daemon_err.log"); } catch (e) {}
}
@@ -1706,16 +1753,26 @@ function run_probe(engine, args_str, target_key, custom_url) {
let pid_path = STATE_DIR + "/fuzzer_byedpi.pid";
let stderr_log = STATE_DIR + "/fuzzer_daemon_err.log";
try { fs.unlink(pid_path); } catch (e) {}
try { fs.unlink(stderr_log); } catch (e) {}
let spawn_cmd = sprintf("cd /tmp && %s -i 127.0.0.1 -p %d %s 2>%s", bin, BYEDPI_PORT, args_str, shell_quote(stderr_log));
system(common.background_command_with_pid(spawn_cmd, ">/dev/null", ">" + shell_quote(pid_path)));
system("sleep 0.25");
let pid_str = fs.readfile(pid_path);
let pid_running = false;
if (pid_str) {
let pid = trim(as_string(pid_str));
if (pid != "" && match(pid, /^[0-9]+$/) != null && system(sprintf("kill -0 %s >/dev/null 2>&1", pid)) == 0) {
pid_running = true;
for (let wait_i = 0; wait_i < 10; wait_i++) {
system("sleep 0.1");
let pid_str = fs.readfile(pid_path);
if (pid_str) {
let pid = trim(as_string(pid_str));
if (pid != "" && match(pid, /^[0-9]+$/) != null && system(sprintf("kill -0 %s >/dev/null 2>&1", pid)) == 0) {
pid_running = true;
break;
}
}
let err_content = fs.readfile(stderr_log);
if (err_content && trim(as_string(err_content)) != "") {
break;
}
}
@@ -1794,11 +1851,14 @@ function run_probe(engine, args_str, target_key, custom_url) {
}
if (engine == "zapret" || engine == "zapret2") {
cleanup_temp_daemons();
let is_z2 = engine == "zapret2";
let bin = is_z2 ? get_zapret2_bin() : get_zapret_bin();
let qnum = is_z2 ? NFQUEUE_QNUM_ZAPRET2 : NFQUEUE_QNUM_ZAPRET;
let pid_path = is_z2 ? (STATE_DIR + "/fuzzer_zapret2.pid") : (STATE_DIR + "/fuzzer_zapret.pid");
let stderr_log = STATE_DIR + "/fuzzer_daemon_err.log";
try { fs.unlink(pid_path); } catch (e) {}
try { fs.unlink(stderr_log); } catch (e) {}
if (!bin) {
result.error = (is_z2 ? "Zapret v2" : "Zapret v1") + " binary not found";
@@ -1822,14 +1882,21 @@ function run_probe(engine, args_str, target_key, custom_url) {
let spawn_cmd = sprintf("cd /tmp && %s --qnum=%d --fwmark=%s %s%s%s%s --pidfile=%s --daemon 2>%s", bin, qnum, FUZZER_FWMARK, lua_init_flags, blob_flags, filter_prefix, args_str, pid_path, shell_quote(stderr_log));
system(common.background_command(spawn_cmd));
system("sleep 0.25");
let pid_str = fs.readfile(pid_path);
let pid_running = false;
if (pid_str) {
let pid = trim(as_string(pid_str));
if (pid != "" && match(pid, /^[0-9]+$/) != null && system(sprintf("kill -0 %s >/dev/null 2>&1", pid)) == 0) {
pid_running = true;
for (let wait_i = 0; wait_i < 10; wait_i++) {
system("sleep 0.1");
let pid_str = fs.readfile(pid_path);
if (pid_str) {
let pid = trim(as_string(pid_str));
if (pid != "" && match(pid, /^[0-9]+$/) != null && system(sprintf("kill -0 %s >/dev/null 2>&1", pid)) == 0) {
pid_running = true;
break;
}
}
let err_content = fs.readfile(stderr_log);
if (err_content && trim(as_string(err_content)) != "") {
break;
}
}
@@ -1909,11 +1976,38 @@ function run_probe(engine, args_str, target_key, custom_url) {
return result;
}
function run_fuzzer_worker(engine, target, custom_url, rule_section, custom_file, mode) {
function run_fuzzer_worker(engine, target, custom_url, rule_section, custom_file, mode, job_id) {
let target_url = resolve_target_url(target, custom_url);
let state = get_fuzzer_state();
if (!state.running || (job_id && state.job_id != job_id)) {
state = {
running: true,
job_id: job_id || sprintf("fuzz_%d", clock()[0]),
engine,
target,
target_url,
mode: as_string(mode || "presets"),
rule_section: as_string(rule_section),
custom_file: as_string(custom_file || ""),
progress_pct: 0,
current_index: 0,
total_strategies: 0,
current_strategy: { name: "Initializing DPI detection...", args: "" },
results: [],
best_strategy: null,
error: null,
started_at: clock()[0],
finished_at: 0,
dpi_detection: null
};
save_fuzzer_state(state);
}
// ── Pre-fuzz DPI detection ────────────────────────────────────────────
let dpi_detection = detect_dpi_type(target, custom_url);
state.dpi_detection = dpi_detection;
save_fuzzer_state(state);
let strategies = null;
if (custom_file && custom_file != "" && fs.stat(custom_file) != null) {
@@ -1927,28 +2021,7 @@ function run_fuzzer_worker(engine, target, custom_url, rule_section, custom_file
strategies = rerank_strategies_by_dpi(strategies, dpi_detection);
let total = length(strategies);
let state = {
running: true,
job_id: sprintf("fuzz_%d", clock()[0]),
engine,
target,
target_url,
mode: as_string(mode || "presets"),
rule_section: as_string(rule_section),
custom_file: as_string(custom_file || ""),
progress_pct: 0,
current_index: 0,
total_strategies: total,
current_strategy: null,
results: [],
best_strategy: null,
error: null,
started_at: clock()[0],
finished_at: 0,
dpi_detection: dpi_detection
};
state.total_strategies = total;
save_fuzzer_state(state);
try {
@@ -1988,6 +2061,8 @@ function run_fuzzer_worker(engine, target, custom_url, rule_section, custom_file
if (item_result.score > highest_score && item_result.success) {
highest_score = item_result.score;
best = item_result;
item_result.badge = "🏆 Best Match";
state.best_strategy = item_result;
}
push(state.results, item_result);
@@ -2042,52 +2117,108 @@ function run_fuzzer_worker(engine, target, custom_url, rule_section, custom_file
});
} catch (err) {
state.running = false;
state.current_strategy = null;
state.error = as_string(err);
state.finished_at = clock()[0];
if (!state.best_strategy && state.results) {
let max_score = -1;
let best_item = null;
for (let r in state.results) {
if (r.success && r.score > max_score) {
max_score = r.score;
best_item = r;
}
}
if (best_item) {
best_item.badge = "🏆 Best Match";
state.best_strategy = best_item;
}
}
save_fuzzer_state(state);
}
cleanup_temp_daemons();
}
function start_fuzzer(engine, target, custom_url, rule_section, custom_file, mode) {
let current = get_fuzzer_state();
if (current.running) {
print(sprintf("%J\n", { success: false, error: "Fuzzer is already running", job_id: current.job_id }));
return;
}
ensure_state_dir();
let job_id = sprintf("fuzz_%d", clock()[0]);
let cmd = sprintf(
"ucode -L /usr/lib/tachyon /usr/lib/tachyon/diagnostics/fuzzer.uc worker %s %s %s %s %s %s",
shell_quote(engine || "zapret2"),
shell_quote(target || "youtube_suite"),
shell_quote(custom_url || ""),
shell_quote(rule_section || ""),
shell_quote(custom_file || ""),
shell_quote(mode || "presets")
);
system(common.background_command_with_pid(cmd, ">/dev/null", ">" + shell_quote(PID_FILE)));
print(sprintf("%J\n", { success: true, job_id, engine: engine || "zapret2", target: target || "youtube_suite", mode: mode || "presets" }));
}
function stop_fuzzer() {
kill_pid_file(PID_FILE);
cleanup_temp_daemons();
let state = get_fuzzer_state();
state.running = false;
state.current_strategy = null;
state.error = "Stopped by user";
state.finished_at = clock()[0];
if (!state.best_strategy && state.results) {
let max_score = -1;
let best_item = null;
for (let r in state.results) {
if (r.success && r.score > max_score) {
max_score = r.score;
best_item = r;
}
}
if (best_item) {
best_item.badge = "🏆 Best Match";
state.best_strategy = best_item;
}
}
save_fuzzer_state(state);
print(sprintf("%J\n", { success: true, message: "Fuzzer stopped" }));
}
function start_fuzzer(engine, target, custom_url, rule_section, custom_file, mode) {
let current = get_fuzzer_state();
if (current.running) {
stop_fuzzer();
system("sleep 0.25");
}
ensure_state_dir();
cleanup_temp_daemons();
let job_id = sprintf("fuzz_%d", clock()[0]);
// Immediately write starting state to prevent race conditions during frontend polling
let state = {
running: true,
job_id: job_id,
engine: engine || "zapret2",
target: target || "youtube_suite",
target_url: resolve_target_url(target, custom_url),
mode: as_string(mode || "presets"),
rule_section: as_string(rule_section),
custom_file: as_string(custom_file || ""),
progress_pct: 0,
current_index: 0,
total_strategies: 0,
current_strategy: { name: "Initializing DPI detection...", args: "" },
results: [],
best_strategy: null,
error: null,
started_at: clock()[0],
finished_at: 0,
dpi_detection: null
};
save_fuzzer_state(state);
let cmd = sprintf(
"ucode -L /usr/lib/tachyon /usr/lib/tachyon/diagnostics/fuzzer.uc worker %s %s %s %s %s %s %s",
shell_quote(engine || "zapret2"),
shell_quote(target || "youtube_suite"),
shell_quote(custom_url || ""),
shell_quote(rule_section || ""),
shell_quote(custom_file || ""),
shell_quote(mode || "presets"),
shell_quote(job_id)
);
system(common.background_command_with_pid(cmd, ">/dev/null", ">" + shell_quote(PID_FILE)));
print(sprintf("%J\n", { success: true, job_id, engine: engine || "zapret2", target: target || "youtube_suite", mode: mode || "presets" }));
}
function get_available_engines() {
return {
zapret2: get_zapret2_bin() != null,
@@ -2179,7 +2310,7 @@ let op = ARGV[0] || "status";
if (op == "start") {
start_fuzzer(ARGV[1], ARGV[2], ARGV[3], ARGV[4], ARGV[5], ARGV[6]);
} else if (op == "worker") {
run_fuzzer_worker(ARGV[1], ARGV[2], ARGV[3], ARGV[4], ARGV[5], ARGV[6]);
run_fuzzer_worker(ARGV[1], ARGV[2], ARGV[3], ARGV[4], ARGV[5], ARGV[6], ARGV[7]);
} else if (op == "status") {
print(sprintf("%J\n", get_fuzzer_state()));
} else if (op == "stop") {