This commit is contained in:
adman
2026-01-12 17:33:26 +01:00
parent 08ddf8dc41
commit 11bf0624a4
16 changed files with 132 additions and 58 deletions
+5 -2
View File
@@ -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)
+20
View File
@@ -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
}
+2 -2
View File
@@ -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"))
}
+23 -21
View File
@@ -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
}
+1 -1
View File
@@ -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
}
+22
View File
@@ -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"
+2 -1
View File
@@ -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
}
}
+17 -7
View File
@@ -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)
+1 -1
View File
@@ -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
+18 -6
View File
@@ -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
}
+5 -2
View File
@@ -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
}
+1 -1
View File
@@ -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)),
}))
+3 -4
View File
@@ -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
}
+7 -5
View File
@@ -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
}
+1 -1
View File
@@ -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
}
+4 -4
View File
@@ -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