bedrocktool/handlers/packet_logger.go

256 lines
5.6 KiB
Go
Raw Normal View History

2023-04-04 01:51:13 +00:00
package handlers
2022-09-04 14:26:32 +00:00
import (
2023-04-04 00:42:17 +00:00
"bufio"
2022-09-04 14:26:32 +00:00
"bytes"
"fmt"
"io"
2022-09-04 14:26:32 +00:00
"net"
2023-04-04 00:42:17 +00:00
"os"
2022-09-04 14:26:32 +00:00
"reflect"
"strings"
"sync"
2022-09-04 14:26:32 +00:00
2023-04-04 01:51:13 +00:00
"github.com/bedrock-tool/bedrocktool/utils"
2023-04-04 00:42:17 +00:00
"github.com/bedrock-tool/bedrocktool/utils/crypt"
2022-09-04 23:40:55 +00:00
"github.com/fatih/color"
2022-09-04 14:26:32 +00:00
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
"github.com/sirupsen/logrus"
"golang.org/x/exp/slices"
)
2022-09-05 11:13:43 +00:00
var MutedPackets = []string{
2022-09-04 23:40:55 +00:00
"packet.UpdateBlock",
"packet.MoveActorAbsolute",
"packet.SetActorMotion",
"packet.SetTime",
"packet.RemoveActor",
"packet.AddActor",
"packet.UpdateAttributes",
"packet.Interact",
"packet.LevelEvent",
"packet.SetActorData",
"packet.MoveActorDelta",
"packet.MovePlayer",
"packet.BlockActorData",
"packet.PlayerAuthInput",
"packet.LevelChunk",
"packet.LevelSoundEvent",
"packet.ActorEvent",
"packet.NetworkChunkPublisherUpdate",
"packet.UpdateSubChunkBlocks",
"packet.SubChunk",
"packet.SubChunkRequest",
"packet.Animate",
"packet.NetworkStackLatency",
"packet.InventoryTransaction",
2022-09-05 11:35:18 +00:00
"packet.PlaySound",
2022-09-04 14:26:32 +00:00
}
2023-03-11 18:50:13 +00:00
func dmpStruct(level int, inputStruct any, withType bool, isInList bool) (s string) {
2023-01-29 21:20:13 +00:00
tBase := strings.Repeat("\t", level)
2023-03-14 01:07:39 +00:00
if inputStruct == nil {
return "nil"
}
2023-03-11 18:50:13 +00:00
ii := reflect.Indirect(reflect.ValueOf(inputStruct))
typeName := reflect.TypeOf(inputStruct).String()
2023-03-30 11:48:03 +00:00
if typeName == "[]interface {}" {
typeName = "[]any"
}
2023-03-11 18:50:13 +00:00
typeString := ""
if withType {
if slices.Contains([]string{"bool", "string"}, typeName) {
} else {
2023-03-30 11:48:03 +00:00
typeString = typeName
2023-03-11 18:50:13 +00:00
}
}
2023-03-14 01:07:39 +00:00
if strings.HasPrefix(typeName, "protocol.Optional") {
v := ii.MethodByName("Value").Call(nil)
val, set := v[0], v[1]
if !set.Bool() {
s += typeName + " Not Set"
} else {
s += typeName + "{\n" + tBase + "\t"
s += dmpStruct(level+1, val.Interface(), false, false)
s += "\n" + tBase + "}"
}
return
}
2023-03-30 11:48:03 +00:00
switch ii.Kind() {
case reflect.Struct:
2023-03-11 18:50:13 +00:00
if ii.NumField() == 0 {
s += typeName + "{}"
} else {
s += typeName + "{\n"
for i := 0; i < ii.NumField(); i++ {
fieldType := ii.Type().Field(i)
if fieldType.IsExported() {
2023-03-30 11:48:03 +00:00
s += fmt.Sprintf("%s\t%s: %s,\n", tBase, fieldType.Name, dmpStruct(level+1, ii.Field(i).Interface(), true, false))
2023-03-11 18:50:13 +00:00
} else {
s += tBase + " " + fieldType.Name + " (unexported)"
}
}
2023-03-11 18:50:13 +00:00
s += tBase + "}"
}
2023-03-30 11:48:03 +00:00
case reflect.Slice:
s += typeName + "{"
2023-03-11 18:50:13 +00:00
if ii.Len() > 1000 {
2023-03-30 11:48:03 +00:00
s += "<slice too long>"
2023-03-11 18:50:13 +00:00
} else if ii.Len() == 0 {
} else {
2023-03-30 11:48:03 +00:00
e := ii.Index(0)
t := reflect.TypeOf(e.Interface())
is_elem_struct := t.Kind() == reflect.Struct
2023-03-11 18:50:13 +00:00
if is_elem_struct {
s += "\n"
}
for i := 0; i < ii.Len(); i++ {
2023-03-11 18:50:13 +00:00
if is_elem_struct {
s += tBase + "\t"
}
2023-03-30 11:48:03 +00:00
s += dmpStruct(level+1, ii.Index(i).Interface(), false, true) + ","
2023-03-11 18:50:13 +00:00
if is_elem_struct {
s += "\n"
} else {
2023-03-30 11:48:03 +00:00
if i != ii.Len()-1 {
s += " "
}
2023-03-11 18:50:13 +00:00
}
}
if is_elem_struct {
2023-01-29 21:20:13 +00:00
s += tBase
}
}
2023-03-30 11:48:03 +00:00
s += "}"
case reflect.Map:
it := reflect.TypeOf(inputStruct)
valType := it.Elem().String()
if valType == "interface {}" {
valType = "any"
}
2023-03-30 11:48:03 +00:00
keyType := it.Key().String()
s += fmt.Sprintf("map[%s]%s{", keyType, valType)
if ii.Len() > 0 {
s += "\n"
}
iter := ii.MapRange()
for iter.Next() {
k := iter.Key()
v := iter.Value()
s += fmt.Sprintf("%s\t%#v: %s,\n", tBase, k.Interface(), dmpStruct(level+1, v.Interface(), true, false))
}
if ii.Len() > 0 {
s += tBase
}
s += "}"
default:
2023-03-14 01:07:39 +00:00
is_array := ii.Kind() == reflect.Array
2023-03-30 11:48:03 +00:00
add_type := !isInList && !is_array && len(typeString) > 0
if add_type {
s += typeString + "("
2023-03-11 18:50:13 +00:00
}
s += fmt.Sprintf("%#v", ii.Interface())
2023-03-30 11:48:03 +00:00
if add_type {
s += ")"
}
}
return s
}
2022-09-05 11:13:43 +00:00
2023-04-04 01:51:13 +00:00
var dirS2C = color.GreenString("S") + "->" + color.CyanString("C")
var dirC2S = color.CyanString("C") + "->" + color.GreenString("S")
2023-03-30 11:48:03 +00:00
var pool = packet.NewPool()
2023-03-23 19:39:47 +00:00
2023-04-04 01:51:13 +00:00
func NewDebugLogger(extraVerbose bool) *utils.ProxyHandler {
2023-04-04 00:42:17 +00:00
var logPlain, logCrypt, logCryptEnc io.WriteCloser
var packetsLogF *bufio.Writer
2023-04-07 14:35:36 +00:00
var dmpLock sync.Mutex
2023-03-09 13:58:54 +00:00
2023-04-04 00:42:17 +00:00
if extraVerbose {
// open plain text log
logPlain, err := os.Create("packets.log")
if err != nil {
logrus.Error(err)
2022-09-05 11:35:18 +00:00
}
2023-04-04 00:42:17 +00:00
// open gpg log
2023-04-07 14:35:36 +00:00
logCryptEnc, err = crypt.Encer("packets.log.gpg")
2023-04-04 00:42:17 +00:00
if err != nil {
logrus.Error(err)
}
2023-04-07 14:35:36 +00:00
if logPlain != nil || logCryptEnc != nil {
packetsLogF = bufio.NewWriter(io.MultiWriter(logPlain, logCryptEnc))
}
}
2023-04-04 01:51:13 +00:00
var proxy *utils.ProxyContext
return &utils.ProxyHandler{
2023-04-04 00:42:17 +00:00
Name: "Debug",
2023-04-04 01:51:13 +00:00
ProxyRef: func(pc *utils.ProxyContext) {
proxy = pc
},
2023-04-04 00:42:17 +00:00
PacketFunc: func(header packet.Header, payload []byte, src, dst net.Addr) {
var pk packet.Packet
if pkFunc, ok := pool[header.PacketID]; ok {
pk = pkFunc()
} else {
pk = &packet.Unknown{PacketID: header.PacketID, Payload: payload}
}
2022-09-04 23:40:55 +00:00
2023-04-04 00:42:17 +00:00
defer func() {
if recoveredErr := recover(); recoveredErr != nil {
logrus.Errorf("%T: %s", pk, recoveredErr.(error))
}
}()
pk.Marshal(protocol.NewReader(bytes.NewBuffer(payload), 0))
2022-09-04 23:40:55 +00:00
2023-04-07 14:35:36 +00:00
if packetsLogF != nil {
2023-04-04 00:42:17 +00:00
dmpLock.Lock()
packetsLogF.Write([]byte(dmpStruct(0, pk, true, false) + "\n\n\n"))
dmpLock.Unlock()
}
2022-09-07 12:07:33 +00:00
2023-04-04 00:42:17 +00:00
pkName := reflect.TypeOf(pk).String()[1:]
if !slices.Contains(MutedPackets, pkName) {
var dir string = dirS2C
2023-04-04 01:51:13 +00:00
if proxy.IsClient(src) {
dir = dirC2S
2023-04-04 00:42:17 +00:00
}
logrus.Debugf("%s 0x%02x, %s", dir, pk.ID(), pkName)
}
},
OnEnd: func() {
2023-04-12 12:10:45 +00:00
dmpLock.Lock()
2023-04-04 00:42:17 +00:00
if packetsLogF != nil {
packetsLogF.Flush()
}
if logPlain != nil {
logPlain.Close()
}
if logCryptEnc != nil {
logCryptEnc.Close()
}
if logCrypt != nil {
logCrypt.Close()
}
2023-04-12 12:10:45 +00:00
dmpLock.Unlock()
2023-04-04 00:42:17 +00:00
},
}
2022-09-04 14:26:32 +00:00
}
2023-04-04 01:51:13 +00:00
func init() {
// hacky solution to allow proxy to add this
utils.NewDebugLogger = NewDebugLogger
}