Files
Erupe/network/pcap/format.go
Houmgaor f712e3c04d feat(pcap): complete replay system with filtering, metadata, and live replay
Wire ExcludeOpcodes config into RecordingConn so configured opcodes
(e.g. ping, nop, position) are filtered at record time. Add padded
metadata with in-place PatchMetadata to populate CharID/UserID after
login. Implement --mode replay using protbot's encrypted connection
with timing-aware packet sending, auto-ping response, concurrent
S→C collection, and byte-level payload diff reporting.
2026-02-23 19:34:30 +01:00

109 lines
2.6 KiB
Go

package pcap
import "encoding/json"
// Capture file format constants.
const (
// Magic is the 4-byte magic number for .mhfr capture files.
Magic = "MHFR"
// FormatVersion is the current capture format version.
FormatVersion uint16 = 1
// HeaderSize is the fixed size of the file header in bytes.
HeaderSize = 32
// MinMetadataSize is the minimum metadata block size in bytes.
// Metadata is padded to at least this size to allow in-place patching
// (e.g., adding CharID/UserID after login).
MinMetadataSize = 512
)
// Direction indicates whether a packet was sent or received.
type Direction byte
const (
DirClientToServer Direction = 0x01
DirServerToClient Direction = 0x02
)
func (d Direction) String() string {
switch d {
case DirClientToServer:
return "C→S"
case DirServerToClient:
return "S→C"
default:
return "???"
}
}
// ServerType identifies which server a capture originated from.
type ServerType byte
const (
ServerTypeSign ServerType = 0x01
ServerTypeEntrance ServerType = 0x02
ServerTypeChannel ServerType = 0x03
)
func (st ServerType) String() string {
switch st {
case ServerTypeSign:
return "sign"
case ServerTypeEntrance:
return "entrance"
case ServerTypeChannel:
return "channel"
default:
return "unknown"
}
}
// FileHeader is the fixed 32-byte header at the start of a .mhfr file.
//
// [4B] Magic "MHFR"
// [2B] Version
// [1B] ServerType
// [1B] ClientMode
// [8B] SessionStartNs
// [4B] Reserved
// [4B] MetadataLen
// [8B] Reserved
type FileHeader struct {
Version uint16
ServerType ServerType
ClientMode byte
SessionStartNs int64
MetadataLen uint32
}
// SessionMetadata is the JSON-encoded metadata block following the file header.
type SessionMetadata struct {
ServerVersion string `json:"server_version,omitempty"`
Host string `json:"host,omitempty"`
Port int `json:"port,omitempty"`
CharID uint32 `json:"char_id,omitempty"`
UserID uint32 `json:"user_id,omitempty"`
RemoteAddr string `json:"remote_addr,omitempty"`
}
// MarshalJSON serializes the metadata to JSON.
func (m *SessionMetadata) MarshalJSON() ([]byte, error) {
type Alias SessionMetadata
return json.Marshal((*Alias)(m))
}
// PacketRecord is a single captured packet.
//
// [8B] TimestampNs [1B] Direction [2B] Opcode [4B] PayloadLen [NB] Payload
type PacketRecord struct {
TimestampNs int64
Direction Direction
Opcode uint16
Payload []byte // Full decrypted packet bytes (includes the 2-byte opcode prefix)
}
// PacketRecordHeaderSize is the fixed overhead per packet record (before payload).
const PacketRecordHeaderSize = 8 + 1 + 2 + 4 // 15 bytes