fix: разделение правил маршрутизации секции (fix коллизии AND) и поддержка http/https ссылок
This commit is contained in:
@@ -2276,22 +2276,12 @@ function nft_populate_runtime_set_for_section(section, deferred_sections, table,
|
||||
"/tmp/sing-box/rulesets/community-subnets-" + service + ".lst",
|
||||
"/etc/tachyon/rulesets/community-subnets-" + service + ".lst"
|
||||
];
|
||||
let found = false;
|
||||
for (let path in cached_paths) {
|
||||
if (helpers.file_is_usable(path, 50)) {
|
||||
nft_add_file_chunks_to_family_sets(path, table, sets.subnets, sets.subnets6, "ips", "", "5000");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (service == "discord") {
|
||||
nft_add_set_elements(table, sets.subnets, "162.158.0.0/15, 172.64.0.0/13, 138.128.136.0/21");
|
||||
}
|
||||
else if (service == "telegram") {
|
||||
nft_add_set_elements(table, sets.subnets, "149.154.160.0/20, 91.108.4.0/22, 91.108.8.0/22, 91.108.12.0/22, 91.108.16.0/22, 91.108.56.0/22, 5.28.192.0/18, 91.105.192.0/23, 95.161.64.0/20, 185.76.151.0/24, 194.221.0.0/16");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -643,8 +643,11 @@ function is_valid_detour(config, tag) {
|
||||
if (tag == runtime_constants.DIRECT_OUTBOUND_TAG || tag == runtime_constants.BYPASS_OUTBOUND_TAG)
|
||||
return true;
|
||||
for (let out in array_or_empty(config.outbounds)) {
|
||||
if (type(out) == "object" && out.tag == tag)
|
||||
if (type(out) == "object" && out.tag == tag) {
|
||||
if (out.tag == "DPI-out" || (out.type == "socks" && (out.server == "127.0.0.1" || out.server == "::1")))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1284,18 +1287,6 @@ function load_community_subnet_cidrs(community) {
|
||||
return cidrs;
|
||||
}
|
||||
}
|
||||
// Hardcoded seed fallback for cold boot before list-update downloads .lst
|
||||
if (service == "discord") {
|
||||
return [ "162.158.0.0/15", "172.64.0.0/13", "138.128.136.0/21" ];
|
||||
}
|
||||
if (service == "telegram") {
|
||||
return [
|
||||
"149.154.160.0/20", "91.108.4.0/22", "91.108.8.0/22",
|
||||
"91.108.12.0/22", "91.108.16.0/22", "91.108.56.0/22",
|
||||
"5.28.192.0/18", "91.105.192.0/23", "95.161.64.0/20",
|
||||
"185.76.151.0/24", "194.221.0.0/16"
|
||||
];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -1321,10 +1312,8 @@ function add_combined_route_for_section(config, section) {
|
||||
let ensured = ensure_community_ruleset(config, section_name, service);
|
||||
push(rule_set_tags, ensured.tag);
|
||||
push(dns_rule_set_tags, ensured.tag);
|
||||
if (service != "cloudflare" && service != "cloudfront" && service != "hetzner" && service != "ovh" && service != "digitalocean") {
|
||||
for (let cidr in load_community_subnet_cidrs(community))
|
||||
push(ip_cidr, cidr);
|
||||
}
|
||||
for (let cidr in load_community_subnet_cidrs(community))
|
||||
push(ip_cidr, cidr);
|
||||
}
|
||||
for (let reference in connections.rule_sets(section)) {
|
||||
let ensured = ensure_custom_ruleset(config, as_string(reference));
|
||||
@@ -1355,9 +1344,9 @@ function add_combined_route_for_section(config, section) {
|
||||
if (target.unsupported)
|
||||
ctx.runtime_generate_unsupported(target.unsupported);
|
||||
|
||||
let has_domain_or_ruleset = length(domain) > 0 || length(domain_suffix) > 0 ||
|
||||
length(domain_keyword) > 0 || length(domain_regex) > 0 ||
|
||||
length(rule_set_tags) > 0;
|
||||
let has_domain = length(domain) > 0 || length(domain_suffix) > 0 ||
|
||||
length(domain_keyword) > 0 || length(domain_regex) > 0;
|
||||
let has_ruleset = length(rule_set_tags) > 0;
|
||||
let has_ip_cidr = length(ip_cidr) > 0;
|
||||
|
||||
let create_section_route_rule = function() {
|
||||
@@ -1375,14 +1364,12 @@ function add_combined_route_for_section(config, section) {
|
||||
return r;
|
||||
};
|
||||
|
||||
if (has_domain_or_ruleset) {
|
||||
if (has_domain) {
|
||||
let domain_rule = create_section_route_rule();
|
||||
add_domain_array(domain_rule, "domain", domain);
|
||||
add_domain_array(domain_rule, "domain_suffix", domain_suffix);
|
||||
add_domain_array(domain_rule, "domain_keyword", domain_keyword);
|
||||
add_domain_array(domain_rule, "domain_regex", domain_regex);
|
||||
if (length(rule_set_tags) > 0)
|
||||
domain_rule.rule_set = single_or_array(rule_set_tags);
|
||||
|
||||
let resolve = runtime_route.resolve_rule_for_section(section, domain_rule);
|
||||
if (type(resolve) == "object" && resolve.warning)
|
||||
@@ -1393,6 +1380,19 @@ function add_combined_route_for_section(config, section) {
|
||||
push_section_route_rule(config, domain_rule, target.outbound);
|
||||
}
|
||||
|
||||
if (has_ruleset) {
|
||||
let rs_rule = create_section_route_rule();
|
||||
rs_rule.rule_set = single_or_array(rule_set_tags);
|
||||
|
||||
let resolve = runtime_route.resolve_rule_for_section(section, rs_rule);
|
||||
if (type(resolve) == "object" && resolve.warning)
|
||||
warn(resolve.warning, "\n");
|
||||
else if (type(resolve) == "object" && resolve.rule)
|
||||
push(config.route.rules, resolve.rule);
|
||||
|
||||
push_section_route_rule(config, rs_rule, target.outbound);
|
||||
}
|
||||
|
||||
if (has_ip_cidr) {
|
||||
let ip_rule = create_section_route_rule();
|
||||
ip_rule.ip_cidr = ip_cidr;
|
||||
@@ -1426,7 +1426,7 @@ function add_combined_route_for_section(config, section) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_domain_or_ruleset && !has_ip_cidr && length(country_list) == 0) {
|
||||
if (!has_domain && !has_ruleset && !has_ip_cidr && 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 ||
|
||||
@@ -1629,20 +1629,20 @@ function add_service_route_rules(config, sections) {
|
||||
push(detour_domains, host);
|
||||
}
|
||||
if (length(detour_ips) > 0) {
|
||||
push(config.route.rules, {
|
||||
push_section_route_rule(config, {
|
||||
action: "route",
|
||||
inbound: tproxy_inbound_matcher(),
|
||||
outbound: detour_target,
|
||||
ip_cidr: single_or_array(detour_ips)
|
||||
});
|
||||
}, detour_target);
|
||||
}
|
||||
if (length(detour_domains) > 0) {
|
||||
push(config.route.rules, {
|
||||
push_section_route_rule(config, {
|
||||
action: "route",
|
||||
inbound: tproxy_inbound_matcher(),
|
||||
outbound: detour_target,
|
||||
domain: single_or_array(detour_domains)
|
||||
});
|
||||
}, detour_target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@ function is_supported_share_link(line) {
|
||||
starts_with(line, "socks://") ||
|
||||
starts_with(line, "socks4://") ||
|
||||
starts_with(line, "socks4a://") ||
|
||||
starts_with(line, "socks5://");
|
||||
starts_with(line, "socks5://") ||
|
||||
starts_with(line, "http://") ||
|
||||
starts_with(line, "https://");
|
||||
}
|
||||
|
||||
function split_csv(value) {
|
||||
@@ -880,6 +882,50 @@ function process_socks(raw, url) {
|
||||
return outbound;
|
||||
}
|
||||
|
||||
function process_http(raw, url) {
|
||||
let port = url.port;
|
||||
if (port == null || port == "")
|
||||
port = url.scheme == "https" ? 443 : 80;
|
||||
if (url.host == "" || is_dummy_server(url.host, port) || !valid_port(port))
|
||||
return null;
|
||||
|
||||
let username = "", password = "";
|
||||
if (url.userinfo != "") {
|
||||
let colon = index(url.userinfo, ":");
|
||||
if (colon >= 0) {
|
||||
username = urldecode(substr(url.userinfo, 0, colon));
|
||||
password = urldecode(substr(url.userinfo, colon + 1));
|
||||
if (username == password)
|
||||
password = "";
|
||||
}
|
||||
else {
|
||||
username = urldecode(url.userinfo);
|
||||
}
|
||||
}
|
||||
|
||||
let outbound = {
|
||||
type: "http",
|
||||
tag: url.fragment != "" ? url.fragment : (url.host + ":" + port),
|
||||
share_link: raw,
|
||||
server: url.host,
|
||||
server_port: int(port)
|
||||
};
|
||||
if (username != "")
|
||||
outbound.username = username;
|
||||
if (password != "")
|
||||
outbound.password = password;
|
||||
|
||||
if (url.scheme == "https") {
|
||||
let tls = { enabled: true };
|
||||
if ((url.query.sni || "") != "")
|
||||
tls.server_name = url.query.sni;
|
||||
if (is_true(url.query.allowInsecure || url.query.insecure))
|
||||
tls.insecure = true;
|
||||
outbound.tls = tls;
|
||||
}
|
||||
return outbound;
|
||||
}
|
||||
|
||||
function is_shadowsocks_userinfo_format(value) {
|
||||
if (type(value) != "string")
|
||||
return false;
|
||||
@@ -1183,6 +1229,8 @@ function parse_share_link(line) {
|
||||
return process_tuic(line, url);
|
||||
if (match(url.scheme, /^socks/))
|
||||
return process_socks(line, url);
|
||||
if (url.scheme == "http" || url.scheme == "https")
|
||||
return process_http(line, url);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -242,6 +242,33 @@ function serialize_socks(outbound) {
|
||||
return scheme + "://" + auth + host_port(outbound.server, outbound.server_port) + fragment(outbound);
|
||||
}
|
||||
|
||||
function serialize_http(outbound) {
|
||||
if (as_string(outbound.server) == "" || outbound.server_port == null)
|
||||
return "";
|
||||
|
||||
let is_tls = type(outbound.tls) == "object" && (outbound.tls.enabled === true || outbound.tls.enabled == 1);
|
||||
let scheme = is_tls ? "https" : "http";
|
||||
let auth = "";
|
||||
if (as_string(outbound.username) != "") {
|
||||
auth = uri_encode(outbound.username);
|
||||
if (as_string(outbound.password) != "")
|
||||
auth += ":" + uri_encode(outbound.password);
|
||||
auth += "@";
|
||||
}
|
||||
|
||||
let params = [];
|
||||
if (is_tls && type(outbound.tls) == "object") {
|
||||
let tls = outbound.tls;
|
||||
if (tls.server_name)
|
||||
add_query(params, "sni", tls.server_name);
|
||||
if (tls.insecure === true)
|
||||
add_query(params, "insecure", "1");
|
||||
}
|
||||
|
||||
return scheme + "://" + auth + host_port(outbound.server, outbound.server_port) + query_string(params) + fragment(outbound);
|
||||
}
|
||||
|
||||
|
||||
function serialize_hysteria2(outbound) {
|
||||
let port = hysteria2_server_ports_uri(outbound);
|
||||
if (port == "" && outbound.server_port != null)
|
||||
@@ -365,6 +392,8 @@ function serialize_outbound_link(outbound) {
|
||||
return serialize_shadowsocks(outbound);
|
||||
if (outbound_type == "socks")
|
||||
return serialize_socks(outbound);
|
||||
if (outbound_type == "http")
|
||||
return serialize_http(outbound);
|
||||
if (outbound_type == "hysteria2")
|
||||
return serialize_hysteria2(outbound);
|
||||
if (outbound_type == "tuic")
|
||||
@@ -379,7 +408,8 @@ function is_copyable_link(value) {
|
||||
let prefixes = [
|
||||
"vless://", "vmess://", "trojan://", "ss://", "ssr://",
|
||||
"hysteria2://", "hy2://", "tuic://",
|
||||
"socks4://", "socks4a://", "socks5://"
|
||||
"socks4://", "socks4a://", "socks5://",
|
||||
"http://", "https://"
|
||||
];
|
||||
for (let prefix in prefixes) {
|
||||
if (starts_with(value, prefix))
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "$TEST_DIR/.." && pwd)"
|
||||
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
|
||||
GENERATOR_UC="$TACHYON_LIB/singbox/generator.uc"
|
||||
|
||||
WORK_DIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$WORK_DIR"' EXIT
|
||||
|
||||
fail() {
|
||||
echo "FAIL: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 1. Test coexistence: section with both domains and community_lists MUST generate separate rules
|
||||
cat >"$WORK_DIR/fixture.json" <<'JSON'
|
||||
{
|
||||
"settings": {
|
||||
".name": "settings",
|
||||
".type": "settings",
|
||||
"enabled": "1",
|
||||
"dns_type": "udp",
|
||||
"dns_server": "1.1.1.1",
|
||||
"service_listen_address": "127.0.0.1"
|
||||
},
|
||||
"section": [
|
||||
{
|
||||
".name": "mixed_sec",
|
||||
".type": "section",
|
||||
"enabled": "1",
|
||||
"action": "connection",
|
||||
"outbound_jsons": [ "{\"type\":\"direct\"}" ],
|
||||
"domain_suffix": [ "customdomain.org" ],
|
||||
"community_lists": [ "discord" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
output="$WORK_DIR/out.json"
|
||||
mkdir -p "$output.section-cache" "$output.rulesets"
|
||||
ucode -L "$TACHYON_LIB" "$GENERATOR_UC" generate-config-fixture \
|
||||
"$WORK_DIR/fixture.json" "$output" "127.0.0.1" "0" "1"
|
||||
|
||||
# Verify route rules in out.json
|
||||
ucode -e '
|
||||
let fs = require("fs");
|
||||
let raw = fs.readfile("'"$output"'");
|
||||
let cfg = json(raw);
|
||||
let rules = cfg.route.rules || [];
|
||||
|
||||
let found_domain_only = false;
|
||||
let found_ruleset_only = false;
|
||||
let found_combined = false;
|
||||
|
||||
for (let r in rules) {
|
||||
if (r.domain_suffix && r.rule_set) {
|
||||
found_combined = true;
|
||||
}
|
||||
if (r.domain_suffix && !r.rule_set) {
|
||||
for (let d in r.domain_suffix) {
|
||||
if (d == "customdomain.org")
|
||||
found_domain_only = true;
|
||||
}
|
||||
}
|
||||
if (r.rule_set && !r.domain_suffix) {
|
||||
let rs_str = sprintf("%s", r.rule_set);
|
||||
if (index(rs_str, "discord") >= 0)
|
||||
found_ruleset_only = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_combined) {
|
||||
print("ERROR: found merged domain_suffix AND rule_set in single rule! Sing-box treats this as logical AND!\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!found_domain_only) {
|
||||
print("ERROR: domain_suffix rule missing for customdomain.org\n");
|
||||
exit(2);
|
||||
}
|
||||
if (!found_ruleset_only) {
|
||||
print("ERROR: rule_set rule missing for discord\n");
|
||||
exit(3);
|
||||
}
|
||||
' || fail "Coexistence check failed: domain and ruleset rules are not cleanly separated"
|
||||
|
||||
# 2. Verify DPI-out is never selected as download_detour
|
||||
cat >"$WORK_DIR/fixture_dpi.json" <<'JSON'
|
||||
{
|
||||
"settings": {
|
||||
".name": "settings",
|
||||
".type": "settings",
|
||||
"enabled": "1",
|
||||
"dns_type": "udp",
|
||||
"dns_server": "1.1.1.1",
|
||||
"service_listen_address": "127.0.0.1"
|
||||
},
|
||||
"section": [
|
||||
{
|
||||
".name": "dpi_sec",
|
||||
".type": "section",
|
||||
"enabled": "1",
|
||||
"action": "connection",
|
||||
"outbound_jsons": [
|
||||
"{\"tag\":\"DPI-out\",\"type\":\"socks\",\"server\":\"127.0.0.1\",\"server_port\":1080}"
|
||||
],
|
||||
"community_lists": [ "discord" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
output_dpi="$WORK_DIR/out_dpi.json"
|
||||
mkdir -p "$output_dpi.section-cache" "$output_dpi.rulesets"
|
||||
ucode -L "$TACHYON_LIB" "$GENERATOR_UC" generate-config-fixture \
|
||||
"$WORK_DIR/fixture_dpi.json" "$output_dpi" "127.0.0.1" "0" "1"
|
||||
|
||||
ucode -e '
|
||||
let fs = require("fs");
|
||||
let raw = fs.readfile("'"$output_dpi"'");
|
||||
let cfg = json(raw);
|
||||
let rulesets = cfg.route.rule_set || [];
|
||||
for (let rs in rulesets) {
|
||||
if (rs.download_detour == "DPI-out") {
|
||||
print("ERROR: DPI-out was selected as download_detour!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
' || fail "DPI-out must never be set as download_detour"
|
||||
|
||||
printf "Route rules coexistence and detour checks passed\n"
|
||||
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "$TEST_DIR/.." && pwd)"
|
||||
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
|
||||
PARSER_UC="$TACHYON_LIB/subscription/parser.uc"
|
||||
GENERATOR_UC="$TACHYON_LIB/singbox/generator.uc"
|
||||
|
||||
WORK_DIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$WORK_DIR"' EXIT
|
||||
|
||||
fail() {
|
||||
echo "FAIL: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 1. Test parsing http:// and https:// share links
|
||||
cat >"$WORK_DIR/http_links.txt" <<'EOF'
|
||||
http://admin:secret123@192.168.1.50:8080#My-Http-Proxy
|
||||
https://user:pass@proxy.example.com:8443?sni=secure.example.com&insecure=1#My-Https-Proxy
|
||||
EOF
|
||||
|
||||
output_json="$WORK_DIR/parsed.json"
|
||||
ucode -L "$TACHYON_LIB" "$PARSER_UC" normalize-uri-list "$WORK_DIR/http_links.txt" "$output_json"
|
||||
|
||||
ucode -e '
|
||||
let fs = require("fs");
|
||||
let parsed = json(fs.readfile("'"$output_json"'"));
|
||||
let list = parsed.outbounds || [];
|
||||
if (length(list) != 2) {
|
||||
print("Expected 2 outbounds, got " + length(list) + "\n");
|
||||
exit(1);
|
||||
}
|
||||
let http = list[0];
|
||||
if (http.type != "http" || http.server != "192.168.1.50" || http.server_port != 8080 ||
|
||||
http.username != "admin" || http.password != "secret123" || http.tag != "My-Http-Proxy") {
|
||||
print("HTTP outbound fields incorrect: " + sprintf("%J", http) + "\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
let https = list[1];
|
||||
if (https.type != "http" || https.server != "proxy.example.com" || https.server_port != 8443 ||
|
||||
https.username != "user" || https.password != "pass" || https.tag != "My-Https-Proxy" ||
|
||||
!https.tls || !https.tls.enabled || https.tls.server_name != "secure.example.com" || !https.tls.insecure) {
|
||||
print("HTTPS outbound fields incorrect: " + sprintf("%J", https) + "\n");
|
||||
exit(3);
|
||||
}
|
||||
' || fail "HTTP/HTTPS share link parsing failed"
|
||||
|
||||
# 2. Test serializing http/https outbound to share link
|
||||
ucode -L "$TACHYON_LIB" -e '
|
||||
let share = require("subscription.share_link");
|
||||
let http_out = {
|
||||
type: "http",
|
||||
server: "1.2.3.4",
|
||||
server_port: 8080,
|
||||
username: "alice",
|
||||
password: "foo",
|
||||
tag: "test-http"
|
||||
};
|
||||
let link = share.serialize_outbound_link(http_out);
|
||||
if (link != "http://alice:foo@1.2.3.4:8080#test-http") {
|
||||
print("Failed http serialize: " + link + "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
let https_out = {
|
||||
type: "http",
|
||||
server: "secure.net",
|
||||
server_port: 443,
|
||||
tls: {
|
||||
enabled: true,
|
||||
server_name: "sni.secure.net",
|
||||
insecure: true
|
||||
},
|
||||
tag: "test-https"
|
||||
};
|
||||
let link_tls = share.serialize_outbound_link(https_out);
|
||||
if (link_tls != "https://secure.net:443?sni=sni.secure.net&insecure=1#test-https") {
|
||||
print("Failed https serialize: " + link_tls + "\n");
|
||||
exit(2);
|
||||
}
|
||||
' || fail "HTTP/HTTPS serialization failed"
|
||||
|
||||
# 3. Test UDP reject rule generation for HTTP outbound to prevent sing-box crash
|
||||
cat >"$WORK_DIR/fixture.json" <<'JSON'
|
||||
{
|
||||
"settings": {
|
||||
".name": "settings",
|
||||
".type": "settings",
|
||||
"enabled": "1",
|
||||
"dns_type": "udp",
|
||||
"dns_server": "1.1.1.1",
|
||||
"service_listen_address": "127.0.0.1"
|
||||
},
|
||||
"section": [
|
||||
{
|
||||
".name": "http_sec",
|
||||
".type": "section",
|
||||
"enabled": "1",
|
||||
"action": "connection",
|
||||
"outbound_jsons": [
|
||||
"{\"tag\":\"http-out\",\"type\":\"http\",\"server\":\"1.2.3.4\",\"server_port\":8080}"
|
||||
],
|
||||
"domain_suffix": [ "example.com" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
gen_out="$WORK_DIR/gen.json"
|
||||
mkdir -p "$gen_out.section-cache" "$gen_out.rulesets"
|
||||
ucode -L "$TACHYON_LIB" "$GENERATOR_UC" generate-config-fixture \
|
||||
"$WORK_DIR/fixture.json" "$gen_out" "127.0.0.1" "0" "1"
|
||||
|
||||
ucode -e '
|
||||
let fs = require("fs");
|
||||
let cfg = json(fs.readfile("'"$gen_out"'"));
|
||||
let rules = cfg.route.rules || [];
|
||||
let found_reject = false;
|
||||
let found_http_route = false;
|
||||
|
||||
for (let r in rules) {
|
||||
if (r.network == "udp" && (r.action == "reject" || r.outbound == "block")) {
|
||||
found_reject = true;
|
||||
}
|
||||
if (r.outbound == "http_sec-out") {
|
||||
found_http_route = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_reject) {
|
||||
print("ERROR: Expected UDP reject rule before HTTP outbound route rule!\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!found_http_route) {
|
||||
print("ERROR: Expected route rule for http_sec-out!\n");
|
||||
exit(2);
|
||||
}
|
||||
' || fail "UDP reject rule for HTTP outbound failed"
|
||||
|
||||
printf "Subscription HTTP tests passed\n"
|
||||
Reference in New Issue
Block a user