Skip to content

AbdulAHAD968/react-native-wireguard-vpn-patched

Repository files navigation

react-native-wireguard-vpn-patched

A production-ready fork of react-native-wireguard-vpn (v1.0.22) with two critical Android fixes applied that are required for real-world VPN application deployment.

Author: Abdul Ahad — github.com/AbdulAHAD968 Base package: react-native-wireguard-vpn@1.0.22 by usama7365 (MIT)


Why This Fork Exists

The original react-native-wireguard-vpn package has two production-blocking issues on Android:

1. VPN Permission Not Requested

Android requires explicit user consent before any app can establish a VPN tunnel (VpnService.prepare()). The original connect() method skipped this check entirely, causing silent failures or crashes on devices where the permission had not been pre-granted. There was no mechanism for the app to know permission was needed, and no way to present the system dialog.

2. No Split Tunneling Support

The original module provided no way to exclude specific applications from the VPN tunnel. Android exposes VpnService.Builder.addDisallowedApplication() (API 21+) for this purpose, but it was not wired up in the native module. Any production VPN application is expected to offer this as a user-facing feature.


Changes in This Fork

Android — WireGuardVpnModule.kt

Fix 1: VPN Permission Request

Before the tunnel is brought up, VpnService.prepare() is now called. If the permission dialog needs to be shown, the native module:

  • Launches the system intent via startActivityForResult(intent, 1000)
  • Rejects the connect promise with error code VPN_PERMISSION_REQUIRED
  • Returns immediately — the tunnel is not started

The caller handles VPN_PERMISSION_REQUIRED and re-calls connect() after the user grants permission (via AppState change detection or equivalent).

val intent = VpnService.prepare(reactApplicationContext)
if (intent != null) {
    val activity = getCurrentActivity()
    if (activity != null) {
        activity.startActivityForResult(intent, 1000)
        promise.reject("VPN_PERMISSION_REQUIRED", "Please accept the Android VPN permission dialog.")
        return
    }
}

Fix 2: Split Tunneling via excludedApps

The connect() method now accepts an optional excludedApps string array. Each entry is an Android package name. The native module calls interfaceBuilder.excludeApplication(packageName) for each, routing those apps outside the VPN tunnel. Failures for individual packages are logged and non-fatal.

if (config.hasKey("excludedApps")) {
    val excludedApps = config.getArray("excludedApps")?.toArrayList()
    excludedApps?.forEach { app ->
        (app as? String)?.let { packageName ->
            try {
                interfaceBuilder.excludeApplication(packageName)
            } catch (e: Exception) {
                println("Failed to exclude app $packageName: ${e.message}")
            }
        }
    }
}

Installation

npm install react-native-wireguard-vpn-patched
# or
yarn add react-native-wireguard-vpn-patched

If you are migrating from react-native-wireguard-vpn, uninstall it first:

npm uninstall react-native-wireguard-vpn

Usage

import WireGuard from 'react-native-wireguard-vpn-patched';
import { AppState } from 'react-native';

// Initialize once on app start
await WireGuard.initialize();

// Basic connection
await WireGuard.connect({
  privateKey: '<client-private-key>',
  publicKey: '<server-public-key>',
  serverAddress: '203.0.113.1',
  serverPort: 51820,
  address: '10.64.0.2/32',
  allowedIPs: ['0.0.0.0/0', '::/0'],
  dns: ['1.1.1.1', '8.8.8.8'],
  mtu: 1420,
});

Handling VPN Permission (Android)

import { AppState } from 'react-native';

const connect = async () => {
  try {
    await WireGuard.connect(config);
    // tunnel is up
  } catch (err) {
    if (err.code === 'VPN_PERMISSION_REQUIRED') {
      // System dialog is now visible to the user.
      // Listen for the app coming back to foreground, then retry.
      const sub = AppState.addEventListener('change', async (state) => {
        if (state === 'active') {
          sub.remove();
          await WireGuard.connect(config); // second call succeeds if user accepted
        }
      });
    }
  }
};

Split Tunneling

Pass an excludedApps array of Android package names. Those apps will route through the device's regular internet connection, bypassing the VPN tunnel.

await WireGuard.connect({
  // ...base config...
  excludedApps: [
    'com.google.android.apps.maps',
    'com.example.bankingapp',
  ],
});

API Reference

WireGuard.initialize(): Promise<void>

Initializes the WireGuard Go backend. Must be called once before connect().

WireGuard.connect(config: WireGuardConfig): Promise<void>

Establishes the VPN tunnel. Rejects with VPN_PERMISSION_REQUIRED on first run on Android if the user has not yet granted VPN permission.

WireGuard.disconnect(): Promise<void>

Tears down the active tunnel.

WireGuard.getStatus(): Promise<WireGuardStatus>

Returns the current tunnel state.

WireGuard.isSupported(): Promise<boolean>

Returns true if WireGuard is supported on the current device.


Types

interface WireGuardConfig {
  privateKey: string;
  publicKey: string;
  serverAddress: string;
  serverPort: number;
  address?: string | string[];   // tunnel interface IP, e.g. "10.64.0.2/32"
  allowedIPs: string[];          // routing rules, e.g. ["0.0.0.0/0", "::/0"]
  dns?: string[];
  mtu?: number;
  presharedKey?: string;
  excludedApps?: string[];       // Android only — package names to bypass VPN
}

interface WireGuardStatus {
  isConnected: boolean;
  tunnelState: 'ACTIVE' | 'INACTIVE' | 'CONNECTING' | 'DISCONNECTING' | 'ERROR' | 'UNKNOWN';
  status: 'CONNECTED' | 'DISCONNECTED' | 'CONNECTING' | 'DISCONNECTING' | 'ERROR' | 'UNKNOWN';
  error?: string;
}

Requirements

Requirement Minimum Version
React Native 0.72.0
Android API 21 (Android 5)
compileSdkVersion 34
Kotlin 1.8.0

Platform Support

Platform Permission Fix Split Tunneling
Android Yes Yes
iOS N/A (handled by OS) Not yet

iOS split tunneling is not implemented in this fork. The iOS implementation is unchanged from the upstream package.


Differences from Upstream

Feature react-native-wireguard-vpn This fork
Android VPN permission request No Yes
Split tunneling (excludedApps) No Yes
VPN_PERMISSION_REQUIRED error code No Yes
TypeScript: excludedApps field No Yes
Base version 1.0.22 1.0.22-patch.2

License

MIT — same as the upstream package.

Original package copyright: usama7365
Fork modifications copyright: Abdul Ahad (ahad06074@gmail.com)

About

Production-ready React Native WireGuard VPN module with Android VPN permission handling and split tunneling support. Forked from react-native-wireguard-vpn v1.0.22.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors