OpenFlux Client Routing Model: Virtual Network Stack and Traffic Flow Implementation
The OpenFlux client routes all TCP traffic through a private tunnel interface using a gVisor-based virtual network stack with a static 10.10.10.2/24 address and a default 0.0.0.0/0 catch-all route.
The OpenFlux client from the p1neappleXpress/OpenFlux repository constructs its own isolated network stack rather than relying on system-level VPN interfaces. By embedding a complete TCP/IP implementation using Google's gVisor, the client captures outbound connections at the application layer and forwards them through pluggable transport layers. This routing model ensures consistent behavior across platforms while maintaining strict control over packet flow.
Virtual Network Stack Initialization
The routing architecture begins in tunnel/tunnel.go with the NewTCPTunnel function, which instantiates a gVisor stack.Stack configured specifically for IPv4 and TCP protocols. This virtualized network layer operates independently of the host operating system's networking stack, allowing OpenFlux to manage connections without modifying system routing tables.
t.gvisorStack = stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol},
TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol},
})
The stack initialization occurs at lines 58-63 in tunnel/tunnel.go, establishing the foundation for all subsequent routing decisions.
Tunnel Interface Configuration and Addressing
Once the virtual stack exists, OpenFlux creates a Network Interface Card (NIC) with ID 1 and attaches it to a TunnelLinkEndpoint. This endpoint serves as the bridge between the virtual TCP/IP stack and the physical transport implementation, forwarding outbound packets to the configured transport.Transport interface (see lines 72-80 in tunnel/tunnel.go).
Static Client Address Assignment
For standard client instances operating in non-exit node mode (isExitNode == false), the setupClient method assigns a predetermined internal address. The client configures itself with 10.10.10.2/24 on the tunnel NIC, creating a predictable private subnet that remains consistent regardless of underlying network changes.
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{})
This address assignment appears at lines 39-45 in tunnel/tunnel.go, establishing the client's identity within the virtual network segment.
Default Route Installation and Traffic Capture
To ensure comprehensive traffic interception, the OpenFlux client installs a catch-all route that redirects all IPv4 destinations into the tunnel. The implementation adds a default route for 0.0.0.0/0 pointing to the tunnel NIC, effectively capturing every outbound TCP connection attempt.
t.gvisorStack.AddRoute(tcpip.Route{
Destination: header.IPv4EmptySubnet,
NIC: tunnelNIC,
})
This route configuration at lines 49-53 in tunnel/tunnel.go ensures that packets destined for any external address traverse the virtual interface rather than the host's standard network adapter.
Connection Handling and Routing Logic
When applications initiate outbound TCP connections through the OpenFlux client, the routing model determines packet paths based on instance configuration and destination addressing.
DialTCP Implementation
The DialTCP method leverages the gVisor stack to handle TCP handshakes internally before transmitting encapsulated packets. The implementation selects the appropriate NIC based on operating mode: NIC ID 1 for standard clients and NIC ID 2 for exit nodes (see lines 55-71 in tunnel/tunnel.go). This distinction allows the same codebase to function as either a tunnel client or traffic termination point.
Transport Layer Integration
After the virtual stack processes packets, the TunnelLinkEndpoint forwards them to the pluggable transport layer defined in transport/transport.go. This abstraction enables the routing model to support multiple delivery mechanisms—including raw sockets, Windivert on Windows, or custom protocols—without modifying the core TCP/IP logic.
Practical Implementation Example
The following example demonstrates creating a client tunnel and routing traffic through the virtual interface:
// Create a client tunnel (non-exit node)
tunnel := tunnel.NewTCPTunnel(myTransport, false)
// Open a TCP connection to a remote host via the tunnel
conn, err := tunnel.DialTCP("example.com:443")
if err != nil {
log.Fatalf("dial error: %v", err)
}
defer conn.Close()
// Listen for incoming connections on port 1080 (SOCKS5 proxy)
ln, _ := tunnel.ListenTCP(1080)
for {
c, _ := ln.Accept()
go handleProxy(c) // your proxy handling logic
}
This pattern appears in export_ios.go through the OpenFluxStartClient function, which exposes the routing model to iOS applications.
Summary
- Virtual Stack Architecture: OpenFlux uses gVisor's
stack.Stackintunnel/tunnel.goto isolate TCP/IP processing from the host operating system. - Fixed Client Addressing: Non-exit nodes receive the static IP 10.10.10.2/24 assigned through
setupClient, ensuring predictable internal routing. - Comprehensive Traffic Capture: A default route for 0.0.0.0/0 forces all IPv4 traffic through the virtual tunnel NIC (ID 1).
- Pluggable Transport Bridge: The
TunnelLinkEndpointconnects virtual packets to physical networks via thetransport.Transportinterface. - Dual-Mode Operation: The routing model distinguishes between client mode (NIC 1) and exit node mode (NIC 2) through conditional logic in
DialTCP.
Frequently Asked Questions
How does OpenFlux ensure all traffic routes through the tunnel?
The client installs a catch-all route matching 0.0.0.0/0 (represented as header.IPv4EmptySubnet in the source) that points exclusively to the tunnel NIC. This default route overrides standard routing decisions within the gVisor stack, ensuring every outbound IPv4 packet traverses the virtual interface regardless of destination address.
What IP address does the OpenFlux client assign itself?
Standard client instances receive the static address 10.10.10.2/24 configured in the setupClient method at lines 39-45 of tunnel/tunnel.go. This fixed addressing scheme simplifies routing configuration and ensures consistent behavior across different network environments without requiring DHCP or manual IP configuration.
Can OpenFlux route traffic through different transport mechanisms?
Yes. The routing model abstracts physical transmission through the transport.Transport interface defined in transport/transport.go. The TunnelLinkEndpoint forwards encapsulated packets to whichever transport implementation—such as TCP sockets, raw sockets, or platform-specific methods like Windivert—is injected during NewTCPTunnel initialization, enabling flexible deployment across operating systems.
How does the routing model differ between client and exit node modes?
In standard client mode (isExitNode == false), the system configures NIC ID 1 with the 10.10.10.2/24 address and default route. When operating as an exit node, the routing logic switches to NIC ID 2 and omits the client-specific address configuration, instead handling packet termination and forwarding rather than tunnel encapsulation. This dual-mode implementation allows a single binary to function as either tunnel endpoint.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →