- 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
127 lines
4.6 KiB
Bash
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'
|