init
Some checks failed
CI / Rust (push) Successful in 20s
CI / Android (push) Failing after 8m35s

This commit is contained in:
2026-05-31 15:36:07 +03:30
commit 4ffbc3bffe
61 changed files with 2760 additions and 0 deletions

141
docs/architecture.md Normal file
View File

@@ -0,0 +1,141 @@
# VPN Share Architecture
## Product Contract
VPN Share shares an Android phone's active VPN with nearby devices through an
encrypted application tunnel. The receiving device runs a small companion client
that installs or opens its own virtual network interface and routes traffic to
the phone automatically.
The phone app does not replace the user's VPN provider. It preserves the active
VPN app and forwards client traffic through Android's default network routing.
## Non-Negotiable Platform Constraints
- No root and Android 8+ means no direct manipulation of system NAT, tethering
routing tables, or hotspot iptables.
- Only one Android app can be prepared as the active `VpnService` owner at a
time. The gateway app therefore cannot run a phone-side `VpnService` while
WireGuard, OpenVPN, Clash, V2Ray, or another VPN is active.
- Android `LocalOnlyHotspot` is local-only and does not provide Internet. VPN
Share uses it only as a local transport for the encrypted tunnel.
- `VpnService.protect()` must not be used for forwarded gateway sockets because
protected sockets bypass VPN routing.
## Component Diagram
```mermaid
flowchart TB
subgraph AndroidPhone[Android phone]
UI[Compose app UI]
FG[Gateway foreground service]
DET[VpnDetector]
DISC[Discovery: QR, mDNS, USB]
FFI[Rust FFI adapter]
ENG[vpnshare-core]
NAT[Userspace TCP/UDP NAT]
DNS[DNS forwarder/cache]
MTU[MTU/MSS manager]
end
subgraph Clients[Receiving devices]
DC[Desktop client]
AC[Android client VpnService]
IC[iOS Network Extension]
end
DC -->|USB/Wi-Fi/hotspot VSHP| FG
AC -->|Wi-Fi/hotspot VSHP| FG
IC -->|Wi-Fi/hotspot VSHP| FG
UI --> FG
FG --> DET
FG --> DISC
FG --> FFI
FFI --> ENG
ENG --> NAT
ENG --> DNS
ENG --> MTU
NAT -->|Android sockets| VPN[Existing active VPN app]
DNS -->|Android resolver/network DNS| VPN
VPN --> Internet[Internet]
```
## Data Flow
```mermaid
flowchart LR
App[Client application traffic] --> TUN[Client virtual NIC]
TUN --> Packetizer[Client VSHP packetizer]
Packetizer --> Crypto[Noise session encryption]
Crypto --> Transport[USB/Wi-Fi/hotspot transport]
Transport --> Gateway[Android gateway service]
Gateway --> Engine[Rust engine]
Engine --> NAT[NAT / DNS / flow control]
NAT --> Socket[Android TCP/UDP sockets]
Socket --> ActiveVpn[Existing active VPN]
ActiveVpn --> Internet
```
## Main Sequences
### USB-First Pairing
```mermaid
sequenceDiagram
participant User
participant Phone
participant Desktop
participant Engine
User->>Phone: Tap Share
Phone->>Phone: Start foreground gateway
Phone->>Phone: Verify active VPN network
Desktop->>Phone: Open USB accessory channel
Desktop->>Phone: HELLO with client public key
Phone->>User: Show pairing code and device name
User->>Phone: Approve
Phone->>Engine: Create peer lease
Phone->>Desktop: AUTH + CONFIG
Desktop->>Desktop: Configure virtual NIC/routes/DNS
Desktop->>Phone: IP_PACKET frames
Phone->>Internet: Forward via active VPN
```
### Reconnection
```mermaid
sequenceDiagram
Client->>Gateway: PING session_id, counters
Gateway--xClient: Transport interruption
Client->>Gateway: RESUME session_id, ticket
Gateway->>Gateway: Validate ticket and peer policy
Gateway->>Client: CONFIG delta
Client->>Gateway: Continue packet frames
```
## Android Domain Model
- `GatewaySession`: active share session with transport set, peer leases, VPN
status, and byte counters.
- `PeerDevice`: trusted receiving device with public key, platform, label,
first seen, last seen, and revocation status.
- `PairingRequest`: short-lived untrusted request created by USB, QR, or mDNS.
- `TransportEndpoint`: USB accessory, LAN UDP/TCP, or local-only-hotspot path.
- `TunnelLease`: client virtual IPs, DNS gateway, MTU, route set, and expiry.
## Runtime Policy
- Gateway starts only from user action and remains foreground while sharing.
- Gateway shows a persistent notification with connected peer count and a stop
action.
- If no active VPN network is detected, the app can still start local pairing
but marks Internet sharing unavailable until the VPN appears.
- Forwarded traffic never leaves the device through a protected or underlying
non-VPN socket unless the user explicitly enables a future advanced bypass
mode.
## Future Desktop Architecture
The Rust protocol/core crates are shared by Android gateway and desktop clients.
Desktop-specific modules only provide virtual NIC, installer, service manager,
tray UI, and OS network configuration.

41
docs/desktop-migration.md Normal file
View File

@@ -0,0 +1,41 @@
# Future Desktop Client Migration Plan
## Shared Core
The Rust crates are already structured so desktop clients can reuse:
- VSHP frame parsing and encoding.
- Peer/session models.
- NAT, MTU, DNS, and flow-control logic where applicable.
- Transport abstractions.
## Desktop-Specific Layers
Windows:
- Wintun adapter.
- Windows service.
- MSI/MSIX installer.
- Credential Manager key storage.
Linux:
- TUN device.
- systemd user/system service.
- NetworkManager integration where available.
- Secret Service key storage.
macOS:
- utun interface.
- launchd service.
- Keychain key storage.
- Notarized app bundle.
## Product Migration Steps
1. Keep `clients/desktop` as the CLI bring-up tool.
2. Add OS-specific virtual NIC crates under `clients/desktop/src/platform`.
3. Add installers once USB IPv4 forwarding is stable.
4. Add tray UI after service lifecycle is reliable.
5. Split GUI from service so crashes do not drop the tunnel.

113
docs/protocol.md Normal file
View File

@@ -0,0 +1,113 @@
# VSHP Protocol Specification
VSHP is the VPN Share packet tunnel protocol. It carries IP packets from a
paired client virtual interface to an Android gateway over USB, Wi-Fi, or
hotspot-local transport.
## Goals
- Encrypted by default.
- Transport independent.
- Resumable after USB or Wi-Fi interruption.
- Small enough for battery-conscious mobile operation.
- Stable enough for third-party open-source clients.
## Version
Current version: `VSHP/1`.
## Frame Header
All multibyte integers are network byte order.
```text
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| magic "VSHP" |
+---------------+---------------+-------------------------------+
| version = 1 | frame_type | flags |
+---------------+---------------+-------------------------------+
| stream_id |
+---------------------------------------------------------------+
| packet_number |
| |
+---------------------------------------------------------------+
| payload_length |
+---------------------------------------------------------------+
| payload... |
+---------------------------------------------------------------+
```
Header length: 24 bytes.
## Frame Types
- `HELLO = 1`: protocol version, platform, client public key, capabilities.
- `AUTH = 2`: Noise handshake payload or resume ticket.
- `CONFIG = 3`: virtual IP lease, DNS, MTU, routes, keepalive interval.
- `IP_PACKET = 4`: encrypted IPv4/IPv6 packet from or to the client.
- `PING = 5`: keepalive and counters.
- `RESUME = 6`: session resumption request.
- `STATS = 7`: byte, packet, loss, RTT, and battery hints.
- `CLOSE = 8`: close code and human-readable reason.
## Security Handshake
- First pairing: Noise `XXpsk2`, X25519, ChaCha20-Poly1305, BLAKE2s/HKDF.
- Known peer: Noise `IKpsk2` with stored peer static key.
- QR/USB pairing PSK is one-time and expires after 2 minutes.
- Every encrypted frame binds protocol version, peer id, transport id, and
transcript hash.
- Replay window: 256 packet numbers per direction.
- Rekey: after 1 GiB or 10 minutes, whichever comes first.
## Pairing URI
```text
vshare://pair?v=1&sid=<session>&server_pk=<base64url>&psk=<base64url>&transports=<csv>&expires=<unix>
```
Rules:
- `psk` is 128 bits minimum.
- `sid` is random and not reused.
- `expires` is enforced by the phone and client.
- QR pairing must be confirmed on the phone before a peer is trusted.
## Client Configuration Payload
```json
{
"lease_id": "base64url",
"peer_ipv4": "10.241.0.2/32",
"peer_ipv6": "fd7a:7670:7368::2/128",
"gateway_dns": "10.241.0.1",
"routes": ["0.0.0.0/0", "::/0"],
"mtu": 1280,
"keepalive_ms": 15000,
"idle_timeout_ms": 120000
}
```
IPv6 routes are omitted unless the gateway verifies upstream IPv6 through the
active VPN.
## Close Codes
- `0`: normal close.
- `1`: unsupported version.
- `2`: authentication failed.
- `3`: peer revoked.
- `4`: VPN unavailable.
- `5`: policy denied.
- `6`: protocol error.
- `7`: overload/backpressure.
## MTU Policy
- Default MTU is `1280`.
- USB may probe and raise the link MTU.
- TCP MSS is clamped to `mtu - 40` for IPv4 and `mtu - 60` for IPv6.
- Oversized packets are dropped with client-visible Packet Too Big signaling
where possible.

View File

@@ -0,0 +1,49 @@
# Repository and Package Structure
## Android Project
```text
apps/android/app
apps/android/core/domain
apps/android/core/engine
apps/android/feature/share
apps/android/service/gateway
```
## Kotlin Packages
```text
org.vpnshare.app
org.vpnshare.domain.model
org.vpnshare.engine
org.vpnshare.feature.share
org.vpnshare.gateway
org.vpnshare.gateway.discovery
org.vpnshare.gateway.transport
```
Guidelines:
- Domain module contains no Android platform APIs.
- Engine module defines Kotlin-facing core interfaces and FFI adapters.
- Gateway service module owns Android network, USB, NSD, hotspot, and
foreground-service integration.
- Feature modules own Compose UI only.
## Rust Workspace
```text
crates/vpnshare-proto
crates/vpnshare-core
crates/vpnshare-transport
crates/vpnshare-ffi
clients/desktop
```
Guidelines:
- `vpnshare-proto` owns stable wire format.
- `vpnshare-core` owns packet tunnel domain logic.
- `vpnshare-transport` owns transport-independent I/O traits.
- `vpnshare-ffi` is the narrow C ABI/JNI bridge.
- Platform clients bind the Rust core to virtual NIC and OS lifecycle APIs.

50
docs/roadmap.md Normal file
View File

@@ -0,0 +1,50 @@
# MVP Roadmap
## M0: Foundation
- Repository metadata, license, contribution docs.
- Android Gradle project and Rust workspace.
- Domain model, engine interface, foreground service skeleton.
- VSHP frame parser with unit tests.
## M1: USB-First MVP
- Android USB accessory transport.
- Desktop USB host transport for Linux and Windows.
- Encrypted pairing over USB with phone-side approval.
- IPv4 TUN/Wintun virtual interface on desktop.
- TCP, UDP, and DNS forwarding through the Android gateway.
- Basic reconnection with session resume ticket.
Acceptance:
- A Windows or Linux laptop paired by USB can browse through the phone's active
VPN without manual proxy, route, DNS, or SSH setup.
## M2: Desktop Productization
- macOS utun support.
- Installers and background service management.
- Tray UI with connect/disconnect and status.
- Peer revoke and rename UI on Android.
- Crash-safe logs without traffic content.
## M3: Wi-Fi and Hotspot
- mDNS/DNS-SD discovery.
- QR pairing for Wi-Fi.
- LocalOnlyHotspot setup flow.
- Automatic transport fallback between USB and Wi-Fi.
## M4: Android Client
- Android receiving-device app using its own `VpnService`.
- QR pairing and one-tap connect.
- Per-app include/exclude on receiving Android device.
## M5: IPv6, Performance, and iOS
- IPv6 upstream validation and route enablement.
- MTU probing, MSS clamping, and adaptive buffers.
- iOS Network Extension client.
- Battery and throughput tuning on physical-device matrix.

70
docs/security.md Normal file
View File

@@ -0,0 +1,70 @@
# Security Design and Threat Model
## Security Objectives
- Only approved devices can use the gateway.
- Local attackers cannot read or alter tunneled traffic.
- A stolen QR code expires quickly and cannot silently enroll a device.
- The gateway does not log browsing history, DNS names, or packet payloads.
- A malicious peer cannot access the phone LAN or other peers by default.
## Trust Boundaries
- Trusted: phone owner approval, installed VPN app, VPN Share signed binaries.
- Semi-trusted: paired devices after explicit approval.
- Untrusted: local Wi-Fi, hotspot participants, USB host before approval,
mDNS announcements, QR observers.
## Threats and Mitigations
| Threat | Mitigation |
| --- | --- |
| Local MITM on Wi-Fi | Noise authenticated encryption, transcript binding, peer keys |
| Stolen QR | One-time PSK, 2-minute expiry, phone-side confirmation |
| Malicious paired device | Per-peer revocation, no inbound LAN access, rate limits |
| Replay | Monotonic packet numbers and replay windows |
| DNS leak | Client DNS points to VPN Share gateway; gateway forwards through Android default VPN network |
| VPN bypass | Gateway does not protect forwarded sockets; UI warns if no active VPN is detected |
| Battery drain | Foreground service only while active, batched stats, adaptive keepalive |
| DoS by paired client | Per-peer queue limits, flow caps, overload close code |
## Data Collection Policy
Default telemetry is local only:
- Connected peer labels.
- Bytes in/out.
- Session duration.
- Error counters.
VPN Share must not collect:
- Packet payloads.
- Browsing history.
- DNS query names.
- Destination IP history outside short-lived in-memory flow tables.
## Key Storage
- Android gateway identity key is generated on first run and stored in Android
Keystore when available.
- Peer public keys and labels are stored in app-private encrypted storage.
- Desktop clients store their device key in the OS credential store where
available, with file-permission fallback.
## Play Store Compliance
The gateway mode itself does not use `VpnService`. If Android client mode is
shipped in the same package, the release must:
- Declare the `VpnService` use in the store listing.
- Show prominent in-app disclosure before Android client VPN permission.
- Explain that traffic is encrypted to the paired VPN Share gateway.
- Avoid traffic redirection for ads or monetization.
- Submit the Play Console `VpnService` declaration.
## Foreground Service Compliance
Active sharing uses a foreground service with `connectedDevice` because it
maintains live communication with external devices. The service must expose a
persistent notification and stop action.

46
docs/testing-ci-play.md Normal file
View File

@@ -0,0 +1,46 @@
# Testing, CI, and Release Compliance
## Testing Strategy
- Rust unit tests: frame parsing, NAT expiry, DNS policy, MTU calculations,
replay windows, lease allocation.
- Rust fuzzing: malformed VSHP frames and packet parser inputs.
- Kotlin unit tests: domain state reducers, pairing expiry, VPN status mapping.
- Android instrumented tests: foreground service lifecycle, notification stop
action, mDNS registration, LocalOnlyHotspot failure paths.
- Hardware integration tests: USB accessory sessions on physical Android
devices and Windows/Linux/macOS hosts.
- E2E matrix: WireGuard, OpenVPN, Clash, V2Ray; IPv4-only, IPv6-capable,
split-tunnel VPNs, VPN absent.
## CI Design
Required jobs:
- `rust`: `cargo fmt --check`, `cargo clippy --workspace -- -D warnings`,
`cargo test --workspace`.
- `android`: Gradle unit tests, lint, assemble debug.
- `security`: dependency audit, CodeQL, license scan, SBOM generation.
- `docs`: markdown lint and Mermaid render smoke test.
Physical-device CI is required before release for USB, LocalOnlyHotspot, battery,
and vendor VPN compatibility.
## Play Store Review Checklist
- Store listing explains VPN Share is a network sharing tool.
- If Android client VPN mode is bundled, `VpnService` declaration is submitted.
- In-app disclosure is separate from privacy policy and requires affirmative
action.
- No personal/sensitive traffic collection.
- No ad traffic manipulation.
- Foreground-service type declaration matches actual use.
- Target SDK follows current Play requirements at release time.
## Release Gates
- No known traffic leaks in VPN-active E2E tests.
- No crash loops on VPN revocation, USB disconnect, Wi-Fi change, or sleep.
- Packet parser fuzz corpus runs clean.
- Reproducible release build and signed SBOM.
- Third-party security review before public 1.0.

49
docs/transports.md Normal file
View File

@@ -0,0 +1,49 @@
# Transport Designs
## USB Transport
USB is the first MVP transport.
### Phone Side
- Android uses accessory-mode APIs through `UsbManager.openAccessory`.
- The gateway treats USB as an ordered byte stream carrying VSHP frames.
- The USB session is accepted only after phone-side pairing approval.
- If USB disconnects, the peer lease remains resumable for a short window.
### Desktop Side
- The desktop client acts as USB host and opens the Android Open Accessory
channel.
- The client advertises platform, app version, and public key in `HELLO`.
- After `CONFIG`, the client configures the local virtual interface and routes.
### Failure Modes
- Cable unplug: transport closes, session enters resumable state.
- Host sleeps: session ticket can resume on reconnect.
- Unknown host: no IP traffic is accepted before pairing approval.
## Wi-Fi Transport
- Discovery uses DNS-SD service type `_vpnshare._udp`.
- QR pairing remains the reliable fallback when multicast is blocked.
- The tunnel uses the same VSHP frame format as USB.
- The gateway never assumes LAN is trusted.
## Hotspot Transport
- Android app-created hotspot uses `LocalOnlyHotspot`.
- The local-only hotspot does not provide Internet; it only provides local reach
to the gateway app.
- The client still installs its virtual interface and uses VSHP for all traffic.
## Transport Selection
Default order:
1. USB if connected and paired.
2. Known Wi-Fi peer on same LAN.
3. Local-only hotspot if the user starts it from the app.
Session resume can switch transports if the peer key and resume ticket validate.