Skip to content

Latest commit

 

History

History
595 lines (452 loc) · 15.4 KB

File metadata and controls

595 lines (452 loc) · 15.4 KB

VPN Protocols — Windscribe Android App

Overview

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.


Supported Protocols

# 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

1. OpenVPN UDP

Implementation: Native C++ (OpenVPN 3 library)

Module: openvpn/

Port: User-configurable (default: 443)

How It Works

  1. Tunnel Establishment:

    • Client initiates UDP handshake with server
    • TLS handshake over UDP
    • Data channel established with AES-256-GCM encryption
  2. Data Transmission:

    • IP packets encapsulated in OpenVPN protocol
    • UDP transport for speed (no TCP overhead)
    • Built-in reliability layer (retransmission, packet ordering)
  3. Advantages:

    • ✅ Faster than TCP (no head-of-line blocking)
    • ✅ Lower latency (no connection establishment overhead)
    • ✅ Efficient for streaming, gaming, VoIP
  4. Disadvantages:

    • ❌ May be blocked by strict firewalls
    • ❌ Can be throttled by ISPs detecting UDP VPN traffic
    • ❌ Not ideal for unstable networks (packet loss)

Configuration

// 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
    )
}

Use Cases

  • Default protocol for most users
  • Streaming video/audio
  • Gaming
  • General browsing on unrestricted networks

2. OpenVPN TCP

Implementation: Native C++ (OpenVPN 3 library)

Module: openvpn/

Port: User-configurable (default: 443 or 80)

How It Works

  1. Tunnel Establishment:

    • Client initiates TCP connection with server
    • TLS handshake over TCP
    • Data channel established (TCP-over-TCP)
  2. Data Transmission:

    • IP packets encapsulated in OpenVPN protocol
    • TCP transport for reliability
    • Looks like HTTPS traffic (port 443)
  3. Advantages:

    • ✅ Works through most firewalls (port 443/80)
    • ✅ Reliable delivery (TCP guarantees order)
    • ✅ Harder to detect/block (looks like HTTPS)
  4. Disadvantages:

    • ❌ Slower than UDP (TCP head-of-line blocking)
    • ❌ TCP-over-TCP meltdown (packet loss causes retransmits at both layers)
    • ❌ Higher latency

TCP-over-TCP Problem

Issue: VPN tunnel uses TCP, encapsulated traffic also often uses TCP (HTTPS, etc.)

Result: When packet loss occurs:

  1. Inner TCP (e.g., HTTPS) detects loss → retransmits
  2. Outer TCP (VPN tunnel) also detects loss → retransmits
  3. Double retransmission causes exponential slowdown

Mitigation: Use OpenVPN TCP only when UDP is blocked. Switch back to UDP when possible.

Use Cases

  • Corporate firewalls blocking UDP
  • Networks with strict port filtering
  • Countries with VPN blocking (Iran, China) — use with Stealth for better results

3. IKEv2

Implementation: Native C (StrongSwan library) + Kotlin wrapper

Module: strongswan/

Port: UDP 500 (IKE), UDP 4500 (NAT-T)

How It Works

  1. 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
  2. Data Transmission:

    • IP packets encapsulated in ESP (Encapsulating Security Payload)
    • IPSec transport (kernel-level, very fast)
    • Perfect Forward Secrecy (new keys per session)
  3. Advantages:

    • ✅ Fast (kernel-level IPSec)
    • ✅ Mobile-optimized (MOBIKE — seamless network switching)
    • ✅ Lower battery usage than OpenVPN
    • ✅ Resilient to network changes (WiFi ↔ Mobile data)
  4. Disadvantages:

    • ❌ Easier to block (fixed ports UDP 500/4500)
    • ❌ Less configurable than OpenVPN
    • ❌ May not work behind restrictive NAT

MOBIKE (IKEv2 Mobility)

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

Use Cases

  • Mobile users frequently switching WiFi ↔ mobile data
  • Battery-conscious users
  • Fast connections on unrestricted networks

4. Stealth Protocol

Implementation: OpenVPN TCP + Stunnel (TLS obfuscation)

Module: wgtunnel/ (stunnel component in Go)

Port: 443 (looks identical to HTTPS)

How It Works

  1. Double-Wrapped TLS:

    • Layer 1: Stunnel TLS tunnel (obfuscation)
    • Layer 2: OpenVPN TLS tunnel (actual VPN)
  2. 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]
    
  3. Advantages:

    • ✅ Indistinguishable from HTTPS traffic
    • ✅ Works in heavily censored countries (China, Iran)
    • ✅ Bypasses Deep Packet Inspection (DPI)
    • ✅ Port 443 always allowed
  4. Disadvantages:

    • ❌ Slowest protocol (double encryption overhead)
    • ❌ Higher CPU usage (two TLS layers)
    • ❌ Still TCP-over-TCP (retransmit issues)

Traffic Analysis

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)

Use Cases

  • Countries with VPN blocking (China, Iran, UAE)
  • Corporate networks with DPI
  • ISPs throttling VPN traffic
  • Maximum privacy (anti-surveillance)

5. WSTunnel (WebSocket Tunnel)

Implementation: OpenVPN over WebSocket

Module: wgtunnel/ (wstunnel component in Go)

Port: 443 (HTTP → WebSocket upgrade)

How It Works

  1. WebSocket Handshake:

    GET /wstunnel HTTP/1.1
    Host: server.windscribe.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    Sec-WebSocket-Version: 13
  2. 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]
    
  3. 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)
  4. Disadvantages:

    • ❌ Slow (WebSocket framing overhead)
    • ❌ Higher latency (HTTP upgrade handshake)
    • ❌ Still TCP-based (retransmit issues)

Why WebSocket?

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

Use Cases

  • Corporate networks with HTTP/HTTPS-only proxies
  • Countries blocking Stealth protocol
  • Networks with WebSocket whitelisting
  • Extreme censorship scenarios

6. WireGuard

Implementation: Native Go (WireGuard-go) compiled to Android library

Module: wgtunnel/ (wireguard component in Go)

Port: UDP user-configurable (default: 51820 or random)

How It Works

  1. Tunnel Establishment:

    • Pre-shared keys (no handshake overhead)
    • Noise protocol framework (1-RTT setup)
    • Cryptokey routing (no complex routing tables)
  2. Data Transmission:

    • ChaCha20-Poly1305 encryption
    • Curve25519 for key exchange
    • Extremely lightweight (4,000 lines of code vs 70,000 for OpenVPN)
  3. 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)
  4. 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)

Why WireGuard is Fast

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

Use Cases

  • Streaming 4K video
  • Gaming (lowest latency)
  • Mobile users (battery savings)
  • Unrestricted networks (no VPN blocking)

Protocol Selection Logic

Default Protocol (User Preference)

Settings → Connection → Protocol:

  • User selects preferred protocol
  • Saved in PreferencesHelper.selectedProtocol
  • Used for all manual connections

Automatic Fallback (On Connection Failure)

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)
    }
}

Per-Network Protocol Preferences

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)
    )
}

Protocol Switching

Manual Switch (User Action)

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

Automatic Switch (Network Change)

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)

Protocol Implementation Comparison

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

Debugging Protocol Issues

Check Active Protocol

"$ANDROID_HOME/platform-tools/adb" logcat | grep -i "WindVPN.*protocol"

Output:

WindVPNController: Selected protocol: WIREGUARD
WindVPNController: Starting WireGuard backend
WireGuardBackend: Connection established

Force Protocol via ADB

"$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

Protocol-Specific Logs

OpenVPN:

adb logcat | grep -i "openvpn"

IKEv2:

adb logcat | grep -i "ikev2\|strongswan"

WireGuard:

adb logcat | grep -i "wireguard"

Performance Benchmarks (Typical)

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.


References


Last Updated: 2026-04-22 Maintained By: Engineering Team