Network Connection Tracking
Relevant source files
The following files were used as context for generating this wiki page:
Purpose and Scope
Network Connection Tracking is the subsystem responsible for correlating network packets with the processes that generate or consume them. This enables ecapture to attribute captured TLS/SSL traffic and network packets to specific processes (PID), users (UID), and connection tuples (IP addresses and ports). The system operates at two levels: kernel-space tracking via eBPF maps and Traffic Control (TC) classifiers, and user-space tracking for socket file descriptors.
For information about the TC packet capture mechanism itself, see Network Packet Capture with TC. For details on the event processing pipeline that consumes connection events, see Event Processing Pipeline.
Architecture Overview
The network connection tracking system consists of three primary components:
- Kernel-space kprobe hooks (
tcp_sendmsg,udp_sendmsg) that capture connection metadata when processes send data - The
network_mapeBPF hash map that stores the PID/UID/comm for each active connection - TC classifiers (ingress/egress) that intercept packets and look up process information
- User-space tracking in the OpenSSL module that maps file descriptors to socket addresses
Sources: kern/tc.h:1-398, user/module/probe_openssl.go:78-106, user/module/probe_openssl.go:398-480
Kernel-Space Connection Tracking
The network_map Structure
The network_map is an LRU (Least Recently Used) hash map that stores process context information indexed by network connection identifiers. It enables the TC classifiers to determine which process owns a particular packet.
Map Definition:
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__type(key, struct net_id_t);
__type(value, struct net_ctx_t);
__uint(max_entries, 10240);
} network_map SEC(".maps");Key Structure (net_id_t):
| Field | Type | Description |
|---|---|---|
protocol | u32 | IP protocol (IPPROTO_TCP=6, IPPROTO_UDP=17) |
src_port | u32 | Source port number |
src_ip4 | u32 | Source IPv4 address |
dst_port | u32 | Destination port number |
dst_ip4 | u32 | Destination IPv4 address |
src_ip6[4] | u32[4] | Source IPv6 address |
dst_ip6[4] | u32[4] | Destination IPv6 address |
Value Structure (net_ctx_t):
| Field | Type | Description |
|---|---|---|
pid | u32 | Process ID |
uid | u32 | User ID |
comm[16] | char[] | Process command name (TASK_COMM_LEN) |
Sources: kern/tc.h:39-54, kern/tc.h:73-77
Kprobe Hooks for Connection Population
The system hooks tcp_sendmsg and udp_sendmsg kernel functions to capture connection metadata as soon as a process attempts to send data over the network. These hooks extract socket information from the struct sock parameter and populate the network_map.
TCP Hook Implementation:
- Entry point:
tcp_sendmsgkprobe at kern/tc.h:290-347 - Reads
struct sockfields usingbpf_probe_read()for both IPv4 and IPv6 - Handles AF_INET (IPv4) and AF_INET6 (IPv6) socket families
- Extracts:
skc_num(local port),skc_dport(remote port, network byte order), IP addresses - Updates
network_mapwith connection tuple and process context
UDP Hook Implementation:
- Entry point:
udp_sendmsgkprobe at kern/tc.h:349-397 - Nearly identical to TCP hook, but sets
protocoltoIPPROTO_UDP - Reuses the same
struct tcphdrlayout for port extraction (UDP header has same initial layout)
Note: These kprobes intentionally do NOT filter by target_pid or target_uid because the TC classifiers need comprehensive connection information for all processes to perform packet attribution.
Sources: kern/tc.h:290-347, kern/tc.h:349-397
TC Classifier Packet Correlation
The TC (Traffic Control) classifiers intercept packets at the data link layer (Layer 2) on both ingress and egress paths. For each packet, they extract the connection tuple (protocol, IPs, ports) and look it up in the network_map to attribute the packet to a process.
Bidirectional Lookup Logic:
The TC classifier first attempts to look up the packet's source-to-destination tuple in network_map. If not found, it swaps source and destination (both IPs and ports) and retries the lookup. This handles packets in both directions:
- Outbound packets: The tuple matches the entry created by
tcp_sendmsg/udp_sendmsg(process is sender) - Inbound packets: The swapped tuple matches the entry (process is receiver)
Filter Application:
After successful lookup, the TC classifier applies PID and UID filters (if target_pid or target_uid are set) to decide whether to capture the packet. Only packets matching the filter criteria are emitted to the skb_events perf array.
Sources: kern/tc.h:135-276, kern/tc.h:279-288
User-Space Connection Tracking
Purpose and Integration with OpenSSL Module
The user-space connection tracking in MOpenSSLProbe maintains a mapping between process file descriptors (FDs) and their corresponding socket addresses (tuples). This is necessary because:
- SSL/TLS functions (e.g.,
SSL_read,SSL_write) operate on file descriptors, not socket structures - The eBPF probes on SSL functions cannot directly access socket metadata
- User-space needs to correlate SSL data events with network packets captured by TC
The tracking is populated by ConnDataEvent structures emitted from eBPF when connections are established or destroyed.
Data Structures
pidConns Structure:
- Type:
map[uint32]map[uint32]ConnInfo - Outer key: Process ID (PID)
- Inner key: File descriptor (FD)
- Value:
ConnInfocontaining tuple string and socket pointer
sock2pidFd Structure:
- Type:
map[uint64][2]uint32 - Key: Socket pointer (from kernel)
- Value: Array of [PID, FD] for reverse lookup
ConnInfo Structure:
tuple(string): Connection tuple in format "src_ip:src_port-dst_ip:dst_port"sock(uint64): Kernel socket structure pointer for consistency checking
Sources: user/module/probe_openssl.go:78-82, user/module/probe_openssl.go:90-94
Connection Lifecycle Management
Connection Creation (AddConn):
When a ConnDataEvent with IsDestroy=0 is dispatched, AddConn is called:
- Validates FD is non-zero probe_openssl.go:399-402
- Acquires
pidLockermutex for thread-safe access probe_openssl.go:404 - Creates nested map for PID if it doesn't exist probe_openssl.go:406-409
- Stores
ConnInfo{tuple, sock}inpidConns[pid][fd]probe_openssl.go:410 - Creates reverse mapping in
sock2pidFd[sock] = [pid, fd]probe_openssl.go:413 - Logs debug message probe_openssl.go:415
Connection Destruction (DelConn → DestroyConn):
When a ConnDataEvent with IsDestroy=1 is dispatched:
DelConnschedulesDestroyConnwith 3-second delay usingtime.AfterFuncprobe_openssl.go:455-462- The delay allows the event processor to finish merging events for this connection
DestroyConnsignals the processor to cleanup viaprocessor.WriteDestroyConn(sock)probe_openssl.go:423- Performs reverse lookup in
sock2pidFdto find [pid, fd] probe_openssl.go:426-433 - Validates socket consistency (stored sock == provided sock) probe_openssl.go:441-445
- Removes entry from
pidConns[pid][fd]and deletes PID map if empty probe_openssl.go:446-449 - Removes reverse mapping from
sock2pidFdprobe_openssl.go:431
Connection Lookup (GetConn):
Called by dumpSslData when processing SSLDataEvent structures:
- Validates FD is non-zero probe_openssl.go:465-467
- Acquires
pidLockermutex probe_openssl.go:469 - Performs two-level lookup:
pidConns[pid][fd]probe_openssl.go:471-478 - Returns pointer to
ConnInfoornilif not found probe_openssl.go:479
Sources: user/module/probe_openssl.go:398-416, user/module/probe_openssl.go:418-462, user/module/probe_openssl.go:464-480
Packet-to-Process Correlation Flow
This section describes the complete flow from a process sending data to the attribution of captured packets.
Step-by-Step Correlation:
Connection Registration (Kprobe):
- Process calls
send()or similar syscall - Kernel invokes
tcp_sendmsgorudp_sendmsg - Kprobe extracts connection tuple and process context
- Populates
network_map[tuple] = {pid, uid, comm}
- Process calls
SSL Data Capture (Uprobe):
- Process calls SSL function (e.g.,
SSL_write) - Uprobe captures
SSLDataEventwith - User-space calls
GetConn(pid, fd)to retrieve tuple - Event is enriched with tuple and socket pointer
- Sent to
EventProcessorfor protocol parsing
- Process calls SSL function (e.g.,
Packet Capture (TC):
- Packet arrives at network interface (egress or ingress)
- TC classifier parses headers to extract connection tuple
- Looks up tuple in
network_map(tries both directions) - If found, checks PID/UID filters
- Emits
TcSkbEventwith packet data and process metadata - User-space writes to pcapng file with DSB (Decryption Secrets Block)
Sources: kern/tc.h:290-347, kern/tc.h:135-276, user/module/probe_openssl.go:756-775
Integration with Module Dispatcher
The MOpenSSLProbe.Dispatcher method routes connection-related events to the appropriate handler:
func (m *MOpenSSLProbe) Dispatcher(eventStruct event.IEventStruct) {
switch ev := eventStruct.(type) {
case *event.ConnDataEvent:
if ev.IsDestroy == 0 {
m.AddConn(ev.Pid, ev.Fd, ev.Tuple, ev.Sock)
} else {
m.DelConn(ev.Sock)
}
case *event.TcSkbEvent:
err := m.dumpTcSkb(ev)
case *event.SSLDataEvent:
m.dumpSslData(ev)
// ... other event types
}
}Event Flow:
| Event Type | Source | Handler | Purpose |
|---|---|---|---|
ConnDataEvent | eBPF uprobe (SSL_new, accept, connect) | AddConn/DelConn | Maintain fd→tuple mapping |
TcSkbEvent | TC classifier (egress/ingress) | dumpTcSkb | Write packets to pcapng |
SSLDataEvent | eBPF uprobe (SSL_read/write) | dumpSslData | Enrich with tuple, send to processor |
The dispatcher is called by Module.Dispatcher user/module/imodule.go:409-448 after event decoding from perf/ring buffers.
Sources: user/module/probe_openssl.go:733-754, user/module/probe_openssl.go:756-775
Configuration and Filtering
The connection tracking system respects process and user filtering configured via command-line flags:
Kernel-Space Filtering:
- Constants
target_pidandtarget_uiddefined at kern/common.h:67-68 - Set via constant editors in user/module/probe_openssl.go:361-387
- Applied in TC classifier at kern/tc.h:243-249
- Note: Kprobes do NOT filter to ensure comprehensive
network_mappopulation
User-Space Filtering:
- Enforced in
dumpSslDatawhen processingSSLDataEvent - Only connections matching filter criteria are tracked in
pidConns - Filter check happens before calling
AddConn
Default Tuple Handling:
When GetConn returns nil (connection not tracked), SSLDataEvent uses default values:
Tuple = DefaultTuple("0.0.0.0:0-0.0.0.0:0") at user/module/probe_openssl.go:43Sock = 0
This occurs when:
- FD is invalid (≤0)
- Connection was not captured (filtered out, or BIO type is non-socket)
- Connection already destroyed
Sources: kern/common.h:67-68, kern/tc.h:243-249, user/module/probe_openssl.go:361-387, user/module/probe_openssl.go:756-775