mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 07:32:32 +01:00
Add a recording and replay foundation for the MHF network protocol. A RecordingConn decorator wraps network.Conn to transparently capture all decrypted packets to binary .mhfr files, with zero handler changes and zero overhead when disabled. - network/pcap: binary capture format (writer, reader, filters) - RecordingConn: thread-safe Conn decorator with direction tracking - CaptureOptions in config (disabled by default) - Capture wired into all three server types (sign, entrance, channel) - cmd/replay: CLI tool with dump, json, stats, and compare modes - 19 new tests, all passing with -race
90 lines
2.1 KiB
Go
90 lines
2.1 KiB
Go
package pcap
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// Writer writes .mhfr capture files.
|
|
type Writer struct {
|
|
bw *bufio.Writer
|
|
}
|
|
|
|
// NewWriter creates a Writer, immediately writing the file header and metadata block.
|
|
func NewWriter(w io.Writer, header FileHeader, meta SessionMetadata) (*Writer, error) {
|
|
metaBytes, err := json.Marshal(&meta)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("pcap: marshal metadata: %w", err)
|
|
}
|
|
header.MetadataLen = uint32(len(metaBytes))
|
|
|
|
bw := bufio.NewWriter(w)
|
|
|
|
// Write 32-byte file header.
|
|
if _, err := bw.WriteString(Magic); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := binary.Write(bw, binary.BigEndian, header.Version); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := bw.WriteByte(byte(header.ServerType)); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := bw.WriteByte(header.ClientMode); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := binary.Write(bw, binary.BigEndian, header.SessionStartNs); err != nil {
|
|
return nil, err
|
|
}
|
|
// 4 bytes reserved
|
|
if _, err := bw.Write(make([]byte, 4)); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := binary.Write(bw, binary.BigEndian, header.MetadataLen); err != nil {
|
|
return nil, err
|
|
}
|
|
// 8 bytes reserved
|
|
if _, err := bw.Write(make([]byte, 8)); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Write metadata JSON block.
|
|
if _, err := bw.Write(metaBytes); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := bw.Flush(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Writer{bw: bw}, nil
|
|
}
|
|
|
|
// WritePacket appends a single packet record.
|
|
func (w *Writer) WritePacket(rec PacketRecord) error {
|
|
if err := binary.Write(w.bw, binary.BigEndian, rec.TimestampNs); err != nil {
|
|
return err
|
|
}
|
|
if err := w.bw.WriteByte(byte(rec.Direction)); err != nil {
|
|
return err
|
|
}
|
|
if err := binary.Write(w.bw, binary.BigEndian, rec.Opcode); err != nil {
|
|
return err
|
|
}
|
|
if err := binary.Write(w.bw, binary.BigEndian, uint32(len(rec.Payload))); err != nil {
|
|
return err
|
|
}
|
|
if _, err := w.bw.Write(rec.Payload); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Flush flushes the buffered writer.
|
|
func (w *Writer) Flush() error {
|
|
return w.bw.Flush()
|
|
}
|