Files
NeoTachyon/tests/zapret_validator.sh
T
Dushnilin e8c1d9d382 feat: стабильность подписок, порог DNS failover, прямой порт прокси и TorrServer Direct
- subscription: детерминированная сортировка аутбаундов при расчете сигнатуры кэша (защита от перезапусков при shuffle)
- dns: порог последовательных ошибок dns_failover_failure_threshold (защита от флаппинга)
- singbox: выделенный direct_bypass inbound (mixed port 2080) для прямого выхода устройств в обход TPROXY
- torrserver: автоматический bypass cgroups v2 services/torrserver прямо в WAN
- zapret: нормализация устаревших параметров conntrack --ctrack-timeouts
- ui: интеграция управления службами TorrServer Direct и Direct Proxy в LuCI
- tests: новые тесты subscription_order_independence и direct_bypass_torrserver
2026-09-06 21:19:42 +03:00

127 lines
4.6 KiB
Bash

#!/usr/bin/env bash
set -eo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
VALIDATOR="$ROOT_DIR/tachyon/files/usr/lib/providers/zapret/validator.uc"
ZAPRET2_VALIDATOR="$ROOT_DIR/tachyon/files/usr/lib/providers/zapret2/validator.uc"
WORK_DIR="$(mktemp -d)"
cleanup() {
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
fail() {
printf 'FAIL: %s\n' "$1" >&2
exit 1
}
json_field() {
local json="$1"
local field="$2"
JSON_VALUE="$json" node - "$field" <<'NODE'
const field = process.argv[2];
const value = JSON.parse(process.env.JSON_VALUE);
const actual = value[field];
if (Array.isArray(actual)) {
console.log(actual.join("\n"));
} else {
console.log(String(actual));
}
NODE
}
assert_json_field() {
local json="$1"
local field="$2"
local expected="$3"
local actual
actual="$(json_field "$json" "$field")"
[ "$actual" = "$expected" ] || fail "expected $field=$expected, got $actual"
}
valid_nfqws="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate-json nfqws '--dpi-desync=fake --dpi-desync-repeats 2')"
assert_json_field "$valid_nfqws" valid true
configured="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" strategy-or-default "$(printf -- '--dpi-desync=fake\t--dpi-desync-repeats 2')" '--default')"
[ "$configured" = "--dpi-desync=fake --dpi-desync-repeats 2" ] ||
fail "configured zapret strategy should be normalized, got '$configured'"
defaulted="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" strategy-or-default "" "$(printf -- '--default\t1')")"
[ "$defaulted" = "--default 1" ] ||
fail "empty zapret strategy should use normalized default, got '$defaulted'"
if invalid_nfqws="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate-json nfqws '--hostlist domains.txt' 2>/dev/null)"; then
fail "hostlist selection should be rejected for nfqws"
fi
assert_json_field "$invalid_nfqws" valid false
assert_json_field "$invalid_nfqws" needle --hostlist
validator_output="$WORK_DIR/zapret-validator.out"
if ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate nfqws '--qnum=200' >"$validator_output" 2>/dev/null; then
fail "qnum override should be rejected for nfqws"
fi
grep -q 'NFQUEUE number is assigned by Tachyon' "$validator_output" ||
fail "qnum rejection should explain ownership"
valid_nfqws2="$(ucode -L "$TACHYON_LIB" -- "$ZAPRET2_VALIDATOR" validate-json nfqws2 '--name tachyon --intercept=1')"
assert_json_field "$valid_nfqws2" valid true
if invalid_nfqws2="$(ucode -L "$TACHYON_LIB" -- "$ZAPRET2_VALIDATOR" validate-json nfqws2 '--intercept=0' 2>/dev/null)"; then
fail "disabled nfqws2 intercept should be rejected"
fi
assert_json_field "$invalid_nfqws2" valid false
assert_json_field "$invalid_nfqws2" needle --intercept
if ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate-json nfqws2 '--name tachyon --intercept=1' >/dev/null 2>&1; then
fail "zapret validator must not own nfqws2 validation"
fi
if ucode -L "$TACHYON_LIB" -- "$ZAPRET2_VALIDATOR" validate-json nfqws '--dpi-desync=fake' >/dev/null 2>&1; then
fail "zapret2 validator must not own nfqws validation"
fi
cat >"$WORK_DIR/require-zapret-validator.uc" <<'UCODE'
let validator = require("providers.zapret.validator");
let zapret2_validator = require("providers.zapret2.validator");
let valid_nfqws = validator.validate_strategy("nfqws", "--dpi-desync=fake --dpi-desync-repeats 2", "");
if (!valid_nfqws.valid)
exit(1);
let invalid_nfqws = validator.validate_strategy("nfqws", "--hostlist domains.txt", "");
if (invalid_nfqws.valid || invalid_nfqws.needle != "--hostlist")
exit(1);
let valid_nfqws2 = zapret2_validator.validate_strategy("nfqws2", "--name tachyon --intercept=1", "");
if (!valid_nfqws2.valid)
exit(1);
if (validator.validate_strategy("nfqws2", "--name tachyon --intercept=1", "").valid)
exit(1);
if (zapret2_validator.validate_strategy("nfqws", "--dpi-desync=fake", "").valid)
exit(1);
if (validator.strategy_or_default("", "--default\t1") != "--default 1")
exit(1);
let runtime = require("providers.nfqueue.runtime");
let cfg = { legacy_runtime_base: "", provider_base_dir: "" };
let normalized = runtime.expand_strategy(cfg, "--filter-tcp=80 --ctrack-timeouts=30,30,600,30,30,30,30,30");
if (normalized != "--filter-tcp=80 --ctrack-timeouts=30:600:30:30") {
print("Unexpected normalized timeouts: " + normalized + "\n");
exit(1);
}
let untouched = runtime.expand_strategy(cfg, "--filter-tcp=80 --ctrack-timeouts=30:600:30:30");
if (untouched != "--filter-tcp=80 --ctrack-timeouts=30:600:30:30") {
print("Untouched timeouts changed: " + untouched + "\n");
exit(1);
}
UCODE
ucode -L "$TACHYON_LIB" "$WORK_DIR/require-zapret-validator.uc"
printf 'Zapret validator checks passed\n'