A Linux-only Go application that captures SIP (Session Initiation Protocol) network packets, tracks call dialogs through their lifecycle, packages them into PCAP files, and uploads them to AWS S3. Designed for high-concurrency VoIP call recording.
Network (AF_PACKET) --> [BPF Filter] --> packet channel (100k buffer)
--> [N Packet Workers] --> SIP parser + Dialog Tracker (state machine)
--> completed calls channel (10k buffer)
--> [PCAP Writer] --> [M S3 Upload Workers]
- Captures raw packets from the network interface using AF_PACKET with a BPF filter for SIP ports
- Packet workers parse SIP messages and feed them into the dialog tracker
- The dialog tracker maintains a state machine per call (TRYING -> EARLY -> CONFIRMED -> TERMINATED)
- When a call ends (BYE, CANCEL, error response, or timeout), all its packets are written to a PCAP file
- The PCAP file is uploaded to S3 at
YEAR/MONTH/call-id.pcap
- Linux (AF_PACKET is Linux-only)
libpcap-devinstalled- Root/sudo privileges (raw socket capture)
- Go 1.22+ (for building from source)
# Install system dependencies
make install-deps
# Copy and configure environment
cp .env.example .env
# Edit .env with your AWS credentials
# Build
make build-local
# Run (requires root)
sudo ./bin/pcap2file| Command | Description |
|---|---|
make build |
Cross-compile for Linux amd64 |
make build-local |
Build for current platform |
make deps |
Download Go dependencies (go mod tidy && go mod download) |
make install-deps |
Install system libraries (libpcap-dev) |
make run |
Build and run with sudo |
make test |
Run tests with race detector |
make test-cover |
Run tests with HTML coverage report |
make lint |
Run golangci-lint |
make clean |
Remove build artifacts |
All configuration is via environment variables or a .env file in the working directory. AWS credentials are required; the application will fail at startup without them.
| Variable | Description | Default |
|---|---|---|
AWS_ACCESS_KEY_ID |
AWS access key (required) | - |
AWS_SECRET_ACCESS_KEY |
AWS secret key (required) | - |
AWS_REGION |
AWS region | us-east-1 |
S3_BUCKET |
S3 bucket name for PCAP uploads | sip-captures |
S3_ENDPOINT |
Custom S3 endpoint (for MinIO or S3-compatible storage) | (empty = AWS) |
| Variable | Description | Default |
|---|---|---|
CAPTURE_INTERFACE |
Network interface to capture on | eth0 |
SIP_PORTS |
Comma-separated list of SIP ports to filter | 5060,5061 |
CAPTURE_RTP |
Capture RTP media packets (not yet implemented) | false |
| Variable | Description | Default |
|---|---|---|
PACKET_WORKERS |
Number of goroutines for SIP parsing | CPU cores |
UPLOAD_WORKERS |
Number of goroutines for S3 uploads | 16 |
MAX_CONCURRENT_CALLS |
Maximum tracked concurrent call dialogs | 50000 |
| Variable | Description | Default |
|---|---|---|
CALL_SETUP_TIMEOUT |
Seconds before unanswered calls are timed out (TRYING/EARLY state) | 30 |
CALL_MAX_DURATION |
Maximum call duration in seconds before forced timeout | 14400 (4 hours) |
CALL_IDLE_TIMEOUT |
Seconds without packets before an active call is timed out | 300 (5 minutes) |
| Variable | Description | Default |
|---|---|---|
LOG_LEVEL |
Log verbosity: debug, info, warn, error |
info |
Uploaded PCAP files are stored at:
YEAR/MONTH/sanitized-call-id.pcap
Example: 2026/02/a84b4c76e66710@pc33.example.com.pcap
Characters unsafe for filenames (/ \ : * ? " < > |) are replaced with _ in the call ID.
Every 30 seconds, the application logs:
active_calls- number of currently tracked dialogsupload_queue- number of PCAP files waiting for S3 uploaddropped_packets- total packets dropped due to full channel buffer
Send SIGINT (Ctrl+C) or SIGTERM to initiate ordered shutdown:
- Packet capture stops
- In-flight SIP packets are processed
- Completed calls are written to PCAP
- Remaining S3 uploads are drained (up to 30s timeout)
Set S3_ENDPOINT to your MinIO URL:
S3_ENDPOINT=http://localhost:9000
AWS_ACCESS_KEY_ID=minioadmin
AWS_SECRET_ACCESS_KEY=minioadmin
S3_BUCKET=sip-captures