Chute Devs

Coming From Another Client, Part Two: What Changed Since

Hello everyone.

Two weeks ago we published the guide to moving your config to Chute — what Chute reads from Surge, Shadowrocket, Clash/mihomo and sing-box, what it converts, and the “does not cross” list. That list is already shorter. Here is what changed since.

The Big One: Proxy Chains

The top item on the “does not cross” list was chaining — mihomo’s dialer-proxy, sing-box’s detour, Clash relay groups, Surge’s underlying-proxy. All of them were parsed, preserved, reported — and ignored, with the policy connecting directly to its own server.

That is over. Chute now supports proxy chains: a policy can ride another policy as its upstream, relay groups import as relay groups with their member order intact, and a group can send its whole membership through one upstream. The semantics — fail-closed refusals, loop detection, which protocols cannot be chained, the sixteen-level nesting cap — are the subject of their own post last week. If your imported config kept a warning about dialer-proxy, reload it: the chain is in the profile now.

Shadowrocket’s random Groups Are First-Class

They used to keep their members and run as a select group with a notice. Now a random group does what the name says: every new connection picks a member at random, with equal probability and no memory of the previous pick. UDP picks only among members that can relay UDP — if none can, your udp-policy-not-supported-behaviour setting decides, as everywhere else. Members accept the same forms as a select group, including policy-provider: references, and a member’s own underlying-proxy is kept.

There is nothing to switch on a random group — the web console and the control API list its members but refuse to change the pick — and HIDDEN=true hides it from every app’s list like any other group.

mihomo SUB-RULE Expands Instead of Dying

mihomo configs that use SUB-RULE,(condition),name with a sub-rules: map used to lose those rules. Now the import expands them into ordinary rules: each rule in the named branch becomes AND,((condition),(rule)),POLICY, and a branch’s own MATCH,X becomes condition,X. Nested sub-rules stack their conditions, up to eight levels deep. A branch that does not exist, or one that references a branch currently being expanded, is skipped with a conversion warning instead of silently disappearing.

Plain DNS Over TCP

A resolver written tcp://8.8.8.8 now queries over TCP (RFC 7766), with the port defaulting to 53 — for networks that drop or tamper with UDP DNS. It is accepted everywhere an ordinary resolver is accepted: dns-server, the dedicated pools (direct-dns-server, proxy-dns-server, fallback-dns-server), SSID-suspend entries, and the server: list of a [Host] entry. Like plain resolvers, it takes an IP address only — no hostnames, no system — and per-server options such as #disable-qtype= and a #proxy suffix apply as usual.

One boundary worth knowing: Surge’s encrypted-dns-server line still ignores tcp:// with a notice, since it is a list of encrypted resolvers. Put tcp:// entries in dns-server or a dedicated pool.

jq Body Rewrites

Surge’s http-request-jq and http-response-jq programs now run: a jq program replaces the pattern/replacement pair in a body-rewrite rule, and the body is treated as JSON. The failure semantics are the careful part — a body that is not JSON, a program that throws, or a program with no output leaves the body unchanged; an invalid program is reported and skips that one rule, never the whole config. jq and oniguruma ship inside the engine, so nothing is downloaded at runtime. (On Chute Android, jq runs on jackson-jq, which caps output at 4096 results or 4 MB and lacks a few jq 1.7 built-ins — a program using one of those leaves the body unchanged rather than half-transforming it.)

The policy editors on iOS and macOS gained fields for jq rewrites, so a module’s jq lines survive a round trip through the editor instead of being dropped as unrepresentable.

ShadowTLS Verifies Its Cover Certificate

A ShadowTLS policy that names an sni now fetches and verifies the cover certificate against that name — the behaviour the server side of the protocol expects, and what Shadowrocket and mihomo do. Without an sni there is nothing to check against, and the connection proceeds as before.

The tun Route Keys

mihomo’s route-address and route-exclude-address map to tun-included-routes and tun-excluded-routes, and both keys are now honoured on both enhanced-mode types, on iPhone and Mac. On the Mac this is the only way to pull a LAN range into enhanced mode — tun-excluded-routes alone does nothing there.

Still Not Crossing

Everything else from part one stands: Loon and Quantumult X profiles, the unimplemented protocols (Snell, Hysteria v1, Juicity and friends — their lines are preserved and their references fail closed), mode: global / mode: direct collapsing to rule mode, process-name rules staying macOS-only, and a converted profile remaining a static snapshot rather than a live subscription.

The full reference for everything above — exact parameters, refusal rules, import mappings — is in the Chute Manual. If you imported a config in the last few weeks and one of these features was the reason you held off, it is worth importing again: an import always writes a new profile, and your old one stays put.

Thanks.

Chute Devs