#!/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 ...\n"); exit(1); }