Documentation
¶
Overview ¶
Package rtmp decodes RTMP (Real-Time Messaging Protocol) wire frames. Originally developed by Macromedia/Adobe for Flash; still the dominant live-streaming ingest protocol on TCP/1935 (default). Widely used by OBS Studio, Twitch, YouTube Live, Facebook Live, Nginx-RTMP, Wowza, SRS (Simple Realtime Server).
Operationally, RTMP is a **high-value live-streaming ingest target** — stream keys transmitted in cleartext. Stream keys are effectively authentication tokens for live-streaming platforms; capturing one lets an attacker broadcast arbitrary content to the victim's channel.
The wire format leaks:
**Handshake version via C0/S0** — first byte is the RTMP version: 0x03 = plaintext RTMP; 0x06 = RTMPE (encrypted RTMP using Diffie-Hellman). The C1/S1 blocks that follow contain a 4-byte timestamp plus 1528 bytes of random data.
**Application name and server URL via AMF0 "connect" command (message type 20)** — the first AMF0 command sent by any RTMP client is "connect"; its argument object contains "app" (the application name, e.g. "live"), "tcUrl" (the full RTMP URL, e.g. "rtmp://server/live"), "flashVer" (client version string), "swfUrl", "pageUrl". The tcUrl often contains auth tokens or stream keys embedded as query parameters.
**Stream keys via "publish" command** — when a client starts publishing, it sends an AMF0 Command Message (type 20) with command name "publish"; the second string argument is the stream name / stream key, transmitted in cleartext. Stream keys are auth tokens for Twitch / YouTube Live / Facebook Live / Wowza / Nginx-RTMP.
**Stream name via "play" command** — consumer clients send "play" with the stream name as the second argument.
**RTMPE (version 0x06) uses Diffie-Hellman key exchange** but has known implementation weaknesses. Standard RTMP (version 0x03) is entirely cleartext.
**Protocol control message types 1-6** — Set Chunk Size (1), Abort (2), Acknowledgement (3), User Control (4), Window Acknowledgement Size (5), Set Peer Bandwidth (6). These reveal session-layer parameters.
**Audio (type 8) and Video (type 9) message streams** — identified by message type; payload not decoded.
Wrap-vs-native judgement
Native. The RTMP specification is publicly available (Adobe RTMP Specification 1.0, December 2012). The chunk format is a deterministic binary layout with no crypto at the parse layer for standard RTMP 0x03. RTMPE (0x06) is detected but not decrypted. AMF0 command parsing is limited to extracting the command name string and best-effort extraction of the "app" and "tcUrl" fields from the following AMF0 object.
What this package covers
**C0+C1 / S0+S1 handshake detection** — leading byte is the RTMP version (0x03 or 0x06), followed by 1536 bytes. Surfaces `is_handshake`, `handshake_version`, `is_encrypted`.
**RTMP chunk header walker** — basic_header (1-3 bytes): fmt (2 bits) + cs_id (6 bits / 1-byte extended / 2-byte LE extended). Message header per fmt: fmt 0 (11 bytes: timestamp 3 BE + message_length 3 BE + message_type_id 1 + message_stream_id 4 LE); fmt 1 (7 bytes: timestamp_delta 3
message_length 3 + message_type_id 1); fmt 2 (3 bytes: timestamp_delta 3); fmt 3 (0 bytes). Extended timestamp (4 BE) if timestamp/delta == 0xFFFFFF.
**17-entry message type name table**: Set Chunk Size (1) / Abort (2) / Acknowledgement (3) / User Control (4) / Window Acknowledgement Size (5) / Set Peer Bandwidth (6) / Audio (8) / Video (9) / Data AMF3 (15) / Shared Object AMF3 (17) / Data AMF0 (18) / Shared Object AMF0 (19) / Command AMF0 (20) / Aggregate (22).
**AMF0 Command Message walker (type 20)** — extracts the command name from the first AMF0 string marker (0x02 + 2-byte BE length + data). Key commands: connect / createStream / play / publish / deleteStream / FCPublish / releaseStream / onStatus / _result / _error.
**"connect" command argument extraction** — best-effort scan for AMF0 object keys "app" and "tcUrl" following the command name; surfaces `app_name` and `tc_url`.
**Classification booleans**: `is_connect`, `is_play`, `is_publish`, `is_audio`, `is_video`, `is_control_message`.
**User Control Message event type decoder (message type 4)** — 6-entry event type name table: StreamBegin (0) / StreamEOF (1) / StreamDry (2) / SetBufferLength (3) / StreamIsRecorded (4) / PingRequest (6) / PingResponse (7).
What this package does NOT cover (deliberately out of scope)
- **RTMPE decryption** — RTMPE (version 0x06) uses a Diffie-Hellman key exchange; the decoder detects it but does NOT decrypt. The DH exchange details are complex and intentionally out of scope.
- **Full AMF0 / AMF3 parser** — only the command name string and best-effort "app"/"tcUrl" extraction are implemented. Full AMF0 value types (numbers, booleans, objects, arrays, dates) and AMF3 are not parsed.
- **Multi-chunk message reassembly** — large messages span multiple chunks; the decoder parses the first chunk header only.
- **RTMPS (TLS-wrapped RTMP, TCP/443)** — handle TLS strip first.
- **RTMPT (HTTP-tunneled RTMP)** — handle HTTP layer separately.
- **Audio/Video payload decoding** — H.264/AAC/FLV codec payloads are out of scope.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Result ¶
type Result struct {
TotalBytes int `json:"total_bytes"`
// Handshake fields (C0+C1 or S0+S1)
IsHandshake bool `json:"is_handshake"`
HandshakeVersion int `json:"handshake_version,omitempty"`
IsEncrypted bool `json:"is_encrypted"`
// Chunk header fields
Fmt int `json:"fmt,omitempty"`
ChunkStreamID int `json:"cs_id,omitempty"`
Timestamp int `json:"timestamp,omitempty"`
MessageLength int `json:"message_length,omitempty"`
MessageTypeID int `json:"message_type_id,omitempty"`
MessageTypeName string `json:"message_type_name,omitempty"`
MessageStreamID int `json:"message_stream_id,omitempty"`
// AMF0 Command Message (type 20)
CommandName string `json:"command_name,omitempty"`
// "connect" command extracted fields
AppName string `json:"app_name,omitempty"`
TcURL string `json:"tc_url,omitempty"`
FlashVer string `json:"flash_ver,omitempty"`
// Classification booleans
IsConnect bool `json:"is_connect"`
IsPlay bool `json:"is_play"`
IsPublish bool `json:"is_publish"`
IsAudio bool `json:"is_audio"`
IsVideo bool `json:"is_video"`
IsControlMessage bool `json:"is_control_message"`
// User Control Message event (type 4)
UserControlEventType int `json:"user_control_event_type,omitempty"`
UserControlEventName string `json:"user_control_event_name,omitempty"`
}
Result is the structured decode of an RTMP wire-protocol frame.
func Decode ¶
Decode parses an RTMP wire-protocol frame from a hex string. It auto-discriminates between handshake blocks (C0+C1 / S0+S1) and post-handshake chunk headers by inspecting the buffer length and leading byte:
- Exactly 1537 bytes with leading 0x03 or 0x06 → handshake.
- All other inputs → RTMP chunk header.
The discrimination uses the exact 1537-byte size to avoid the fmt=0 / cs_id=3 ambiguity (chunk basic-header byte 0x03 is also a valid first byte for a chunk with fmt=0 and cs_id=3).