fix(singbox): устранение утечки Discord в direct на Sing-box 1.14 и верификация троттлинга DPI
- singbox/generator_routes.uc: восстановлена маршрутизация IP-подсетей сервисов в ip_cidr, добавлены сиды для холодного старта - nft/apply.uc: наполнение sets.subnets сидами подсетей Discord и Telegram до первой загрузки .lst - components/updates.uc: автоматический reload ядра Sing-box после фонового list_update при обновлении ruleset - diagnostics/fuzzer.uc: учет объема скачанных данных, детектирование троттлинга DPI 16KB и вердикты проходимости - fe-app-tachyon: отображение статусов верификации данных и DPI вердиктов в UI фаззера
This commit is contained in:
@@ -1309,6 +1309,53 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
),
|
||||
];
|
||||
|
||||
if (item.data_verified) {
|
||||
statusChildren.push(
|
||||
E(
|
||||
'span',
|
||||
{
|
||||
class: 'label badge-success',
|
||||
style:
|
||||
'font-size: 9px; padding: 2px 5px; border-radius: 3px; margin-left: 4px; display: inline-block; background: #28a745; color: #fff; font-weight: 500;',
|
||||
title: _(
|
||||
'Data transfer verified: streamed >= 32KB without throttling or disconnect',
|
||||
),
|
||||
},
|
||||
'✓ 32KB Прокачано',
|
||||
),
|
||||
);
|
||||
} else if (item.dpi_verdict === 'throttled_16k') {
|
||||
statusChildren.push(
|
||||
E(
|
||||
'span',
|
||||
{
|
||||
class: 'label badge-danger',
|
||||
style:
|
||||
'font-size: 9px; padding: 2px 5px; border-radius: 3px; margin-left: 4px; display: inline-block; background: #dc3545; color: #fff; font-weight: 500;',
|
||||
title: _(
|
||||
'DPI throttling: stream cut off after ~16KB payload transfer',
|
||||
),
|
||||
},
|
||||
'✗ Задушено на 16KB',
|
||||
),
|
||||
);
|
||||
} else if (item.dpi_verdict === 'server_fakes') {
|
||||
statusChildren.push(
|
||||
E(
|
||||
'span',
|
||||
{
|
||||
class: 'label badge-warning',
|
||||
style:
|
||||
'font-size: 9px; padding: 2px 5px; border-radius: 3px; margin-left: 4px; display: inline-block; background: #ffc107; color: #111; font-weight: 500;',
|
||||
title: _(
|
||||
'Fake packets reached remote server (HTTP 400 Bad Request)',
|
||||
),
|
||||
},
|
||||
'⚠️ Сервер получил фейки',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -1376,7 +1423,18 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
E(
|
||||
'td',
|
||||
{ style: 'padding: 8px 10px;' },
|
||||
item.success ? `${(item.speed_kbps / 1024).toFixed(1)}MB/s` : '—',
|
||||
item.success
|
||||
? [
|
||||
E('div', {}, `${(item.speed_kbps / 1024).toFixed(1)}MB/s`),
|
||||
item.data_bytes && item.data_bytes > 0
|
||||
? E(
|
||||
'div',
|
||||
{ style: 'font-size: 10px; opacity: 0.65;' },
|
||||
`${(item.data_bytes / 1024).toFixed(1)} KB`,
|
||||
)
|
||||
: '',
|
||||
]
|
||||
: '—',
|
||||
),
|
||||
E(
|
||||
'td',
|
||||
@@ -1488,6 +1546,11 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
|
||||
updateProgressUI(res.data);
|
||||
|
||||
if (res.data.dpi_detection) {
|
||||
currentDpiDetection = res.data.dpi_detection;
|
||||
updateDpiBanner(res.data.dpi_detection);
|
||||
}
|
||||
|
||||
// Only re-render results when new results arrive or benchmark finishes
|
||||
const resultCount = res.data.results?.length || 0;
|
||||
const finishedAt = res.data.finished_at || 0;
|
||||
@@ -1568,6 +1631,11 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
border: '#17a2b8',
|
||||
icon: '🔵',
|
||||
},
|
||||
ip_block: {
|
||||
bg: 'rgba(220, 53, 69, 0.18)',
|
||||
border: '#dc3545',
|
||||
icon: '🚫',
|
||||
},
|
||||
unknown: {
|
||||
bg: 'rgba(108, 117, 125, 0.12)',
|
||||
border: '#6c757d',
|
||||
@@ -1584,6 +1652,7 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
rst: 'TCP Reset Injection',
|
||||
throttle: 'Throttling / Deep Inspection',
|
||||
dns_block: 'DNS Blocking',
|
||||
ip_block: _('Блокировка по IP (Таймаут TCP SYN)'),
|
||||
unknown: 'Unknown DPI Pattern',
|
||||
none: 'No Blocking Detected',
|
||||
};
|
||||
@@ -1591,6 +1660,13 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
const colors = typeColors[detection.type] || typeColors.unknown;
|
||||
const label = typeLabels[detection.type] || detection.type;
|
||||
|
||||
const ipBlockNotice =
|
||||
detection.type === 'ip_block'
|
||||
? `<div style="margin-top: 8px; padding: 8px 12px; background: rgba(220, 53, 69, 0.15); border: 1px solid rgba(220, 53, 69, 0.35); border-radius: 4px; color: #ff6b6b; font-size: 11px; font-weight: 500; line-height: 1.4;">
|
||||
⚠️ ${_('Обнаружена блокировка по IP! Ресурс блокируется на сетевом уровне (нет ответа на TCP SYN). Методы обхода DPI (Zapret / ByeDPI) бессильны для этого адреса — настройте маршрутизацию через прокси/VPN (Sing-box) для данного домена!')}
|
||||
</div>`
|
||||
: '';
|
||||
|
||||
banner.style.display = 'block';
|
||||
banner.style.background = colors.bg;
|
||||
banner.style.borderLeft = `3px solid ${colors.border}`;
|
||||
@@ -1603,6 +1679,7 @@ export function renderStrategyFuzzerModal(ruleNames: string[] = []) {
|
||||
${detection.recommended_engines.length > 0 ? `<div style="font-size: 11px; opacity: 0.7;">${_('Recommended')}: ${detection.recommended_engines.join(', ')}</div>` : ''}
|
||||
</div>
|
||||
<div style="margin-top: 4px; opacity: 0.8; font-size: 11px;">${detection.details}</div>
|
||||
${ipBlockNotice}
|
||||
`;
|
||||
};
|
||||
|
||||
|
||||
@@ -918,6 +918,9 @@ export namespace Tachyon {
|
||||
handshake_ms: number;
|
||||
ttfb_ms: number;
|
||||
speed_kbps: number;
|
||||
data_verified?: boolean;
|
||||
data_bytes?: number;
|
||||
dpi_verdict?: string;
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}
|
||||
@@ -934,6 +937,9 @@ export namespace Tachyon {
|
||||
handshake_ms: number;
|
||||
ttfb_ms: number;
|
||||
speed_kbps: number;
|
||||
data_verified?: boolean;
|
||||
data_bytes?: number;
|
||||
dpi_verdict?: string;
|
||||
score: number;
|
||||
error?: string;
|
||||
badge?: string;
|
||||
@@ -944,6 +950,9 @@ export namespace Tachyon {
|
||||
handshake_ms: number;
|
||||
ttfb_ms: number;
|
||||
speed_kbps: number;
|
||||
data_verified?: boolean;
|
||||
data_bytes?: number;
|
||||
dpi_verdict?: string;
|
||||
score: number;
|
||||
success: boolean;
|
||||
error?: string;
|
||||
@@ -1047,7 +1056,7 @@ export namespace Tachyon {
|
||||
}
|
||||
|
||||
export interface FuzzerDpiDetection {
|
||||
type: 'rst' | 'throttle' | 'dns_block' | 'unknown' | 'none';
|
||||
type: 'rst' | 'throttle' | 'dns_block' | 'ip_block' | 'unknown' | 'none';
|
||||
confidence: number;
|
||||
details: string;
|
||||
recommended_engines: string[];
|
||||
@@ -1056,6 +1065,7 @@ export namespace Tachyon {
|
||||
handshake_ms: number;
|
||||
ttfb_ms: number;
|
||||
speed_kbps: number;
|
||||
data_bytes?: number;
|
||||
error: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13422,6 +13422,49 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
item.success ? `HTTP ${item.http_code}` : "DROP"
|
||||
)
|
||||
];
|
||||
if (item.data_verified) {
|
||||
statusChildren.push(
|
||||
E(
|
||||
"span",
|
||||
{
|
||||
class: "label badge-success",
|
||||
style: "font-size: 9px; padding: 2px 5px; border-radius: 3px; margin-left: 4px; display: inline-block; background: #28a745; color: #fff; font-weight: 500;",
|
||||
title: _(
|
||||
"Data transfer verified: streamed >= 32KB without throttling or disconnect"
|
||||
)
|
||||
},
|
||||
"\u2713 32KB \u041F\u0440\u043E\u043A\u0430\u0447\u0430\u043D\u043E"
|
||||
)
|
||||
);
|
||||
} else if (item.dpi_verdict === "throttled_16k") {
|
||||
statusChildren.push(
|
||||
E(
|
||||
"span",
|
||||
{
|
||||
class: "label badge-danger",
|
||||
style: "font-size: 9px; padding: 2px 5px; border-radius: 3px; margin-left: 4px; display: inline-block; background: #dc3545; color: #fff; font-weight: 500;",
|
||||
title: _(
|
||||
"DPI throttling: stream cut off after ~16KB payload transfer"
|
||||
)
|
||||
},
|
||||
"\u2717 \u0417\u0430\u0434\u0443\u0448\u0435\u043D\u043E \u043D\u0430 16KB"
|
||||
)
|
||||
);
|
||||
} else if (item.dpi_verdict === "server_fakes") {
|
||||
statusChildren.push(
|
||||
E(
|
||||
"span",
|
||||
{
|
||||
class: "label badge-warning",
|
||||
style: "font-size: 9px; padding: 2px 5px; border-radius: 3px; margin-left: 4px; display: inline-block; background: #ffc107; color: #111; font-weight: 500;",
|
||||
title: _(
|
||||
"Fake packets reached remote server (HTTP 400 Bad Request)"
|
||||
)
|
||||
},
|
||||
"\u26A0\uFE0F \u0421\u0435\u0440\u0432\u0435\u0440 \u043F\u043E\u043B\u0443\u0447\u0438\u043B \u0444\u0435\u0439\u043A\u0438"
|
||||
)
|
||||
);
|
||||
}
|
||||
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;
|
||||
@@ -13482,7 +13525,14 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
E(
|
||||
"td",
|
||||
{ style: "padding: 8px 10px;" },
|
||||
item.success ? `${(item.speed_kbps / 1024).toFixed(1)}MB/s` : "\u2014"
|
||||
item.success ? [
|
||||
E("div", {}, `${(item.speed_kbps / 1024).toFixed(1)}MB/s`),
|
||||
item.data_bytes && item.data_bytes > 0 ? E(
|
||||
"div",
|
||||
{ style: "font-size: 10px; opacity: 0.65;" },
|
||||
`${(item.data_bytes / 1024).toFixed(1)} KB`
|
||||
) : ""
|
||||
] : "\u2014"
|
||||
),
|
||||
E(
|
||||
"td",
|
||||
@@ -13577,6 +13627,10 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
startBtn.disabled = false;
|
||||
}
|
||||
updateProgressUI(res.data);
|
||||
if (res.data.dpi_detection) {
|
||||
currentDpiDetection = res.data.dpi_detection;
|
||||
updateDpiBanner(res.data.dpi_detection);
|
||||
}
|
||||
const resultCount = res.data.results?.length || 0;
|
||||
const finishedAt = res.data.finished_at || 0;
|
||||
if (resultCount !== lastRenderedCount || finishedAt !== lastRenderedFinishedAt) {
|
||||
@@ -13642,6 +13696,11 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
border: "#17a2b8",
|
||||
icon: "\u{1F535}"
|
||||
},
|
||||
ip_block: {
|
||||
bg: "rgba(220, 53, 69, 0.18)",
|
||||
border: "#dc3545",
|
||||
icon: "\u{1F6AB}"
|
||||
},
|
||||
unknown: {
|
||||
bg: "rgba(108, 117, 125, 0.12)",
|
||||
border: "#6c757d",
|
||||
@@ -13657,11 +13716,15 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
rst: "TCP Reset Injection",
|
||||
throttle: "Throttling / Deep Inspection",
|
||||
dns_block: "DNS Blocking",
|
||||
ip_block: _("\u0411\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043A\u0430 \u043F\u043E IP (\u0422\u0430\u0439\u043C\u0430\u0443\u0442 TCP SYN)"),
|
||||
unknown: "Unknown DPI Pattern",
|
||||
none: "No Blocking Detected"
|
||||
};
|
||||
const colors = typeColors[detection.type] || typeColors.unknown;
|
||||
const label = typeLabels[detection.type] || detection.type;
|
||||
const ipBlockNotice = detection.type === "ip_block" ? `<div style="margin-top: 8px; padding: 8px 12px; background: rgba(220, 53, 69, 0.15); border: 1px solid rgba(220, 53, 69, 0.35); border-radius: 4px; color: #ff6b6b; font-size: 11px; font-weight: 500; line-height: 1.4;">
|
||||
\u26A0\uFE0F ${_("\u041E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D\u0430 \u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u043A\u0430 \u043F\u043E IP! \u0420\u0435\u0441\u0443\u0440\u0441 \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u043D\u0430 \u0441\u0435\u0442\u0435\u0432\u043E\u043C \u0443\u0440\u043E\u0432\u043D\u0435 (\u043D\u0435\u0442 \u043E\u0442\u0432\u0435\u0442\u0430 \u043D\u0430 TCP SYN). \u041C\u0435\u0442\u043E\u0434\u044B \u043E\u0431\u0445\u043E\u0434\u0430 DPI (Zapret / ByeDPI) \u0431\u0435\u0441\u0441\u0438\u043B\u044C\u043D\u044B \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u0430\u0434\u0440\u0435\u0441\u0430 \u2014 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u0442\u0435 \u043C\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044E \u0447\u0435\u0440\u0435\u0437 \u043F\u0440\u043E\u043A\u0441\u0438/VPN (Sing-box) \u0434\u043B\u044F \u0434\u0430\u043D\u043D\u043E\u0433\u043E \u0434\u043E\u043C\u0435\u043D\u0430!")}
|
||||
</div>` : "";
|
||||
banner.style.display = "block";
|
||||
banner.style.background = colors.bg;
|
||||
banner.style.borderLeft = `3px solid ${colors.border}`;
|
||||
@@ -13674,6 +13737,7 @@ function renderStrategyFuzzerModal(ruleNames = []) {
|
||||
${detection.recommended_engines.length > 0 ? `<div style="font-size: 11px; opacity: 0.7;">${_("Recommended")}: ${detection.recommended_engines.join(", ")}</div>` : ""}
|
||||
</div>
|
||||
<div style="margin-top: 4px; opacity: 0.8; font-size: 11px;">${detection.details}</div>
|
||||
${ipBlockNotice}
|
||||
`;
|
||||
};
|
||||
const handleToggleRun = async () => {
|
||||
|
||||
@@ -2975,6 +2975,7 @@ function list_update() {
|
||||
if (ok) {
|
||||
write_list_update_timestamp(now_seconds());
|
||||
log_message("Lists update completed successfully", "info");
|
||||
reload_singbox_after_list_update();
|
||||
}
|
||||
else {
|
||||
log_message("Lists update failed", "info");
|
||||
@@ -3092,6 +3093,34 @@ function write_current_reload_state_clean() {
|
||||
]);
|
||||
}
|
||||
|
||||
function reload_singbox_after_list_update() {
|
||||
let sing_box_pid = trim(module_output([ LIB_DIR + "/service/state.uc", "sing-box-service-runtime-pid" ]));
|
||||
if (sing_box_pid == "" || int(sing_box_pid) <= 0)
|
||||
return true;
|
||||
let sing_box_config_path = option(uci_settings(), "config_path", "") || "/etc/sing-box/config.json";
|
||||
let sing_box_config_hash_before = file_md5(sing_box_config_path);
|
||||
if (!singbox_runtime_success([ "init-config", "0", "1", "1" ]))
|
||||
return false;
|
||||
let sing_box_config_hash_after = file_md5(sing_box_config_path);
|
||||
if (sing_box_config_hash_before != sing_box_config_hash_after) {
|
||||
log_message("Rulesets updated on disk; reloading sing-box with new configuration", "info");
|
||||
module_success([ DNS_FAILOVER_UC, "stop-runtime" ]);
|
||||
module_success([ PRIORITY_UC, "stop-runtime" ]);
|
||||
let ok = service_state_success([
|
||||
"reload-sing-box-runtime",
|
||||
sing_box_pid,
|
||||
sing_box_config_hash_before,
|
||||
sing_box_config_hash_after,
|
||||
"1"
|
||||
]);
|
||||
module_success([ PRIORITY_UC, "start-runtime" ]);
|
||||
module_success([ DNS_FAILOVER_UC, "start-runtime" ]);
|
||||
write_current_reload_state_clean();
|
||||
return ok;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function mark_pending_reload(reason) {
|
||||
service_state_success([ "mark-pending-reload", PENDING_RELOAD_FILE, reason ]);
|
||||
}
|
||||
|
||||
@@ -583,6 +583,134 @@ const STRATEGIES_ZAPRET2 = [
|
||||
engine: "zapret2",
|
||||
args: "--lua-desync=oob:pos=1",
|
||||
description: "TCP Out-Of-Band URG flag packet to desynchronize DPI reassembly."
|
||||
},
|
||||
|
||||
// ── 8. BLOCKCHECKW & BLOCKCHECK2 COMBAT STRATEGIES ─────────────────────────
|
||||
{
|
||||
id: "z2_bc_multisplit_7point",
|
||||
name: "7-Point MultiSplit (ClientHello Full Spectrum)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=multisplit:pos=1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1",
|
||||
description: "Splits at start, SNI extension, host header, mid-SLD, and end of host. Top blockcheck2 bypass."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_multidisorder_7point",
|
||||
name: "7-Point MultiDisorder (ClientHello Full Spectrum)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=multidisorder:pos=1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1",
|
||||
description: "Disorders all critical TLS ClientHello headers. Devastates stateful DPI reassembly."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_multisplit_1220",
|
||||
name: "Tri-Point MultiSplit (pos=1,midsld,1220)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=multisplit:pos=1,midsld,1220",
|
||||
description: "Splits at start, mid-SLD, and packet boundary (1220 B)."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_multidisorder_1220",
|
||||
name: "Tri-Point MultiDisorder (pos=1,midsld,1220)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=multidisorder:pos=1,midsld,1220",
|
||||
description: "Disorders stream at start, mid-SLD, and MTU boundary (1220 B)."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_tcpseg_rep260",
|
||||
name: "TCP Segment Desync (repeats=260, pos=0,1)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=tcpseg:pos=0,1:ip_id=rnd:repeats=260",
|
||||
description: "Forces randomized IP ID TCP segmentation burst with 260 repeats to overflow DPI state table."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_tcpseg_rep100_midsld",
|
||||
name: "TCP Segment Desync (repeats=100, midsld)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=tcpseg:pos=0,midsld:ip_id=rnd:repeats=100",
|
||||
description: "Mid-SLD TCP segmentation with 100 repeats."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_oob_midsld",
|
||||
name: "OOB Desync (urp=midsld)",
|
||||
engine: "zapret2",
|
||||
args: "--in-range=-s1 --lua-desync=oob:urp=midsld",
|
||||
description: "TCP Out-Of-Band packet with urgent pointer pointing directly to mid-domain."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_oob_b",
|
||||
name: "OOB Desync (urp=b)",
|
||||
engine: "zapret2",
|
||||
args: "--in-range=-s1 --lua-desync=oob:urp=b",
|
||||
description: "TCP Out-Of-Band with beginning urgent pointer offset."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_seqovl_sniext",
|
||||
name: "Exact SeqOvl Pattern Overlap (sniext+1, Max.ru)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=multidisorder:pos=sniext+1:seqovl=sniext:seqovl_pattern=tls_max",
|
||||
description: "Disorders at SNI extension with exact sequence overlap pattern."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_seqovl_midsld",
|
||||
name: "Exact SeqOvl Pattern Overlap (midsld, Google)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=multidisorder:pos=midsld:seqovl=midsld-1:seqovl_pattern=tls_google",
|
||||
description: "Disorders at mid-SLD with exact sequence overlap pattern from Google ClientHello."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_lua_padencap",
|
||||
name: "Dynamic Lua TLS Mod (padencap + dupsid) + MultiSplit",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=luaexec:code=desync.patmod=tls_mod(fake_default_tls,'rnd,dupsid,padencap',desync.reasm_data) --lua-desync=multisplit:pos=10,sniext+1:seqovl=#patmod:seqovl_pattern=patmod",
|
||||
description: "Dynamically pads and encapsulates ClientHello payload via Lua runtime."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_tcp_ack_offset",
|
||||
name: "TCP ACK Offset Spoofing (-66000) + TS_UP",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=fake:blob=tls_max:tcp_ack=-66000:tcp_ts_up:repeats=6",
|
||||
description: "Injects fake packets with corrupted ACK number and ascending TCP timestamps."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_tcp_flags_unset_ack",
|
||||
name: "TCP Flags Manipulation (Unset ACK)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=fake:blob=tls_google:tcp_flags_unset=ACK:repeats=6",
|
||||
description: "Fake packets with ACK flag cleared, accepted only by DPI state trackers."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_tcp_flags_set_syn",
|
||||
name: "TCP Flags Manipulation (Set SYN on Data)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=fake:blob=tls_max:tcp_flags_set=SYN:repeats=6",
|
||||
description: "Sets SYN flag on ClientHello fake packets to trigger DPI state desynchronization."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_badsum",
|
||||
name: "BadSum Checksum Invalidation",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=fake:blob=tls_google:badsum:repeats=6",
|
||||
description: "Packets with invalid L4 checksum are dropped by remote server NIC but inspected by DPI."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_autottl_1",
|
||||
name: "Auto-TTL Adaptive Probe (autottl=-1, 3-20)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=fake:blob=tls_max:ip_autottl=-1,3-20:repeats=6",
|
||||
description: "Dynamically calculates hop distance to target and injects fake packets right before DPI hop."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_autottl_2",
|
||||
name: "Auto-TTL Adaptive Probe (autottl=-2, 3-20)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=fake:blob=tls_google:ip_autottl=-2,3-20:repeats=6",
|
||||
description: "Auto-TTL probe with 2 hops before target."
|
||||
},
|
||||
{
|
||||
id: "z2_bc_pktmod",
|
||||
name: "PktMod Packet Mutation (ip_ttl=1)",
|
||||
engine: "zapret2",
|
||||
args: "--payload=tls_client_hello --lua-desync=fake:blob=tls_max:ip_ttl=1:repeats=6 --payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip_ttl=1",
|
||||
description: "Mutates outgoing packets in the range between server SYN and data."
|
||||
}
|
||||
];
|
||||
|
||||
@@ -702,6 +830,79 @@ const STRATEGIES_ZAPRET = [
|
||||
];
|
||||
|
||||
const STRATEGIES_BYEDPI = [
|
||||
// ── 1. COMBAT MULTI-SPLIT & LADDER CHAINS (Real TSPU Bypass) ───────────────
|
||||
{
|
||||
id: "bd_ladder_interleaved_10x",
|
||||
name: "Ultimate Multi-Split Ladder (10x SNI + Reverse + Drop-SACK)",
|
||||
engine: "byedpi",
|
||||
args: "-d1 -d3+s -s6+s -d9+s -s12+s -d15+s -s20+s -d25+s -s30+s -d35+s -r1+s -S -a1 -As",
|
||||
description: "10-stage interleaved split and disorder ladder across SNI offsets with reverse segment and SACK drop. Bypasses advanced stateful DPI reassembly."
|
||||
},
|
||||
{
|
||||
id: "bd_ladder_split_9x",
|
||||
name: "Staircase Split Ladder (9x SNI + Reverse + Drop-SACK)",
|
||||
engine: "byedpi",
|
||||
args: "-s1 -s3+s -s6+s -s9+s -s12+s -s15+s -s20+s -s25+s -s30+s -r1+s -S -a1",
|
||||
description: "Dense forward multi-split sequence along SNI with reverse disorder tail and SACK drop."
|
||||
},
|
||||
{
|
||||
id: "bd_ladder_disorder_8x",
|
||||
name: "Staircase Disorder Ladder (8x SNI + SACK Drop + Auto-s)",
|
||||
engine: "byedpi",
|
||||
args: "-d1 -d3+s -d6+s -d9+s -d12+s -d15+s -d20+s -d25+s -r1+s -S -As",
|
||||
description: "Out-of-order segment ladder across SNI payload prevents stateful DPI reassembly."
|
||||
},
|
||||
{
|
||||
id: "bd_ladder_fake_drop_t4",
|
||||
name: "Fake Ladder (TTL=4) + 4x SNI Step + Drop-SACK",
|
||||
engine: "byedpi",
|
||||
args: "-s1+s -d2+s -s3+s -d4+s -f-1 -t4 -r1+s -S -a1",
|
||||
description: "Low-TTL fake ClientHello burst followed by 4-step SNI fragmentation ladder."
|
||||
},
|
||||
{
|
||||
id: "bd_ladder_fake_drop_t6",
|
||||
name: "Fake Ladder (TTL=6) + 4x SNI Step + Drop-SACK",
|
||||
engine: "byedpi",
|
||||
args: "-s1+s -d2+s -s3+s -d4+s -f-1 -t6 -r1+s -S -a1 -As",
|
||||
description: "TTL=6 fake packet with stepped SNI offsets and reverse tail."
|
||||
},
|
||||
{
|
||||
id: "bd_ladder_fake_drop_t8",
|
||||
name: "Fake Ladder (TTL=8) + 4x SNI Step + Drop-SACK",
|
||||
engine: "byedpi",
|
||||
args: "-s1+s -d2+s -s3+s -d4+s -f-1 -t8 -r1+s -S -a1 -As",
|
||||
description: "TTL=8 fake packet with stepped SNI offsets."
|
||||
},
|
||||
{
|
||||
id: "bd_tlsrec_ladder",
|
||||
name: "TLS Record Fragment + SNI Ladder",
|
||||
engine: "byedpi",
|
||||
args: "--tlsrec 1+sniext -d1 -d3+s -s6+s -d9+s -r1+s -S -a1",
|
||||
description: "Fragments outer TLS Record header before SNI extension ladder."
|
||||
},
|
||||
{
|
||||
id: "bd_oob_ladder",
|
||||
name: "OOB Desync + SNI Ladder",
|
||||
engine: "byedpi",
|
||||
args: "-o 1 -q 1 -d1 -d3+s -s6+s -d9+s -r1+s -S -a1",
|
||||
description: "TCP Out-Of-Band URG flag with 4-step ladder."
|
||||
},
|
||||
{
|
||||
id: "bd_dense_staircase",
|
||||
name: "Dense Alternating Staircase (8-step) + Drop-SACK",
|
||||
engine: "byedpi",
|
||||
args: "-s1 -d2 -s3+s -d4+s -s5+s -d6+s -s7+s -d8+s -r1+s -S -As",
|
||||
description: "Alternating 1-byte split and disorder steps along SNI boundary."
|
||||
},
|
||||
{
|
||||
id: "bd_reverse_sni_combo",
|
||||
name: "Reverse SNI (-r 1+s) + Drop-SACK + Auto",
|
||||
engine: "byedpi",
|
||||
args: "-s 1 -d 1 -r 1+s -S --auto=r,s",
|
||||
description: "Reverses SNI chunks with auto fallback and SACK suppression."
|
||||
},
|
||||
|
||||
// ── 2. CLASSIC & COMPATIBILITY SUITE ───────────────────────────────────────
|
||||
{
|
||||
id: "bd_auto_tr_d2",
|
||||
name: "ByeDPI Auto (t,r,a,s) + Disorder",
|
||||
@@ -944,6 +1145,54 @@ function generate_combinatorial_zapret2() {
|
||||
sprintf("--lua-desync=hostfakesplit:pos=%s:fooling=badseq", pos),
|
||||
"Host header substitution in initial packet");
|
||||
}
|
||||
|
||||
// 8. Blockcheck2 & Blockcheckw Heavy Multi-Split Chains
|
||||
let multi_chains = [
|
||||
"1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1",
|
||||
"1,midsld,1220",
|
||||
"1,sniext+1,host+1",
|
||||
"10,sniext+4"
|
||||
];
|
||||
for (let chain in multi_chains) {
|
||||
add(sprintf("7-Point MultiSplit (%s)", chain),
|
||||
sprintf("--payload=tls_client_hello --lua-desync=multisplit:pos=%s", chain),
|
||||
"Full-spectrum ClientHello multisplit fragmentation");
|
||||
add(sprintf("7-Point MultiDisorder (%s)", chain),
|
||||
sprintf("--payload=tls_client_hello --lua-desync=multidisorder:pos=%s", chain),
|
||||
"Full-spectrum ClientHello multidisorder fragmentation");
|
||||
}
|
||||
|
||||
// 9. TCP Segmentation & OOB combinations
|
||||
for (let rep in [ 20, 100, 260 ]) {
|
||||
add(sprintf("TCPSegment (repeats=%d, pos=0,1)", rep),
|
||||
sprintf("--payload=tls_client_hello --lua-desync=tcpseg:pos=0,1:ip_id=rnd:repeats=%d", rep),
|
||||
"Randomized IP-ID TCP segmentation burst");
|
||||
add(sprintf("TCPSegment (repeats=%d, midsld)", rep),
|
||||
sprintf("--payload=tls_client_hello --lua-desync=tcpseg:pos=0,midsld:ip_id=rnd:repeats=%d", rep),
|
||||
"Mid-SLD TCP segmentation burst");
|
||||
}
|
||||
|
||||
for (let urp in [ "midsld", "b", "2" ]) {
|
||||
add(sprintf("OOB Desync (urp=%s)", urp),
|
||||
sprintf("--in-range=-s1 --lua-desync=oob:urp=%s", urp),
|
||||
"TCP Out-Of-Band URG packet with urgent pointer offset");
|
||||
}
|
||||
|
||||
// 10. Advanced TCP flag & ACK offsets with authentic blobs
|
||||
for (let blob in [ "tls_max", "tls_google" ]) {
|
||||
add(sprintf("TCP ACK Offset (-66000, %s)", blob),
|
||||
sprintf("--payload=tls_client_hello --lua-desync=fake:blob=%s:tcp_ack=-66000:tcp_ts_up:repeats=6", blob),
|
||||
"Corrupted TCP ACK offset with PAWS ascending timestamps");
|
||||
add(sprintf("TCP Flags Unset ACK (%s)", blob),
|
||||
sprintf("--payload=tls_client_hello --lua-desync=fake:blob=%s:tcp_flags_unset=ACK:repeats=6", blob),
|
||||
"Fake packets with ACK flag cleared");
|
||||
add(sprintf("BadSum Checksum Invalidation (%s)", blob),
|
||||
sprintf("--payload=tls_client_hello --lua-desync=fake:blob=%s:badsum:repeats=6", blob),
|
||||
"Corrupted L4 checksum fake packets");
|
||||
add(sprintf("Auto-TTL Adaptive Probe (%s, autottl=-1,3-20)", blob),
|
||||
sprintf("--payload=tls_client_hello --lua-desync=fake:blob=%s:ip_autottl=-1,3-20:repeats=6", blob),
|
||||
"Adaptive distance TTL calculation before DPI hop");
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
@@ -1037,6 +1286,7 @@ function generate_combinatorial_byedpi() {
|
||||
let oobs = p.oobs || [ "1", "2" ];
|
||||
let autos = p.autos || [ "t,r,a,s", "r,s", "t,a" ];
|
||||
|
||||
// 1. Classic adaptive combinations
|
||||
for (let a in autos) {
|
||||
for (let o in oobs) {
|
||||
for (let d in disorders) {
|
||||
@@ -1052,6 +1302,7 @@ function generate_combinatorial_byedpi() {
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fake with split & disorder
|
||||
for (let ttl in [ 3, 4, 8 ]) {
|
||||
for (let s in [ "1", "1+sniext", "midsld" ]) {
|
||||
for (let d in [ "1", "2" ]) {
|
||||
@@ -1061,6 +1312,43 @@ function generate_combinatorial_byedpi() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Multi-split ladder chains (Combinatorial combat suites)
|
||||
let ladder_bases = [
|
||||
{ name: "Ladder 3-Step", args: "-d1 -d3+s -s6+s" },
|
||||
{ name: "Ladder 5-Step", args: "-d1 -d3+s -s6+s -d9+s -s12+s" },
|
||||
{ name: "Ladder 8-Step", args: "-d1 -d3+s -s6+s -d9+s -s12+s -d15+s -s20+s -d25+s" },
|
||||
{ name: "Ladder 10-Step", args: "-d1 -d3+s -s6+s -d9+s -s12+s -d15+s -s20+s -d25+s -s30+s -d35+s" },
|
||||
{ name: "Split Ladder 6-Step", args: "-s1 -s3+s -s6+s -s9+s -s12+s -s15+s" },
|
||||
{ name: "Disorder Ladder 6-Step", args: "-d1 -d3+s -d6+s -d9+s -d12+s -d15+s" }
|
||||
];
|
||||
|
||||
let reverse_tails = [ "", " -r1+s", " -r2+s" ];
|
||||
let sack_options = [ " -S", "" ];
|
||||
let auto_tails = [ " -a1 -As", " -a1", " --auto=r,s", "" ];
|
||||
|
||||
for (let lb in ladder_bases) {
|
||||
for (let rt in reverse_tails) {
|
||||
for (let so in sack_options) {
|
||||
for (let at in auto_tails) {
|
||||
let comb_args = trim(sprintf("%s%s%s%s", lb.args, rt, so, at));
|
||||
add(sprintf("%s%s%s%s", lb.name, rt != "" ? " + Rev" : "", so != "" ? " + SACK" : "", at != "" ? " + Auto" : ""),
|
||||
comb_args,
|
||||
"Multi-stage ladder split & disorder chain for resilient DPI bypass");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Fake packet with multi-split ladder
|
||||
for (let ttl in [ 3, 4, 6, 8 ]) {
|
||||
add(sprintf("Fake (TTL=%d) + 4-Step Ladder + SACK Drop", ttl),
|
||||
sprintf("-s1+s -d2+s -s3+s -d4+s -f-1 -t%d -r1+s -S -a1", ttl),
|
||||
"Fake handshake packet followed by 4-step SNI ladder and SACK suppression");
|
||||
add(sprintf("Fake (TTL=%d) + TLS Record Split + SACK Drop", ttl),
|
||||
sprintf("--tlsrec 1+sniext -s1+s -d2+s -f-1 -t%d -S -a1", ttl),
|
||||
"TLS record boundary split with fake packet and SACK drop");
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
@@ -1477,6 +1765,9 @@ function parse_curl_output(output, result) {
|
||||
result.handshake_ms = 0;
|
||||
result.ttfb_ms = 0;
|
||||
result.speed_kbps = 0;
|
||||
result.data_bytes = 0;
|
||||
result.data_verified = false;
|
||||
result.dpi_verdict = "timeout";
|
||||
result.score = 0;
|
||||
result.error = "Probe timeout or connection refused";
|
||||
return result;
|
||||
@@ -1487,6 +1778,9 @@ function parse_curl_output(output, result) {
|
||||
result.success = false;
|
||||
result.http_code = 0;
|
||||
result.score = 0;
|
||||
result.data_bytes = 0;
|
||||
result.data_verified = false;
|
||||
result.dpi_verdict = "malformed";
|
||||
result.error = "Malformed probe metrics output";
|
||||
return result;
|
||||
}
|
||||
@@ -1495,24 +1789,69 @@ function parse_curl_output(output, result) {
|
||||
let appconnect = double(parts[1]);
|
||||
let starttransfer = double(parts[2]);
|
||||
let speed_bytes = double(parts[3]);
|
||||
let size_download = length(parts) >= 5 ? int(parts[4]) : 0;
|
||||
let exit_code = length(parts) >= 6 ? int(parts[5]) : 0;
|
||||
|
||||
result.http_code = http_code;
|
||||
result.handshake_ms = int(appconnect * 1000.0);
|
||||
result.ttfb_ms = int(starttransfer * 1000.0);
|
||||
result.speed_kbps = int(speed_bytes / 1024.0);
|
||||
result.data_bytes = size_download;
|
||||
|
||||
// Check for HTTP 400 (Server Receives Fakes - desync corruption)
|
||||
if (http_code == 400) {
|
||||
result.success = false;
|
||||
result.score = 0;
|
||||
result.data_verified = false;
|
||||
result.dpi_verdict = "server_fakes";
|
||||
result.error = "HTTP 400 (Remote server rejected corrupted/fake packet payload)";
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check for 16KB DPI Throttling (TSPU stream drop / connection reset after 10-28KB)
|
||||
if (exit_code != 0 && size_download >= 10240 && size_download <= 28672) {
|
||||
result.success = false;
|
||||
result.score = 0;
|
||||
result.data_verified = false;
|
||||
result.dpi_verdict = "throttled_16k";
|
||||
result.error = sprintf("16KB DPI Data Throttle (stream killed after %d B, curl exit %d)", size_download, exit_code);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (exit_code != 0 && http_code == 0) {
|
||||
result.success = false;
|
||||
result.score = 0;
|
||||
result.data_verified = false;
|
||||
result.dpi_verdict = "dropped";
|
||||
result.error = sprintf("Connection dropped by DPI (curl exit %d)", exit_code);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (exit_code != 0 && http_code >= 200 && http_code < 400) {
|
||||
result.success = false;
|
||||
result.score = 0;
|
||||
result.data_verified = false;
|
||||
result.dpi_verdict = "transfer_failed";
|
||||
result.error = sprintf("Data transfer aborted after %d B (curl exit %d)", size_download, exit_code);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Any valid HTTP response from origin (including 401/403/404/405 when hitting endpoints without auth headers)
|
||||
// proves that TCP handshake, TLS ClientHello, and HTTP negotiation successfully reached the remote server past TSPU.
|
||||
if ((http_code >= 200 && http_code < 400) || http_code == 401 || http_code == 403 || http_code == 404 || http_code == 405) {
|
||||
result.success = true;
|
||||
let base_score = (http_code >= 200 && http_code < 400) ? 100 : 85;
|
||||
let latency_score = max(0, 1000 - result.ttfb_ms);
|
||||
let speed_score = int(result.speed_kbps / 10.0);
|
||||
result.score = base_score + latency_score + speed_score;
|
||||
let data_bonus = size_download >= 32768 ? 50 : (size_download >= 1024 ? 20 : 0);
|
||||
result.score = base_score + latency_score + speed_score + data_bonus;
|
||||
result.error = "";
|
||||
result.data_verified = size_download >= 32768;
|
||||
result.dpi_verdict = size_download >= 32768 ? "verified_32k" : "available";
|
||||
} else {
|
||||
result.success = false;
|
||||
result.score = 0;
|
||||
result.data_verified = false;
|
||||
result.dpi_verdict = "failed";
|
||||
result.error = http_code > 0 ? sprintf("HTTP Status %d", http_code) : "Connection dropped by DPI";
|
||||
}
|
||||
|
||||
@@ -1521,7 +1860,7 @@ function parse_curl_output(output, result) {
|
||||
|
||||
// ── DPI Type Detection ──────────────────────────────────────────────────────
|
||||
// Probes the target without any bypass to determine how it's being blocked.
|
||||
// Returns: { type: "rst"|"throttle"|"dns_block"|"unknown"|"none",
|
||||
// Returns: { type: "rst"|"throttle"|"dns_block"|"ip_block"|"unknown"|"none",
|
||||
// confidence: 0-100, details: string, recommended_engines: string[] }
|
||||
function detect_dpi_type(target_key, custom_url) {
|
||||
let urls_list = resolve_target_urls_list(target_key, custom_url);
|
||||
@@ -1542,7 +1881,7 @@ function detect_dpi_type(target_key, custom_url) {
|
||||
system("nft 'add rule inet tachyon_fuzzer bypass_singbox meta l4proto tcp tcp dport { 80, 443 } meta mark set meta mark | 0x00200000 counter' 2>/dev/null");
|
||||
|
||||
let curl_cmd = sprintf(
|
||||
"curl %s-so /dev/null -w '%%{http_code}\\t%%{time_appconnect}\\t%%{time_starttransfer}\\t%%{speed_download}' -L --connect-timeout 4 --max-time 6 %s 2>&1",
|
||||
"curl %s-so /dev/null -w '%%{http_code}\\t%%{time_appconnect}\\t%%{time_starttransfer}\\t%%{speed_download}\\t%%{size_download}' -L --connect-timeout 4 --max-time 6 %s 2>&1; printf '\\t%%d\\n' $?",
|
||||
dns_flags,
|
||||
shell_quote(target_url)
|
||||
);
|
||||
@@ -1560,6 +1899,8 @@ function detect_dpi_type(target_key, custom_url) {
|
||||
handshake_ms: metrics.handshake_ms || 0,
|
||||
ttfb_ms: metrics.ttfb_ms || 0,
|
||||
speed_kbps: metrics.speed_kbps || 0,
|
||||
data_bytes: metrics.data_bytes || 0,
|
||||
dpi_verdict: metrics.dpi_verdict || "unknown",
|
||||
error: metrics.error || ""
|
||||
};
|
||||
|
||||
@@ -1589,6 +1930,16 @@ function detect_dpi_type(target_key, custom_url) {
|
||||
result.confidence = 90;
|
||||
result.details = sprintf("DNS resolution failed for %s — likely DNS-level blocking or hijacking", domain);
|
||||
result.recommended_engines = ["byedpi", "zapret2"];
|
||||
} else if (metrics.dpi_verdict == "throttled_16k" || (http_code == 200 && metrics.data_bytes >= 10240 && metrics.data_bytes <= 28672)) {
|
||||
result.type = "throttle";
|
||||
result.confidence = 95;
|
||||
result.details = sprintf("16KB DPI throttling detected on %s — handshake succeeded but stream dropped at ~16KB data transfer", domain);
|
||||
result.recommended_engines = ["byedpi", "zapret2"];
|
||||
} else if ((http_code == 0 && handshake == 0) && (index(error_str, "timed out") >= 0 || index(error_str, "Connection timed out") >= 0 || index(error_str, "ETIMEDOUT") >= 0)) {
|
||||
result.type = "ip_block";
|
||||
result.confidence = 95;
|
||||
result.details = sprintf("TCP connect timed out before TLS handshake for %s — host is blocked at the IP layer. DPI bypass cannot unblock this; route via Sing-box VPN/Proxy outbound instead.", domain);
|
||||
result.recommended_engines = [];
|
||||
} else if (index(error_str, "Connection reset") >= 0 || index(error_str, "ECONNRESET") >= 0) {
|
||||
result.type = "rst";
|
||||
result.confidence = 85;
|
||||
@@ -1798,11 +2149,14 @@ function run_probe(engine, args_str, target_key, custom_url) {
|
||||
let sum_handshake = 0;
|
||||
let sum_ttfb = 0;
|
||||
let max_speed = 0;
|
||||
let sum_data_bytes = 0;
|
||||
let all_data_verified = true;
|
||||
let last_http = 0;
|
||||
let last_dpi_verdict = "available";
|
||||
|
||||
for (let target_item in urls_list) {
|
||||
let curl_cmd = sprintf(
|
||||
"curl -x socks5h://127.0.0.1:%d -so /dev/null -w '%%{http_code}\\t%%{time_appconnect}\\t%%{time_starttransfer}\\t%%{speed_download}' -L --connect-timeout 4 --max-time 6 %s 2>/dev/null",
|
||||
"curl -x socks5h://127.0.0.1:%d -so /dev/null -w '%%{http_code}\\t%%{time_appconnect}\\t%%{time_starttransfer}\\t%%{speed_download}\\t%%{size_download}' -L --connect-timeout 4 --max-time 6 %s 2>/dev/null; printf '\\t%%d\\n' $?",
|
||||
BYEDPI_PORT,
|
||||
shell_quote(target_item.url)
|
||||
);
|
||||
@@ -1819,11 +2173,16 @@ function run_probe(engine, args_str, target_key, custom_url) {
|
||||
passed_count++;
|
||||
sum_handshake += single_res.handshake_ms;
|
||||
sum_ttfb += single_res.ttfb_ms;
|
||||
sum_data_bytes += single_res.data_bytes || 0;
|
||||
if (!single_res.data_verified) all_data_verified = false;
|
||||
if (single_res.speed_kbps > max_speed) max_speed = single_res.speed_kbps;
|
||||
last_http = single_res.http_code;
|
||||
last_dpi_verdict = single_res.dpi_verdict || "available";
|
||||
} else {
|
||||
all_data_verified = false;
|
||||
if (last_http == 0) last_http = single_res.http_code;
|
||||
if (single_res.error && result.error == "") result.error = single_res.error;
|
||||
last_dpi_verdict = single_res.dpi_verdict || "failed";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1836,11 +2195,17 @@ function run_probe(engine, args_str, target_key, custom_url) {
|
||||
result.handshake_ms = int(sum_handshake / double(total_urls));
|
||||
result.ttfb_ms = int(sum_ttfb / double(total_urls));
|
||||
result.speed_kbps = max_speed;
|
||||
result.score = 100 + max(0, 1000 - result.ttfb_ms) + int(result.speed_kbps / 10.0);
|
||||
result.data_bytes = int(sum_data_bytes / double(total_urls));
|
||||
result.data_verified = all_data_verified;
|
||||
result.dpi_verdict = all_data_verified ? "verified_32k" : last_dpi_verdict;
|
||||
result.score = 100 + max(0, 1000 - result.ttfb_ms) + int(result.speed_kbps / 10.0) + (result.data_verified ? 50 : 20);
|
||||
result.error = "";
|
||||
} else {
|
||||
result.success = false;
|
||||
result.http_code = last_http;
|
||||
result.data_bytes = sum_data_bytes;
|
||||
result.data_verified = false;
|
||||
result.dpi_verdict = last_dpi_verdict;
|
||||
result.score = 0;
|
||||
if (result.error == "") {
|
||||
result.error = sprintf("Failed %d of %d endpoints", total_urls - passed_count, total_urls);
|
||||
@@ -1919,12 +2284,15 @@ function run_probe(engine, args_str, target_key, custom_url) {
|
||||
let sum_handshake = 0;
|
||||
let sum_ttfb = 0;
|
||||
let max_speed = 0;
|
||||
let sum_data_bytes = 0;
|
||||
let all_data_verified = true;
|
||||
let last_http = 0;
|
||||
let last_dpi_verdict = "available";
|
||||
let dns_flags = get_fuzzer_curl_dns_flags();
|
||||
|
||||
for (let target_item in urls_list) {
|
||||
let curl_cmd = sprintf(
|
||||
"curl %s-so /dev/null -w '%%{http_code}\\t%%{time_appconnect}\\t%%{time_starttransfer}\\t%%{speed_download}' -L --connect-timeout 4 --max-time 6 %s 2>/dev/null",
|
||||
"curl %s-so /dev/null -w '%%{http_code}\\t%%{time_appconnect}\\t%%{time_starttransfer}\\t%%{speed_download}\\t%%{size_download}' -L --connect-timeout 4 --max-time 6 %s 2>/dev/null; printf '\\t%%d\\n' $?",
|
||||
dns_flags,
|
||||
shell_quote(target_item.url)
|
||||
);
|
||||
@@ -1941,11 +2309,16 @@ function run_probe(engine, args_str, target_key, custom_url) {
|
||||
passed_count++;
|
||||
sum_handshake += single_res.handshake_ms;
|
||||
sum_ttfb += single_res.ttfb_ms;
|
||||
sum_data_bytes += single_res.data_bytes || 0;
|
||||
if (!single_res.data_verified) all_data_verified = false;
|
||||
if (single_res.speed_kbps > max_speed) max_speed = single_res.speed_kbps;
|
||||
last_http = single_res.http_code;
|
||||
last_dpi_verdict = single_res.dpi_verdict || "available";
|
||||
} else {
|
||||
all_data_verified = false;
|
||||
if (last_http == 0) last_http = single_res.http_code;
|
||||
if (single_res.error && result.error == "") result.error = single_res.error;
|
||||
last_dpi_verdict = single_res.dpi_verdict || "failed";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1958,11 +2331,17 @@ function run_probe(engine, args_str, target_key, custom_url) {
|
||||
result.handshake_ms = int(sum_handshake / double(total_urls));
|
||||
result.ttfb_ms = int(sum_ttfb / double(total_urls));
|
||||
result.speed_kbps = max_speed;
|
||||
result.score = 100 + max(0, 1000 - result.ttfb_ms) + int(result.speed_kbps / 10.0);
|
||||
result.data_bytes = int(sum_data_bytes / double(total_urls));
|
||||
result.data_verified = all_data_verified;
|
||||
result.dpi_verdict = all_data_verified ? "verified_32k" : last_dpi_verdict;
|
||||
result.score = 100 + max(0, 1000 - result.ttfb_ms) + int(result.speed_kbps / 10.0) + (result.data_verified ? 50 : 20);
|
||||
result.error = "";
|
||||
} else {
|
||||
result.success = false;
|
||||
result.http_code = last_http;
|
||||
result.data_bytes = sum_data_bytes;
|
||||
result.data_verified = false;
|
||||
result.dpi_verdict = last_dpi_verdict;
|
||||
result.score = 0;
|
||||
if (result.error == "") {
|
||||
result.error = sprintf("Failed %d of %d endpoints", total_urls - passed_count, total_urls);
|
||||
@@ -2050,6 +2429,9 @@ function run_fuzzer_worker(engine, target, custom_url, rule_section, custom_file
|
||||
handshake_ms: probe.handshake_ms,
|
||||
ttfb_ms: probe.ttfb_ms,
|
||||
speed_kbps: probe.speed_kbps,
|
||||
data_bytes: probe.data_bytes || 0,
|
||||
data_verified: probe.data_verified || false,
|
||||
dpi_verdict: probe.dpi_verdict || "unknown",
|
||||
score: probe.score,
|
||||
error: probe.error,
|
||||
sub_probes: probe.sub_probes || [],
|
||||
|
||||
@@ -2273,12 +2273,22 @@ function nft_populate_runtime_set_for_section(section, deferred_sections, table,
|
||||
"/tmp/sing-box/rulesets/community-subnets-" + service + ".lst",
|
||||
"/etc/tachyon/rulesets/community-subnets-" + service + ".lst"
|
||||
];
|
||||
let found = false;
|
||||
for (let path in cached_paths) {
|
||||
if (helpers.file_is_usable(path, 50)) {
|
||||
nft_add_file_chunks_to_family_sets(path, table, sets.subnets, sets.subnets6, "ips", "", "5000");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (service == "discord") {
|
||||
nft_add_set_elements(table, sets.subnets, "162.158.0.0/15, 172.64.0.0/13, 138.128.136.0/21");
|
||||
}
|
||||
else if (service == "telegram") {
|
||||
nft_add_set_elements(table, sets.subnets, "149.154.160.0/20, 91.108.4.0/22, 91.108.8.0/22, 91.108.12.0/22, 91.108.16.0/22, 91.108.56.0/22, 5.28.192.0/18, 91.105.192.0/23, 95.161.64.0/20, 185.76.151.0/24, 194.221.0.0/16");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1213,10 +1213,11 @@ function add_protocol_matchers(rule, section) {
|
||||
|
||||
|
||||
function load_community_subnet_cidrs(community) {
|
||||
let service = as_string(community);
|
||||
let paths = [
|
||||
"/tmp/sing-box/rulesets/community-subnets-" + as_string(community) + ".lst",
|
||||
"/etc/tachyon/rulesets/community-subnets-" + as_string(community) + ".lst",
|
||||
(ctx.runtime_ruleset_folder || runtime_ruleset_folder || "/tmp/sing-box/rulesets") + "/community-subnets-" + as_string(community) + ".lst"
|
||||
"/tmp/sing-box/rulesets/community-subnets-" + service + ".lst",
|
||||
"/etc/tachyon/rulesets/community-subnets-" + service + ".lst",
|
||||
(ctx.runtime_ruleset_folder || runtime_ruleset_folder || "/tmp/sing-box/rulesets") + "/community-subnets-" + service + ".lst"
|
||||
];
|
||||
for (let path in paths) {
|
||||
let content = fs.readfile(path);
|
||||
@@ -1231,6 +1232,18 @@ function load_community_subnet_cidrs(community) {
|
||||
return cidrs;
|
||||
}
|
||||
}
|
||||
// Hardcoded seed fallback for cold boot before list-update downloads .lst
|
||||
if (service == "discord") {
|
||||
return [ "162.158.0.0/15", "172.64.0.0/13", "138.128.136.0/21" ];
|
||||
}
|
||||
if (service == "telegram") {
|
||||
return [
|
||||
"149.154.160.0/20", "91.108.4.0/22", "91.108.8.0/22",
|
||||
"91.108.12.0/22", "91.108.16.0/22", "91.108.56.0/22",
|
||||
"5.28.192.0/18", "91.105.192.0/23", "95.161.64.0/20",
|
||||
"185.76.151.0/24", "194.221.0.0/16"
|
||||
];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -1252,9 +1265,14 @@ function add_combined_route_for_section(config, section) {
|
||||
|
||||
|
||||
for (let community in connections.community_lists(section)) {
|
||||
let ensured = ensure_community_ruleset(config, section_name, as_string(community));
|
||||
let service = as_string(community);
|
||||
let ensured = ensure_community_ruleset(config, section_name, service);
|
||||
push(rule_set_tags, ensured.tag);
|
||||
push(dns_rule_set_tags, ensured.tag);
|
||||
if (service != "cloudflare" && service != "cloudfront" && service != "hetzner" && service != "ovh" && service != "digitalocean") {
|
||||
for (let cidr in load_community_subnet_cidrs(community))
|
||||
push(ip_cidr, cidr);
|
||||
}
|
||||
}
|
||||
for (let reference in connections.rule_sets(section)) {
|
||||
let ensured = ensure_custom_ruleset(config, as_string(reference));
|
||||
|
||||
Reference in New Issue
Block a user