fix(singbox): resolve 1.14.1 DNS deprecation, store_rdrc, ruleset download_detour, and provider routing isolation

This commit is contained in:
Dushnilin
2026-09-17 10:46:04 +03:00
parent 0efa47abdc
commit 287a8f8e0c
13 changed files with 335 additions and 83 deletions
+2 -2
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: TACHYON\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-09-17 05:45+0300\n"
"PO-Revision-Date: 2026-09-17 05:45+0300\n"
"POT-Creation-Date: 2026-09-17 07:46+0300\n"
"PO-Revision-Date: 2026-09-17 07:46+0300\n"
"Last-Translator: Dushnilin <dushnilin@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
+2 -2
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: TACHYON\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-09-17 08:45+0300\n"
"PO-Revision-Date: 2026-09-17 08:45+0300\n"
"POT-Creation-Date: 2026-09-17 10:46+0300\n"
"PO-Revision-Date: 2026-09-17 10:46+0300\n"
"Last-Translator: Dushnilin\n"
"Language-Team: none\n"
"Language: ru\n"
+2 -2
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: TACHYON\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-09-17 08:45+0300\n"
"PO-Revision-Date: 2026-09-17 08:45+0300\n"
"POT-Creation-Date: 2026-09-17 10:46+0300\n"
"PO-Revision-Date: 2026-09-17 10:46+0300\n"
"Last-Translator: Dushnilin\n"
"Language-Team: none\n"
"Language: ru\n"
+2 -2
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: TACHYON\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-09-17 05:45+0300\n"
"PO-Revision-Date: 2026-09-17 05:45+0300\n"
"POT-Creation-Date: 2026-09-17 07:46+0300\n"
"PO-Revision-Date: 2026-09-17 07:46+0300\n"
"Last-Translator: Dushnilin <dushnilin@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
+92 -1
View File
@@ -751,6 +751,93 @@ function rule_sets_with_subnets_value(section) {
return list_option_value_from_array(rule_sets_with_subnets(section));
}
function section_has_routing_matchers(section) {
if (section == null || type(section) != "object")
return false;
if (has_dns_matchers(section))
return true;
if (length(list_option(section, "domain")) > 0 || option(section, "domain", "") != "" || option(section, "domain_text", "") != "" ||
length(list_option(section, "domain_suffix")) > 0 || option(section, "domain_suffix", "") != "" || option(section, "domain_suffix_text", "") != "" ||
length(list_option(section, "domain_keyword")) > 0 || option(section, "domain_keyword", "") != "" || option(section, "domain_keyword_text", "") != "" ||
length(list_option(section, "domain_regex")) > 0 || option(section, "domain_regex", "") != "" || option(section, "domain_regex_text", "") != "" ||
length(list_option(section, "user_domains")) > 0 || option(section, "user_domains", "") != "" || option(section, "user_domains_text", "") != "")
return true;
if (rule_condition_csv(section, "ip_cidr", "subnets") != "" ||
rule_condition_csv(section, "source_ip_cidr", "subnets") != "" ||
length(list_option(section, "fully_routed_ips")) > 0 ||
option(section, "fully_routed_ips", "") != "" ||
length(list_option(section, "ip_cidr")) > 0 ||
option(section, "ip_cidr", "") != "" ||
option(section, "ip_cidr_text", "") != "" ||
length(list_option(section, "source_ip_cidr")) > 0 ||
option(section, "source_ip_cidr", "") != "" ||
option(section, "source_ip_cidr_text", "") != "")
return true;
if (rule_condition_csv(section, "ports", "ports") != "" ||
length(list_option(section, "ports")) > 0 ||
option(section, "ports", "") != "" ||
option(section, "ports_text", "") != "" ||
option(section, "port", "") != "" ||
option(section, "port_range", "") != "")
return true;
if (length(list_option(section, "protocol")) > 0 ||
option(section, "protocol", "") != "")
return true;
if (length(dscp_list(section)) > 0)
return true;
if (length(geoip_country_list(section)) > 0)
return true;
return false;
}
function section_is_active_provider(section, action) {
if (section == null || type(section) != "object")
return false;
let name = section_name(section);
if (name == "")
return false;
if (!bool_option(section, "enabled", true))
return false;
if (action != null && action != "" && option(section, "action", "") != action)
return false;
return section_has_routing_matchers(section) || bool_option(section, "match_all", false);
}
function active_provider_sections(action, sections) {
let result = [];
let list = sections;
if (list == null)
list = uci_core.section_objects(CONFIG_NAME, "section");
for (let section in list) {
if (section_is_active_provider(section, action))
push(result, section);
}
return result;
}
function active_provider_section_index(action, sections, target_section) {
let target_name = type(target_section) == "object" ? section_name(target_section) : as_string(target_section);
if (target_name == "")
return 0;
let active = active_provider_sections(action, sections);
for (let i = 0; i < length(active); i++) {
if (section_name(active[i]) == target_name)
return i + 1;
}
return 0;
}
function has_connection_sources(section) {
return length(connection_urls(section)) > 0 ||
length(subscription_urls(section)) > 0 ||
@@ -1653,5 +1740,9 @@ return {
fptn_sections,
is_wdtt_action,
is_olcrtc_action,
is_fptn_action
is_fptn_action,
section_has_routing_matchers,
section_is_active_provider,
active_provider_sections,
active_provider_section_index
};
+13
View File
@@ -1537,6 +1537,19 @@ function validate_rule(section, sections, context) {
fail_validation("FPTN rule '" + name + "': " + vres.error + ". Aborted.");
}
let provider_labels = {
zapret: "Zapret",
zapret2: "Zapret2",
byedpi: "ByeDPI",
wdtt: "WDTT",
olcrtc: "OlcRTC",
fptn: "FPTN"
};
if (provider_labels[action] != null) {
if (!connections.section_has_routing_matchers(section) && !bool_option(section, "match_all", false))
fail_validation(provider_labels[action] + " rule '" + name + "' has no routing conditions. Add domains, community lists, IP/subnet/port/protocol matchers or enable Match All explicitly. Aborted.");
}
if (connections.is_connections_action(action)) {
validate_dashboard_filter(section);
@@ -36,11 +36,13 @@ function provider_available() {
}
function enabled_sections() {
let sections = uci_core.section_objects(CONFIG_NAME, "section");
if (connections && connections.active_provider_sections)
return connections.active_provider_sections("fptn", sections);
if (connections && connections.fptn_sections)
return connections.fptn_sections();
let result = [];
let sections = uci_core.section_objects(CONFIG_NAME, "section");
for (let s in sections) {
if (bool_option(s, "enabled", true) && option(s, "action", "") == "fptn")
push(result, s);
@@ -94,6 +96,7 @@ function remove_kernel_routing() {
}
command_status("ip route flush table " + cfg.route_table + " 2>/dev/null; true");
command_status("ip -4 route del default dev " + shell_quote(cfg.tun_interface) + " table main 2>/dev/null; true");
if (command_status("ip link show " + shell_quote(cfg.tun_interface) + " >/dev/null 2>&1") == 0)
command_status("ip link set dev " + shell_quote(cfg.tun_interface) + " down 2>/dev/null; true");
}
@@ -116,6 +119,13 @@ function install_kernel_routing() {
return false;
}
// Ensure table main default route was not hijacked by fptn-client-cli
let main_default_dev = trim(command_output("ip -4 route show table main default 2>/dev/null | awk '{print $5; exit}'"));
if (main_default_dev == cfg.tun_interface) {
log_message("FPTN client hijacked table main default route; restoring WAN route", "warn");
command_status("ip -4 route del default dev " + shell_quote(cfg.tun_interface) + " table main 2>/dev/null; true");
}
return true;
}
@@ -5,6 +5,7 @@ let common = require("core.common");
let constants = require("core.constants");
let uci_core = require("core.uci");
let runtime_constants = require("singbox.constants");
let connections = require("config.connections");
let as_string = common.as_string;
let bool_value = common.bool_value;
@@ -77,11 +78,7 @@ function strategy_words(value) {
}
function enabled_sections(cfg) {
let result = [];
for (let section in uci_sections("section"))
if (bool_option(section, "enabled", true) && option(section, "action", "") == cfg.action)
push(result, section);
return result;
return connections.active_provider_sections(cfg.action, uci_sections("section"));
}
let parse_number = common.parse_number;
+36
View File
@@ -464,6 +464,39 @@ function has_domain_matchers(path) {
return value_has_domain_matchers(read_json_file(path));
}
function value_has_ip_matchers(value) {
if (type(value) == "array") {
for (let item in value) {
if (value_has_ip_matchers(item))
return true;
}
return false;
}
if (type(value) != "object")
return false;
for (let key, item in value) {
if (key == "ip_cidr" || key == "source_ip_cidr" || key == "ip_is_private") {
if (type(item) == "array" && length(item) > 0)
return true;
if (type(item) == "string" && item != "")
return true;
if (type(item) == "boolean" && item)
return true;
}
if (value_has_ip_matchers(item))
return true;
}
return false;
}
function has_ip_matchers(path) {
return value_has_ip_matchers(read_json_file(path));
}
function has_rules(path) {
let ruleset = object_or_empty(read_json_file(path));
return length(array_or_empty(ruleset.rules)) > 0;
@@ -507,6 +540,7 @@ function module_exports() {
extract_ip_cidr,
extract_ip_cidr_nft_elements,
has_domain_matchers,
has_ip_matchers,
has_rules,
compile_plain_list,
ruleset_tag,
@@ -534,6 +568,8 @@ else if (mode == "extract-ip-cidr-nft")
extract_ip_cidr_nft_elements(ARGV[1], ARGV[2], ARGV[3], ARGV[4] || "[]", ARGV[5] || "[]");
else if (mode == "has-domain-matchers")
exit(has_domain_matchers(ARGV[1]) ? 0 : 1);
else if (mode == "has-ip-matchers")
exit(has_ip_matchers(ARGV[1]) ? 0 : 1);
else if (mode == "has-rules")
exit(has_rules(ARGV[1]) ? 0 : 1);
else {
+86 -47
View File
@@ -422,29 +422,76 @@ function tproxy_inbound_matcher() {
return [ runtime_constants.TPROXY_INBOUND_TAG, runtime_constants.TPROXY_INBOUND6_TAG ];
}
function is_sb_1_14_plus_detected(sb_version_val) {
if (sb_version_val == null || sb_version_val == "") {
let sb_version_file = getenv("SB_VERSION_STATE_FILE") || "/etc/tachyon/sing-box-version";
sb_version_val = trim(fs.readfile(sb_version_file) || "");
if (sb_version_val == "") {
let sb_ui_cache = getenv("TACHYON_UI_SING_BOX_VERSION_CACHE_FILE") || "/var/run/tachyon/ui-state/sing-box-version";
sb_version_val = trim(fs.readfile(sb_ui_cache) || "");
}
if (sb_version_val == "") {
try {
let pipe = fs.popen("sing-box version 2>/dev/null", "r");
if (pipe) {
let out = pipe.read("all");
pipe.close();
let m = match(out, /sing-box version ([^\s]+)/);
if (m)
sb_version_val = m[1];
}
} catch (e) {}
let cached_sb_version = null;
function detect_sing_box_version() {
if (cached_sb_version != null)
return cached_sb_version;
let env_file = getenv("SB_VERSION_STATE_FILE");
if (env_file != null && env_file != "") {
let ver = trim(fs.readfile(env_file) || "");
if (ver != "") {
cached_sb_version = ver;
return ver;
}
}
try {
for (let cmd in [ "sing-box version 2>/dev/null", "/usr/bin/sing-box version 2>/dev/null" ]) {
let pipe = fs.popen(cmd, "r");
if (pipe) {
let out = pipe.read("all");
pipe.close();
let m = match(out, /sing-box version ([^\s]+)/);
if (m) {
cached_sb_version = m[1];
try {
let cur_disk = trim(fs.readfile("/etc/tachyon/sing-box-version") || "");
if (cur_disk != cached_sb_version)
fs.writefile("/etc/tachyon/sing-box-version", cached_sb_version + "\n");
} catch (e) {}
return cached_sb_version;
}
}
}
} catch (e) {}
let sb_version_file = "/etc/tachyon/sing-box-version";
let sb_version_val = trim(fs.readfile(sb_version_file) || "");
if (sb_version_val == "") {
let sb_ui_cache = getenv("TACHYON_UI_SING_BOX_VERSION_CACHE_FILE") || "/var/run/tachyon/ui-state/sing-box-version";
sb_version_val = trim(fs.readfile(sb_ui_cache) || "");
}
cached_sb_version = sb_version_val;
return cached_sb_version;
}
function is_sb_1_14_plus_detected(sb_version_val) {
if (sb_version_val == null || sb_version_val == "")
sb_version_val = detect_sing_box_version();
if (sb_version_val != "") {
let m = match(sb_version_val, /^v?([0-9]+)\.([0-9]+)/);
if (m) {
let major = int(m[1]);
let minor = int(m[2]);
return major > 1 || (major == 1 && minor >= 14);
}
}
return false;
}
function is_sb_1_15_plus_detected(sb_version_val) {
if (sb_version_val == null || sb_version_val == "")
sb_version_val = detect_sing_box_version();
if (sb_version_val != "") {
let m = match(sb_version_val, /^v?([0-9]+)\.([0-9]+)/);
if (m) {
let major = int(m[1]);
let minor = int(m[2]);
return major > 1 || (major == 1 && minor >= 15);
}
}
if (sb_version_val != "")
return match(sb_version_val, /^v?1\.(1[4-9]|[2-9][0-9])\./) != null;
return false;
}
@@ -567,39 +614,25 @@ function base_config(settings, service_address, runtime_context) {
strategy: option(settings, "dns_strategy", "prefer_ipv4")
};
let sb_version_file = getenv("SB_VERSION_STATE_FILE") || "/etc/tachyon/sing-box-version";
let sb_version_val = trim(fs.readfile(sb_version_file) || "");
if (sb_version_val == "") {
let sb_ui_cache = getenv("TACHYON_UI_SING_BOX_VERSION_CACHE_FILE") || "/var/run/tachyon/ui-state/sing-box-version";
sb_version_val = trim(fs.readfile(sb_ui_cache) || "");
}
if (sb_version_val == "") {
try {
let pipe = fs.popen("sing-box version 2>/dev/null", "r");
if (pipe) {
let out = pipe.read("all");
pipe.close();
let m = match(out, /sing-box version ([^\s]+)/);
if (m)
sb_version_val = m[1];
}
} catch (e) {}
}
let sb_variant_file = getenv("SB_VARIANT_STATE_FILE") || "/etc/tachyon/sing-box-variant";
let sb_variant_val = trim(fs.readfile(sb_variant_file) || "");
let is_extended_variant = sb_variant_val == "extended" || sb_variant_val == "extended-compressed" || index(sb_version_val, "extended") >= 0;
let use_legacy_rdrc = is_extended_variant || (sb_version_val != ""
? (match(sb_version_val, /^v?1\.1[0-3]\./) != null)
: false);
let sb_version_val = detect_sing_box_version();
let is_sb_1_14_plus = is_sb_1_14_plus_detected(sb_version_val);
let is_sb_1_15_plus = is_sb_1_15_plus_detected(sb_version_val);
ctx.is_sb_1_14_plus = function() { return is_sb_1_14_plus; };
ctx.is_sb_1_15_plus = function() { return is_sb_1_15_plus; };
let use_legacy_rdrc = !is_sb_1_14_plus;
let route_section = runtime_route.config(settings, runtime_context);
if (is_sb_1_14_plus)
route_section.default_http_client = "ruleset-http";
if (is_sb_1_14_plus) {
dns_section.optimistic = {
enabled: true,
timeout: "3d"
};
}
let cache_file_section = {
enabled: true,
path: cache_path,
@@ -610,6 +643,11 @@ function base_config(settings, service_address, runtime_context) {
else
cache_file_section.store_dns = true;
if (is_sb_1_15_plus) {
cache_file_section.buffer_size = "1MB";
cache_file_section.flush_interval = "10m";
}
let base_cfg = {
log: {
disabled: false,
@@ -1547,6 +1585,7 @@ ctx.uci_bin_to_hex = uci_bin_to_hex;
ctx.download_detour_tag = download_detour_tag;
ctx.atomic_write_json_file = atomic_write_json_file;
ctx.is_sb_1_14_plus = is_sb_1_14_plus_detected;
ctx.is_sb_1_15_plus = is_sb_1_15_plus_detected;
generator_outbounds.init(ctx);
generator_routes.init(ctx);
@@ -1772,6 +1772,8 @@ function add_openvpn_endpoint(config, section) {
}
function enabled_action_index(sections, target_section, action_name) {
if (connections && connections.active_provider_section_index)
return connections.active_provider_section_index(action_name, sections, target_section);
let index = 0;
for (let section in sections) {
if (option(section, "action", "") != action_name)
@@ -1784,6 +1786,8 @@ function enabled_action_index(sections, target_section, action_name) {
}
function add_zapret_outbound(config, section, sections) {
if (connections && !connections.section_is_active_provider(section, "zapret"))
return;
let index = enabled_action_index(sections, section, "zapret");
if (index <= 0)
ctx.runtime_generate_unsupported("unable to resolve Zapret index for " + section[".name"]);
@@ -1795,6 +1799,8 @@ function add_zapret_outbound(config, section, sections) {
}
function add_zapret2_outbound(config, section, sections) {
if (connections && !connections.section_is_active_provider(section, "zapret2"))
return;
let index = enabled_action_index(sections, section, "zapret2");
if (index <= 0)
ctx.runtime_generate_unsupported("unable to resolve Zapret2 index for " + section[".name"]);
@@ -1806,6 +1812,8 @@ function add_zapret2_outbound(config, section, sections) {
}
function add_byedpi_outbound(config, section, sections) {
if (connections && !connections.section_is_active_provider(section, "byedpi"))
return;
let index = enabled_action_index(sections, section, "byedpi");
if (index <= 0)
ctx.runtime_generate_unsupported("unable to resolve ByeDPI index for " + section[".name"]);
@@ -1819,6 +1827,8 @@ function add_byedpi_outbound(config, section, sections) {
}
function add_wdtt_outbound(config, section, sections) {
if (connections && !connections.section_is_active_provider(section, "wdtt"))
return;
let index = enabled_action_index(sections, section, "wdtt");
if (index <= 0)
ctx.runtime_generate_unsupported("unable to resolve WDTT index for " + section[".name"]);
@@ -1832,6 +1842,8 @@ function add_wdtt_outbound(config, section, sections) {
}
function add_olcrtc_outbound(config, section, sections) {
if (connections && !connections.section_is_active_provider(section, "olcrtc"))
return;
let index = enabled_action_index(sections, section, "olcrtc");
if (index <= 0)
ctx.runtime_generate_unsupported("unable to resolve OlcRTC index for " + section[".name"]);
@@ -1847,6 +1859,8 @@ function add_olcrtc_outbound(config, section, sections) {
// FPTN routes traffic through its TUN interface (tun-fptn) via kernel routing.
// fwmark 0x00300000 (3145728) → ip rule → routing table 4249 → dev tun-fptn.
function add_fptn_outbound(config, section, sections) {
if (connections && !connections.section_is_active_provider(section, "fptn"))
return;
push(config.outbounds, {
type: "direct",
tag: outbound_tag(section[".name"]),
@@ -919,6 +919,9 @@ function ensure_custom_ruleset(config, reference) {
else if (runtime_rulesets.is_valid_srs_file(etc_srs) || helpers.file_is_usable(etc_srs, 16))
local_path = etc_srs;
if (config.route.rule_set == null)
config.route.rule_set = [];
if (local_path != null) {
push(config.route.rule_set, {
type: "local",
@@ -935,8 +938,7 @@ function ensure_custom_ruleset(config, reference) {
url: runtime_rulesets.community_url(reference)
};
let detour = ctx.download_detour_tag(ctx.runtime_settings());
let is_1_14 = ctx.is_sb_1_14_plus && ctx.is_sb_1_14_plus();
if (!is_1_14 && is_valid_detour(config, detour))
if (is_valid_detour(config, detour))
rule_set.download_detour = detour;
rule_set.update_interval = remote_ruleset_update_interval();
push(config.route.rule_set, rule_set);
@@ -946,8 +948,6 @@ function ensure_custom_ruleset(config, reference) {
}
tag_name = "inline-custom-" + runtime_rulesets.hash12(reference) + "-ruleset";
if (kind == "unknown")
kind = "domains";
if (ruleset_registered(config, tag_name))
return { tag: tag_name, kind };
@@ -1072,6 +1072,8 @@ function ensure_custom_ruleset(config, reference) {
// Skip broken local ruleset files — nonexistent or suspiciously small
if (!helpers.file_is_usable(reference, 100))
return null;
if (config.route.rule_set == null)
config.route.rule_set = [];
push(config.route.rule_set, {
type: "local",
tag: tag_name,
@@ -1087,10 +1089,11 @@ function ensure_custom_ruleset(config, reference) {
url: reference
};
let detour = ctx.download_detour_tag(ctx.runtime_settings());
let is_1_14 = ctx.is_sb_1_14_plus && ctx.is_sb_1_14_plus();
if (!is_1_14 && is_valid_detour(config, detour))
if (is_valid_detour(config, detour))
rule_set.download_detour = detour;
rule_set.update_interval = remote_ruleset_update_interval();
if (config.route.rule_set == null)
config.route.rule_set = [];
push(config.route.rule_set, rule_set);
}
else {
@@ -1118,6 +1121,9 @@ function ensure_community_ruleset(config, section_name, community) {
else if (runtime_rulesets.is_valid_srs_file(etc_srs) || helpers.file_is_usable(etc_srs, 16))
local_path = etc_srs;
if (config.route.rule_set == null)
config.route.rule_set = [];
if (local_path != null) {
push(config.route.rule_set, {
type: "local",
@@ -1141,8 +1147,7 @@ function ensure_community_ruleset(config, section_name, community) {
detour = sec_out;
}
}
let is_1_14 = ctx.is_sb_1_14_plus && ctx.is_sb_1_14_plus();
if (!is_1_14 && is_valid_detour(config, detour))
if (is_valid_detour(config, detour))
rule_set.download_detour = detour;
push(config.route.rule_set, rule_set);
}
@@ -1210,7 +1215,7 @@ function rebuild_local_domain_ip_list_ruleset(section_name, references, domains_
}
}
function add_domain_ip_list_ruleset(config, section_name, rule_set_tags, dns_rule_set_tags, references, domains_only) {
function add_domain_ip_list_ruleset(config, section_name, rule_set_tags, dns_query_rule_set_tags, dns_response_rule_set_tags, references, domains_only) {
if (length(references) == 0)
return;
@@ -1222,6 +1227,8 @@ function add_domain_ip_list_ruleset(config, section_name, rule_set_tags, dns_rul
let tag_name = domain_ip_list_ruleset_tag(section_name);
if (!ruleset_registered(config, tag_name)) {
if (config.route.rule_set == null)
config.route.rule_set = [];
push(config.route.rule_set, {
type: "local",
tag: tag_name,
@@ -1232,8 +1239,23 @@ function add_domain_ip_list_ruleset(config, section_name, rule_set_tags, dns_rul
if (!domains_only)
push(rule_set_tags, tag_name);
if (source_rulesets.has_domain_matchers(ruleset_path))
push(dns_rule_set_tags, tag_name);
let is_1_14 = ctx.is_sb_1_14_plus && ctx.is_sb_1_14_plus();
if (source_rulesets.has_domain_matchers(ruleset_path)) {
if (is_1_14 && source_rulesets.has_ip_matchers(ruleset_path)) {
if (dns_response_rule_set_tags != null)
push(dns_response_rule_set_tags, tag_name);
else if (dns_query_rule_set_tags != null)
push(dns_query_rule_set_tags, tag_name);
} else if (dns_query_rule_set_tags != null) {
push(dns_query_rule_set_tags, tag_name);
}
} else if (source_rulesets.has_ip_matchers(ruleset_path)) {
if (is_1_14 && dns_response_rule_set_tags != null)
push(dns_response_rule_set_tags, tag_name);
else if (!is_1_14 && dns_query_rule_set_tags != null)
push(dns_query_rule_set_tags, tag_name);
}
}
function legacy_condition_values(section, key) {
@@ -1441,14 +1463,25 @@ function add_dns_action_rules_for_section(config, section) {
}
for (let reference in connections.rule_sets(section)) {
let ensured = ensure_custom_ruleset(config, as_string(reference));
if (ensured != null && ensured.kind == "domains")
if (ensured == null)
continue;
if (ensured.kind == "domains")
push(query_rule_set_tags, ensured.tag);
else
push(response_rule_set_tags, ensured.tag);
}
for (let reference in connections.rule_sets_with_subnets(section)) {
let ensured = ensure_custom_ruleset(config, as_string(reference));
if (ensured == null)
continue;
push(response_rule_set_tags, ensured.tag);
}
add_domain_ip_list_ruleset(
config,
section_name,
[],
query_rule_set_tags,
response_rule_set_tags,
list_option(section, "domain_ip_lists"),
true
);
@@ -1833,20 +1866,22 @@ function add_combined_route_for_section(config, section) {
push(rule_set_tags, ensured.tag);
if (ensured.kind == "domains")
push(dns_query_rule_set_tags, ensured.tag);
else
push(dns_response_rule_set_tags, ensured.tag);
}
for (let reference in connections.rule_sets_with_subnets(section)) {
let ensured = ensure_custom_ruleset(config, as_string(reference));
if (ensured == null)
continue;
push(rule_set_tags, ensured.tag);
if (ensured.kind == "domains")
push(dns_query_rule_set_tags, ensured.tag);
push(dns_response_rule_set_tags, ensured.tag);
}
add_domain_ip_list_ruleset(
config,
section_name,
rule_set_tags,
dns_query_rule_set_tags,
dns_response_rule_set_tags,
list_option(section, "domain_ip_lists"),
false
);
@@ -1945,7 +1980,11 @@ function add_combined_route_for_section(config, section) {
}
}
if (!has_domain && !has_ruleset && !has_ip_cidr && length(discord_cf_subnets) == 0 && length(country_list) == 0) {
if (bool_option(section, "match_all", false)) {
let all_rule = create_section_route_rule();
push_section_route_rule(config, all_rule, target.outbound, excluded_cidrs);
}
else if (!has_domain && !has_ruleset && !has_ip_cidr && length(discord_cf_subnets) == 0 && length(country_list) == 0) {
let fallback_rule = create_section_route_rule();
let has_any_matcher = fallback_rule.source_ip_cidr != null ||
fallback_rule.port != null || fallback_rule.port_range != null ||
+19 -6
View File
@@ -180,13 +180,26 @@ function file_extension(value) {
function kind_from_reference_hint(reference) {
reference = lc(as_string(reference));
if (index(reference, "geosite") >= 0 || index(reference, "domain") >= 0 ||
index(reference, "domains") >= 0 || index(reference, "adguard") >= 0 ||
index(reference, "filter") >= 0)
return "domains";
if (index(reference, "geoip") >= 0 || index(reference, "subnet") >= 0 ||
index(reference, "subnets") >= 0 || index(reference, "cidr") >= 0)
let has_ip_hint = index(reference, "geoip") >= 0 ||
index(reference, "subnet") >= 0 ||
index(reference, "subnets") >= 0 ||
index(reference, "cidr") >= 0 ||
match(reference, /(^|[-_.\/])ips?([-_.\/]|$)/) != null;
let has_domain_hint = index(reference, "geosite") >= 0 ||
index(reference, "domain") >= 0 ||
index(reference, "domains") >= 0 ||
index(reference, "adguard") >= 0 ||
index(reference, "adblock") >= 0 ||
index(reference, "host") >= 0 ||
index(reference, "hosts") >= 0;
if (has_ip_hint && has_domain_hint)
return "mixed";
if (has_ip_hint)
return "subnets";
if (has_domain_hint)
return "domains";
return "unknown";
}