Documentation
¶
Overview ¶
Package l2tp decodes L2TPv3 packets per RFC 3931 (UDP- encapsulated mode on UDP port 1701). L2TPv3 is the pseudowire encapsulation that pairs with PPPoE (covered by `pppoe_decode`) to complete the broadband subscriber- management story: PPPoE handles the access-side session from the customer modem to the BNG; L2TPv3 handles the backhaul/aggregation tunnel from the BNG to a Layer-2 VPN concentrator (LAC → LNS in classic deployments).
L2TPv3 is also the dominant transport for:
**Lawful intercept (LI) at every ISP** — voice + data captures are funnelled through L2TPv3 tunnels from edge LACs to a centralised LI mediation function.
**L2 VPN services** — Ethernet, ATM, Frame Relay, PPP, and HDLC pseudowires across MPLS or IP cores.
**Subscriber backhaul** — wholesale broadband resellers tunnel customers from CLEC LACs to their LNS for centralised AAA + IP allocation.
Wrap-vs-native judgement
Native. RFC 3931 is fully public. L2TPv3 has a tight bit-packed common header that dispatches between Control Messages (T=1) and Data Messages (T=0) via the high bit. Control Messages carry an AVP (Attribute-Value Pair) list with a small set of well-defined Attribute Types; Data Messages carry an opaque L2 frame after a small Session ID + Cookie envelope. No crypto at the parse layer.
What this package covers
**16-bit common header** (RFC 3931 §3.2.1): bit 0 = **T** (Type: 0 Data, 1 Control); bit 1 = L (Length present); bits 2-3 reserved; bit 4 = S (Ns/Nr present); bits 5-7 reserved; bits 8-11 reserved; bits 12-15 = **Version** (must be 3 for L2TPv3).
**Control Message** (T=1; RFC 3931 §3.2.2): Length (uint16 BE; total bytes including this field's position) + Control Connection ID (uint32 BE; the peer-end's connection identifier) + Ns (uint16 BE; send sequence number) + Nr (uint16 BE; expected receive sequence number) + AVP list.
**AVP walker** (RFC 3931 §5.2) — each AVP:
2 bytes: 1-bit Mandatory + 1-bit Hidden + 1-bit Reserved + 10-bit Length + 3 reserved bits packed into the high 6 bits + 10-bit Length in low 10 bits. (The bit-pack is `M H r r r r LLLLLLLLLL`.)
2 bytes: Vendor ID (uint16 BE; 0 = IETF, others = SMI Private Enterprise Number).
2 bytes: Attribute Type (uint16 BE).
Length-6 bytes: Value. **~15-entry IETF AVP name table** (when Vendor ID = 0): Message Type / Result Code / Protocol Version / Framing Capabilities / Bearer Capabilities / Tie Breaker / Firmware Revision / Host Name / Vendor Name / Assigned Tunnel ID / Receive Window Size / Challenge / Challenge Response / Cause Code / Q.931 Cause Code / Assigned Session ID / Call Serial Number / Local Session ID / Remote Session ID / Random Vector.
**Message Type AVP** (Attribute 0) — first AVP in every Control Message; its 2-byte value names the control message kind via a **16-entry name table** (RFC 3931 §5.4): 1 SCCRQ (Start-Control-Connection- Request) / 2 SCCRP (Start-Control-Connection-Reply) / 3 SCCCN (Start-Control-Connection-Connected) / 4 StopCCN (Stop-Control-Connection-Notification) / 6 HELLO (Keepalive) / 7 OCRQ (Outgoing-Call-Request) / 8 OCRP (Outgoing-Call-Reply) / 9 OCCN (Outgoing- Call-Connected) / 10 ICRQ (Incoming-Call-Request) / 11 ICRP (Incoming-Call-Reply) / 12 ICCN (Incoming- Call-Connected) / 14 CDN (Call-Disconnect-Notify) / 15 WEN (WAN-Error-Notify) / 16 SLI (Set-Link-Info) / 20 ACK (Acknowledgement, RFC 3931 addition).
**Data Message** (T=0): Session ID (uint32 BE; the peer-end's session identifier) + optional Cookie (4 or 8 bytes, negotiated during ICRQ/ICRP via "Assigned Cookie" AVP) + L2-Specific Sublayer (varies by encap; default L2SS is empty) + L2 Frame (opaque; surfaced as hex preview). The decoder surfaces the Session ID and the rest as raw hex pending operator-provided framing context.
What this package does NOT cover (deliberately out of scope)
UDP framing — feed L2TPv3 bytes after the UDP header strip. UDP-mode L2TPv3 runs on destination port 1701; IP-mode runs as IP protocol 115.
IP-mode L2TPv3 (IP protocol 115) — different envelope (no UDP header; Session ID 0 indicates a Control Message). Could share most decoder logic; deferred.
Per-AVP value type-aware decoding beyond Message Type and a few well-known integer/string AVPs — values are surfaced as hex with plausibly-text UTF-8 surfacing for Host Name / Vendor Name.
Hidden (encrypted) AVPs — the H bit is surfaced but decryption requires the shared secret + RFC 3931 §4.3 procedure; deferred.
PPP / HDLC / Ethernet / ATM / FR frame dissection inside Data Message payload — operator pulls bytes out of the payload preview and feeds into the appropriate L2 decoder.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AVP ¶
type AVP struct {
Mandatory bool `json:"mandatory"`
Hidden bool `json:"hidden"`
Length int `json:"length"`
VendorID int `json:"vendor_id"`
AttributeType int `json:"attribute_type"`
AttributeName string `json:"attribute_name,omitempty"`
ValueHex string `json:"value_hex,omitempty"`
ValueText string `json:"value_text,omitempty"`
}
AVP is one (Mandatory, Hidden, Length, Vendor ID, Attribute Type, Value) record from the AVP walker.
type ControlMessage ¶
type ControlMessage struct {
Length int `json:"length"`
ControlConnectionID uint32 `json:"control_connection_id"`
Ns int `json:"send_sequence"`
Nr int `json:"expected_receive_sequence"`
MessageType int `json:"message_type,omitempty"`
MessageTypeName string `json:"message_type_name,omitempty"`
AVPs []AVP `json:"avps"`
}
ControlMessage is the decoded body of an L2TPv3 control message (T=1).
type DataMessage ¶
type DataMessage struct {
SessionID uint32 `json:"session_id"`
PayloadBytes int `json:"payload_bytes"`
PayloadBytesShown int `json:"payload_bytes_shown,omitempty"`
PayloadHex string `json:"payload_hex,omitempty"`
}
DataMessage is the decoded body of an L2TPv3 data message (T=0).
type DecodeOpts ¶
type DecodeOpts struct {
// MaxPayloadBytes caps the Data Message payload hex
// preview. Zero surfaces the full payload.
MaxPayloadBytes int
}
DecodeOpts tunes the walker for output size.
func DefaultDecodeOpts ¶
func DefaultDecodeOpts() DecodeOpts
DefaultDecodeOpts returns a 256-byte payload preview cap.
type Result ¶
type Result struct {
Type int `json:"type"`
TypeName string `json:"type_name"`
LengthPresent bool `json:"length_present"`
SequencePresent bool `json:"sequence_present"`
Version int `json:"version"`
Control *ControlMessage `json:"control_message,omitempty"`
Data *DataMessage `json:"data_message,omitempty"`
TotalBytes int `json:"total_bytes"`
Notes []string `json:"notes,omitempty"`
}
Result is the top-level decoded view of an L2TPv3 packet.