mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-27 01:53:19 +01:00
feat(network): add protocol packet capture and replay system
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
This commit is contained in:
65
network/pcap/recording_conn.go
Normal file
65
network/pcap/recording_conn.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package pcap
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"erupe-ce/network"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RecordingConn wraps a network.Conn and records all packets to a Writer.
|
||||
// It is safe for concurrent use from separate send/recv goroutines.
|
||||
type RecordingConn struct {
|
||||
inner network.Conn
|
||||
writer *Writer
|
||||
startNs int64
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// NewRecordingConn wraps inner, recording all packets to w.
|
||||
// startNs is the session start time in nanoseconds (used as the time base).
|
||||
func NewRecordingConn(inner network.Conn, w *Writer, startNs int64) *RecordingConn {
|
||||
return &RecordingConn{
|
||||
inner: inner,
|
||||
writer: w,
|
||||
startNs: startNs,
|
||||
}
|
||||
}
|
||||
|
||||
// ReadPacket reads from the inner connection and records the packet as client-to-server.
|
||||
func (rc *RecordingConn) ReadPacket() ([]byte, error) {
|
||||
data, err := rc.inner.ReadPacket()
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
rc.record(DirClientToServer, data)
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// SendPacket sends via the inner connection and records the packet as server-to-client.
|
||||
func (rc *RecordingConn) SendPacket(data []byte) error {
|
||||
err := rc.inner.SendPacket(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rc.record(DirServerToClient, data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rc *RecordingConn) record(dir Direction, data []byte) {
|
||||
var opcode uint16
|
||||
if len(data) >= 2 {
|
||||
opcode = binary.BigEndian.Uint16(data[:2])
|
||||
}
|
||||
|
||||
rec := PacketRecord{
|
||||
TimestampNs: time.Now().UnixNano(),
|
||||
Direction: dir,
|
||||
Opcode: opcode,
|
||||
Payload: data,
|
||||
}
|
||||
|
||||
rc.mu.Lock()
|
||||
_ = rc.writer.WritePacket(rec)
|
||||
rc.mu.Unlock()
|
||||
}
|
||||
Reference in New Issue
Block a user