flutter_wireguard 0.1.4
flutter_wireguard: ^0.1.4 copied to clipboard
A Flutter plugin for managing WireGuard VPN tunnels. Currently supports Android and Linux; iOS, macOS and Windows are work-in-progress.
flutter_wireguard #
A Flutter plugin for creating and managing WireGuard VPN tunnels.
Platform support #
| Android | Linux | iOS | macOS | Windows |
|---|---|---|---|---|
| ✅ | ✅ | 🚧 | 🚧 | 🚧 |
The API is identical across supported platforms (multi-tunnel, status streaming, backend introspection, key generation).
Install #
dependencies:
flutter_wireguard: ^0.1.0
Usage #
The API is a small set of top-level functions — no facade class to instantiate.
import 'package:flutter_wireguard/flutter_wireguard.dart' as wg;
Start / stop a tunnel #
await wg.start(
'wg0',
'''
[Interface]
PrivateKey = <your-private-key>
Address = 10.0.0.2/32
DNS = 1.1.1.1
[Peer]
PublicKey = <server-public-key>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0
''',
);
await wg.stop('wg0');
Query / stream tunnel status #
final TunnelStatus s = await wg.status('wg0');
print('${s.name} ${s.state} rx=${s.rx} tx=${s.tx} hs=${s.handshake}');
wg.statusStream().listen((TunnelStatus s) {
print('${s.name}: ${s.state}'); // TunnelState.up | down | toggle
});
List active tunnels #
final List<String> names = await wg.tunnelNames();
Backend introspection #
final BackendInfo b = await wg.backend();
// b.kind: BackendKind.kernel | userspace | unknown
// b.detail: e.g. "WgQuickBackend (kernel)" / "wg-quick + wireguard-go"
Key generation (pure Dart, no native call) #
final kp = await wg.generateKeyPair(); // base64 X25519
final pub = await wg.publicKeyFromPrivate(kp.privateKey);
final psk = wg.generatePresharedKey();
Platform notes #
Android (minSdk 26) #
The WireGuard Go runtime runs in a dedicated :wireguard process (isolated from the main Flutter process) so the JVM never holds two Go runtimes at once. VPN permission is requested automatically when the plugin attaches to an activity.
Required manifest entry:
<uses-permission android:name="android.permission.INTERNET" />
BIND_VPN_SERVICE is contributed by the WireGuard library.
Linux #
Linux uses the system wg-quick tool, automatically falling back to a userspace implementation when the in-kernel module is unavailable.
Required:
wireguard-tools(provideswg,wg-quick)- A
resolvconfprovider — eitheropenresolvorsystemd-resolved— only if your config setsDNS = ....wg-quickcallsresolvconfto install/restore DNS servers and will fail at start if neither is present. Configs without aDNS =line work fine without it. - One of the following for kernel-less systems:
wireguard-go,boringtun-cli, orboringtun polkit(providespkexec) when the calling user is not root
The plugin runs wg-quick directly when it is root; otherwise it elevates via pkexec. The pkexec child is persistent — one prompt at the first privileged op covers every subsequent Start / Stop / Status for the lifetime of the app. Status polls also avoid prompting by reading byte counters from /sys/class/net/<iface>/statistics/{rx,tx}_bytes (world-readable). Tunnel configurations are written to $XDG_RUNTIME_DIR/flutter_wireguard/<name>.conf with 0600 permissions; tunnel names are validated (max 15 chars, [A-Za-z0-9_=+.-]) before reaching the shell.
Packaging for Linux distributions
The plugin discovers wg-quick, wg, pkexec, and the userspace impl (wireguard-go / boringtun-cli / boringtun) on $PATH at runtime. Bundling is therefore a packaging-layer concern, not a plugin-layer one. Recipes for the common formats:
- Debian / Ubuntu (
.deb) —Depends: wireguard-tools, policykit-1indebian/control;wireguard-toolsalreadyRecommends: openresolv | systemd-resolvedso DNS works out of the box. AddRecommends: wireguard-gofor users on kernels without the in-tree module. - Fedora / RHEL (
.rpm) —Requires: wireguard-tools, polkitin your spec; addRequires: systemd-resolved(oropenresolvfrom EPEL) if your tunnels useDNS =. Optional:Recommends: wireguard-toolsandwireguard-gofrom RPM Fusion. - Arch (
PKGBUILD) —depends=('wireguard-tools' 'polkit'),optdepends=('openresolv: DNS handling for wg-quickDNS =' 'wireguard-go: userspace impl for kernels without the module'). - Snap — add
wireguard-toolstostage-packagesand thenetwork-controlinterface plug. Buildwireguard-gofrom source as a separatepartsentry if needed. - AppImage — bundle
wireguard-toolsandwireguard-goinside the AppDir; prepend$APPDIR/usr/bintoPATHbefore launch. The host still needs polkit. - Flatpak — build
wireguard-toolsand (optionally)wireguard-goasmodulesin your manifest. Note thatpkexecdoes not work from inside the sandbox; either ship a system D-Bus helper, talk to polkit directly, or setFLUTTER_WIREGUARD_ELEVATE=flatpak-spawn --host pkexecto escape the sandbox for elevation. Permissions:--share=network,--device=all(for/dev/net/tun),--filesystem=xdg-run/flutter_wireguard:create.
Customising privilege elevation
The environment variable FLUTTER_WIREGUARD_ELEVATE lets the embedding app override how the plugin acquires CAP_NET_ADMIN:
| Value | Behavior |
|---|---|
| unset or empty | Default: spawn pkexec sh -c <loop> (one prompt per app session). |
none |
Skip elevation entirely. The plugin runs wg-quick/wg directly. Use when the app already has CAP_NET_ADMIN (e.g. a system service started by systemd with AmbientCapabilities=CAP_NET_ADMIN). |
| any other string | Whitespace-split argv prefix that wraps the persistent shell — e.g. flatpak-spawn --host pkexec to escape a flatpak sandbox, or sudo -A for a custom askpass helper. |
iOS / macOS / Windows #
⚠️ Not yet implemented.
Example #
A full-featured example app lives under example/ — keypair generation, saved tunnels, live status, backend banner. Run it with:
cd example
flutter run -d linux # or: -d <android-device-id>
Testing #
# Dart unit tests
flutter test
# Android Kotlin (Robolectric) tests
cd example/android && ./gradlew :flutter_wireguard:testDebugUnitTest
# Linux native (gtest) tests
cmake -S linux -B linux/build -Dinclude_flutter_wireguard_tests=ON
cmake --build linux/build && ctest --test-dir linux/build --output-on-failure
# Integration tests (require a device / desktop)
cd example && flutter test integration_test
License #
See LICENSE.