# Understanding the Two OpenFlux Endpoint Roles: Tunnel Link vs. Raw Socket

> Discover the two OpenFlux endpoint roles: Tunnel Link Endpoint and Raw Socket Endpoint. Learn how they connect gVisor's virtual network to host transport.

- Repository: [p1neappleXpress/OpenFlux](https://github.com/p1neappleXpress/OpenFlux)
- Tags: deep-dive
- Published: 2026-09-14

---

**OpenFlux implements two distinct link-endpoint roles—the Tunnel Link Endpoint and the Raw Socket Endpoint—that serve as the bridge between the gVisor virtual network stack and the host's underlying transport mechanisms.**

OpenFlux is an open-source user-space VPN framework that leverages gVisor's network stack to create isolated virtual network interfaces. Understanding the two OpenFlux endpoint roles is critical for developers building cross-platform tunneling solutions, as these components separate virtual network abstraction from raw packet I/O operations.

## Tunnel Link Endpoint: The Virtual Interface

The **Tunnel Link Endpoint** acts as the virtual network interface for the gVisor stack, receiving packets injected from the tunnel ("inbound") and forwarding outbound packets to the transport layer. This role is implemented in [[`tunnel/endpoint.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/endpoint.go)](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/endpoint.go) and serves as the primary interface that the VPN client interacts with.

According to the OpenFlux source code, this endpoint implements the `stack.LinkEndpoint` interface from gVisor. Key methods include:

- **`InjectInbound`**: Injects incoming packets from the tunnel into the gVisor network stack.
- **`WritePackets`**: Called by the gVisor stack to emit outbound packets, which are then handed over to a configurable `onOutgoingPacket` callback.

The endpoint creation and callback configuration follows this pattern:

```go
// Creating the virtual tunnel endpoint
tunnelEP := tunnel.NewTunnelLinkEndpoint()

// Hook to forward outbound packets to the raw-socket transport
tunnelEP.onOutgoingPacket = func(pkt []byte) {
    // … send pkt via RawSocketEndpoint …
}

```

## Raw Socket Endpoint: The Physical Transport Layer

The **Raw Socket Endpoint** provides low-level raw-socket transport that reads and writes raw IP packets directly on the host's network interface. This endpoint handles the actual transmission of packets over the physical network, bypassing higher-level networking APIs to operate as a true user-space VPN.

OpenFlux implements this role across multiple platforms:
- Linux: [[`tunnel/rawsocket_linux.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/rawsocket_linux.go)](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/rawsocket_linux.go)
- Windows: [[`tunnel/rawsocket_windows.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/rawsocket_windows.go)](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/rawsocket_windows.go)
- macOS: [[`tunnel/rawsocket_darwin.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/rawsocket_darwin.go)](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/rawsocket_darwin.go)

Like the Tunnel Link Endpoint, the Raw Socket Endpoint implements `stack.LinkEndpoint`. It reads raw IP packets from the host interface and forwards them into the gVisor stack, while sending packets produced by the stack out through the raw socket.

## How the Endpoint Roles Interact

Together, these two endpoints enable OpenFlux to function as a **user-space VPN**. The `TunnelLinkEndpoint` provides the virtual interface that the VPN application sees, while the `RawSocketEndpoint` manages the physical network transmission.

The connection between them is established through attachment:

```go
// Raw-socket endpoint (Linux example)
rawEP := tunnel.NewRawSocketEndpoint()
rawEP.Attach(tunnelEP) // Connect raw socket to the virtual tunnel

```

This architecture separates concerns: the virtual endpoint handles gVisor stack integration and packet queuing, while the raw socket endpoint manages platform-specific kernel bypass and network interface access.

## Platform-Specific Implementation Details

While the Tunnel Link Endpoint remains platform-agnostic in [`tunnel/endpoint.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/endpoint.go), the Raw Socket Endpoint requires operating-system-specific implementations to handle raw socket creation and packet framing. Each platform-specific file implements the same `stack.LinkEndpoint` interface but uses native system calls for socket creation, binding, and raw packet I/O operations.

## Summary

- **Tunnel Link Endpoint**: The virtual network interface in [`tunnel/endpoint.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/endpoint.go) that bridges the gVisor stack with the VPN application, handling inbound injection via `InjectInbound` and outbound routing via `WritePackets` callbacks.
- **Raw Socket Endpoint**: The physical transport layer implemented in platform-specific files ([`rawsocket_linux.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/rawsocket_linux.go), [`rawsocket_windows.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/rawsocket_windows.go), [`rawsocket_darwin.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/rawsocket_darwin.go)) that performs raw IP packet I/O directly on host network interfaces.
- **Integration**: Both endpoints implement `stack.LinkEndpoint` and work together to create a complete user-space VPN solution, with the Tunnel Link handling virtual abstraction and the Raw Socket managing physical transmission.

## Frequently Asked Questions

### What are the two endpoint roles in OpenFlux?

OpenFlux defines two link-endpoint roles: the **Tunnel Link Endpoint**, which serves as the virtual network interface for the gVisor stack, and the **Raw Socket Endpoint**, which handles low-level raw IP packet transmission on the host's physical network interface. Together, these roles separate virtual network abstraction from physical transport operations.

### How does the Tunnel Link Endpoint forward outbound packets to the transport layer?

According to the source code in [`tunnel/endpoint.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/endpoint.go), the Tunnel Link Endpoint uses an `onOutgoingPacket` callback function configured during initialization. When the gVisor stack calls `WritePackets` to emit outbound traffic, the endpoint invokes this callback to hand packets over to the Raw Socket Endpoint for physical transmission.

### Which source files contain the Raw Socket Endpoint implementations?

The Raw Socket Endpoint implementations are platform-specific and located in three separate files: [`tunnel/rawsocket_linux.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/rawsocket_linux.go) for Linux systems, [`tunnel/rawsocket_windows.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/rawsocket_windows.go) for Windows, and [`tunnel/rawsocket_darwin.go`](https://github.com/p1neappleXpress/OpenFlux/blob/main/tunnel/rawsocket_darwin.go) for macOS. Each file contains OS-specific logic for creating raw sockets and performing packet I/O.

### Do both OpenFlux endpoint roles implement the same gVisor interface?

Yes, both the Tunnel Link Endpoint and the Raw Socket Endpoint implement the **`stack.LinkEndpoint`** interface from the gVisor network stack. This shared implementation pattern allows the virtual and physical transport layers to communicate seamlessly while maintaining distinct responsibilities for packet handling and network I/O.