fix(validator,migration,fuzzer): resilient domain validation, strip prefixed comments and fix zapret1 fuzzer fwmark

This commit is contained in:
Dushnilin
2026-09-09 21:44:43 +03:00
parent 9d7e53f260
commit 7fe6a84f80
10 changed files with 87 additions and 20 deletions
+8 -2
View File
@@ -1,7 +1,13 @@
export function parseValueList(value: string): string[] {
return value
.split(/\n/)
.map((line) => line.split('//')[0].split('#')[0])
.split(/\r?\n/)
.map((line) => {
const stripped = line.replace(
/^(full|keyword|regex):[ \t]*(\/\/|#).*$/,
'',
);
return stripped.split('//')[0].split('#')[0];
})
.join(' ')
.split(/[,\s]+/)
.map((s) => s.trim())
@@ -1046,7 +1046,13 @@ function validateProxyUrl(url) {
// src/helpers/parseValueList.ts
function parseValueList(value) {
return value.split(/\n/).map((line) => line.split("//")[0].split("#")[0]).join(" ").split(/[,\s]+/).map((s) => s.trim()).filter(Boolean);
return value.split(/\r?\n/).map((line) => {
const stripped = line.replace(
/^(full|keyword|regex):[ \t]*(\/\/|#).*$/,
""
);
return stripped.split("//")[0].split("#")[0];
}).join(" ").split(/[,\s]+/).map((s) => s.trim()).filter(Boolean);
}
// src/helpers/getProxyUrlName.ts
@@ -5521,8 +5521,9 @@ function parseCommentAwareListTokens(value) {
let offset = 0;
lines.forEach((line, index) => {
const hashIndex = line.indexOf("#");
const slashIndex = line.indexOf("//");
const cleanLine = line.replace(/^(full|keyword|regex):[ \t]*(\/\/|#).*$/, "");
const hashIndex = cleanLine.indexOf("#");
const slashIndex = cleanLine.indexOf("//");
let commentIndex = -1;
if (hashIndex >= 0 && slashIndex >= 0) {
@@ -5533,7 +5534,7 @@ function parseCommentAwareListTokens(value) {
commentIndex = slashIndex;
}
const source = commentIndex >= 0 ? line.slice(0, commentIndex) : line;
const source = commentIndex >= 0 ? cleanLine.slice(0, commentIndex) : cleanLine;
const matcher = /[^,\s]+/g;
let match;
+17 -6
View File
@@ -10,6 +10,7 @@ let core_url = require("core.url");
let constants_module = require("core.constants");
let singbox_constants_module = require("singbox.constants");
let domain_config = require("config.domain");
let rule_config = require("config.rule");
let subscription_share_link = require("subscription.share_link");
let as_string = common.as_string;
@@ -925,7 +926,9 @@ function migrate_connection_section(ctx, section, constants, legacy_connection_k
}
function strip_list_comment(line) {
line = replace(as_string(line), /[[:space:]]*\/\/.*$/, "");
line = replace(as_string(line), /^(full|keyword|regex):[[:space:]]*\/\/.*$/, "");
line = replace(line, /^(full|keyword|regex):[[:space:]]*#.*$/, "");
line = replace(line, /[[:space:]]*\/\/.*$/, "");
return replace(line, /[[:space:]]*#.*$/, "");
}
@@ -1004,7 +1007,11 @@ function has_domain_condition_prefix(value) {
function add_values_with_prefix(result, seen, values, prefix) {
for (let value in values) {
value = trim(as_string(value));
add_unique_value(result, seen, has_domain_condition_prefix(value) ? value : prefix + value);
if (value == "")
continue;
let candidate = has_domain_condition_prefix(value) ? value : prefix + value;
if (rule_config.prefixed_domain_kind_value(candidate) != null)
add_unique_value(result, seen, candidate);
}
}
@@ -1038,10 +1045,14 @@ function migrate_combined_domain_conditions(ctx, section) {
let values = [];
let seen = {};
for (let value in list_option(section, "domain_suffix"))
add_unique_value(values, seen, value);
for (let value in raw_text_condition_values(section, "domain_suffix_text"))
add_unique_value(values, seen, value);
for (let value in list_option(section, "domain_suffix")) {
if (rule_config.prefixed_domain_kind_value(value) != null)
add_unique_value(values, seen, value);
}
for (let value in raw_text_condition_values(section, "domain_suffix_text")) {
if (rule_config.prefixed_domain_kind_value(value) != null)
add_unique_value(values, seen, value);
}
add_domain_values_with_prefix(values, seen, section, "domain", "full:", "domains");
add_domain_values_with_prefix(values, seen, section, "domain_keyword", "keyword:", "generic");
+4 -2
View File
@@ -7,7 +7,9 @@ let common = require("core.common");
let as_string = common.as_string;
function strip_list_comment(line) {
line = replace(as_string(line), /[[:space:]]*\/\/.*$/, "");
line = replace(as_string(line), /^(full|keyword|regex):[[:space:]]*\/\/.*$/, "");
line = replace(line, /^(full|keyword|regex):[[:space:]]*#.*$/, "");
line = replace(line, /[[:space:]]*\/\/.*$/, "");
return replace(line, /[[:space:]]*#.*$/, "");
}
@@ -72,7 +74,7 @@ function prefixed_domain_kind_value(value) {
if (prefix != "")
body = strip_repeated_domain_prefix(prefix, body);
if (body == "")
if (body == "" || substr(body, 0, 2) == "//" || substr(body, 0, 1) == "#")
return null;
if (prefix == "") {
+6 -3
View File
@@ -1203,14 +1203,17 @@ function validate_combined_domain_value(value, section) {
if (as_string(value) == "" || combined_domain_valid(value))
return;
fail_validation("Invalid domain condition '" + value + "' in rule '" + section + "'. Use plain domains or full:, keyword:, regex: prefixes. Aborted.");
log_message("Ignoring invalid domain condition '" + value + "' in rule '" + section + "'. Use plain domains or full:, keyword:, regex: prefixes.", "warn");
}
function validate_combined_domain_text_value(value, section) {
if (as_string(value) == "" || combined_domain_text_valid(value))
if (as_string(value) == "")
return;
fail_validation("Invalid domain conditions in rule '" + section + "'. Use plain domains or full:, keyword:, regex: prefixes. Aborted.");
for (let item in rule_config.text_list_values(value, "comma-space")) {
if (!combined_domain_valid(item))
log_message("Ignoring invalid domain condition '" + item + "' in rule '" + section + "'. Use plain domains or full:, keyword:, regex: prefixes.", "warn");
}
}
function validate_service_value(service, context) {
+3 -1
View File
@@ -383,7 +383,9 @@ function normalize_strategy_whitespace(value) {
}
function strip_list_comment(line) {
line = replace(as_string(line), /[[:space:]]*\/\/.*$/, "");
line = replace(as_string(line), /^(full|keyword|regex):[[:space:]]*\/\/.*$/, "");
line = replace(line, /^(full|keyword|regex):[[:space:]]*#.*$/, "");
line = replace(line, /[[:space:]]*\/\/.*$/, "");
return replace(line, /[[:space:]]*#.*$/, "");
}
+10 -1
View File
@@ -2245,7 +2245,16 @@ function run_probe(engine, args_str, target_key, custom_url) {
filter_prefix += "--filter-udp=443 --payload=quic_initial ";
}
let spawn_cmd = sprintf("cd /tmp && %s --qnum=%d --fwmark=%s %s%s%s%s --pidfile=%s --daemon 2>%s", bin, qnum, FUZZER_FWMARK, lua_init_flags, blob_flags, filter_prefix, args_str, pid_path, shell_quote(stderr_log));
let fwmark_flag = "";
if (is_z2) {
if (index(args_str, "--fwmark") < 0)
fwmark_flag = sprintf("--fwmark=%s ", FUZZER_FWMARK);
} else {
if (index(args_str, "--dpi-desync-fwmark") < 0)
fwmark_flag = sprintf("--dpi-desync-fwmark=%s ", FUZZER_FWMARK);
}
let spawn_cmd = sprintf("cd /tmp && %s --qnum=%d %s%s%s%s%s --pidfile=%s --daemon 2>%s", bin, qnum, fwmark_flag, lua_init_flags, blob_flags, filter_prefix, args_str, pid_path, shell_quote(stderr_log));
system(common.background_command(spawn_cmd));
let pid_running = false;
+3 -1
View File
@@ -140,7 +140,9 @@ function log_fatal(message) {
}
function strip_list_comment(line) {
line = replace(as_string(line), /[[:space:]]*\/\/.*$/, "");
line = replace(as_string(line), /^(full|keyword|regex):[[:space:]]*\/\/.*$/, "");
line = replace(line, /^(full|keyword|regex):[[:space:]]*#.*$/, "");
line = replace(line, /[[:space:]]*\/\/.*$/, "");
return replace(line, /[[:space:]]*#.*$/, "");
}
+25
View File
@@ -522,4 +522,29 @@ fi
printf '%s\n' "$output" | grep -Fq "ByeDPI listen address and port are assigned" ||
fail "executable byedpi provider: unexpected message '$output'"
# ─── Domain condition validation resilience ─────────────────────────────────
cat >"$WORK_DIR/domain_resilience.json" <<'JSON'
{
"settings": {
".name": "settings",
".type": "settings",
"dns_server": [ "77.88.8.8" ],
"bootstrap_dns_server": [ "77.88.8.8" ]
},
"section": [
{
".name": "resilient_rule",
".type": "section",
"enabled": "1",
"action": "bypass",
"domain": "valid.example.com\nfull://\nfull:=====\nfull:(не\nanother.example.org"
}
]
}
JSON
if ! TACHYON_LIB="$TACHYON_LIB" ucode -L "$TACHYON_LIB" "$VALIDATOR" validate-runtime-fixture "$WORK_DIR/domain_resilience.json" "{}" >/dev/null 2>&1; then
fail "Validator must not abort startup on invalid domain conditions in rules"
fi
printf 'config validator runtime checks passed\n'