This document describes the protocol handler layer that processes TCP, UDP, and ICMP traffic in Firestack. Protocol handlers receive demultiplexed packets from the gVisor netstack, apply firewall rules, perform DNS interception, route connections through proxies, and forward data bidirectionally.
For information about the network stack integration with gVisor, see 4.1 Tunnel Management and Lifecycle For proxy selection and routing logic, see 3. Proxy Management System For DNS resolution and ALG translation, see 2. DNS Resolution System
The protocol handler system consists of a baseHandler providing shared functionality and three protocol-specific handlers (tcpHandler, udpHandler, icmpHandler) that extend it.
Title: Protocol Handler Class Hierarchy
Sources: intra/common.go81-101 intra/tcp.go46-49 intra/udp.go44-47 intra/icmp.go25-27 intra/netstack/tcp.go47-49 intra/netstack/udp.go35-38 intra/netstack/icmp.go21-24 intra/netstack/hdl.go25-55
The baseHandler struct provides common functionality for all protocol handlers. It coordinates with the DNS resolver, proxy provider, and socket listener to implement the complete flow processing pipeline.
| Component | Type | Purpose |
|---|---|---|
resolver | dnsx.Resolver | DNS resolver to forward queries to intra/common.go85 |
prox | ipn.ProxyProvider | Proxy provider for selecting egress routes intra/common.go86 |
listener | FlowListener | Flow policy decisions and socket summaries intra/common.go88 |
conntracker | core.ConnMapper | Active connection tracking by CID/UID/PID intra/common.go90 |
fwtracker | core.ExpMap[string, string] | Firewalled flow tracking for stall logic intra/common.go91 |
smmch | chan *FlowSummary | Summary delivery channel (256 buffer) intra/common.go87 |
Sources: intra/common.go81-119 intra/common.go34
The onFlow() method determines the routing policy for outgoing connections. It handles NAT/ALG reverse translation and queries the listener for firewall rules.
Title: Egress Flow Policy Decision (onFlow)
Sources: intra/common.go148-280 intra/netstat/procfs.go20-50
Key features:
netstat.FindProcNetEntry lookups in BlockModeFilterProc mode intra/common.go161-163undoAlg to recover real IPs and domains intra/common.go213dialers.ResolveFor() intra/common.go225FlowListener for a Mark containing proxy IDs or block instructions intra/common.go244-246For incoming connections (reverse proxy scenarios), onInflow() performs policy checks using listener.Inflow intra/common.go122-145
The forward() method establishes a bidirectional pipe between the local netstack connection and the remote egress connection, tracking the flow via conntracker.Track intra/common.go282-321
The tcpHandler implements TCP connection proxying with support for endpoint-independent mapping (EIM) and Happy Eyeballs.
The tcpNat structure maintains mappings of {proxy_id, src_addr} → ext_addr to support EIM behavior intra/tcp.go52-89
Sources: intra/tcp.go52-89 intra/tcp.go203-214
When a new TCP flow arrives, Proxy() is called. It triggers onFlow() to determine the policy. If the destination is a DNS server, dnsOverride() may intercept the traffic intra/tcp.go343-346 Otherwise, it iterates through target IPs and attempts to dial via the selected proxy intra/tcp.go366-460
Sources: intra/tcp.go237-460
The udpHandler implements UDP association proxying with multiplexing support for endpoint-independent mapping and filtering (EIM/EIF).
UDP multiplexing enables EIM/EIF by sharing a single net.PacketConn across multiple logical connections, keyed by remote address.
Title: UDP Multiplexing Architecture
Sources: intra/udpmux.go69-145 intra/udpmux.go203-270 intra/udp.go44-47
Key components:
mxconn and demultiplexes packets to demuxconn instances intra/udpmux.go69-90demuxconn intra/udpmux.go203-270The icmpHandler implements ICMP echo (ping) functionality using unprivileged ICMP sockets (via UDP on Android) intra/icmp.go43-50
Firestack implements an icmpForwarder within the netstack layer that handles ICMP packets intra/netstack/icmp.go26-30
icmpForwarder.reply4 or reply6 intercepts packets from the netstack intra/netstack/icmp.go58-163icmpHandler.Ping() intra/netstack/icmp.go141onFlow() determines the egress policy intra/icmp.go58prox.ProxyTo() intra/icmp.go97Probe() intra/icmp.go123core.Echo() sends the ICMP request and waits for a reply intra/icmp.go144Sources: intra/icmp.go51-153 intra/netstack/icmp.go26-175 intra/netstack/icmpecho.go39-72
The core.ConnMapper tracks active connections by connection ID (CID), user ID (UID), and proxy ID (PID). Handlers use Track() and Untrack() to manage this state intra/icmp.go135-136
Sources: intra/common.go90 intra/core/connmap.go32-49 intra/icmp.go135-136
Each connection generates a FlowSummary when it closes, reporting statistics (Rx, Tx, Duration, Rtt) to the FlowListener intra/listener.go20-47 Summaries are queued in smmch and processed asynchronously intra/common.go87
Sources: intra/common.go87 intra/listener.go20-47
When a connection is blocked, handlers implement a "stall" mechanism via baseHandler.stall(). This delays the connection failure to mitigate busy-retry loops intra/common.go149 Stalls are triggered in the Error() methods of the handlers intra/tcp.go149 intra/udp.go150
Refresh this wiki