mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-04 18:03:56 +08:00
🎈 Sync 2026-10-04 14:38:18
This commit is contained in:
1 parent
0e6611f767
commit
aba12667c5
88 files changed
+4600
-1458
No files matched your search
@@ -18,7 +18,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { isEmpty } from '../homeproxy-pro.uc';
|
||||
import { isEmpty, HP_DIR } from '../homeproxy-pro.uc';
|
||||
|
||||
import { ConfigQuery } from '../config/model.uc';
|
||||
|
||||
@@ -142,43 +142,42 @@ export function rule_set_tags(cfg) {
|
||||
return tags;
|
||||
};
|
||||
|
||||
/* BUILTIN_REMOTE_RULE_SETS - the remote rule-sets the generator declares
|
||||
* itself, in the modes that split on mainland China.
|
||||
/* The routing modes that split on mainland China, and the rule-sets they
|
||||
* declare.
|
||||
*
|
||||
* geoip-cn referenced by the route rule to split destinations by IP
|
||||
* geosite-cn referenced only by the DNS rule (server: china-dns); the
|
||||
* route layer never matches it, but sing-box still loads and
|
||||
* keeps it, so removing it would break the DNS split
|
||||
* The three of them - china-ip, china-ip6, china-domain - are local files the
|
||||
* resource updater generates, one per list, and each is declared only when
|
||||
* something references it and its file is on disk. route.uc owns that
|
||||
* decision because the conditions are per-tag (the address list in both
|
||||
* mainland modes, the v6 half only with IPv6 on, the domain list only in
|
||||
* bypass mode), so there is nothing here for a shared list to keep in step
|
||||
* with.
|
||||
*
|
||||
* This list is shared with generate_client.uc, which has to create the
|
||||
* "do not block startup" fallback file for each of them before the generator
|
||||
* runs. The two used to be independent: route.uc hard-coded the entries and
|
||||
* the CLI knew nothing about them, which is why a cold-cache first start
|
||||
* blocked on downloading them and why a change to either side could not be
|
||||
* checked against the other. One list, two readers.
|
||||
* They were `type: remote` entries pointing at SagerNet's sing-geoip and
|
||||
* sing-geosite repositories, and two things followed from that which the local
|
||||
* arrangement does not have:
|
||||
*
|
||||
* Not a conffile-order dependency - this is the generator's own declaration,
|
||||
* in the order the generated rule_set array must keep so the emitted bytes
|
||||
* stay stable. */
|
||||
export const BUILTIN_REMOTE_RULE_SETS = [
|
||||
{
|
||||
tag: 'geoip-cn',
|
||||
format: 'binary',
|
||||
url: 'https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs',
|
||||
update_interval: '24h'
|
||||
},
|
||||
{
|
||||
tag: 'geosite-cn',
|
||||
format: 'binary',
|
||||
url: 'https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs',
|
||||
update_interval: '24h'
|
||||
}
|
||||
];
|
||||
|
||||
/* The routing modes that declare them. Kept beside the list so the CLI can
|
||||
* decide whether it needs to create their fallbacks without repeating the
|
||||
* condition route.uc branches on - and so the two cannot drift. */
|
||||
export function declaresBuiltinRemoteRuleSets(routing_mode) {
|
||||
* - a cold start had to download them before the inbounds bind, over the
|
||||
* node (download_detour), so a first start - or a start after the cache
|
||||
* was cleared - depended on GitHub being reachable through the proxy it
|
||||
* was trying to bring up;
|
||||
* - the two halves of the same split read two different files. The kernel's
|
||||
* came from china_ip4.txt and the resolver's from a .srs, and the route.uc
|
||||
* comment about them disagreeing is the scar of patching that instead of
|
||||
* fixing it.
|
||||
*
|
||||
* Now the nft set and the sing-box rule-set are both generated from the same
|
||||
* list, on the same schedule, with nothing to download.
|
||||
*
|
||||
* Source JSON, not a compiled .srs: the updater writes the canonical form and
|
||||
* sing-box watches the file, so a new list is picked up in place. Compiling
|
||||
* first was measured rather than assumed - 111k domain suffixes cost 3.7 MB of
|
||||
* RSS in source form (44.9 MB baseline vs 48.7 MB loaded), which is not worth
|
||||
* a second artifact and a second failure mode. */
|
||||
/* The routing modes that split on mainland China. The China domain list is
|
||||
* only meaningful where the split is by domain: proxy_mainland_china decides
|
||||
* by address on the route side and leaves the resolver to the mode default. */
|
||||
export function declaresBuiltinRuleSets(routing_mode) {
|
||||
return routing_mode === 'bypass_mainland_china' || routing_mode === 'proxy_mainland_china';
|
||||
};
|
||||
|
||||
|
||||
@@ -138,6 +138,11 @@ export function build_context(dm, env) {
|
||||
* whole config. Default false - an absent env must not turn into an
|
||||
* optimistic "assume the file is there". */
|
||||
china_ip6_ready: (env?.china_ip6_ready === true),
|
||||
/* Whether china-domain.json is on disk. Same one-sided default as
|
||||
* the field above, for the same reason: it is a filesystem fact the
|
||||
* CLI resolves, and an absent env must not be read as "assume the
|
||||
* file is there". */
|
||||
china_domain_ready: (env?.china_domain_ready === true),
|
||||
/* Which enabled `type: local` rule-sets have a usable file on disk,
|
||||
* keyed by UCI section name: { '<section>': true }.
|
||||
*
|
||||
@@ -256,29 +261,6 @@ export function build_context(dm, env) {
|
||||
* Default '0' preserves the
|
||||
* 300ms / default-list behaviour so an upgrade is invisible. */
|
||||
sniffer_advanced_mode: dm.general.sniffer_advanced_mode || '0',
|
||||
/* ruleset_safe_start: when '1' (opt-in), every enabled remote
|
||||
* rule-set that has no initial_path of its own gets one, pointing at
|
||||
* an EMPTY rule-set the generator writes before the config is
|
||||
* checked. A remote rule-set with no initial file is fetched during
|
||||
* initialization, before the inbounds bind, so on a cold cache the
|
||||
* first start depends on the CDN being reachable - and on the node,
|
||||
* because the fetch goes through http_clients.
|
||||
*
|
||||
* The fallback is empty on purpose and that is the trade: a rule-set
|
||||
* with no rules matches nothing, so its traffic falls through to
|
||||
* `final`. That is a routing change, not a robustness tweak, which
|
||||
* is why the default is '0' and why the whole repository stays
|
||||
* fail-loud by default. Guard 52 pins the default, the way guard 39
|
||||
* pins sniffer_advanced_mode's. */
|
||||
ruleset_safe_start: dm.general.ruleset_safe_start || '0',
|
||||
/* Which empty startup fallbacks the CLI actually wrote, keyed by
|
||||
* rule_set tag. Presence, not a path: the generator emits
|
||||
* `initial_path` only for tags it can point at, so a fallback that
|
||||
* could not be written leaves that rule-set on today's behaviour
|
||||
* rather than pointing at a file that is not there. Pessimistic by
|
||||
* construction - an env that forgot the field (the server path) has
|
||||
* no fallbacks, and the server declares no remote rule-sets anyway. */
|
||||
ruleset_initial: (env?.ruleset_initial || {}),
|
||||
main_urltest_nodes: dm.general.main_urltest_nodes || [],
|
||||
main_urltest_interval: dm.general.main_urltest_interval,
|
||||
main_urltest_tolerance: dm.general.main_urltest_tolerance,
|
||||
|
||||
@@ -278,11 +278,22 @@ function append_proxy_dns(config, dm, ctx) {
|
||||
server: 'default-dns'
|
||||
});
|
||||
|
||||
push(config.dns.rules, {
|
||||
rule_set: 'geosite-cn',
|
||||
action: 'route',
|
||||
server: 'china-dns'
|
||||
});
|
||||
/* The China domain list, generated from china_list.txt - the same
|
||||
* schedule and the same updater as the address list the route and
|
||||
* firewall halves read. It replaced geosite-geolocation-cn.srs,
|
||||
* which had to be downloaded before the inbounds could bind.
|
||||
*
|
||||
* Only with the file there: a rule naming a tag nothing declares
|
||||
* fails the config, and a rule-set whose path is missing fails it
|
||||
* too, so both the declaration (route.uc) and this reference are
|
||||
* gated on the same lstat. */
|
||||
if (ctx.china_domain_ready) {
|
||||
push(config.dns.rules, {
|
||||
rule_set: 'china-domain',
|
||||
action: 'route',
|
||||
server: 'china-dns'
|
||||
});
|
||||
}
|
||||
|
||||
/* sing-box 1.14: restore CN-IP fallback via evaluate/match_response (opt-in) */
|
||||
if (ctx.cn_ip_fallback === '1') {
|
||||
@@ -292,18 +303,17 @@ function append_proxy_dns(config, dm, ctx) {
|
||||
tag: 'cn-fallback'
|
||||
});
|
||||
/* The response is matched by the addresses the upstream returned,
|
||||
* and geoip-cn has no IPv6 in it, so with IPv6 support on a
|
||||
* mainland domain that resolved to an AAAA address was never
|
||||
* recognised as mainland and its answer kept coming from the
|
||||
* proxy resolver. Adding the v6 rule-set here is what makes the
|
||||
* DNS half of the split agree with the route half, which
|
||||
* classifies the same destinations through the same list
|
||||
* (route.uc: china-ip6). Both tags have to be declared before
|
||||
* this rule runs, which is why the list is built here rather than
|
||||
* inlined: a rule_set naming an undeclared tag fails the config.
|
||||
* china-ip6 is only declared when its file exists, so it is only
|
||||
* named here under the same condition. */
|
||||
const cn_fallback_sets = ['geoip-cn'];
|
||||
* and the address list has to be the one the route half uses for
|
||||
* the same decision to agree with it - so this names china-ip, not
|
||||
* a list of its own. It is the same reason the declaration lives
|
||||
* in common.uc.
|
||||
*
|
||||
* china-ip6 is added only when it is declared: the rule_set list
|
||||
* has to name declared tags only, or the config is rejected.
|
||||
* Without it a mainland domain that resolved to an AAAA address
|
||||
* is never recognised as mainland and its answer keeps coming
|
||||
* from the proxy resolver. */
|
||||
const cn_fallback_sets = ['china-ip'];
|
||||
if (ctx.ipv6_support === '1' && ctx.china_ip6_ready)
|
||||
push(cn_fallback_sets, 'china-ip6');
|
||||
push(config.dns.rules, {
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { isEmpty, strToInt, strToTime, strToBool, parse_port, ruleSetInitialFallback, HP_DIR } from '../homeproxy-pro.uc';
|
||||
import { isEmpty, strToInt, strToTime, strToBool, parse_port, HP_DIR } from '../homeproxy-pro.uc';
|
||||
|
||||
import { BUILTIN_REMOTE_RULE_SETS, declaresBuiltinRemoteRuleSets, get_outbound, get_resolver, get_ruleset, get_direct_override } from './common.uc';
|
||||
import { declaresBuiltinRuleSets, get_outbound, get_resolver, get_ruleset, get_direct_override } from './common.uc';
|
||||
|
||||
/* --- shared initial block (every routing mode) ------------------------- */
|
||||
|
||||
@@ -93,10 +93,10 @@ function build_route_proxy(config, dm, ctx, direct_overrides) {
|
||||
outbound: 'direct-out'
|
||||
});
|
||||
|
||||
/* Split by destination IP, in both directions.
|
||||
/* Split by destination address, in both directions.
|
||||
*
|
||||
* sing-box does not match an IP-based rule set (geoip-cn) against a
|
||||
* domain destination unless it is resolved first, so an explicit resolve
|
||||
* sing-box does not match an address-based rule set against a domain
|
||||
* destination unless it is resolved first, so an explicit resolve
|
||||
* action comes first. Which way the split points is the mode's default
|
||||
* policy (ctx.proxy_fallback):
|
||||
*
|
||||
@@ -105,10 +105,17 @@ function build_route_proxy(config, dm, ctx, direct_overrides) {
|
||||
* proxy_mainland_china mainland -> proxy, the rest falls through to
|
||||
* direct-out
|
||||
*
|
||||
* Using geoip-cn rather than the geosite-* domain lists is deliberate:
|
||||
* those mis-classify foreign domains (Google's gvt2.com beacons) as "cn"
|
||||
* and would send them direct to time out. Keep the direct-domain
|
||||
* fast-path above for known direct domains. */
|
||||
* Using china-ip rather than a domain list is deliberate: those
|
||||
* mis-classify foreign domains (Google's gvt2.com beacons) as "cn" and
|
||||
* would send them direct to time out. Keep the direct-domain fast-path
|
||||
* above for known direct domains.
|
||||
*
|
||||
* One list for both halves of the split: china-ip is generated from the
|
||||
* same china_ip4.txt the firewall renders homeproxy_mainland_addr_v4
|
||||
* from, so the kernel and the resolver cannot disagree about what counts
|
||||
* as mainland. It used to be geoip-cn, with china-ip added later as a
|
||||
* correction for the two disagreeing - two rule-sets, one of them
|
||||
* redundant in this mode, neither able to see the other's data. */
|
||||
if (ctx.routing_mode === 'bypass_mainland_china'
|
||||
|| ctx.routing_mode === 'proxy_mainland_china') {
|
||||
push(config.route.rules, {
|
||||
@@ -116,37 +123,20 @@ function build_route_proxy(config, dm, ctx, direct_overrides) {
|
||||
strategy: (ctx.ipv6_support !== '1') ? 'prefer_ipv4' : null
|
||||
});
|
||||
push(config.route.rules, {
|
||||
rule_set: 'geoip-cn',
|
||||
rule_set: 'china-ip',
|
||||
action: 'route',
|
||||
outbound: ctx.proxy_fallback ? 'direct-out' : 'main-out'
|
||||
});
|
||||
}
|
||||
if (ctx.routing_mode === 'bypass_mainland_china') {
|
||||
/* geoip-cn.srs is upstream's list; the firewall's mainland set is
|
||||
* built from our own china_ip4.txt (firewall_post.ut reads it
|
||||
* directly). The two disagree - the bundled list has 8.152.0.0/13
|
||||
* (Alibaba Cloud) and geoip-cn.srs does not - so a connection into
|
||||
* that range passes the firewall as "not mainland" and would then be
|
||||
* sent direct by the rule above instead of to the proxy. This local
|
||||
* rule-set is generated from the same china_ip4.txt, which is what
|
||||
* makes both sides decide from one list. In
|
||||
* proxy_mainland_china it is not needed twice: the geoip-cn rule
|
||||
* already selects the mainland side for the proxy. */
|
||||
push(config.route.rules, {
|
||||
rule_set: 'china-ip',
|
||||
action: 'route',
|
||||
outbound: 'direct-out'
|
||||
});
|
||||
|
||||
/* IPv6 half of the same split, and the reason a mainland site opened
|
||||
* over IPv6 used to go through the proxy even with IPv6 support on.
|
||||
* geoip-cn.srs carries no IPv6 and china_ip4.json is generated from an
|
||||
* IPv4 list, so a destination that resolved to an AAAA address matched
|
||||
* neither and fell through to `final` - which in this mode is main-out.
|
||||
* The rule is emitted in both mainland modes (unlike china-ip, which
|
||||
* proxy_mainland_china does not need twice because geoip-cn already
|
||||
* picks the mainland side there): with no IPv6 in geoip-cn there is
|
||||
* nothing left to pick it, so the side has to be named explicitly.
|
||||
/* The IPv6 half of the same split, and the reason a mainland site
|
||||
* opened over IPv6 used to go through the proxy even with IPv6
|
||||
* support on. china_ip4.json is generated from an IPv4 list, so a
|
||||
* destination that resolved to an AAAA address matched nothing and
|
||||
* fell through to `final` - which in bypass mode is main-out. The
|
||||
* rule is emitted in both mainland modes for that reason. Declared
|
||||
* only when china_ip6.json is actually there: a rule_set pointing at
|
||||
* a missing file takes the whole config down with it, and a router
|
||||
* whose v6 list is unusable must still start (the firewall has
|
||||
* already degraded to passing IPv6 through, with a warning).
|
||||
* `prefer_ipv4` on the resolve rule above is what lets both families
|
||||
* through - it biases, it does not filter. */
|
||||
if (ctx.ipv6_support === '1' && ctx.china_ip6_ready) {
|
||||
@@ -211,90 +201,36 @@ function build_route_proxy(config, dm, ctx, direct_overrides) {
|
||||
]
|
||||
});
|
||||
|
||||
/* Both mainland modes split on geoip-cn, so both need it declared - it is
|
||||
* what the route rule added above matches. `proxy_mainland_china` used
|
||||
* to reach this point without it and sing-box refused the whole config
|
||||
* with "initialize rule[3]: rule-set not found: geoip-cn", which the
|
||||
* health gate turned into a rollback and an unproxied network. */
|
||||
if (declaresBuiltinRemoteRuleSets(ctx.routing_mode)) {
|
||||
/*
|
||||
* Fetched straight from the upstream SagerNet repositories and
|
||||
* downloaded through the selected node. A direct fetch depends on
|
||||
* the CDN staying reachable from mainland China, where DNS pollution
|
||||
* makes it fail intermittently; the files total ~250 KB per
|
||||
* day, so proxying the download costs almost nothing.
|
||||
*
|
||||
* Both rule_sets are emitted, but they are consumed by different
|
||||
* blocks:
|
||||
*
|
||||
* geoip-cn - referenced by the route rule above to split
|
||||
* destinations by IP: mainland -> direct-out in
|
||||
* bypass_mainland_china, mainland -> main-out in
|
||||
* proxy_mainland_china.
|
||||
* geosite-cn - referenced only by the DNS rule in
|
||||
* generator/dns.uc (rule_set: geosite-cn ->
|
||||
* server: china-dns); the route layer never matches
|
||||
* it. Sing-box still loads and keeps the rule-set in
|
||||
* memory even when only one block references it, so
|
||||
* removing it would also break the DNS split.
|
||||
*
|
||||
* History: a third geosite-noncn used to be declared here as well,
|
||||
* but no rule referenced it and sing-box still loaded and updated
|
||||
* it daily, so it was removed (the comment above was rewritten
|
||||
* during the 2026-09-29 review to clarify that geosite-cn is still
|
||||
* in use - the DNS side - just not from this block).
|
||||
*
|
||||
* The list itself lives in common.uc, because the CLI has to create
|
||||
* an "initial" fallback file for each of these before this generator
|
||||
* runs - see the note on BUILTIN_REMOTE_RULE_SETS. That is the whole
|
||||
* reason this block is a loop: these two are the rule-sets a cold
|
||||
* install blocks on, so a change to them that only reached one of the
|
||||
* two readers would put the fallback out of step with the config
|
||||
* that points at it.
|
||||
*/
|
||||
for (let rs in BUILTIN_REMOTE_RULE_SETS) {
|
||||
push(config.route.rule_set, {
|
||||
type: 'remote',
|
||||
tag: rs.tag,
|
||||
format: rs.format,
|
||||
url: rs.url,
|
||||
update_interval: rs.update_interval,
|
||||
/* Only with the opt-in on, and only for a fallback the CLI
|
||||
* actually wrote. A remote rule-set with no initial_path is
|
||||
* fetched during initialization, before the inbounds bind, so
|
||||
* a cold cache makes the first start depend on the CDN - and
|
||||
* on the node, since these go through http_clients. The
|
||||
* fallback is an EMPTY rule-set, which changes routing for
|
||||
* everything it would have matched, so it stays off unless
|
||||
* the user asks for it.
|
||||
*
|
||||
* These two are the rule-sets a fresh install blocks on, so
|
||||
* they are also the whole point of the feature: an earlier
|
||||
* version of this block only knew how to build the entries,
|
||||
* and the CLI had no idea they existed. */
|
||||
initial_path: (ctx.ruleset_safe_start === '1' && ctx.ruleset_initial[rs.tag])
|
||||
? ruleSetInitialFallback([ rs.tag ], rs.format, rs.url) : null,
|
||||
download_detour: 'main-out'
|
||||
});
|
||||
}
|
||||
/* Local, and not downloaded: it is generated from the same
|
||||
* china_ip4.txt the firewall renders homeproxy_mainland_addr_v4
|
||||
* from, so the two cannot drift apart. `type: local` is watched by
|
||||
* sing-box with fswatch, so when the resource updater replaces the
|
||||
* file the running instance reloads it in place - no restart and,
|
||||
* more importantly, no second copy of the list to keep in sync. */
|
||||
/* Both mainland modes split on the China address list, so both need it
|
||||
* declared - it is what the route rule added above matches.
|
||||
* `proxy_mainland_china` used to reach this point without a declaration and
|
||||
* sing-box refused the whole config with "initialize rule[3]: rule-set not
|
||||
* found: geoip-cn", which the health gate turned into a rollback and an
|
||||
* unproxied network.
|
||||
*
|
||||
* All three are `type: local` and none of them is downloaded. Each is
|
||||
* generated by runtime/{china_ip,domain}_ruleset.uc from a list the resource
|
||||
* updater maintains, and sing-box watches the file with fswatch, so a new
|
||||
* list is picked up in place - no restart, and no second copy of the data to
|
||||
* keep in step with the firewall's nft set.
|
||||
*
|
||||
* Which ones are declared depends on what references them:
|
||||
* china-ip the route rule above, in both mainland modes
|
||||
* china-ip6 the IPv6 route rule, when there is one
|
||||
* china-domain the DNS rule in generator/dns.uc, bypass mode only -
|
||||
* proxy_mainland_china decides by address and leaves the
|
||||
* resolver to the mode default, so declaring it there would
|
||||
* load 111k suffixes for a rule that does not exist. */
|
||||
if (declaresBuiltinRuleSets(ctx.routing_mode)) {
|
||||
push(config.route.rule_set, {
|
||||
type: 'local',
|
||||
tag: 'china-ip',
|
||||
path: HP_DIR + '/resources/china_ip4.json'
|
||||
});
|
||||
|
||||
/* The IPv6 counterpart, from china_ip6.txt - the same list the
|
||||
* firewall renders homeproxy_mainland_addr_v6 from, and the only
|
||||
* IPv6 mainland data either side of the split has. Declared only
|
||||
* when the file is actually there: a rule_set pointing at a missing
|
||||
* file takes the whole config down with it, and a router whose v6
|
||||
* list is unusable must still start (the firewall has already
|
||||
/* Declared only when the file is actually there: a rule_set pointing
|
||||
* at a missing file takes the whole config down with it, and a router
|
||||
* whose v6 list is unusable must still start (the firewall has already
|
||||
* degraded to passing IPv6 through, with a warning). */
|
||||
if (ctx.ipv6_support === '1' && ctx.china_ip6_ready) {
|
||||
push(config.route.rule_set, {
|
||||
@@ -303,6 +239,18 @@ function build_route_proxy(config, dm, ctx, direct_overrides) {
|
||||
path: HP_DIR + '/resources/china_ip6.json'
|
||||
});
|
||||
}
|
||||
|
||||
/* The DNS half. Same "only when it is there" rule as the v6 one
|
||||
* above, for the same reason: generate_client.uc's dns rule names this
|
||||
* tag, and a declaration whose file is missing fails the start rather
|
||||
* than degrading. */
|
||||
if (ctx.routing_mode === 'bypass_mainland_china' && ctx.china_domain_ready) {
|
||||
push(config.route.rule_set, {
|
||||
type: 'local',
|
||||
tag: 'china-domain',
|
||||
path: HP_DIR + '/resources/china-domain.json'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (isEmpty(config.route.rule_set))
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { isEmpty, rulePathRootsText, ruleSetFormatFromPath, ruleSetInitialFallback, strToTime, validateRuleSetPath } from '../homeproxy-pro.uc';
|
||||
import { isEmpty, rulePathRootsText, ruleSetFormatFromPath, strToTime, validateRuleSetPath } from '../homeproxy-pro.uc';
|
||||
|
||||
import { get_outbound, isDirectOutboundTag, rule_set_tags } from './common.uc';
|
||||
|
||||
@@ -214,37 +214,6 @@ export function build_user_rulesets(rule_set_array, dm, ctx) {
|
||||
if (!validateRuleSetPath(cfg.initial_path))
|
||||
die(sprintf("homeproxy-pro: rule-set '%s' initial_path '%s' is outside the allowed rule-set roots (%s); move the file into one of them, or clear the field to let sing-box fetch the rule-set on its own.", cfg.name, cfg.initial_path, rulePathRootsText()));
|
||||
ruleset.initial_path = cfg.initial_path;
|
||||
} else if (cfg.type === 'remote' && ctx.ruleset_safe_start === '1') {
|
||||
/* No initial file of the user's own, and the opt-in is on: point at
|
||||
* the empty fallback the CLI wrote before this generator ran.
|
||||
*
|
||||
* ctx.ruleset_initial records PRESENCE, not a path, and every tag
|
||||
* has to be present. sing-box substitutes {tag} and opens every
|
||||
* resulting file, so a multi-tag rule-set whose second file is
|
||||
* missing blocks startup exactly as surely as one whose first is -
|
||||
* measured on 1.14.2, where a literal "{tag}.srs" on disk makes
|
||||
* it fall back to downloading and fail. All-or-nothing is the
|
||||
* only correct answer here.
|
||||
*
|
||||
* Nothing is emitted when the answer is no: the rule-set then
|
||||
* behaves exactly as it does today, which is also what happens if
|
||||
* the CLI could not write the file. */
|
||||
const fallback = ruleSetInitialFallback(all_tags, cfg.format, cfg.url);
|
||||
|
||||
if (fallback) {
|
||||
let ready = true;
|
||||
|
||||
for (let t in all_tags)
|
||||
if (!ctx.ruleset_initial[t]) {
|
||||
ready = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ready)
|
||||
ruleset.initial_path = fallback;
|
||||
else
|
||||
warn(sprintf("homeproxy-pro: rule-set '%s' has no complete empty fallback, so it will be fetched during startup as before.", cfg.name));
|
||||
}
|
||||
}
|
||||
push(rule_set_array, ruleset);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user