From 11bf0624a4de166f94c5084a9095c5e4b358f6f5 Mon Sep 17 00:00:00 2001 From: adman Date: Mon, 12 Jan 2026 17:33:26 +0100 Subject: [PATCH] Mutex --- client/client.go | 7 +++- client/dns.go | 20 +++++++++ client/modules/config_ignorer.go | 4 +- client/modules/login.go | 44 ++++++++++---------- client/modules/status.go | 2 +- crypto/cfb8.go | 22 ++++++++++ event/event_bus.go | 3 +- proto/connection.go | 24 +++++++---- proto/connection_test.go | 2 +- proto/raw_conn.go | 24 ++++++++--- proto_base/base_types.go | 7 +++- proto_generator/helper_generator.go | 2 +- server/server.go | 7 ++-- server/server_modules/login_server.go | 12 +++--- server/server_modules/status.go | 2 +- tools/uncodeable_packet_hunter_proxy/main.go | 8 ++-- 16 files changed, 132 insertions(+), 58 deletions(-) create mode 100644 client/dns.go diff --git a/client/client.go b/client/client.go index 3c70611..0cbc069 100644 --- a/client/client.go +++ b/client/client.go @@ -9,8 +9,11 @@ import ( func Connect(addr string) (ret *proto.Conn, err error) { ret = &proto.Conn{} - ret.Version = "1.21.8" - ret.State = proto_base.Handshaking + err = ret.SetVersion("1.21.8") + if err != nil { + return + } + ret.SetState(proto_base.Handshaking) ret.CompressionThreshold = -1 ret.Actor = proto_base.Client ret.Conn, err = net.Dial("tcp", addr) diff --git a/client/dns.go b/client/dns.go new file mode 100644 index 0000000..338a7f1 --- /dev/null +++ b/client/dns.go @@ -0,0 +1,20 @@ +package client + +import ( + "net" + "strings" +) + +func LookupMinecraftSRV(host string, port uint16) (hostRet string, portRet uint16) { + if port != 25565 { + return + } + _, srvs, err := net.LookupSRV("minecraft", "tcp", host) + if err != nil || len(srvs) == 0 { + return + } + target := strings.TrimSuffix(srvs[0].Target, ".") + hostRet = target + portRet = srvs[0].Port + return +} diff --git a/client/modules/config_ignorer.go b/client/modules/config_ignorer.go index 4bcf493..1c3ecfc 100644 --- a/client/modules/config_ignorer.go +++ b/client/modules/config_ignorer.go @@ -28,7 +28,7 @@ func (c *ConfigIgnorer) OnFinish(_ v1_21_8.ConfigurationToClientPacketFinishConf if err != nil { return } - c.State = proto_base.Play + c.SetState(proto_base.Play) err = event.ErrHandlerDone return } @@ -44,7 +44,7 @@ func (c *ConfigIgnorer) OnKeepAlive(packet *v1_21_8.ConfigurationToClientPacketK } func IgnoreConfig(c *proto.Conn) (err error) { - err = c.StartOne(&ConfigIgnorer{c}) + err = c.Start(&ConfigIgnorer{c}) if err != nil { err = errors.Join(err, errors.New("failed to ignore config")) } diff --git a/client/modules/login.go b/client/modules/login.go index fc2c439..85bbfa0 100644 --- a/client/modules/login.go +++ b/client/modules/login.go @@ -16,13 +16,14 @@ import ( "github.com/admin-else/strom/proto" "github.com/admin-else/strom/proto_base" - "github.com/admin-else/strom/data" "github.com/admin-else/strom/proto_generated/v1_21_8" ) type LoginClient struct { *proto.Conn - Account *api.Account + Account *api.Account + ServerHost string + ServerPort uint16 GivenAccount *v1_21_8.LoginToClientPacketSuccess } @@ -37,29 +38,30 @@ func (s *LoginClient) OnCycle(_ event.Tick) (err error) { } func (s *LoginClient) OnStart(_ event.OnStart) (err error) { - host, portStr, err := net.SplitHostPort(s.RemoteAddr().String()) - if err != nil { - return - } - versionData, err := data.LookUpProtocolVersionByName(s.Version) - if err != nil { - return - } - s.ProtocolVersion = int32(versionData.Version) - port, err := strconv.Atoi(portStr) - if err != nil { - return + if s.ServerHost == "" && s.ServerPort == 0 { + var portStr string + s.ServerHost, portStr, err = net.SplitHostPort(s.RemoteAddr().String()) + if err != nil { + return + } + var portUint uint64 + portUint, err = strconv.ParseUint(portStr, 10, 16) + if err != nil { + return + } + s.ServerPort = uint16(portUint) } + err = s.Send(&v1_21_8.HandshakingToServerPacketSetProtocol{ ProtocolVersion: s.ProtocolVersion, - ServerHost: host, - ServerPort: uint16(port), + ServerHost: s.ServerHost, + ServerPort: s.ServerPort, NextState: int32(proto_base.Login), }) if err != nil { return } - s.State = proto_base.Login + s.SetState(proto_base.Login) err = s.Send(&v1_21_8.LoginToServerPacketLoginStart{Username: s.Account.Name, PlayerUUID: s.Account.Uuid}) return } @@ -118,13 +120,13 @@ func (s *LoginClient) OnSuccess(success *v1_21_8.LoginToClientPacketSuccess) (er if err != nil { return } - s.State = proto_base.Configuration + s.SetState(proto_base.Configuration) err = event.ErrHandlerDone return } func Login(c *proto.Conn, account *api.Account) (err error) { - err = c.StartOne(&LoginClient{ + err = c.Start(&LoginClient{ Conn: c, Account: account, }) @@ -139,12 +141,12 @@ func ConnectAndLogin(connectTo string, account *api.Account) (c *proto.Conn, err if err != nil { return } - err = c.StartOne(&LoginClient{ + err = c.Start(&LoginClient{ Conn: c, Account: account, }) if err != nil { - err = errors.Join(err, errors.New("failed to login")) + err = errors.Join(errors.New("failed to login"), err) } return } diff --git a/client/modules/status.go b/client/modules/status.go index e264e42..b8439a2 100644 --- a/client/modules/status.go +++ b/client/modules/status.go @@ -42,7 +42,7 @@ func (s *StatusClient) OnStart(_ event.OnStart) (err error) { if err != nil { return } - s.State = proto_base.Status + s.SetState(proto_base.Status) err = s.Send(&v1_21_8.StatusToServerPacketPingStart{}) return } diff --git a/crypto/cfb8.go b/crypto/cfb8.go index 8613e3a..a000997 100644 --- a/crypto/cfb8.go +++ b/crypto/cfb8.go @@ -3,6 +3,28 @@ package crypto // https://github.com/Tnze/go-mc/blob/master/net/CFB8/cfb8.go // Package CFB8 implements CFB8 block cipher mode of operation used by Minecraft protocol. +// MIT License +// +//Copyright (c) 2019 Tnze +// +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files (the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions: +// +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. +// +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. + import ( "crypto/cipher" "crypto/subtle" diff --git a/event/event_bus.go b/event/event_bus.go index 54cf16b..af43ee7 100644 --- a/event/event_bus.go +++ b/event/event_bus.go @@ -33,6 +33,7 @@ var ErrHandlerDone = errors.New("handler done") // ErrDontForward will stop the event from being forwarded to other handlers, including anything handlers. var ErrDontForward = errors.New("dont forward") +// FindHandlers initializes and populates the HandlerFunctions map by reflecting over methods of registered handlers. func (l *Loop) FindHandlers() { l.HandlerFunctions = make(map[reflect.Type][]reflect.Value) for _, inst := range l.Handlers { @@ -62,7 +63,7 @@ func (l *Loop) FireFound(event any) (found bool, err error) { errV := handler.Call([]reflect.Value{reflect.ValueOf(event)})[0] if !errV.IsNil() { err = errV.Interface().(error) - err = errors.Join(err, fmt.Errorf("event handler failed: at ")) + err = errors.Join(fmt.Errorf("event handler failed at: %s(%T)", handler.Type().In(0), event), err) return } } diff --git a/proto/connection.go b/proto/connection.go index 54a405c..80b0998 100644 --- a/proto/connection.go +++ b/proto/connection.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "io" + "sync" "github.com/admin-else/strom/data" "github.com/admin-else/strom/event" @@ -34,12 +35,25 @@ func (u *UnCodablePacket) Decode(r io.Reader) (err error) { type Conn struct { RawConn *event.Loop - State proto_base.State + state proto_base.State + stateMutex sync.RWMutex Actor proto_base.Actor Version string ProtocolVersion int32 } +func (c *Conn) SetState(state proto_base.State) { + c.stateMutex.Lock() + defer c.stateMutex.Unlock() + c.state = state +} + +func (c *Conn) State() proto_base.State { + c.stateMutex.RLock() + defer c.stateMutex.RUnlock() + return c.state +} + func (c *Conn) SetVersion(version string) (err error) { c.Version = version versionData, err := data.LookUpProtocolVersionByName(c.Version) @@ -55,7 +69,7 @@ func (c *Conn) Send(packet proto_base.EncodeDecodeAble) (err error) { case *UnCodablePacket: err = c.SendRaw(packet.Data) default: - i, ok := LookupPacketInfoByTypeLookupPacketInfoByTypeAndMore(packet, c.State) + i, ok := LookupPacketInfoByTypeLookupPacketInfoByTypeAndMore(packet, c.State()) if !ok { err = BadPacketTypeError } @@ -83,7 +97,7 @@ func (c *Conn) Receive() (packet proto_base.EncodeDecodeAble, err error) { if err != nil { return } - packet, ok := LookUpTypeByPacketInfoAndCopyType(c.Actor.ReceiveDirection(), c.State, id, c.ProtocolVersion) + packet, ok := LookUpTypeByPacketInfoAndCopyType(c.Actor.ReceiveDirection(), c.State(), id, c.ProtocolVersion) if !ok { packet = &UnCodablePacket{Err: BadPacketIdError, Data: packetBytes, Direction: c.Actor.ReceiveDirection()} return @@ -110,10 +124,6 @@ func (c *Conn) OnTick(_ event.Tick) (err error) { return } -func (c *Conn) StartOne(handler any) (err error) { - return c.Start(handler) -} - func (c *Conn) Start(handlers ...any) (err error) { c.Loop = &event.Loop{} c.Handlers = append(c.Handlers, c) diff --git a/proto/connection_test.go b/proto/connection_test.go index 78194c5..58754f1 100644 --- a/proto/connection_test.go +++ b/proto/connection_test.go @@ -25,7 +25,7 @@ func NewStateFuzzer(state proto_base.State, actor proto_base.Actor) func(t *test b1 := bytes.NewBuffer(inbytes) b2 := bytes.NewBuffer(nil) conn := server.Servee(nil) - conn.State = state + conn.SetState(state) conn.Actor = actor conn.R = b1 conn.W = b2 diff --git a/proto/raw_conn.go b/proto/raw_conn.go index 56fd45d..ce97921 100644 --- a/proto/raw_conn.go +++ b/proto/raw_conn.go @@ -21,15 +21,21 @@ type RawConn struct { } func (c *RawConn) SendRaw(rawPacketBytes []byte) (err error) { + //fmt.Println("send:", rawPacketBytes) var packetBytes []byte if c.CompressionThreshold > 0 { packetBuffer := bytes.NewBuffer(nil) - if int32(len(packetBytes)) >= c.CompressionThreshold { - err = proto_base.EncodeVarInt(packetBuffer, int32(len(packetBytes))) + if int32(len(rawPacketBytes)) >= c.CompressionThreshold { + err = proto_base.EncodeVarInt(packetBuffer, int32(len(rawPacketBytes))) if err != nil { return } - _, err = zlib.NewWriter(packetBuffer).Write(rawPacketBytes) + zW := zlib.NewWriter(packetBuffer) + _, err = zW.Write(rawPacketBytes) + if err != nil { + return + } + err = zW.Close() if err != nil { return } @@ -47,11 +53,16 @@ func (c *RawConn) SendRaw(rawPacketBytes []byte) (err error) { } else { packetBytes = rawPacketBytes } - err = proto_base.EncodeVarInt(c.W, int32(len(packetBytes))) + packetWithLenBuffer := bytes.NewBuffer(nil) + err = proto_base.EncodeVarInt(packetWithLenBuffer, int32(len(packetBytes))) if err != nil { return } - _, err = c.W.Write(packetBytes) + _, err = packetWithLenBuffer.Write(packetBytes) + if err != nil { + return + } + _, err = c.W.Write(packetWithLenBuffer.Bytes()) return } @@ -86,15 +97,16 @@ func (c *RawConn) ReceiveRaw() (packetBytes []byte, err error) { if err != nil { return } - defer zReader.Close() packetBytes, err = io.ReadAll(zReader) if err != nil { return } + err = zReader.Close() } } else { packetBytes = rawPacketBytes } + //fmt.Println("recv:", packetBytes) return } diff --git a/proto_base/base_types.go b/proto_base/base_types.go index 353c094..4c7201c 100644 --- a/proto_base/base_types.go +++ b/proto_base/base_types.go @@ -28,7 +28,7 @@ func (d Direction) Opposite() Direction { return d ^ 1 } -type State int +type State int32 const ( Handshaking State = iota @@ -82,7 +82,10 @@ var ToDoError = errors.New("to do") var BadTypeError = errors.New("bad type") func (b *RestBuffer) Encode(w io.Writer) (err error) { - _, err = w.Write(*b) + n, err := w.Write(*b) + if n != len(*b) { + panic("fucking write not writing all") + } return } diff --git a/proto_generator/helper_generator.go b/proto_generator/helper_generator.go index 04d11c7..f0294d1 100644 --- a/proto_generator/helper_generator.go +++ b/proto_generator/helper_generator.go @@ -46,7 +46,7 @@ func GeneratePacketInfoFile(versions []string, packetInfos []PacketInfo) (err er KeyValueExpr(Ident("Type"), AddrOf(CompLit(typeExpr, nil))), KeyValueExpr(Ident("Name"), StrLit(p.Name)), KeyValueExpr(Ident("Direction"), Selector("proto_base", p.Direction)), - KeyValueExpr(Ident("State"), Selector("proto_base", p.State)), + KeyValueExpr(Ident("state"), Selector("proto_base", p.State)), KeyValueExpr(Ident("PacketId"), NumLit(int(packetId))), KeyValueExpr(Ident("ProtocolVersion"), NumLit(protocolVersion)), })) diff --git a/server/server.go b/server/server.go index 6cd9127..b2b78f8 100644 --- a/server/server.go +++ b/server/server.go @@ -10,9 +10,8 @@ import ( func Servee(c net.Conn) (ret *proto.Conn) { ret = &proto.Conn{} - ret.Version = "1.21.8" - ret.ProtocolVersion = 772 - ret.State = proto_base.Handshaking + _ = ret.SetVersion("1.21.8") // cant fail + ret.SetState(proto_base.Handshaking) ret.CompressionThreshold = -1 ret.Actor = proto_base.Server ret.Conn = c @@ -27,7 +26,7 @@ func ServeClient(cNet net.Conn, factory func(c *proto.Conn) (h any, err error)) if err != nil { return } - err = c.StartOne(h) + err = c.Start(h) return } diff --git a/server/server_modules/login_server.go b/server/server_modules/login_server.go index b35710e..476cf5f 100644 --- a/server/server_modules/login_server.go +++ b/server/server_modules/login_server.go @@ -28,14 +28,16 @@ func (u UnexpectedNextStateError) Error() string { type LoginServer struct { *proto.Conn - //OnlineMode bool TODO: implement this + //OnlineMode bool FIXME: implement this + ServerHost string Requested NameAndUUID Given *NameAndUUID CompressionThreshold int32 } func (l *LoginServer) OnHandshake(packet *v1_21_8.HandshakingToServerPacketSetProtocol) (err error) { - l.State = proto_base.State(packet.NextState) + l.SetState(proto_base.State(packet.NextState)) + l.ServerHost = packet.ServerHost if packet.NextState != int32(proto_base.Login) { err = UnexpectedNextStateError{proto_base.State(packet.NextState)} return @@ -70,7 +72,7 @@ func (l *LoginServer) OnLoginStart(packet *v1_21_8.LoginToServerPacketLoginStart } func (l *LoginServer) OnLoginAcknowledged(_ *v1_21_8.LoginToServerPacketLoginAcknowledged) (err error) { - l.State = proto_base.Configuration + l.SetState(proto_base.Configuration) err = event.ErrHandlerDone return } @@ -92,7 +94,7 @@ func (l *LoginServer) OnCycle(_ event.Tick) (err error) { func ServeLogin(c *proto.Conn) (ret *LoginServer, err error) { ret = &LoginServer{Conn: c} ret.CompressionThreshold = 256 - err = ret.StartOne(ret) + err = ret.Start(ret) return } @@ -102,6 +104,6 @@ func ServeLoginWithOtherAccount(c *proto.Conn, a *api.Account) (ret *LoginServer UUID: a.Uuid, }} ret.CompressionThreshold = 256 - err = ret.StartOne(ret) + err = ret.Start(ret) return } diff --git a/server/server_modules/status.go b/server/server_modules/status.go index cb367c8..b2d0ada 100644 --- a/server/server_modules/status.go +++ b/server/server_modules/status.go @@ -54,6 +54,6 @@ func ServeStatus(c *proto.Conn, s StatusResponse) (err error) { Conn: c, Status: string(status), } - err = server.StartOne(server) + err = server.Start(server) return } diff --git a/tools/uncodeable_packet_hunter_proxy/main.go b/tools/uncodeable_packet_hunter_proxy/main.go index 26240f0..e99eeeb 100644 --- a/tools/uncodeable_packet_hunter_proxy/main.go +++ b/tools/uncodeable_packet_hunter_proxy/main.go @@ -74,8 +74,8 @@ func (p *Proxy) OnFinishConfiguration(packet *v1_21_8.ConfigurationToServerPacke if err != nil { return } - p.State = proto_base.Play - p.Client.State = proto_base.Play + p.SetState(proto_base.Play) + p.Client.SetState(proto_base.Play) return } @@ -151,10 +151,10 @@ func main() { defer pc.Close() defer p.Close() go func() { - errChan <- pc.StartOne(pc) + errChan <- pc.Start(pc) }() go func() { - errChan <- p.StartOne(p) + errChan <- p.Start(p) }() err = <-errChan return