- feat(diagnostics): router-level IP & DNS leak detection * одновременный опрос прямого WAN сокета (SO_MARK 0x08000000) и локального прокси (127.0.0.1:4534) * выявление утечки реального публичного IP адреса * тестирование восходящих DNS-резолверов по протоколу bash.ws и обнаружение DNS провайдера * CLI команды: tachyon leak_check [--pretty], check_ip_leak, check_dns_leak * LuCI модальное окно с детализированными таблицами изоляции IP и анализа резолверов - fix(hosts): устранение ложного предупреждения [warn] No hosts list URLs configured * запуск HOSTS_UC в lifecycle.uc только при наличии активных списков хостов * hosts.uc возвращает success:true и код 0 без лишних записей в syslog при отсутствии URL * добавлена проверка has-hosts-list-update-sources в state.uc - i18n: полная синхронизация русской локализации в каталогах gettext PO/POT - bump: версия пакета 1.3.24
113 lines
3.3 KiB
Bash
113 lines
3.3 KiB
Bash
#!/usr/bin/env bash
|
|
set -eo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
HOSTS_UC="${HOSTS_UC:-$ROOT_DIR/tachyon/files/usr/lib/components/hosts.uc}"
|
|
TACHYON_LIB="${TACHYON_LIB:-$ROOT_DIR/tachyon/files/usr/lib}"
|
|
TMP_DIR="$(mktemp -d)"
|
|
PASS=0
|
|
FAIL=0
|
|
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
|
|
mkdir -p "$TMP_DIR/cache" "$TMP_DIR/tmp"
|
|
export TACHYON_HOSTS_CACHE_DIR="$TMP_DIR/cache"
|
|
export TACHYON_HOSTS_TMP_DIR="$TMP_DIR/tmp"
|
|
|
|
ucode() {
|
|
command ucode -L "$TACHYON_LIB" "$@"
|
|
}
|
|
|
|
fail() {
|
|
printf 'FAIL: %s\n' "$1" >&2
|
|
FAIL=$((FAIL + 1))
|
|
}
|
|
|
|
pass() {
|
|
PASS=$((PASS + 1))
|
|
}
|
|
|
|
assert_eq() {
|
|
local expected="$1"
|
|
local actual="$2"
|
|
local label="$3"
|
|
if [ "$actual" = "$expected" ]; then
|
|
pass
|
|
else
|
|
fail "$label: expected '$expected', got '$actual'"
|
|
fi
|
|
}
|
|
|
|
# --- Test 1: Parse hosts file with mixed formats ---
|
|
cat > "$TMP_DIR/test_hosts.txt" <<'EOF'
|
|
# This is a comment
|
|
127.0.0.1 localhost
|
|
localhost 127.0.0.1
|
|
45.155.204.190 chatgpt.com
|
|
45.155.204.190 ab.chatgpt.com
|
|
0.0.0.0 ad.doubleclick.net
|
|
0.0.0.0 tracker.example.com
|
|
|
|
# IPv6
|
|
::1 localhost
|
|
fe80::1 host.local
|
|
EOF
|
|
|
|
# --- Test 2: Parse file with only comments ---
|
|
cat > "$TMP_DIR/comments_only.txt" <<'EOF'
|
|
# Just comments
|
|
# Nothing else
|
|
EOF
|
|
|
|
# --- Test 3: Parse empty file ---
|
|
: > "$TMP_DIR/empty.txt"
|
|
|
|
# --- Test 4: Parse file with invalid lines ---
|
|
cat > "$TMP_DIR/invalid.txt" <<'EOF'
|
|
not a valid line
|
|
also not valid
|
|
45.155.204.190 chatgpt.com
|
|
valid.com 1.2.3.4
|
|
EOF
|
|
|
|
# Run the hosts list status command (should not fail with no URLs)
|
|
echo "=== Test: hosts_list_status with no URLs ==="
|
|
output=$(ucode "$HOSTS_UC" list-status 2>/dev/null || true)
|
|
assert_eq "false" "$(echo "$output" | grep -o '"cache_exists":[a-z]*' | cut -d: -f2)" "cache_exists should be false initially"
|
|
|
|
# Run hosts_list_update with no URLs (should succeed cleanly with success: true and exit 0)
|
|
echo "=== Test: hosts_list_update with no URLs ==="
|
|
update_output=$(ucode "$HOSTS_UC" list-update 2>/dev/null || true)
|
|
assert_eq "true" "$(echo "$update_output" | grep -o '"success":[a-z]*' | cut -d: -f2)" "list-update should succeed when no URLs configured"
|
|
|
|
# --- Test 5: Safe name length for long percent-encoded URLs ---
|
|
echo "=== Test: safe_name length for long URLs ==="
|
|
long_url_safe_len=$(ucode -e '
|
|
let common = require("core.common");
|
|
let as_string = common.as_string;
|
|
function hash12(str) {
|
|
str = as_string(str);
|
|
let h1 = 5381;
|
|
let h2 = 52711;
|
|
for (let i = 0; i < length(str); i++) {
|
|
let code = ord(str, i);
|
|
h1 = ((h1 * 33) + code) % 2147483647;
|
|
h2 = ((h2 * 31) + code) % 2147483647;
|
|
}
|
|
return sprintf("%08x%04x", h1, h2 % 65536);
|
|
}
|
|
let url = "https://raw.githubusercontent.com/V3nilla/IPSets-For-Bypass-in-Russia/main/%D0%A0%D0%B0%D0%B7%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0%20%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%B0%20%D1%81%D0%B5%D1%80%D0%B2%D0%B8%D1%81%D0%BE%D0%B2(%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%20-%20ChatGPT)/hosts";
|
|
let clean = replace(replace(url, /:/g, "_"), /[^a-zA-Z0-9_]/g, "_");
|
|
if (length(clean) > 40) clean = substr(clean, 0, 40);
|
|
let safe_name = clean + "_" + hash12(url);
|
|
print(length(safe_name));
|
|
')
|
|
if [ "$long_url_safe_len" -le 60 ]; then
|
|
pass
|
|
else
|
|
fail "safe_name too long: $long_url_safe_len"
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== Results: $PASS passed, $FAIL failed ==="
|
|
[ "$FAIL" -eq 0 ] || exit 1
|