Let people keep chosen sites out of the tunnel - #76
Merged
Conversation
Asked for directly: Iranian sites should not travel to another country and back, and people were disconnecting the VPN to reach a bank or a government form and then forgetting to turn it on again. A connection people keep switching off is not protecting them. It is the user's own two lists — websites and address ranges — rather than a country switch, and that is a deliberate refusal of the obvious design. mihomo can match a country with GEOIP, but NewGEOIP calls InitGeoIP, which downloads a database when one is not on disk and returns an error when it cannot, and a rule that fails to parse fails the whole configuration. Nothing ships that database with this app. So on a filtered network, on the first connection after an install, a GEOIP rule would not send Iranian traffic around the tunnel — it would stop the tunnel existing, for exactly the people who most need it. Two lists cost nothing and cannot fail. "ir" as a domain suffix covers every .ir address on its own with no database anywhere, which is most of what this was asked for, and it also makes the feature useful to somebody whose list has nothing to do with Iran. The starting list ships off but not empty. The switch is the decision; the list is the explanation of what the switch does, and an empty one behind it teaches nothing and leaves a person guessing at the format. Off by default because an update must not move anybody's traffic without them choosing it. Order is the whole of a rule list's meaning. These are matched before the split tunnel, not after: both can send traffic direct, so under bypass the order changes nothing, but under "only these programs are tunnelled" it decides whether a tunnelled program's Iranian traffic still goes around. It should — somebody who named their bank has named it whichever program opens it. There is a test that fails if the two are swapped. Address rules carry no-resolve, or every request would resolve before routing and hand the name to whichever resolver answered, which is the leak this app closes elsewhere. What people type is not what mihomo matches, so a leading dot, a scheme, a path, a port and stray capitals are all trimmed rather than rejected: each could have meant exactly one thing, and a validation message would only be teaching someone a syntax to satisfy this field. The warning sits with the lists rather than in a tooltip. Anything listed here leaves with the user's real address, and somebody who has just sent their bank around the tunnel should know that before they close the page. Three parameters became a Routing struct on the way through. They are one decision made in three parts, read together at the one place that orders them into a rule list, which is where getting it wrong is the whole failure mode. The old two builders stay as thin wrappers, so no existing caller moved. Not touched: V2RaySettingsProfile.IranRoutingEnabled, which is on the legacy Xray profile and is read by nothing. It predates this and removing it is its own change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Iranian sites should not travel to another country and back. People were disconnecting the VPN to reach a bank or a government form and then forgetting to turn it on again — and a connection people keep switching off is not protecting them.
Settings → Sites that skip the tunnel, with two lists the user owns: websites and address ranges.
Why not GEOIP
This is the important decision, and it goes against the obvious design.
mihomo can match a country with
GEOIP,IR,DIRECT. ButNewGEOIPcallsInitGeoIP, which downloads a database when one is not on disk and returns an error when it cannot:Nothing ships that database with this app —
cores/holds the engine andwintun.dll, and thegeoip.datin the Makefile is staged for the legacy Xray core, not mihomo.So on a filtered network, on the first connection after an install, a GEOIP rule would not route Iranian traffic around the tunnel. It would stop the tunnel existing, for exactly the people who most need it.
Two lists cost nothing and cannot fail.
iras a domain suffix covers every.iraddress with no database anywhere — most of what this was asked for — and the rest is names people add as they meet them, which also makes the feature useful to someone whose list has nothing to do with Iran.The starting list ships off, but not empty
The switch is the decision; the list is the explanation of what the switch does. An empty one behind it teaches nothing and leaves a person guessing at the format. Off by default, because an update must not move anybody's traffic without them choosing it. Every entry is ordinary — editable, removable, no more privileged than one added later.
Turning the switch off keeps the lists, so testing whether a site is misbehaving does not cost retyping them.
Order is the whole of a rule list's meaning
Direct rules are matched before the split tunnel. Both can send traffic direct, so under bypass mode the order changes nothing — but under "only these programs are tunnelled" it decides whether a tunnelled program's Iranian traffic still goes around. It should: somebody who named their bank has named it whichever program opens it.
TestDirectRulesAreMatchedBeforeTheSplitTunnelfails if the two are swapped — confirmed by mutation, not just asserted.Details worth reviewing
no-resolve. Without it every request resolves before routing and hands the name to whichever resolver answered — the leak this app closes elsewhere./32(or/128).Shape
Three parameters became a
Routingstruct on the way through — one decision made in three parts, read together at the one place that orders them into a rule list.BuildProxiesYAMLandBuildProxiesYAMLWithChainstay as thin wrappers, so no existing caller moved and no test churned.Testing
12 new tests: input normalisation, rule shape and ordering, settings behaviour, and one that puts the generated rules through the real engine's parser —
ValidateConfigonly catches what fails to parse, which is exactly the class of fault a malformed rule would be. That one runs green against a locally built core.Full suite green,
go vetclean,tsc --noEmitclean, frontend builds.Noted, not touched
V2RaySettingsProfile.IranRoutingEnabledexists on the legacy Xray profile and is read by nothing — another stored-and-never-read control, like the four this codebase has already found. It predates this change and removing it is its own.🤖 Generated with Claude Code