feat(adguard): add AdGuard Home component with DNS modes, failover and section upstream
Add AdGuard Home as an installable Tachyon component (component card with check/update/remove/rollback/enable/disable) backed by providers/adguard (validator + runtime) and an init.d service. Backend: - action.uc: install/remove/enable/backup/rollback/dispatch/releases for 'adguard' (tar.gz from AdguardTeam/AdGuardHome, OpenWrt->AdGuard arch map) - updater.uc: adguard asset selection; updates.uc: valid_component_name and automatic update checks - runtime.uc: generates AdGuardHome.yaml from UCI (upstream=single-box DNS, fallback_dns for failover, web UI on LAN, filters), manages the daemon - dns/apply.uc: dns_main_mode (dnsmasq->AdGuard->sing-box chain, or AdGuard on :53 with dnsmasq DHCP-only) - settings: dns_main_mode (Main DNS) + dns_adguard_failover_enabled - sections: routed_dns_type/dns_type 'adguard' resolve via the AdGuard provider upstreams; validator accepts the new type - system-info: adguard_version/installed/enabled/backup fields Frontend: - component card 'AdGuard Home' with enable/disable + version actions - LuCI DNS settings tab: Main DNS selector and failover flag - section.js: AdGuard Home routed DNS protocol option Tests: tests/adguard_validator.sh, tests/adguard_runtime.sh
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
|
||||
RUNTIME="$ROOT_DIR/tachyon/files/usr/lib/providers/adguard/runtime.uc"
|
||||
|
||||
fail() {
|
||||
printf 'FAIL: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# The binary is absent in the test environment, so "installed" must be false.
|
||||
if ucode -L "$TACHYON_LIB" -- "$RUNTIME" installed >/dev/null 2>&1; then
|
||||
fail "installed should be false without an AdGuardHome binary"
|
||||
fi
|
||||
|
||||
if ucode -L "$TACHYON_LIB" -- "$RUNTIME" provider-available >/dev/null 2>&1; then
|
||||
fail "provider-available should be false without an AdGuardHome binary"
|
||||
fi
|
||||
|
||||
# package-version of a missing binary must be empty.
|
||||
ver="$(ucode -L "$TACHYON_LIB" -- "$RUNTIME" package-version)"
|
||||
[ -z "$ver" ] || fail "package-version should be empty when not installed, got '$ver'"
|
||||
|
||||
# Without UCI the provider section is absent -> disabled.
|
||||
if ucode -L "$TACHYON_LIB" -- "$RUNTIME" provider-enabled >/dev/null 2>&1; then
|
||||
fail "provider-enabled should be false when the adguard provider section is absent"
|
||||
fi
|
||||
|
||||
# Default DNS main mode is dnsmasq.
|
||||
mode="$(ucode -L "$TACHYON_LIB" -- "$RUNTIME" dns-main-mode)"
|
||||
[ "$mode" = "dnsmasq" ] || fail "default dns_main_mode should be dnsmasq, got '$mode'"
|
||||
|
||||
# Default listen port in dnsmasq mode is the local 5354 port.
|
||||
port="$(ucode -L "$TACHYON_LIB" -- "$RUNTIME" dns-listen-port)"
|
||||
[ "$port" = "5354" ] || fail "dnsmasq mode listen port should be 5354, got '$port'"
|
||||
|
||||
host="$(ucode -L "$TACHYON_LIB" -- "$RUNTIME" dns-listen-host)"
|
||||
[ "$host" = "127.0.0.1" ] || fail "dnsmasq mode listen host should be 127.0.0.1, got '$host'"
|
||||
|
||||
status="$(ucode -L "$TACHYON_LIB" -- "$RUNTIME" status)"
|
||||
JSON_VALUE="$status" node - <<'NODE'
|
||||
const value = JSON.parse(process.env.JSON_VALUE);
|
||||
if (String(value.installed) !== 'false') process.exit(1);
|
||||
if (String(value.enabled) !== 'false') process.exit(1);
|
||||
if (String(value.dns_main_mode) !== 'dnsmasq') process.exit(1);
|
||||
NODE
|
||||
|
||||
check="$(ucode -L "$TACHYON_LIB" -- "$RUNTIME" check)"
|
||||
JSON_VALUE="$check" node - <<'NODE'
|
||||
const value = JSON.parse(process.env.JSON_VALUE);
|
||||
if (String(value.adguard_installed) !== 'false') process.exit(1);
|
||||
if (value.adguard_provider_path !== '/usr/bin/AdGuardHome') process.exit(1);
|
||||
NODE
|
||||
|
||||
printf 'OK: adguard runtime tests passed\n'
|
||||
@@ -0,0 +1,83 @@
|
||||
#!/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/adguard/validator.uc"
|
||||
|
||||
fail() {
|
||||
printf 'FAIL: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
assert_json_field() {
|
||||
local json="$1"
|
||||
local field="$2"
|
||||
local expected="$3"
|
||||
|
||||
JSON_VALUE="$json" node - "$field" "$expected" <<'NODE'
|
||||
const field = process.argv[2];
|
||||
const expected = process.argv[3];
|
||||
const value = JSON.parse(process.env.JSON_VALUE);
|
||||
const actual = String(value[field]);
|
||||
if (actual !== expected) {
|
||||
console.error(`expected ${field}=${expected}, got ${actual}`);
|
||||
process.exit(1);
|
||||
}
|
||||
NODE
|
||||
}
|
||||
|
||||
doh_json="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate-upstream 'https://dns.google/dns-query')"
|
||||
assert_json_field "$doh_json" valid true
|
||||
|
||||
dot_json="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate-upstream 'tls://1.1.1.1')"
|
||||
assert_json_field "$dot_json" valid true
|
||||
|
||||
plain_json="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate-upstream '8.8.8.8')"
|
||||
assert_json_field "$plain_json" valid true
|
||||
|
||||
udp_json="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate-upstream 'udp://1.1.1.1:53')"
|
||||
assert_json_field "$udp_json" valid true
|
||||
|
||||
bad_doh_json="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate-upstream 'http://not-tls.example')"
|
||||
assert_json_field "$bad_doh_json" valid false
|
||||
|
||||
empty_json="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate-upstream '')"
|
||||
assert_json_field "$empty_json" valid false
|
||||
|
||||
bad_port_json="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate-upstream '1.1.1.1:99999')"
|
||||
assert_json_field "$bad_port_json" valid false
|
||||
|
||||
if ucode -L "$TACHYON_LIB" -- "$VALIDATOR" dns-main-mode-valid 'dnsmasq' >/dev/null 2>&1; then
|
||||
:
|
||||
else
|
||||
fail "dnsmasq should be a valid dns_main_mode"
|
||||
fi
|
||||
|
||||
if ucode -L "$TACHYON_LIB" -- "$VALIDATOR" dns-main-mode-valid 'adguard' >/dev/null 2>&1; then
|
||||
:
|
||||
else
|
||||
fail "adguard should be a valid dns_main_mode"
|
||||
fi
|
||||
|
||||
if ucode -L "$TACHYON_LIB" -- "$VALIDATOR" dns-main-mode-valid 'bogus' >/dev/null 2>&1; then
|
||||
fail "bogus dns_main_mode should be rejected"
|
||||
fi
|
||||
|
||||
if ucode -L "$TACHYON_LIB" -- "$VALIDATOR" valid-port '3000' >/dev/null 2>&1; then
|
||||
:
|
||||
else
|
||||
fail "3000 should be a valid port"
|
||||
fi
|
||||
|
||||
if ucode -L "$TACHYON_LIB" -- "$VALIDATOR" valid-port 'notaport' >/dev/null 2>&1; then
|
||||
fail "non-numeric port should be rejected"
|
||||
fi
|
||||
|
||||
filter_json="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate-filter-url 'https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt')"
|
||||
assert_json_field "$filter_json" valid true
|
||||
|
||||
bad_filter_json="$(ucode -L "$TACHYON_LIB" -- "$VALIDATOR" validate-filter-url 'ftp://filter')"
|
||||
assert_json_field "$bad_filter_json" valid false
|
||||
|
||||
printf 'OK: adguard validator tests passed\n'
|
||||
Reference in New Issue
Block a user