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
113 lines
3.5 KiB
Ucode
113 lines
3.5 KiB
Ucode
#!/usr/bin/env ucode
|
|
|
|
let common = require("core.common");
|
|
let as_string = common.as_string;
|
|
|
|
function write_json(value) {
|
|
print(sprintf("%J", value), "\n");
|
|
}
|
|
|
|
function words(value) {
|
|
value = replace(as_string(value), /[\t\r\n]/g, " ");
|
|
value = replace(value, / +/g, " ");
|
|
value = replace(value, /^ /, "");
|
|
value = replace(value, / $/, "");
|
|
return value == "" ? [] : split(value, " ");
|
|
}
|
|
|
|
function contains(values, needle) {
|
|
for (let value in values)
|
|
if (as_string(value) == as_string(needle))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
function valid_port(value) {
|
|
value = as_string(value);
|
|
return value != "" && match(value, /^[0-9]+$/) != null &&
|
|
int(value) >= 1 && int(value) <= 65535;
|
|
}
|
|
|
|
// Upstream DNS accepted forms:
|
|
// - plain IP[:port] e.g. 1.1.1.1, 8.8.8.8:53
|
|
// - https://host[/dns-query] DoH
|
|
// - tls://host[:port] DoT
|
|
// - quic://host[:port] DoQ
|
|
// - udp://host[:port] explicit plain
|
|
function validate_upstream(value) {
|
|
value = trim(as_string(value));
|
|
if (value == "")
|
|
return { valid: false, message: "Empty DNS server" };
|
|
|
|
if (match(value, /^https:\/\//) != null)
|
|
return match(value, /^https:\/\/[^\s\/]+\//) != null || match(value, /^https:\/\/[^\s\/]+$/) != null
|
|
? { valid: true, message: "" }
|
|
: { valid: false, message: "Invalid DoH URL: " + value };
|
|
|
|
if (match(value, /^tls:\/\//) != null || match(value, /^quic:\/\//) != null)
|
|
return { valid: true, message: "" };
|
|
|
|
if (match(value, /^udp:\/\//) != null)
|
|
value = substr(value, 6);
|
|
|
|
let hostport = value;
|
|
let colon = rindex(hostport, ":");
|
|
let host = "";
|
|
let port = "";
|
|
if (colon >= 0 && index(hostport, "]") < 0) {
|
|
host = substr(hostport, 0, colon);
|
|
port = substr(hostport, colon + 1);
|
|
} else {
|
|
host = hostport;
|
|
}
|
|
if (host == "")
|
|
return { valid: false, message: "Empty DNS host" };
|
|
if (port != "" && !valid_port(port))
|
|
return { valid: false, message: "Invalid DNS port in: " + value };
|
|
|
|
return { valid: true, message: "" };
|
|
}
|
|
|
|
function validate_upstreams(values) {
|
|
for (let value in (type(values) == "array" ? values : [])) {
|
|
let result = validate_upstream(value);
|
|
if (!result.valid)
|
|
return result;
|
|
}
|
|
return { valid: true, message: "" };
|
|
}
|
|
|
|
function dns_main_mode_valid(mode) {
|
|
mode = as_string(mode);
|
|
return mode == "dnsmasq" || mode == "adguard";
|
|
}
|
|
|
|
function print_dns_main_mode_valid(mode) {
|
|
exit(dns_main_mode_valid(mode) ? 0 : 1);
|
|
}
|
|
|
|
function validate_filter_url(value) {
|
|
value = trim(as_string(value));
|
|
if (value == "")
|
|
return { valid: false, message: "Empty filter list URL" };
|
|
return match(value, /^https?:\/\//) != null
|
|
? { valid: true, message: "" }
|
|
: { valid: false, message: "Filter list must be an http(s) URL: " + value };
|
|
}
|
|
|
|
let mode = ARGV[0] || "";
|
|
|
|
if (mode == "validate-upstream")
|
|
write_json(validate_upstream(ARGV[1]));
|
|
else if (mode == "validate-upstreams")
|
|
write_json(validate_upstreams(ARGV[1] != null ? [ ARGV[1] ] : []));
|
|
else if (mode == "validate-filter-url")
|
|
write_json(validate_filter_url(ARGV[1]));
|
|
else if (mode == "dns-main-mode-valid")
|
|
print_dns_main_mode_valid(ARGV[1]);
|
|
else if (mode == "valid-port")
|
|
exit(valid_port(ARGV[1]) ? 0 : 1);
|
|
else {
|
|
warn("Usage: providers/adguard/validator.uc <validate-upstream|validate-filter-url|dns-main-mode-valid|valid-port> ...\n");
|
|
exit(1);
|
|
} |