mirror of
https://github.com/StikDebug/StikDebug.git
synced 2026-10-15 20:10:30 +00:00
docs: design embedded loopback vpn
This commit is contained in:
parent
8e0c396d06
commit
db4b808d43
1 changed files with 169 additions and 0 deletions
|
|
@ -0,0 +1,169 @@
|
||||||
|
# Embedded Loopback VPN Design
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Remove StikDebug's dependency on the separately installed LocalDevVPN app by embedding an equivalent local Network Extension Packet Tunnel, while removing WiFi as a hard prerequisite and preserving the existing RPPairing/RSD feature set.
|
||||||
|
|
||||||
|
## Context and constraints
|
||||||
|
|
||||||
|
StikDebug currently creates RPPairing tunnels to `DeviceConnectionContext.targetIPAddress` on port `49152`. The default address is `10.7.0.1`, which is supplied by the external LocalDevVPN virtual interface. JIT, app discovery, device information, debugging, syslog, and location simulation all ultimately depend on this path.
|
||||||
|
|
||||||
|
The existing app contains WiFi-only DNS diagnostics and user-facing WiFi error text, but the actual RPPairing FFI calls do not inspect WiFi. The replacement must therefore validate tunnel readiness and RSD connectivity rather than interface type. Internet-dependent DDI downloads remain separate from the local RSD transport.
|
||||||
|
|
||||||
|
The reference implementation is the LocalDevVPN Packet Tunnel design: configure a point-to-point IPv4 interface, include only the peer route (`10.7.0.1/32` by default), exclude the default route, and exchange packets through `NEPacketTunnelProvider.packetFlow`. WLocApp is used only as a reference for target layout, VPN manager lifecycle, App Group sharing, and entitlements; its location proxy is out of scope.
|
||||||
|
|
||||||
|
## Approved approach
|
||||||
|
|
||||||
|
### 1. Add an embedded Packet Tunnel target
|
||||||
|
|
||||||
|
Add a `StikDebugTunnel` app extension target to `StikDebug.xcodeproj` with:
|
||||||
|
|
||||||
|
- `PacketTunnelProvider` subclassing `NEPacketTunnelProvider`.
|
||||||
|
- A small constants/configuration module shared with the main app.
|
||||||
|
- Extension `Info.plist` declaring `com.apple.networkextension.packet-tunnel`.
|
||||||
|
- Packet Tunnel Network Extension entitlement.
|
||||||
|
- The existing app group entitlement shared by the main app and extension.
|
||||||
|
|
||||||
|
The provider accepts interface and peer IP values from `NETunnelProviderProtocol.providerConfiguration` and/or `startVPNTunnel(options:)`. It configures an IPv4 interface, includes only the peer IP route, excludes the default route, then swaps the source and destination IPv4 addresses for packets read from `packetFlow` before writing them back. This reproduces the LocalDevVPN loopback behavior without carrying ordinary Internet traffic through StikDebug.
|
||||||
|
|
||||||
|
The implementation will be an equivalent implementation rather than copying unrelated WLocApp proxy code. If LocalDevVPN source code is reused verbatim, its license and attribution must be preserved; StikDebug is already AGPL-3.0.
|
||||||
|
|
||||||
|
### 2. Add main-app VPN lifecycle management
|
||||||
|
|
||||||
|
Add `StikDebugVPNManager` in the main app. It owns one `NETunnelProviderManager` identified by the embedded extension bundle identifier and provides:
|
||||||
|
|
||||||
|
- `prepare()` to load or create the saved VPN profile.
|
||||||
|
- `start()` to save/reload the profile and call `startVPNTunnel(options:)`.
|
||||||
|
- `stop()` to stop the active tunnel.
|
||||||
|
- `status` derived from `NEVPNStatus`.
|
||||||
|
- `isTunnelReady()` for non-UI callers.
|
||||||
|
|
||||||
|
The manager uses `providerConfiguration` for the interface IP and peer IP, defaults to interface `10.7.0.0` and peer `10.7.0.1`, and configures an on-demand rule only for the peer address. It must not require WiFi or enable a full-device default route. Existing VPNs are not silently destroyed; if another VPN is active, the manager reports a clear conflict and waits for the user to stop it.
|
||||||
|
|
||||||
|
The app group is reserved for shared tunnel configuration and diagnostics. Pairing files remain in the existing app-owned store unless the extension later needs them; the Packet Tunnel itself does not read pairing material.
|
||||||
|
|
||||||
|
### 3. Gate the RSD layer on transport readiness
|
||||||
|
|
||||||
|
Keep `tunnel_create_rppairing` as the RSD transport primitive. Before calling it, `JITEnableContext` ensures the embedded VPN profile is prepared and active. The FFI call still targets the configured peer IP and port `49152`.
|
||||||
|
|
||||||
|
The transport readiness abstraction will expose:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
enum DeviceTransportState {
|
||||||
|
case unavailable(String)
|
||||||
|
case starting
|
||||||
|
case ready
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol DeviceTransport {
|
||||||
|
func ensureReady() throws
|
||||||
|
func makeRPPairingTunnel(hostname: String) throws -> RPPairingTunnel
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The concrete implementation wraps `StikDebugVPNManager` plus the existing FFI tunnel creation. `JITEnableContext` remains responsible for lifecycle and FFI handle ownership, while callers no longer need to know whether the external or embedded VPN is present.
|
||||||
|
|
||||||
|
All direct RPPairing entry points must use this path, including:
|
||||||
|
|
||||||
|
- the main RSD/debug session;
|
||||||
|
- debug heartbeat tunnels;
|
||||||
|
- syslog relay tunnels;
|
||||||
|
- location simulation in `IdeviceFFIBridge.swift`.
|
||||||
|
|
||||||
|
### 4. Replace WiFi diagnostics with transport diagnostics
|
||||||
|
|
||||||
|
Remove WiFi from the connection prerequisite and error copy. The old `DNSChecker` will either be removed if unused or reduced to an explicit Internet diagnostics utility that reports DNS/Internet status without blocking RSD.
|
||||||
|
|
||||||
|
Connection errors will distinguish:
|
||||||
|
|
||||||
|
- VPN profile missing or permission denied;
|
||||||
|
- VPN starting or disconnected;
|
||||||
|
- peer route/RPPairing connection failed;
|
||||||
|
- invalid or expired pairing file;
|
||||||
|
- RSD service handshake failure;
|
||||||
|
- ordinary Internet unavailable for DDI/news/map requests.
|
||||||
|
|
||||||
|
No code path will call `NWPathMonitor(requiredInterfaceType: .wifi)` to decide whether JIT, debugging, syslog, or location simulation may proceed.
|
||||||
|
|
||||||
|
### 5. Preserve existing user flows
|
||||||
|
|
||||||
|
The existing start-tunnel call sites continue to call `startTunnelInBackground`, but that function delegates to the embedded VPN manager before establishing RSD. Settings may expose the embedded VPN status and a stop control, while the existing custom peer IP setting remains supported.
|
||||||
|
|
||||||
|
The README and localized strings will describe the built-in VPN, remove the external LocalDevVPN installation step, and explain that Internet is only needed when downloading uncached DDI files or using network-backed content.
|
||||||
|
|
||||||
|
## Data flow
|
||||||
|
|
||||||
|
```text
|
||||||
|
User action / background reconnect
|
||||||
|
|
|
||||||
|
v
|
||||||
|
StikDebugVPNManager.prepare/start
|
||||||
|
|
|
||||||
|
v
|
||||||
|
StikDebugTunnel PacketTunnelProvider
|
||||||
|
10.7.0.0 interface, route 10.7.0.1/32
|
||||||
|
|
|
||||||
|
v
|
||||||
|
JITEnableContext.ensureReady
|
||||||
|
|
|
||||||
|
v
|
||||||
|
tunnel_create_rppairing(10.7.0.1:49152)
|
||||||
|
|
|
||||||
|
v
|
||||||
|
RSD services: apps, device info, debug proxy, syslog, location
|
||||||
|
```
|
||||||
|
|
||||||
|
The tunnel includes only the peer route, so ordinary network requests continue to use WiFi or cellular according to iOS routing. A cached-DDI JIT session should not need an Internet connection; a first-time DDI download still does.
|
||||||
|
|
||||||
|
## Error handling and lifecycle
|
||||||
|
|
||||||
|
- VPN profile creation and permission errors are surfaced before FFI tunnel creation.
|
||||||
|
- Concurrent start requests are coalesced by the VPN manager and `JITEnableContext`.
|
||||||
|
- A disconnected/reasserting VPN invalidates cached RSD handles; the next operation recreates the tunnel.
|
||||||
|
- Stopping or losing the VPN frees RSD/adapter handles and sets the published connection state to disconnected.
|
||||||
|
- Background reconnect attempts are allowed to start the embedded profile, but UI permission prompts remain user-driven.
|
||||||
|
- No automatic default-route VPN behavior is added.
|
||||||
|
|
||||||
|
## Testing strategy
|
||||||
|
|
||||||
|
### Unit tests
|
||||||
|
|
||||||
|
Test pure configuration and state behavior without Network Extension runtime:
|
||||||
|
|
||||||
|
- default interface/peer values;
|
||||||
|
- custom peer IP propagation;
|
||||||
|
- peer route is `/32` and default route is excluded;
|
||||||
|
- WiFi interface status cannot block transport readiness;
|
||||||
|
- error mapping preserves invalid pairing versus tunnel unavailable;
|
||||||
|
- repeated `ensureReady()` does not create duplicate starts.
|
||||||
|
|
||||||
|
### Build/static checks
|
||||||
|
|
||||||
|
- Verify the main app and extension targets are present in the Xcode project.
|
||||||
|
- Verify both entitlements contain the required Network Extension and App Group entries.
|
||||||
|
- Verify the extension Info.plist has the packet-tunnel extension point.
|
||||||
|
- Verify no RSD/JIT call site requires `NWPathMonitor(.wifi)` or references external LocalDevVPN installation.
|
||||||
|
- Run the available Swift test/build commands on the development machine.
|
||||||
|
|
||||||
|
### Real-device acceptance matrix
|
||||||
|
|
||||||
|
Test on a physical supported iOS device with a valid pairing file:
|
||||||
|
|
||||||
|
1. WiFi on, cellular off, embedded VPN on.
|
||||||
|
2. WiFi off, cellular on, embedded VPN on.
|
||||||
|
3. WiFi and cellular both off, embedded VPN on.
|
||||||
|
4. WiFi and cellular both on.
|
||||||
|
5. VPN stopped or permission denied.
|
||||||
|
6. DDI cached with no Internet.
|
||||||
|
7. DDI missing with cellular-only Internet.
|
||||||
|
8. Background/foreground transition and VPN restart.
|
||||||
|
|
||||||
|
Acceptance requires app discovery, JIT enablement, device info, debug session/heartbeat, syslog, and location simulation to continue using the same pairing and RSD behavior.
|
||||||
|
|
||||||
|
## Risks and non-goals
|
||||||
|
|
||||||
|
- Network Extension entitlement and distribution/signing support may be unavailable for some sideload profiles. The project will expose signing failures clearly, but cannot solve Apple entitlement policy in code.
|
||||||
|
- The packet swap loop is intentionally limited to the LocalDevVPN-compatible peer route; this is not a general-purpose VPN or Internet proxy.
|
||||||
|
- USB/usbmuxd transport is not part of this change.
|
||||||
|
- WLocApp's HTTPS interception, certificate installation, DNS proxy, and location response mutation are not part of this change.
|
||||||
|
- The final no-WiFi result cannot be claimed until the real-device matrix is executed.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue