Windscribe Android supports 6 VPN protocols, each optimized for different network conditions and use cases. This document explains how each protocol is implemented, when to use it, and how protocol selection/fallback works.
| # | Protocol | Speed | Stealth | Firewall Bypass | Use Case |
|---|---|---|---|---|---|
| 1 | OpenVPN UDP | ⚡⚡⚡ | ⭐ | ⭐ | Default — fast, efficient |
| 2 | OpenVPN TCP | ⚡⚡ | ⭐⭐ | ⭐⭐⭐ | Reliable, works through firewalls |
| 3 | IKEv2 | ⚡⚡⚡ | ⭐ | ⭐⭐ | Fast mobile, good for switching networks |
| 4 | Stealth | ⚡ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Maximum obfuscation (China, Iran) |
| 5 | WSTunnel | ⚡ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | OpenVPN over WebSocket (extreme censorship) |
| 6 | WireGuard | ⚡⚡⚡⚡ | ⭐ | ⭐⭐ | Fastest, modern, efficient |
Implementation: Native C++ (OpenVPN 3 library)
Module: openvpn/
Port: User-configurable (default: 443)
-
Tunnel Establishment:
- Client initiates UDP handshake with server
- TLS handshake over UDP
- Data channel established with AES-256-GCM encryption
-
Data Transmission:
- IP packets encapsulated in OpenVPN protocol
- UDP transport for speed (no TCP overhead)
- Built-in reliability layer (retransmission, packet ordering)
-
Advantages:
- ✅ Faster than TCP (no head-of-line blocking)
- ✅ Lower latency (no connection establishment overhead)
- ✅ Efficient for streaming, gaming, VoIP
-
Disadvantages:
- ❌ May be blocked by strict firewalls
- ❌ Can be throttled by ISPs detecting UDP VPN traffic
- ❌ Not ideal for unstable networks (packet loss)
// base/backend/openvpn/VpnBackend.kt
fun buildOpenVPNConfig(protocol: Protocol.UDP, port: Int): OpenVPNConfig {
return OpenVPNConfig(
proto = "udp",
remote = "$serverIP $port",
cipher = "AES-256-GCM",
auth = "SHA512",
cert = serverCertificate,
key = privateKey
)
}- Default protocol for most users
- Streaming video/audio
- Gaming
- General browsing on unrestricted networks
Implementation: Native C++ (OpenVPN 3 library)
Module: openvpn/
Port: User-configurable (default: 443 or 80)
-
Tunnel Establishment:
- Client initiates TCP connection with server
- TLS handshake over TCP
- Data channel established (TCP-over-TCP)
-
Data Transmission:
- IP packets encapsulated in OpenVPN protocol
- TCP transport for reliability
- Looks like HTTPS traffic (port 443)
-
Advantages:
- ✅ Works through most firewalls (port 443/80)
- ✅ Reliable delivery (TCP guarantees order)
- ✅ Harder to detect/block (looks like HTTPS)
-
Disadvantages:
- ❌ Slower than UDP (TCP head-of-line blocking)
- ❌ TCP-over-TCP meltdown (packet loss causes retransmits at both layers)
- ❌ Higher latency
Issue: VPN tunnel uses TCP, encapsulated traffic also often uses TCP (HTTPS, etc.)
Result: When packet loss occurs:
- Inner TCP (e.g., HTTPS) detects loss → retransmits
- Outer TCP (VPN tunnel) also detects loss → retransmits
- Double retransmission causes exponential slowdown
Mitigation: Use OpenVPN TCP only when UDP is blocked. Switch back to UDP when possible.
- Corporate firewalls blocking UDP
- Networks with strict port filtering
- Countries with VPN blocking (Iran, China) — use with Stealth for better results
Implementation: Native C (StrongSwan library) + Kotlin wrapper
Module: strongswan/
Port: UDP 500 (IKE), UDP 4500 (NAT-T)
-
Tunnel Establishment (IKE_SA):
- Client sends IKE_SA_INIT (Diffie-Hellman exchange)
- Server responds with crypto parameters
- IKE_AUTH completes authentication
- CHILD_SA created for actual VPN traffic
-
Data Transmission:
- IP packets encapsulated in ESP (Encapsulating Security Payload)
- IPSec transport (kernel-level, very fast)
- Perfect Forward Secrecy (new keys per session)
-
Advantages:
- ✅ Fast (kernel-level IPSec)
- ✅ Mobile-optimized (MOBIKE — seamless network switching)
- ✅ Lower battery usage than OpenVPN
- ✅ Resilient to network changes (WiFi ↔ Mobile data)
-
Disadvantages:
- ❌ Easier to block (fixed ports UDP 500/4500)
- ❌ Less configurable than OpenVPN
- ❌ May not work behind restrictive NAT
Feature: Automatically resume VPN connection when network changes
Flow:
User on WiFi (connected via IKEv2)
↓
WiFi disconnects, mobile data connects
↓
IKEv2 detects IP change (MOBIKE)
↓
Sends UPDATE_SA_ADDRESSES
↓
VPN reconnects with new IP (seamless, no user action)
Why It Matters: No disconnect/reconnect when switching networks
- Mobile users frequently switching WiFi ↔ mobile data
- Battery-conscious users
- Fast connections on unrestricted networks
Implementation: OpenVPN TCP + Stunnel (TLS obfuscation)
Module: wgtunnel/ (stunnel component in Go)
Port: 443 (looks identical to HTTPS)
-
Double-Wrapped TLS:
- Layer 1: Stunnel TLS tunnel (obfuscation)
- Layer 2: OpenVPN TLS tunnel (actual VPN)
-
Flow:
[Client] ↓ (OpenVPN TCP traffic) [Stunnel Client] — wraps in TLS ↓ (looks like HTTPS) [Network/Firewall] — sees only HTTPS, allows ↓ [Stunnel Server] — unwraps TLS ↓ (OpenVPN TCP traffic) [OpenVPN Server] -
Advantages:
- ✅ Indistinguishable from HTTPS traffic
- ✅ Works in heavily censored countries (China, Iran)
- ✅ Bypasses Deep Packet Inspection (DPI)
- ✅ Port 443 always allowed
-
Disadvantages:
- ❌ Slowest protocol (double encryption overhead)
- ❌ Higher CPU usage (two TLS layers)
- ❌ Still TCP-over-TCP (retransmit issues)
Regular OpenVPN TCP (detectable):
Port: 443
Pattern: OpenVPN TLS handshake (recognizable fingerprint)
DPI Detection: High (OpenVPN signatures known)
Stealth Protocol (undetectable):
Port: 443
Pattern: Standard TLS 1.3 handshake (looks like HTTPS)
DPI Detection: Very low (identical to Google/Facebook HTTPS)
- Countries with VPN blocking (China, Iran, UAE)
- Corporate networks with DPI
- ISPs throttling VPN traffic
- Maximum privacy (anti-surveillance)
Implementation: OpenVPN over WebSocket
Module: wgtunnel/ (wstunnel component in Go)
Port: 443 (HTTP → WebSocket upgrade)
-
WebSocket Handshake:
GET /wstunnel HTTP/1.1 Host: server.windscribe.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13
-
After Upgrade:
[Client] ↓ (OpenVPN traffic) [WSTunnel Client] — wraps in WebSocket frames ↓ (WebSocket over HTTPS) [Network/Firewall] — sees WebSocket (allowed, used for chat apps) ↓ [WSTunnel Server] — unwraps from WebSocket ↓ (OpenVPN traffic) [OpenVPN Server] -
Advantages:
- ✅ Bypasses firewalls blocking all VPNs
- ✅ Looks like legitimate WebSocket app (Slack, Discord)
- ✅ Works behind corporate proxies
- ✅ Harder to block than Stealth (WebSocket widely used)
-
Disadvantages:
- ❌ Slow (WebSocket framing overhead)
- ❌ Higher latency (HTTP upgrade handshake)
- ❌ Still TCP-based (retransmit issues)
Problem: Some firewalls allow HTTPS but block:
- Non-HTTP protocols on port 443
- Long-lived connections without HTTP traffic
- OpenVPN signatures (even wrapped in TLS)
Solution: WebSocket is an HTTP protocol (starts as HTTP, upgrades to persistent connection)
- ✅ Firewall sees HTTP GET request → Allowed
- ✅ After upgrade, sees WebSocket frames → Allowed (used by apps)
- ✅ OpenVPN traffic hidden inside WebSocket → Undetectable
- Corporate networks with HTTP/HTTPS-only proxies
- Countries blocking Stealth protocol
- Networks with WebSocket whitelisting
- Extreme censorship scenarios
Implementation: Native Go (WireGuard-go) compiled to Android library
Module: wgtunnel/ (wireguard component in Go)
Port: UDP user-configurable (default: 51820 or random)
-
Tunnel Establishment:
- Pre-shared keys (no handshake overhead)
- Noise protocol framework (1-RTT setup)
- Cryptokey routing (no complex routing tables)
-
Data Transmission:
- ChaCha20-Poly1305 encryption
- Curve25519 for key exchange
- Extremely lightweight (4,000 lines of code vs 70,000 for OpenVPN)
-
Advantages:
- ✅ Fastest protocol (minimal overhead)
- ✅ Modern cryptography (safer than OpenVPN)
- ✅ Lower battery usage (less CPU)
- ✅ Faster reconnects (no handshake)
- ✅ Better for mobile (handles network changes well)
- ✅ Smaller codebase (easier to audit)
-
Disadvantages:
- ❌ Easier to detect (distinctive packet patterns)
- ❌ Easier to block (UDP)
- ❌ No TCP fallback (UDP only)
- ❌ Fixed IP assignment (privacy concern — mitigated by server rotation)
OpenVPN:
- Complex state machine
- Full TLS handshake
- Cipher negotiation
- Per-packet overhead: ~40 bytes
WireGuard:
- Simple state machine
- Pre-shared keys (no handshake)
- Fixed ciphers (no negotiation)
- Per-packet overhead: ~32 bytes
Result: ~30-40% faster throughput, ~20% lower latency
- Streaming 4K video
- Gaming (lowest latency)
- Mobile users (battery savings)
- Unrestricted networks (no VPN blocking)
Settings → Connection → Protocol:
- User selects preferred protocol
- Saved in
PreferencesHelper.selectedProtocol - Used for all manual connections
Fallback Order:
1. User's preferred protocol (attempt)
↓ (fails)
2. OpenVPN TCP (port 443)
↓ (fails)
3. IKEv2
↓ (fails)
4. Stealth
↓ (fails)
5. Show error (all protocols failed)
Implementation (base/backend/managers/ProtocolConnectionManager.kt):
class ProtocolConnectionManager {
private val fallbackOrder = listOf(
Protocol.OPENVPN_TCP,
Protocol.IKEV2,
Protocol.STEALTH
)
suspend fun connectWithFallback(preferredProtocol: Protocol) {
var attempts = 0
val protocols = listOf(preferredProtocol) + fallbackOrder
for (protocol in protocols) {
if (attempts++ >= 3) break
val result = windVpnController.connect(protocol)
if (result is ConnectionResult.Success) {
return
}
delay(2000) // Wait 2s before trying next protocol
}
// All failed
emit(ConnectionError.AllProtocolsFailed)
}
}Feature: Different protocols for different networks
Use Case:
- Home WiFi: WireGuard (fast, unrestricted)
- Office WiFi: OpenVPN TCP (firewall-friendly)
- Mobile Data: IKEv2 (mobile-optimized)
Storage: NetworkInfo entity in Room database
Flow:
Network change detected
↓
AutoConnectService triggered
↓
Load network profile from database (SSID → protocol mapping)
↓
If profile exists → Use saved protocol
↓
Else → Use user's default protocol
↓
Connect with selected protocol
Implementation (base/repository/NetworkInfoRepository.kt):
suspend fun getNetworkProfile(networkId: String): NetworkProfile? {
return localDb.getNetworkInfoBySSID(networkId)
}
fun saveNetworkProfile(networkId: String, protocol: Protocol) {
localDb.insertNetworkInfo(
NetworkInfo(ssid = networkId, preferredProtocol = protocol.name)
)
}Flow:
User selects new protocol in settings
↓
SettingsViewModel.setProtocol(newProtocol)
↓
PreferencesHelper.selectedProtocol = newProtocol
↓
If VPN connected:
↓
WindVpnController.switchProtocol(newProtocol)
↓
VpnBackend.stop(error = null) // System disconnect, no whitelist
↓
VpnBackend.start(newProtocol)
↓
UI shows "Reconnecting with [newProtocol]"
Important: Pass error = null to prevent auto-secure whitelist from triggering
Requires: autoConnect preference enabled (it's an "auto" feature)
Flow:
Network change (WiFi A → WiFi B)
↓
DeviceStateReceiverWrapper detects change
↓
Clear auto-secure whitelist (DeviceStateManager)
↓
AutoConnectService.checkAutoConnect()
↓
Load network profile for WiFi B
↓
If protocol different from current:
↓
WindVpnController.switchProtocol(wifiBProtocol)
| Aspect | OpenVPN | IKEv2 | WireGuard |
|---|---|---|---|
| Code | C++ (50K LOC) | C (70K LOC) | Go (4K LOC) |
| Crypto | OpenSSL | StrongSwan | ChaCha20 |
| Handshake | Full TLS | IKE_SA + CHILD_SA | Noise (1-RTT) |
| Speed | Medium | Fast | Fastest |
| Battery | High usage | Medium | Low |
| Reconnect | Slow (5-10s) | Fast (2-5s) | Fastest (<1s) |
| Stealth | Good (TCP) | Poor (fixed ports) | Poor (UDP patterns) |
| Build | CMake + NDK | Prebuilt | Go → .so |
"$ANDROID_HOME/platform-tools/adb" logcat | grep -i "WindVPN.*protocol"Output:
WindVPNController: Selected protocol: WIREGUARD
WindVPNController: Starting WireGuard backend
WireGuardBackend: Connection established
"$ANDROID_HOME/platform-tools/adb" shell am broadcast \
-a com.windscribe.vpn.SWITCH_PROTOCOL \
--es protocol "ikev2"Valid values: openvpn_udp, openvpn_tcp, ikev2, stealth, wstunnel, wireguard
OpenVPN:
adb logcat | grep -i "openvpn"IKEv2:
adb logcat | grep -i "ikev2\|strongswan"WireGuard:
adb logcat | grep -i "wireguard"Test Setup: 1 Gbps server connection, Galaxy S21, Android 13
| Protocol | Download (Mbps) | Upload (Mbps) | Latency (ms) | CPU (%) |
|---|---|---|---|---|
| WireGuard | 850 | 820 | 12 | 8% |
| OpenVPN UDP | 620 | 590 | 18 | 15% |
| IKEv2 | 780 | 750 | 15 | 10% |
| OpenVPN TCP | 480 | 460 | 25 | 18% |
| Stealth | 320 | 310 | 40 | 22% |
| WSTunnel | 280 | 270 | 45 | 25% |
Note: Actual performance varies by server load, network conditions, and device hardware.
- AGENTS.md — Architecture overview
- docs/architecture/MODULE_STRUCTURE.md — Module details
- docs/guides/OPENVPN_UPDATE.md — OpenVPN update guide
- docs/features/AUTO_SECURE_WHITELIST.md — Auto-secure system
Last Updated: 2026-04-22 Maintained By: Engineering Team