feat: Tailscale override (proxy node + MagicDNS routing + UI) - #811
Open
yourtion wants to merge 3 commits into
Open
feat: Tailscale override (proxy node + MagicDNS routing + UI)#811yourtion wants to merge 3 commits into
yourtion wants to merge 3 commits into
Conversation
Add a flat ConfigurationOverride.Tailscale data class that the Kotlin app serializes into the override JSON. A single 'enabled' toggle controls creation (allowing a fully-default node, e.g. after clearing a one-time auth-key or relying on tsnet interactive login). The node and group names are fixed constants on the kernel side, so there is no user-configurable name. Fields: enabled, hostname, authKey, controlUrl, stateDir, exitNode, ipCidrs. Kept as a plain @serializable so it rides through the Android Parcel (IPC) path correctly.
Expand the override 'tailscale' block into a proxy node, a select group,
prepend rules and DNS wiring, all on the kernel side so the Kotlin model
stays a plain flat object.
Node and group names are fixed constants ('Tailscale' / 'Tailscale-Group')
to keep them URL-safe in the 'tailscale://<name>' nameserver-policy and
free of collisions with mihomo built-in names. Before appending, any
same-named proxy/group already present in the subscription is removed
from BOTH cfg.Proxy and cfg.ProxyGroup, since mihomo registers proxies
and groups in one shared map.
DNS wiring:
- nameserver-policy '+.ts.net' -> 'tailscale://Tailscale' (always
overwritten, so enabling the feature owns MagicDNS resolution)
- fake-ip-filter entry shaped per FakeIPFilterMode: '+.ts.net' for
blacklist, nothing for whitelist (policy short-circuits), and
'DOMAIN-SUFFIX,ts.net,real-ip' for rule mode (a bare suffix would
fail parseFakeIPRules).
Routing rules prepend DOMAIN-SUFFIX,ts.net and the CGNAT range
100.64.0.0/10 (overridable via ipCidrs) to the Tailscale-Group.
Add a Tailscale category to the override settings screen with an 'enabled' switch and editable fields for auth-key, hostname, control URL, state directory, exit node and route IP CIDRs. All fields below the switch are disabled until it is turned on. String resources added for all 8 locales (en, zh, zh-rTW, zh-rHK, ja, ko, ru, vi).
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.
Summary
Adds a first-class Tailscale override to the override settings screen. Flipping the switch creates a Tailscale proxy node + a select group + routing rules + DNS wiring, so tailnet FQDNs (
*.ts.net) and CGNAT IPs (100.64.0.0/10) reach the user's tailnet through MagicDNS without manual subscription editing.Why
CMFA already bundles the
tailscaleoutbound type (mihomo's tsnet integration), but wiring it up today means hand-editing the subscription YAML — proxy node, proxy-group, rules, and critically thenameserver-policythat points*.ts.netat thetailscale://DNS transport. The latter is easy to miss: without it, MagicDNS FQDNs silently fall through to the system DNS and fail to resolve. This PR automates all of it from the UI.What it does
ConfigurationOverride.Tailscale— a singleenabledtoggle + optional fields (authKey,hostname,controlUrl,stateDir,exitNode,ipCidrs)patchTailscaleexpands the override into a fixed-name proxyTailscale+ groupTailscale-Group+ prepended rules;patchDnsinjects thenameserver-policyand fake-ip-filter entriesenabledswitch. 8 localesDesign choices (and the bugs they avoid)
Tailscale/Tailscale-Group), not user-configurable. A user-supplied name could collide with mihomo built-ins (DIRECT,REJECT, … → "duplicate name" load error) or embed/(whichurl.Parsesplits into Host/Path, desyncing the DNS lookup key from the transport registration). Constants make both classes of bug structurally impossible.enabledis a single boolean, not "any field non-empty". Tailscale supports a fully-default node (interactive login, persistent state dir, auth-key cleared after first use). Inferring "enabled" from non-empty fields would drop the node exactly when the user wants to keep it running with defaults.cfg.Proxyandcfg.ProxyGroupbefore append. mihomo registers proxies and groups in one shared map, so a subscription-defined group namedTailscalewould clash with our proxy even though we only append a group namedTailscale-Group. Clearing both names from both slices covers every cross-category collision.nameserver-policyfor+.ts.netis always overwritten. If the subscription already has a+.ts.netpolicy pointing elsewhere, keeping it would silently leave MagicDNS broken — the opposite of what enabling the feature promises.FakeIPFilterMode:+.ts.netfor blacklist (default), nothing for whitelist (the policy short-circuits before fake-ip), andDOMAIN-SUFFIX,ts.net,real-ipfor rule mode (a bare suffix failsparseFakeIPRules).nas) are intentionally not supported. tsnet'sQueryDNSdoes not append the MagicDNS search suffix, so only full*.ts.netFQDNs (or IPs) resolve. This is documented in the code comments.Commits
feat(core): add Tailscale override model— Kotlin data classfeat(core): inject Tailscale proxy, routing and DNS via override— Go expansion + DNS wiringfeat(design): add Tailscale override UI— settings screen + stringsVerification
gofmtclean,go build -tags "android cmfa"+go vetpassapp:assembleAlphaReleasesucceeds (all 5 ABIs)*.ts.netvia MagicDNS, and routes traffic to the Tailscale-GroupNotes for reviewers
routingEnabledwas intentionally folded intoenabledafter iteration — the two-stage toggle added complexity without enabling any real use case that a single switch doesn't cover.