Skip to content

Repository files navigation

OpenProtect

A modern, open-source GlobalProtect VPN client for Windows, Linux, and macOS.
CLI + GUI desktop app, written in Rust.

CIReleaseLicense


OpenProtect connects to Palo Alto Networks GlobalProtect VPN portals — including Prisma Access with cloud authentication — with both a desktop GUI and a powerful CLI (opc).

Download:Latest Release (Windows GUI + CLI, Linux CLI, macOS CLI + GUI tarballs)

macOS: CLI-first support is now in-tree. Use sudo for opc connect so libopenconnect can create the utun device. See docs/macos.md.


Desktop GUI

The GUI (opc-gui) provides a clean, modern interface for connecting to GlobalProtect VPN:

OpenProtect GUI — Connect view

Features:

  • One-click SAML — Click Connect, browser opens automatically, paste the callback URL and it auto-submits
  • Split tunnel — Enter comma-separated CIDRs, routes are applied automatically
  • System tray — Close to tray, double-click to restore, colored status icon (green/yellow/red)
  • Real-time logs — View connection logs with verbose/info toggle
  • Cancel & reconnect — Cancel mid-connection and retry without restarting
  • Dark theme — Modern slate + blue accent color scheme

Highlights

OpenProtect
Desktop GUIegui-based dark-themed app with system tray, SAML browser flow, split tunnel input.
Single binary CLIOne opc executable. No Python helpers, no webkit2gtk, no sidecar processes.
Headless SAMLBrowser-of-your-choice + local HTTP callback. Works over SSH, in containers, in systemd units.
Okta headlessDrives Okta API directly — password, TOTP, push, SMS. No browser needed.
Split tunnelBuilt-in gateway pin prevents the 20-second ESP death loop. --only Just Works.
macOS CLIHomebrew libopenconnect, native route/DNS/IPC, HIP + SAML paste fixes. connect currently runs with sudo.
Windows nativeWintun + ESP tunnel, NRPT split DNS, Named Pipe IPC.
Multi-instanceopc connect -i work + opc connect -i client-a — parallel tunnels.
OS-aware HIPPlausible host integrity profiles for Windows, macOS, and Linux.
Prometheus metrics--metrics-port 9100 for monitoring dashboards.
systemd readyTemplate unit openprotect@.service — one service per saved profile.

Quick start

Windows GUI (recommended)

  1. Download openprotect-gui-windows-x86_64.zip from Releases
  2. Extract and run opc-gui.exe as Administrator
  3. Enter your portal address, click Connect
  4. Complete SAML in the browser, right-click "click here" -> Copy Link
  5. Paste the link in the GUI — it auto-submits and connects

Windows CLI

Run in an Administrator PowerShell:

opc.exe connect vpn.example.com--only 10.0.0.0/8,172.16.0.0/12--log info

Open the printed URL in your browser, complete SAML, then POST the callback to the URL opc prints (the port is OS-assigned by default — each run gets a fresh free port, so a previous opc stuck in TIME_WAIT can't block a reconnect):

curl.exe-X POST http://127.0.0.1:<port>/callback --data-raw 'globalprotectcallback:...'

Use single quotes — PowerShell interprets & in double quotes.

Linux — split tunnel with SAML

sudo -E opc connect vpn.example.com \
--only 10.0.0.0/8,172.16.0.0/12

opc starts a local HTTP server, prints a URL. Open it in any browser, complete SAML, paste the globalprotectcallback: URL back.

macOS — source build, split tunnel with SAML

brew install pkgconf openconnect
cargo build --release --bin opc
sudo -E target/release/opc connect vpn.example.com \
--only 10.0.0.0/8,172.16.0.0/12

Use the same privilege context for control commands on that session:

sudo -E target/release/opc status
sudo -E target/release/opc disconnect

Linux — Okta headless (no browser)

sudo -E opc connect vpn.example.com \
--auth-mode okta --okta-url https://tenant.okta.com --user alice

Drives Okta's API directly. Supports password, TOTP, push, SMS.

Verify

# Should go through VPN
ping 10.0.0.1
# Should still be your home IP (not tunneled)
curl https://ifconfig.me

Install

Pre-built binaries

Download from Releases:

PlatformArchiveNotes
Windows GUIopenprotect-gui-windows-x86_64.zipopc.exe + opc-gui.exe + DLLs + Wintun. Run as Administrator.
Windows CLIopenprotect-cli-windows-x86_64.zipopc.exe + DLLs + Wintun. Run as Administrator.
Linux x86_64openprotect-cli-linux-x86_64.tar.gzRequires libopenconnect at runtime.
macOS GUI (Apple Silicon)openprotect-gui-macos-arm64.tar.gzopc + opc-gui + bundled libopenconnect dylibs. connect still runs with sudo.
macOS CLI (Apple Silicon)openprotect-cli-macos-arm64.tar.gzopc + bundled libopenconnect dylibs. connect still runs with sudo.
macOS GUI (Intel)openprotect-gui-macos-x86_64.tar.gzopc + opc-gui + bundled libopenconnect dylibs. connect still runs with sudo.
macOS CLI (Intel)openprotect-cli-macos-x86_64.tar.gzopc + bundled libopenconnect dylibs. connect still runs with sudo.

macOS release tarballs are raw unsigned binaries, not notarized .app bundles. See docs/macos.md.

Build from source — Linux

# Dependencies (Debian/Ubuntu)
sudo apt install -y libopenconnect-dev libclang-dev libssl-dev libdbus-1-dev pkg-config
# Build
git clone https://github.com/kyaky/openprotect &&cd openprotect
cargo build --release
sudo install -m 0755 target/release/opc /usr/local/bin/opc

Build from source — macOS

brew install pkgconf openconnect
git clone https://github.com/kyaky/openprotect &&cd openprotect
cargo build --release --bin opc
sudo install -m 0755 target/release/opc /usr/local/bin/opc

opc connect must currently run with sudo on macOS because libopenconnect needs elevated privileges to create the utun device.

Build from source — Windows

Click to expand

Requires MSYS2, LLVM, and a manual libopenconnect build:

# 1. In MSYS2 MINGW64 terminal: install deps + build libopenconnect
pacman -S mingw-w64-x86_64-{gnutls,libxml2,zlib,lz4,p11-kit,gmp,nettle,autotools,gcc,pkg-config,libidn2,jq,tools-git}
cd /tmp && git clone --depth 1 https://gitlab.com/openconnect/openconnect.git && cd openconnect
./autogen.sh && mkdir -p /mingw64/etc && echo "#!/bin/sh">/mingw64/etc/vpnc-script && chmod +x /mingw64/etc/vpnc-script
./configure --prefix=/mingw64 --with-gnutls --without-openssl --disable-nls--disable-docs \
--without-libpskc --without-stoken --without-libpcsclite --with-vpnc-script=/mingw64/etc/vpnc-script
make -j$(nproc) && make install
# 2. In MSYS2: generate .def file
gendef /mingw64/bin/libopenconnect-5.dll
# 3. In PowerShell: create MSVC import librarylib.exe/def:C:\msys64\tmp\libopenconnect-5.def /out:C:\msys64\mingw64\lib\openconnect.lib /machine:x64
# 4. Build openprotect$env:OPENCONNECT_DIR="C:\msys64\mingw64"$env:LIBCLANG_PATH="C:\Program Files\LLVM\bin"
cargo build --release
# 5. Build GUI (standalone, excluded from workspace)
cd bins/opc-gui && cargo build --release

Copy libopenconnect-5.dll, MinGW runtime DLLs, and wintun.dll next to opc.exe / opc-gui.exe.


CLI reference

opc connect [PORTAL] [OPTIONS]
-u, --user <USER> Username
--passwd-on-stdin Read password from stdin
--only <CIDR,CIDR,...> Split-tunnel targets (comma-separated)
--auth-mode <paste|okta> Authentication method (default: paste)
--okta-url <URL> Okta tenant URL (with --auth-mode okta)
--os <win|mac|linux> Reported OS (default: linux)
--esp[=BOOL] ESP/UDP transport (default: on)
--reconnect[=BOOL] Auto-reconnect on disconnect
--hip <auto|force|off> HIP reporting mode
--metrics-port <PORT> Prometheus endpoint
-i, --instance <NAME> Instance name for parallel tunnels
--vpnc-script <PATH> External route/DNS script
--insecure Accept invalid TLS certificates
opc status [-i NAME | --all] Show running session(s)
opc disconnect [-i NAME | --all] Tear down session(s)
opc portal add <NAME> --url <URL> [FLAGS] Save a profile
opc portal list List profiles
opc portal use <NAME> Set default
opc portal show <NAME> Show details
opc portal rm <NAME> Remove
opc diagnose <PORTAL> DNS + TCP + TLS connectivity check
opc completions <bash|zsh|fish> Generate shell completions

All commands support --json for machine-readable output.

On macOS, use the same privilege context for connect, status, and disconnect for a given session.


Comparison

openconnectyuezk v2OpenProtect
Desktop GUIGTK/WebKitegui (no deps)
Single binary CLIyes
Split tunnel without vpn-sliceyes
Headless SAML (no webview)yes
Okta headless APIyes
Windows tunnel (Wintun + ESP)experimentalyes
Windows NRPT split DNSyes
Parallel multi-instance tunnelsyes
OS-aware HIP reportspartialpartialyes
Prometheus metricsyes
systemd templatepartialyes
Client certificate authyesyes
Non-GP protocols (AnyConnect, etc.)yes
macOSyesyesCLI beta (source build)
15+ years production maturityyes

Architecture

opc connect vpn.example.com --only 10.0.0.0/8
|
v
gp-auth Prelogin -> SAML/Password/Okta -> Portal config -> Gateway login
|
v
gp-tunnel libopenconnect FFI: CSTP -> TUN device -> ESP/UDP
|
v
gp-route Install split routes + gateway pin (ip/netsh)
|
v
gp-dns Split DNS (systemd-resolved / NRPT)
|
v
gp-ipc Control socket (Unix) / Named Pipe (Windows)
CrateRole
gp-protoGP XML protocol types (no I/O)
gp-authAuth providers: Password, SAML paste, Okta headless
gp-tunnelSafe libopenconnect wrapper (session lifecycle, cancellation)
gp-openconnect-sysbindgen FFI + C variadic trampoline
gp-routeRoute management — Linux: ip(8), macOS: ifconfig/route, Windows: netsh/route.exe
gp-dnsDNS — Linux: resolvectl, macOS: networksetup, Windows: NRPT via PowerShell
gp-ipcIPC — Linux/macOS: Unix sockets, Windows: Named Pipes
gp-hipOS-aware HIP report XML generator
gp-configProfile storage (~/.config/openprotect/config.toml)
opcCLI binary
opc-guiDesktop GUI (egui + system tray)

Design rule: libopenconnect handles the tunnel. Rust handles everything else.


Multiple tunnels

sudo opc connect -i work vpn.work.com --only 10.0.0.0/8
sudo opc connect -i client-a vpn.client.com --only 172.16.0.0/12
sudo opc status --all
sudo opc disconnect -i work

Each instance gets its own TUN device, routes, DNS, and control socket.

On macOS today, connect is expected to run under sudo, so use sudo opc status / sudo opc disconnect for those sessions too.


systemd service

sudo install -m 0644 packaging/systemd/openprotect@.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now openprotect@work.service
sudo journalctl -u openprotect@work.service -f

The instance name is a saved profile. Uses Restart=on-failure with 15-second backoff.


Roadmap

  • Phase 1 — Auth + tunnel handshake (SAML, password, ESP, CSTP)
  • Phase 2 — Routes, DNS, HIP, profiles, auto-reconnect, systemd, metrics
  • Phase 3a — Okta headless, client certificates, Windows support
  • Phase 3b — Desktop GUI (egui), system tray, SAML browser flow
  • Phase 4 — macOS polish, FIDO2/YubiKey, NetworkManager, Windows service, auto-connect

Contributing

cargo fmt --all
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace

Justify new crate dependencies in the PR description.


License

Dual-licensed under Apache 2.0 or MIT at your option.

Not affiliated with Palo Alto Networks. "GlobalProtect" and "Prisma Access" are trademarks of their respective owners.

About

Modern, open-source GlobalProtect VPN client. CLI + GUI, written in Rust. Supports SAML, Okta, HIP, NRPT split DNS, Windows + Linux.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages