# How Amnezia-Client Handles Network Connections: Modular VPN Protocol Architecture

> Discover how Amnezia-Client's modular VPN protocol architecture manages network connections leveraging inheritance for configuration, process management, and kill-switch enforcement with a unified API.

- Repository: [Amnezia VPN/amnezia-client](https://github.com/amnezia-vpn/amnezia-client)
- Tags: internals
- Published: 2026-07-29

---

**Amnezia-Client manages network connections through a modular protocol architecture where each VPN implementation inherits from an abstract `VpnProtocol` class, handling configuration parsing, privileged process management, and kill-switch enforcement while exposing a uniform API to the UI layer.**

The amnezia-vpn/amnezia-client repository implements a sophisticated networking stack that abstracts platform-specific VPN implementations behind a common interface. Understanding how Amnezia-Client handles network connections reveals a design pattern that isolates protocol-specific logic—such as OpenVPN's management interface versus WireGuard's in-process tunnel controller—from the core connection management code. This architecture enables the addition of new protocols without modifying the core connection management logic.

## The Modular Protocol Architecture

At the heart of Amnezia-Client's networking layer is the abstract `VpnProtocol` class, which serves as the base for all supported protocols including OpenVPN, WireGuard, and Xray. Each protocol implementation is responsible for its own configuration parsing, environment preparation, and connection lifecycle management while exposing standardized methods like `prepare()`, `start()`, and `stop()` to the UI layer.

Protocol selection and configuration retrieval utilize utility functions defined in [`client/core/protocols/protocolUtils.cpp`](https://github.com/amnezia-vpn/amnezia-client/blob/main/client/core/protocols/protocolUtils.cpp), which handles JSON-encoded container configuration through `ProtocolUtils::key_proto_config_data()`.

## Configuration Parsing and Environment Preparation

Before establishing any connection, the client reads protocol-specific configuration data and verifies system requirements. In [`client/core/protocols/openVpnProtocol.cpp`](https://github.com/amnezia-vpn/amnezia-client/blob/main/client/core/protocols/openVpnProtocol.cpp), the `readOpenVpnConfiguration()` method (lines 11-23) extracts the VPN configuration from the container settings and writes the raw config to a temporary file.

Environment preparation occurs in the `prepare()` method (lines 84-100), which validates that required kernel modules and TAP/TUN drivers are present on the system. This step ensures Windows TAP adapters, Linux TUN interfaces, or macOS Network Extensions are ready before attempting connection establishment.

## Process Management: OpenVPN vs. WireGuard

### OpenVPN Privileged Process Spawning

OpenVPN connections rely on launching the external `openvpn` binary as a privileged process. The `OpenVpnProtocol::start()` method (lines 80-62 in [`client/core/protocols/openVpnProtocol.cpp`](https://github.com/amnezia-vpn/amnezia-client/blob/main/client/core/protocols/openVpnProtocol.cpp)) utilizes `IpcClient::CreatePrivilegedProcess()` from [`client/core/ipc.h`](https://github.com/amnezia-vpn/amnezia-client/blob/main/client/core/ipc.h) to spawn the process with elevated rights.

The implementation passes the `--management <host> <port>` argument to enable a local TCP management interface, allowing the client to monitor connection state and statistics:

```cpp
// Assume `containerConfig` holds a DockerContainer::OpenVpn entry
auto *protocol = new OpenVpnProtocol(containerConfig.getOpenVpnProtocolConfig()->toJson(), nullptr);
if (protocol->prepare() == ErrorCode::NoError) {
    protocol->start();          // launches privileged openvpn process
}

```

### WireGuard In-Process LocalSocketController

Contrasting with OpenVPN's external process model, WireGuard operates entirely in-process. The `WireguardProtocol` class defined in [`client/core/protocols/wireGuardProtocol.cpp`](https://github.com/amnezia-vpn/amnezia-client/blob/main/client/core/protocols/wireGuardProtocol.cpp) (lines 12-68) instantiates a `LocalSocketController`—a lightweight wrapper around the Mozilla WireGuard implementation.

This approach directly creates the TUN interface without spawning separate processes, reducing context-switching overhead:

```cpp
auto *protocol = new WireguardProtocol(containerConfig.getWireGuardProtocolConfig()->toJson(), nullptr);
protocol->start();               // activates the LocalSocketController

```

## Management Interface and State Monitoring

For OpenVPN, the client implements a `ManagementServer` that listens on the TCP port specified during process startup. The `OpenVpnProtocol::onReadyReadDataFromManagementServer()` method (lines 80-42 in [`client/core/protocols/openVpnProtocol.cpp`](https://github.com/amnezia-vpn/amnezia-client/blob/main/client/core/protocols/openVpnProtocol.cpp)) parses status messages, byte-count updates via the `>BYTECOUNT:` directive, and routing information.

The client automatically requests byte-count updates when reaching the `CONNECTED` state:

```cpp
protocol->sendByteCount();   // sent automatically when CONNECTED
// onReadyReadDataFromManagementServer() parses the ">BYTECOUNT:" line

```

Each protocol updates the high-level `Vpn::ConnectionState` enum—tracking states from `Preparing` and `Connecting` to `Connected`, `Reconnecting`, and `Disconnected`—and emits `protocolError` signals when fatal conditions occur.

## Kill-Switch and Routing Management

### Kill-Switch Implementation

After the VPN tunnel is established, Amnezia-Client optionally enables a kill-switch that blocks all traffic not routed through the tunnel. The implementation in `OpenVpnProtocol::updateVpnGateway()` (lines 44-89) checks the `configKey::killSwitchOption` configuration value before invoking platform-specific logic:

```cpp
// Inside OpenVpnProtocol::updateVpnGateway()
if (QVariant(m_configData.value(configKey::killSwitchOption).toString()).toBool()) {
    iface->enableKillSwitch(m_configData, netInterfaces.at(i).index());
}

```

The kill-switch behavior differs by operating system:

- **Windows**: Uses the specific network interface index from `netInterfaces.at(i).index()`
- **Linux/macOS**: Passes `0` as the interface parameter to `iface->enableKillSwitch(m_configData, 0)`

### Gateway and Route Selection

The client parses OpenVPN management messages including `ROUTE_GATEWAY` and `net_route_v4_best_gw` to discover the VPN gateway IP, storing it in the `m_routeGateway` member variable. For macOS systems, the implementation additionally invokes the system `route` command to determine the default gateway.

This logic resides in `OpenVpnProtocol::updateRouteGateway()` at lines 63-78 of [`client/core/protocols/openVpnProtocol.cpp`](https://github.com/amnezia-vpn/amnezia-client/blob/main/client/core/protocols/openVpnProtocol.cpp).

## Summary

- **Modular Architecture**: All VPN protocols inherit from the abstract `VpnProtocol` class, providing a consistent API while isolating implementation details.
- **Process Models**: OpenVPN spawns external privileged processes via `IpcClient::CreatePrivilegedProcess()`, while WireGuard uses an in-process `LocalSocketController`.
- **State Management**: OpenVPN utilizes a local `ManagementServer` TCP socket to parse status messages and byte-count updates from the `>BYTECOUNT:` directive.
- **Kill-Switch**: Automatically enabled after connection establishment using OS-specific logic in `updateVpnGateway()`, with Windows requiring interface indices while Linux and macOS use generic parameters.
- **Gateway Detection**: Routing information is extracted from management interface messages and system commands, stored in `m_routeGateway` for traffic routing decisions.

## Frequently Asked Questions

### How does Amnezia-Client support multiple VPN protocols without code duplication?

The client implements an abstract `VpnProtocol` base class that defines common interfaces for `prepare()`, `start()`, and connection state management. Each protocol-specific class (such as `OpenVpnProtocol` or `WireguardProtocol`) inherits from this base and implements only the protocol-specific logic. This design allows the UI layer to interact with any protocol through the same API, regardless of whether the underlying implementation spawns external processes or uses in-process controllers.

### What is the difference between OpenVPN and WireGuard connection handling in Amnezia-Client?

OpenVPN connections rely on launching the external `openvpn` binary as a privileged process via `IpcClient::CreatePrivilegedProcess()`, communicating through a TCP management interface (`--management` flag) to receive status updates and routing information. WireGuard connections use an in-process `LocalSocketController` that directly creates the TUN interface without spawning separate processes, resulting in lower overhead and simpler state management without requiring inter-process communication for status monitoring.

### How does the kill-switch feature work across different operating systems?

The kill-switch is implemented in `OpenVpnProtocol::updateVpnGateway()` and activates after the VPN tunnel is fully established. On Windows, the client passes the specific network interface index to `enableKillSwitch()`, ensuring only traffic through that interface is allowed. On Linux and macOS, the implementation passes `0` as the interface parameter, relying on platform-specific firewall rules to block non-tunnel traffic. The feature is controlled by the `killSwitchOption` configuration key.

### Where does Amnezia-Client store routing and gateway information?

Gateway information is parsed from OpenVPN management interface messages (such as `ROUTE_GATEWAY` and `net_route_v4_best_gw`) and stored in the `m_routeGateway` member variable of the `OpenVpnProtocol` class. For macOS clients, the default gateway is additionally determined by executing the system `route` command. This information is used to configure routing tables and enable the kill-switch after the connection is established.