Embedded Mihomo Bridge
Embedded Mihomo Bridge
Swihomo vendors MetaCubeX/mihomo from the Alpha branch at
Vendor/mihomo. It is compiled as the static Vendor/MihomoCore.xcframework
and linked only by the Packet Tunnel extension.
Packet Flow Architecture
The bridge does not create another system TUN device, access a private utun file descriptor, or forward through a local SOCKS port.
NEPacketTunnelFlow <-> PacketFlowTun <-> mihomo sing-tun gVisor stack
Swift reads raw IPv4 and IPv6 packets through readPackets, sends copied data
to the Go bridge, and writes Go callback output through writePackets.
Controller Access
The external controller listens in the Packet Tunnel extension process. The app
uses NETunnelProviderSession.sendProviderMessage to request controller paths;
the extension performs the loopback HTTP request and returns the status and
body. This keeps the controller secret and loopback connection inside the
extension boundary.
Logs
The app records lifecycle, profile, tunnel, proxy, and error events in its own sandbox. The Go bridge subscribes to mihomo’s log stream and sends each event through a C callback to the extension’s own log store. The Logs screen fetches the core store through provider messages while connected and presents both sources together. App and core sources each retain their newest 1,000 entries.
Entries include source, module, level, and timestamp. The Logs screen supports keyword search plus source and level filters. App errors additionally record the Swift error type, NSError domain and code, failure reason, and underlying error when present.
Resources
The extension discovers file and http entries in the active profile’s
proxy-providers and rule-providers after it merges runtime overrides. It
resolves each provider cache within mihomo’s home directory and exposes only an
opaque resource ID to the app through provider messages. The app can read,
edit, or replace those files. It then calls mihomo’s matching provider update
endpoint through controller IPC to load file changes or download the latest
HTTP resource. Inline providers have no backing file and are intentionally
excluded.
Configuration Ownership
MihomoConfigurationBuilder continues to create the profile and runtime
override YAML data. Custom YAML is deep-merged into the profile first, then
the app’s basic overrides take precedence. Custom YAML follows ClashParty’s
override syntax: key! replaces an object, +key prepends an array, key+
appends an array, and <key> escapes a key that begins or ends with +.
When the bridge installs its packet-flow TUN factory, the mihomo fork ignores profile TUN fields that would create or configure an operating-system interface:
enable,device,stack,file-descriptor- routes, interface filters, UID filters, route marks, and auto-route options
auto-route,auto-detect-interface,auto-redirect, GSO,recvmsgx, andsendmsgx
It instead uses the Network Extension addresses 198.18.0.1/24 and
fd00::1/64, with the gVisor stack and no host routing changes. DNS hijacking,
NAT behavior, timeouts, and all non-TUN profile settings remain under the
profile’s control.
Rebuild
Run this after changing Vendor/mihomo or the Go bridge:
bash scripts/build-mihomo.sh
The script produces device, simulator, and macOS slices in
Vendor/MihomoCore.xcframework. It requires Go, Xcode command-line tools, and
the Go modules declared by the pinned mihomo source.
Signing Checklist
- Both the app and
PacketTunnelrequire the approvedpacket-tunnel-providerNetwork Extension entitlement. - Production iOS builds need an explicit App ID and provisioning profile with that entitlement.
- The linked mihomo source is GPL-3.0. Distributed builds must meet its source-distribution obligations.