mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 23:54:33 +01:00
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.
109 lines
2.6 KiB
Go
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
|