🌴 Sync 2026-10-06 02:20:56

This commit is contained in:
github-actions[bot] committed 2026-10-06 02:20:56 +08:00
1 parent 5c201dd3af
commit 487c4fad50
111 files changed
+4641 -746

No files matched your search

@@ -67,6 +67,18 @@ export function build_context(dm, env) {
const self_mark = match(proxy_mode, /redirect/)
? (dm.infra.self_mark || '100') : null;
/* The same mark, but resolved for every mode.
*
* In TUN mode self_mark is null (see above), so no outbound carries
* `routing_mark` and sing-box's own sockets carried no mark at all - which
* meant the firewall's TUN output chain could not exempt them, and the
* node-address bypass that exists for tproxy was missing for tun. A LAN
* client (or the router itself) dialling the node's own address went back
* into the tunnel; measured earlier for tproxy ("wget hangs on the node's
* address"), fixed there, never for tun. route.default_mark stamps every
* outbound socket with this value, and the TUN chain returns on it. */
const tun_self_mark = (dm.infra.self_mark || '100');
/* proxy-mode-derived ports / TUN params */
let redirect_port, tproxy_port, tun_name, tun_addr4, tun_addr6,
tun_mtu, tcpip_stack, endpoint_independent_nat;
@@ -137,6 +149,7 @@ export function build_context(dm, env) {
* and one of them naming a tag the other never declared fails the
* whole config. Default false - an absent env must not turn into an
* optimistic "assume the file is there". */
china_ip4_ready: (env?.china_ip4_ready === true),
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
@@ -170,7 +183,7 @@ export function build_context(dm, env) {
* with no initial_path silently declared as source JSON, and a binary
* .srs fetched from a URL would then fail to parse at startup. */
ruleset_formats: (env?.ruleset_formats || {}),
self_mark, ntp_server, dns_port, mixed_port,
self_mark, tun_self_mark, ntp_server, dns_port, mixed_port,
redirect_port, tproxy_port,
tun_name, tun_addr4, tun_addr6, tun_mtu,
tcpip_stack, endpoint_independent_nat,
@@ -295,12 +295,27 @@ function append_proxy_dns(config, dm, ctx) {
});
}
/* sing-box 1.14: restore CN-IP fallback via evaluate/match_response (opt-in) */
if (ctx.cn_ip_fallback === '1') {
/* sing-box 1.14: restore CN-IP fallback via evaluate/match_response (opt-in).
* Gated on china_ip4_ready as well: the response-match rule below names
* the china-ip tag, and a rule_set list may only name declared tags -
* with the file absent the declaration is skipped too, so emitting the
* reference would make sing-box reject the whole configuration. */
if (ctx.cn_ip_fallback === '1' && ctx.china_ip4_ready) {
/* The evaluate query goes through main-dns, i.e. through the
* tunnel, and it sits on the cold path of every domain that is
* not in the direct/proxy/china lists - so it is the one DNS step
* that can add a whole round trip to a page load. Emitted bare,
* as it was, its timeout fell back to the 10 s DNS default and it
* carried no ECS; the package's own reference notes call that out
* ("拖慢首包"). A short bound plus the China ECS prefix keeps the
* fallback cheap and lets the upstream answer with a domestic
* address when it has one. */
push(config.dns.rules, {
action: 'evaluate',
server: 'main-dns',
tag: 'cn-fallback'
tag: 'cn-fallback',
timeout: '2s',
client_subnet: '223.5.5.0/24'
});
/* The response is matched by the addresses the upstream returned,
* and the address list has to be the one the route half uses for
@@ -116,8 +116,9 @@ function build_route_proxy(config, dm, ctx, direct_overrides) {
* 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') {
if (ctx.china_ip4_ready
&& (ctx.routing_mode === 'bypass_mainland_china'
|| ctx.routing_mode === 'proxy_mainland_china')) {
push(config.route.rules, {
action: 'resolve',
strategy: (ctx.ipv6_support !== '1') ? 'prefer_ipv4' : null
@@ -173,6 +174,14 @@ function build_route_proxy(config, dm, ctx, direct_overrides) {
/* The route half of the mode's default policy - the other consumer of
* ctx.proxy_fallback, and the reason dns.final and this line are
* asserted together per mode. */
/* TUN mode carries no per-outbound `routing_mark` (self_mark is null there,
* see context.uc), so sing-box's own dials - including the one to the node -
* were unmarked and the firewall's TUN output chain captured them; the
* node-address bypass existed for tproxy only. `default_mark` stamps every
* outbound socket with the same value the firewall's TUN chain exempts. */
if (match(ctx.proxy_mode, /tun/))
config.route.default_mark = strToInt(ctx.tun_self_mark);
config.route.final = ctx.proxy_fallback ? 'main-out' : 'direct-out';
/* --- proxy-mode rule_set block ----------------------------------- */
@@ -222,11 +231,19 @@ function build_route_proxy(config, dm, ctx, direct_overrides) {
* 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'
});
/* Declared only when the file is actually there - the same rule the v6
* and domain halves already follow, and the reason a fresh install no
* longer dies: a `path` that does not exist fails `sing-box check` and
* takes the whole configuration (and the service) with it. The
* rule-set is produced before generation now, so this is the
* belt-and-braces case (a failed generation, a read-only fs). */
if (ctx.china_ip4_ready) {
push(config.route.rule_set, {
type: 'local',
tag: 'china-ip',
path: HP_DIR + '/resources/china_ip4.json'
});
}
/* 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