Documentation
¶
Overview ¶
Package ike decodes IKEv2 (Internet Key Exchange version 2) messages per RFC 7296. IKEv2 is the control-plane protocol that negotiates the IPsec Security Associations (SAs) consumed by ESP (RFC 4303, covered by `esp_decode`) and AH (RFC 4302, covered by `ah_decode`). Without IKE the SPIs + keys + algorithms ESP/AH need come from nowhere; with IKEv2 we decode the negotiation that produces them.
IKEv2 is universal on every site-to-site VPN + IPsec remote-access deployment — StrongSwan, OpenSwan/Libreswan, Cisco AnyConnect IPsec mode, FortiGate, pfSense, OPNsense, Windows IPsec, macOS IKEv2 client. Runs on UDP destination port 500, or UDP 4500 with a 4-byte all-zeros marker when behind NAT (NAT-T per RFC 3947 / 3948).
Wrap-vs-native judgement
Native. RFC 7296 is fully public. IKEv2 has a tight 28-byte fixed header followed by a chained list of payloads (each a 4-byte header + body). The first exchange (IKE_SA_INIT) is sent unencrypted so SA proposals, KE shares, nonces, and NAT-T markers are decoded fully; from IKE_AUTH onwards the payload bodies are wrapped in an Encrypted (SK) payload whose plaintext is opaque without the IKE-derived keys (surfaced as hex; full decryption would require an IKE-state-aware iteration).
What this package covers
**28-byte fixed header** (RFC 7296 §3.1):
bytes 0-7: Initiator SPI (uint64 BE; the SA's initiator-side identifier).
bytes 8-15: Responder SPI (uint64 BE; zero in the first IKE_SA_INIT request, set in the reply).
byte 16: Next Payload (first payload's type code).
byte 17: Version (4-bit Major / 4-bit Minor; 2/0 for IKEv2).
byte 18: **Exchange Type** with **4-entry name table** (RFC 7296 §3.1): 34 IKE_SA_INIT, 35 IKE_AUTH, 36 CREATE_CHILD_SA, 37 INFORMATIONAL.
byte 19: **Flags** decoded into **3 named bits**: R (Response — 0x20), V (Version — 0x10; only set by responders), I (Initiator — 0x08).
bytes 20-23: Message ID (uint32 BE; per-SA monotonic; matches request/reply).
bytes 24-27: Length (uint32 BE; total message length including this header).
**Payload walker** — chained list driven by the Next Payload field of the previous payload (or of the IKE header for the first). Each payload header is 4 bytes: Next Payload (1B) + Critical (1B; high bit only) + Payload Length (uint16 BE; total including this 4-byte header). Walker terminates when Next Payload = 0.
**~15-entry payload type name table** (RFC 7296 §3.2 + IANA "IKEv2 Payload Types" registry): 33 SA (Security Association proposal/transform tree) / 34 KE (Key Exchange — DH/ECDH public value) / 35 IDi (Identification - Initiator) / 36 IDr (Identification - Responder) / 37 CERT (Certificate) / 38 CERTREQ (Certificate Request) / 39 AUTH (Authentication — signature/PSK proof) / 40 Ni or Nr (Nonce) / 41 N (Notify — error / status / capability) / 42 D (Delete — tear down SAs) / 43 V (Vendor ID — feature negotiation) / 44 TSi (Traffic Selector - Initiator) / 45 TSr (Traffic Selector - Responder) / 46 SK (Encrypted and Authenticated — wraps inner payloads from IKE_AUTH onwards) / 47 CP (Configuration — remote-access settings like IP allocation) / 48 EAP (Extensible Authentication Protocol).
**N (Notify) payload body** (Type 41; RFC 7296 §3.10): 1-byte Protocol ID (0 IKE / 2 AH / 3 ESP)
1-byte SPI Size + 2-byte **Notify Message Type** resolved via a **~30-entry name table** covering the most common error / status codes: **Errors**: 1 UNSUPPORTED_CRITICAL_PAYLOAD / 4 INVALID_IKE_SPI / 5 INVALID_MAJOR_VERSION / 7 INVALID_SYNTAX / 9 INVALID_MESSAGE_ID / 11 INVALID_SPI / 14 NO_PROPOSAL_CHOSEN / 17 INVALID_KE_PAYLOAD / 24 AUTHENTICATION_FAILED / 34 SINGLE_PAIR_REQUIRED / 35 NO_ADDITIONAL_SAS / 36 INTERNAL_ADDRESS_FAILURE / 37 FAILED_CP_REQUIRED / 38 TS_UNACCEPTABLE / 39 INVALID_SELECTORS / 43 TEMPORARY_FAILURE / 44 CHILD_SA_NOT_FOUND. **Status**: 16384 INITIAL_CONTACT / 16385 SET_WINDOW_SIZE / 16386 ADDITIONAL_TS_POSSIBLE / 16387 IPCOMP_SUPPORTED / 16388 NAT_DETECTION_SOURCE_IP / 16389 NAT_DETECTION_DESTINATION_IP / 16390 COOKIE / 16391 USE_TRANSPORT_MODE / 16393 REKEY_SA / 16395 NON_FIRST_FRAGMENTS_ALSO / 16404 MOBIKE_SUPPORTED / 16407 NO_NATS_ALLOWED / 16408 AUTH_LIFETIME / 16431 SIGNATURE_HASH_ALGORITHMS.
**SK (Encrypted) payload** (Type 46) — surfaced with the encrypted body as opaque hex pending the IKE-derived keys. The body wraps inner payloads (the Next Payload of the SK header names the type of the first inner payload).
What this package does NOT cover (deliberately out of scope)
UDP framing — feed IKE bytes after the UDP header strip. IKE runs on UDP destination port 500 (or 4500 with a 4-byte all-zeros marker prefix when behind NAT, per RFC 3948 NAT-T).
SA proposal/transform tree deep dissection — the SA payload (Type 33) contains a nested list of Proposals + Transforms (encryption / integrity / PRF / DH algorithms negotiated); surfaced as opaque hex; would warrant a separate iteration.
KE / Ni / Nr / IDi / IDr / AUTH / CERT body dissection — surfaced as opaque hex; per-body decoders are future work.
SK payload decryption — requires the SK_e/SK_a keys derived from the IKE_SA_INIT KE + Nonce exchange; surfaced as opaque hex with an encryption note.
IKEv1 (RFC 2409) — different header (8-byte SPIs
Initiator Cookie / Responder Cookie naming + Exchange Type code 1-5 mapping to Identity Protection / Aggressive / Authentication Only / Informational / Quick Mode); long-deprecated but still seen in legacy deployments; would warrant its own Spec.
NAT-T marker stripping — when the 4-byte all-zeros marker is present (UDP port 4500), the operator must strip it before feeding bytes into this decoder. ESP-in-UDP (RFC 3948) doesn't have the all-zeros marker, so the demux is unambiguous.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type DecodeOpts ¶
type DecodeOpts struct {
// MaxPayloadBodyBytes caps the per-payload body hex
// preview (default 256). Zero shows the full body.
MaxPayloadBodyBytes int
}
DecodeOpts tunes the walker for output size.
func DefaultDecodeOpts ¶
func DefaultDecodeOpts() DecodeOpts
DefaultDecodeOpts returns a 256-byte body preview cap.
type NotifyBody ¶
type NotifyBody struct {
ProtocolID int `json:"protocol_id"`
ProtocolIDName string `json:"protocol_id_name"`
SPISize int `json:"spi_size"`
NotifyMessageType int `json:"notify_message_type"`
NotifyMessageName string `json:"notify_message_name"`
NotifyMessageClass string `json:"notify_message_class"`
SPIHex string `json:"spi_hex,omitempty"`
NotificationDataHex string `json:"notification_data_hex,omitempty"`
}
NotifyBody is the decoded body of an N (Notify) payload.
type Payload ¶
type Payload struct {
Type int `json:"type"`
TypeName string `json:"type_name"`
NextType int `json:"next_type"`
Critical bool `json:"critical"`
Length int `json:"length"`
BodyHex string `json:"body_hex,omitempty"`
// Decoded forms populated for known payload types.
Notify *NotifyBody `json:"notify,omitempty"`
Encrypted *SKBody `json:"encrypted,omitempty"`
}
Payload is one (Next Payload, Critical, Length, Body) record from the payload walker.
type Result ¶
type Result struct {
InitiatorSPI uint64 `json:"initiator_spi"`
InitiatorSPIHex string `json:"initiator_spi_hex"`
ResponderSPI uint64 `json:"responder_spi"`
ResponderSPIHex string `json:"responder_spi_hex"`
FirstPayloadType int `json:"first_payload_type"`
FirstPayloadName string `json:"first_payload_name"`
VersionMajor int `json:"version_major"`
VersionMinor int `json:"version_minor"`
ExchangeType int `json:"exchange_type"`
ExchangeTypeName string `json:"exchange_type_name"`
FlagResponse bool `json:"flag_response"`
FlagVersion bool `json:"flag_version"`
FlagInitiator bool `json:"flag_initiator"`
MessageID uint32 `json:"message_id"`
Length uint32 `json:"length"`
Payloads []Payload `json:"payloads"`
TotalBytes int `json:"total_bytes"`
Notes []string `json:"notes,omitempty"`
}
Result is the top-level decoded view of an IKEv2 message.