# How OpenFlux Configures the gVisor Stack for Client Mode

> Discover how OpenFlux configures the gVisor stack for client mode. Learn about its lightweight TCP/IP stack, IP assignment, and outbound traffic routing via TunnelLinkEndpoint.

- Repository: [p1neappleXpress/OpenFlux](https://github.com/p1neappleXpress/OpenFlux)
- Tags: how-to-guide
- Published: 2026-09-14

---

**When OpenFlux runs with the `--client` flag, it initializes a lightweight userspace TCP/IP stack using gVisor in [`tunnel/tunnel.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/tunnel.go), assigns the fixed IPv4 address `10.10.10.2/24`, and installs a default route to forward all outbound traffic through a virtual NIC backed by `TunnelLinkEndpoint`.**

OpenFlux is an open-source tunneling solution that implements a pure userspace networking layer using Google's gVisor. When operating in client mode, the application creates an isolated TCP/IP environment that encapsulates and forwards connections through various transport layers toward an exit node.

## Client Mode Architecture Overview

In client mode, OpenFlux behaves like a tiny virtual machine that processes all TCP connections internally before sending them across the wire. The architecture centers on a single virtual NIC with ID `1` that connects the gVisor stack to the underlying transport mechanism.

Unlike exit node mode, the client configuration does not create raw sockets or secondary NICs. Instead, it relies entirely on the `TunnelLinkEndpoint` to move packets between the gVisor stack and the selected transport provider (Yandex, MAX, Cups.online, etc.).

## Step-by-Step gVisor Stack Configuration

The client-side initialization occurs inside the `(*TCPTunnel) setupClient` method in [`tunnel/tunnel.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/tunnel.go). This function performs three critical operations to establish network connectivity.

### Virtual NIC Initialization

The stack comes pre-configured with a NIC using ID `1`. This interface is backed by the in-process `TunnelLinkEndpoint` structure defined in [`tunnel/endpoint.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/endpoint.go). The endpoint acts as the bridge between gVisor's network layer and OpenFlux's transport abstraction, allowing packets to flow from the userspace stack into the encrypted tunnel.

### IPv4 Address Assignment

OpenFlux assigns a fixed internal address to the client: `10.10.10.2/24`. This address resides on the same subnet as the exit node (`10.10.10.0/24`), enabling direct Layer 3 communication between the two endpoints.

The implementation calls `gvisorStack.AddProtocolAddress` to register the address with the stack:

```go
clientAddr := tcpip.AddrFrom4([4]byte{10, 10, 10, 2})
t.gvisorStack.AddProtocolAddress(tunnelNIC, tcpip.ProtocolAddress{
    Protocol: ipv4.ProtocolNumber,
    AddressWithPrefix: tcpip.AddressWithPrefix{
        Address:   clientAddr,
        PrefixLen: 24,
    },
}, stack.AddressProperties{})

```

### Default Route Installation

To ensure all outbound traffic traverses the virtual tunnel, OpenFlux installs a default route covering the entire IPv4 address space. The route uses `header.IPv4EmptySubnet` (0.0.0.0/0) as its destination and points to the virtual NIC:

```go
t.gvisorStack.AddRoute(tcpip.Route{
    Destination: header.IPv4EmptySubnet,
    NIC:         tunnelNIC,
})

```

This configuration forces every TCP connection initiated by applications using the SOCKS5 proxy to flow through the gVisor stack and out via the transport layer.

## Implementation Details

The complete client setup logic resides in [`tunnel/tunnel.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/tunnel.go) between lines 44-58. The resulting stack provides full TCP semantics including retransmission, flow control, and independent buffer sizing via `SetTCPBuffers`.

```go
// tunnel/tunnel.go – client-side stack setup
func (t *TCPTunnel) setupClient(tunnelNIC tcpip.NICID) {
    // 1️⃣ Fixed client address: 10.10.10.2/24
    clientAddr := tcpip.AddrFrom4([4]byte{10, 10, 10, 2})
    t.gvisorStack.AddProtocolAddress(tunnelNIC, tcpip.ProtocolAddress{
        Protocol: ipv4.ProtocolNumber,
        AddressWithPrefix: tcpip.AddressWithPrefix{
            Address:   clientAddr,
            PrefixLen: 24,
        },
    }, stack.AddressProperties{})

    // 2️⃣ Default route – send everything via the virtual NIC
    t.gvisorStack.AddRoute(tcpip.Route{
        Destination: header.IPv4EmptySubnet,
        NIC:         tunnelNIC,
    })
}

```

Because the client operates entirely in userspace, it never requires elevated privileges for raw socket creation. The `TunnelLinkEndpoint` handles all packet encapsulation, making the stack portable across different operating systems and network environments.

## Practical Usage Examples

To start a client tunnel from your application, initialize the `TCPTunnel` with `isExitNode` set to `false`:

```go
// Example: start a client tunnel (used by the CLI)
tunnel := NewTCPTunnel(transport, /*isExitNode=*/ false)

// Dial a remote host through the gVisor client stack
conn, err := tunnel.DialTCP("example.com:80")
if err != nil {
    log.Fatalf("dial error: %v", err)
}
defer conn.Close()

// Simple HTTP request over the client-side gVisor stack
fmt.Fprintf(conn, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
io.Copy(os.Stdout, conn)

```

For SOCKS5 proxy support, the client listens on the virtual NIC and forwards connections through the tunnel:

```go
// Example: client-side SOCKS5 listener (used by the CLI)
listener, _ := tunnel.ListenTCP(1080) // listen on virtual NIC
for {
    client, _ := listener.Accept()
    go func(c net.Conn) {
        // handle SOCKS5 handshake, then forward to remote via tunnel.DialTCP
    }(client)
}

```

## Summary

- **Primary configuration file**: [`tunnel/tunnel.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/tunnel.go) contains the `setupClient` method that configures the gVisor stack.
- **Fixed client address**: The stack uses `10.10.10.2/24` to ensure subnet compatibility with the exit node.
- **Default routing**: All IPv4 traffic routes through the virtual NIC using `header.IPv4EmptySubnet`.
- **Transport integration**: The `TunnelLinkEndpoint` bridges the gVisor stack with OpenFlux's transport layer, eliminating the need for raw sockets.
- **SOCKS5 compatibility**: The client stack supports local SOCKS5 servers that transparently tunnel connections through the gVisor implementation.

## Frequently Asked Questions

### What IP address does OpenFlux assign to the client gVisor stack?

OpenFlux assigns the fixed address `10.10.10.2/24` to the client stack. This address is hardcoded in [`tunnel/tunnel.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/tunnel.go) within the `setupClient` method and places the client on the same `/24` subnet as the exit node (`10.10.10.0/24`).

### How does the client stack route traffic to the exit node?

The client installs a default route covering `header.IPv4EmptySubnet` (0.0.0.0/0) via `gvisorStack.AddRoute`, pointing to the virtual NIC. This ensures all outbound packets flow through the `TunnelLinkEndpoint`, which encapsulates them for transmission through the selected transport layer to the exit node.

### What is the difference between client mode and exit node mode in OpenFlux?

Client mode creates a userspace TCP/IP stack with a single virtual NIC for forwarding connections through a SOCKS5 proxy, while exit node mode typically requires raw socket access to handle incoming traffic from the transport layer. The client configuration in `setupClient` does not create raw sockets or secondary NICs, unlike the server-side initialization.

### Which source files are essential to the client stack configuration?

The primary files involved are [`tunnel/tunnel.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/tunnel.go) (containing `setupClient` and stack initialization), [`tunnel/endpoint.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/endpoint.go) (implementing `TunnelLinkEndpoint`), and [`transport/transport.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/transport/transport.go) (defining the interface used to send and receive raw packets). The CLI entry point in [`main.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/main.go) parses the `--client` flag to trigger this configuration path.