yes a lot of stuff

This commit is contained in:
adman
2026-01-18 17:10:46 +01:00
parent ac2713433e
commit 6deff7f6ea
12 changed files with 193 additions and 60 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ func (c *ConfigIgnorer) OnFinish(_ v1_21_8.ConfigurationToClientPacketFinishConf
return return
} }
c.SetState(proto_base.Play) c.SetState(proto_base.Play)
err = event.ErrHandlerDone err = event.HandlerDoneErr{}
return return
} }
+1 -1
View File
@@ -141,7 +141,7 @@ func (s *LoginClient) OnSuccess(success *v1_21_8.LoginToClientPacketSuccess) (er
return return
} }
s.SetState(proto_base.Configuration) s.SetState(proto_base.Configuration)
err = event.ErrHandlerDone err = event.HandlerDoneErr{}
return return
} }
+1 -1
View File
@@ -49,6 +49,6 @@ func (s *StatusClient) OnStart(_ event.OnStart) (err error) {
func (s *StatusClient) OnStatus(p v1_21_8.StatusToClientPacketServerInfo) (err error) { func (s *StatusClient) OnStatus(p v1_21_8.StatusToClientPacketServerInfo) (err error) {
s.Status = p.Response s.Status = p.Response
err = event.ErrHandlerDone err = event.HandlerDoneErr{}
return return
} }
-8
View File
@@ -1,8 +0,0 @@
package error_utils
func Unwrap[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
+14 -4
View File
@@ -27,8 +27,18 @@ type (
Tick struct{} Tick struct{}
) )
// ErrHandlerDone will stop the event loop. // HandlerDoneErr will stop the event loop and return the error if provided.
var ErrHandlerDone = errors.New("handler done") type HandlerDoneErr struct {
Return error
}
func (e HandlerDoneErr) Error() string {
return "HandlerDoneErr"
}
func (e HandlerDoneErr) Unwrap() error {
return e.Return
}
// ErrDontForward will stop the event from being forwarded to other handlers, including anything handlers. // ErrDontForward will stop the event from being forwarded to other handlers, including anything handlers.
var ErrDontForward = errors.New("dont forward") var ErrDontForward = errors.New("dont forward")
@@ -101,8 +111,8 @@ func (l *Loop) Start() (err error) {
break break
} }
} }
if errors.Is(err, ErrHandlerDone) { if errors.Is(err, HandlerDoneErr{}) {
err = nil err = errors.Unwrap(err)
} }
return return
} }
+5 -5
View File
@@ -62,7 +62,7 @@ func NewStateFuzzer(state proto_base.State, actor proto_base.Actor) func(t *test
} }
func FuzzConnHandshakingToServer(f *testing.F) { func FuzzConnHandshakingToServer(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Handshaking, proto_base.Server)) f.Fuzz(NewStateFuzzer(proto_base.Handshaking, proto_base.Servee))
} }
func FuzzConnHandshakingToClient(f *testing.F) { func FuzzConnHandshakingToClient(f *testing.F) {
@@ -70,7 +70,7 @@ func FuzzConnHandshakingToClient(f *testing.F) {
} }
func FuzzConnStatusToServer(f *testing.F) { func FuzzConnStatusToServer(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Status, proto_base.Server)) f.Fuzz(NewStateFuzzer(proto_base.Status, proto_base.Servee))
} }
func FuzzConnStatusToClient(f *testing.F) { func FuzzConnStatusToClient(f *testing.F) {
@@ -78,7 +78,7 @@ func FuzzConnStatusToClient(f *testing.F) {
} }
func FuzzConnLoginToServer(f *testing.F) { func FuzzConnLoginToServer(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Login, proto_base.Server)) f.Fuzz(NewStateFuzzer(proto_base.Login, proto_base.Servee))
} }
func FuzzConnLoginToClient(f *testing.F) { func FuzzConnLoginToClient(f *testing.F) {
@@ -86,7 +86,7 @@ func FuzzConnLoginToClient(f *testing.F) {
} }
func FuzzConnConfigToServer(f *testing.F) { func FuzzConnConfigToServer(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Configuration, proto_base.Server)) f.Fuzz(NewStateFuzzer(proto_base.Configuration, proto_base.Servee))
} }
func FuzzConnConfigToClient(f *testing.F) { func FuzzConnConfigToClient(f *testing.F) {
@@ -94,7 +94,7 @@ func FuzzConnConfigToClient(f *testing.F) {
} }
func FuzzConnPlayToServer(f *testing.F) { func FuzzConnPlayToServer(f *testing.F) {
f.Fuzz(NewStateFuzzer(proto_base.Play, proto_base.Server)) f.Fuzz(NewStateFuzzer(proto_base.Play, proto_base.Servee))
} }
func FuzzConnPlayToClient(f *testing.F) { func FuzzConnPlayToClient(f *testing.F) {
+3 -3
View File
@@ -41,13 +41,13 @@ const (
type Actor int type Actor int
const ( const (
Server Actor = iota Servee Actor = iota // Servee is the one being served
Client Client
) )
func (a Actor) SendDirection() Direction { func (a Actor) SendDirection() Direction {
switch a { switch a {
case Server: case Servee:
return ToClient return ToClient
case Client: case Client:
return ToServer return ToServer
@@ -58,7 +58,7 @@ func (a Actor) SendDirection() Direction {
func (a Actor) ReceiveDirection() Direction { func (a Actor) ReceiveDirection() Direction {
switch a { switch a {
case Server: case Servee:
return ToServer return ToServer
case Client: case Client:
return ToClient return ToClient
+12 -4
View File
@@ -1,11 +1,13 @@
package server package server
import ( import (
"log" "log/slog"
"net" "net"
"github.com/admin-else/strom/proto" "github.com/admin-else/strom/proto"
"github.com/admin-else/strom/proto_base" "github.com/admin-else/strom/proto_base"
"github.com/admin-else/strom/server/server_modules"
"github.com/admin-else/strom/text"
) )
func Servee(c net.Conn) (ret *proto.Conn) { func Servee(c net.Conn) (ret *proto.Conn) {
@@ -13,7 +15,7 @@ func Servee(c net.Conn) (ret *proto.Conn) {
_ = ret.SetVersion("1.21.8") // cant fail _ = ret.SetVersion("1.21.8") // cant fail
ret.SetState(proto_base.Handshaking) ret.SetState(proto_base.Handshaking)
ret.CompressionThreshold = -1 ret.CompressionThreshold = -1
ret.Actor = proto_base.Server ret.Actor = proto_base.Servee
ret.Conn = c ret.Conn = c
ret.R = c ret.R = c
ret.W = c ret.W = c
@@ -57,9 +59,15 @@ func StartServerWithOnConn(listenAddr string, onConn func(c *proto.Conn) (err er
return return
} }
go func() { go func() {
connErr := onConn(Servee(cNet)) c := Servee(cNet)
defer c.Close()
connErr := onConn(c)
if connErr != nil { if connErr != nil {
log.Println(connErr) slog.Error("Error while handling client", "error", connErr, "client", c.Conn.RemoteAddr())
connErr = server_modules.Kick(c, text.Pretty(connErr.Error()))
if connErr != nil {
slog.Error("Error while kicking client", "error", connErr, "client", c.Conn.RemoteAddr())
}
} }
}() }()
} }
+39
View File
@@ -0,0 +1,39 @@
package server_modules
import (
"errors"
"github.com/admin-else/strom/nbt"
"github.com/admin-else/strom/proto"
"github.com/admin-else/strom/proto_base"
"github.com/admin-else/strom/proto_generated/v1_21_8"
"github.com/admin-else/strom/text"
)
var (
NotClientErr = errors.New("not a servee")
CantKickInStateErr = errors.New("cant kick in this state")
)
func Kick(c *proto.Conn, reason *text.Component) (err error) {
if c.Actor != proto_base.Servee {
err = NotClientErr
return
}
switch c.State() {
case proto_base.Handshaking, proto_base.Status:
err = CantKickInStateErr
case proto_base.Login:
var b []byte
b, err = reason.MarshalJSON()
if err != nil {
return
}
err = c.Send(&v1_21_8.LoginToClientPacketDisconnect{Reason: string(b)})
case proto_base.Configuration:
err = c.Send(&v1_21_8.ConfigurationToClientPacketDisconnect{Reason: nbt.Anon{Value: reason.ToNBT()}})
case proto_base.Play:
err = c.Send(&v1_21_8.PlayToClientPacketKickDisconnect{Reason: nbt.Anon{Value: reason.ToNBT()}})
}
return
}
+86 -13
View File
@@ -1,7 +1,11 @@
package server_modules package server_modules
import ( import (
"encoding/json"
"errors"
"fmt" "fmt"
"log/slog"
"slices"
"github.com/admin-else/strom/api" "github.com/admin-else/strom/api"
"github.com/admin-else/strom/event" "github.com/admin-else/strom/event"
@@ -11,6 +15,8 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
) )
var StatusServedError = errors.New("status served")
var UnexpectedStatusRequest = UnexpectedNextStateError{proto_base.Status} var UnexpectedStatusRequest = UnexpectedNextStateError{proto_base.Status}
type NameAndUUID struct { type NameAndUUID struct {
@@ -26,25 +32,51 @@ func (u UnexpectedNextStateError) Error() string {
return fmt.Sprintf("unexpected next state: %v", u.NextState) return fmt.Sprintf("unexpected next state: %v", u.NextState)
} }
var IncompatibleProtocolVersionError = fmt.Errorf("incompatible protocol version")
type LoginServer struct { type LoginServer struct {
*proto.Conn *proto.Conn
//OnlineMode bool FIXME: implement this //OnlineMode bool FIXME: implement this
ServerHost string ServerHost string
ServerPort uint16
Requested NameAndUUID Requested NameAndUUID
Given *NameAndUUID Given *NameAndUUID
CompressionThreshold int32 CompressionThreshold int32
Status []byte
CompatibleVersions []int32
} }
func (l *LoginServer) OnHandshake(packet *v1_21_8.HandshakingToServerPacketSetProtocol) (err error) { func (l *LoginServer) OnHandshake(packet *v1_21_8.HandshakingToServerPacketSetProtocol) (err error) {
l.SetState(proto_base.State(packet.NextState)) l.SetState(proto_base.State(packet.NextState))
l.ServerHost = packet.ServerHost l.ServerHost = packet.ServerHost
if packet.NextState != int32(proto_base.Login) { l.ServerPort = packet.ServerPort
if len(l.CompatibleVersions) != 0 {
if !slices.Contains(l.CompatibleVersions, packet.ProtocolVersion) {
err = IncompatibleProtocolVersionError
return
}
}
if packet.NextState != int32(proto_base.Login) && !(l.Status != nil && packet.NextState == int32(proto_base.Status)) {
err = UnexpectedNextStateError{proto_base.State(packet.NextState)} err = UnexpectedNextStateError{proto_base.State(packet.NextState)}
return
} }
return return
} }
func (l *LoginServer) OnStatusRequest(_ *v1_21_8.StatusToServerPacketPingStart) (err error) {
err = l.Send(&v1_21_8.StatusToClientPacketServerInfo{Response: string(l.Status)})
return
}
func (l *LoginServer) OnStatusPing(packet *v1_21_8.StatusToServerPacketPing) (err error) {
err = l.Send(&v1_21_8.StatusToClientPacketPing{Time: packet.Time})
if err != nil {
return
}
return event.HandlerDoneErr{Return: StatusServedError}
}
func (l *LoginServer) SetCompressionThreshold(threshold int32) (err error) { func (l *LoginServer) SetCompressionThreshold(threshold int32) (err error) {
err = l.Send(&v1_21_8.LoginToClientPacketCompress{Threshold: threshold}) err = l.Send(&v1_21_8.LoginToClientPacketCompress{Threshold: threshold})
if err != nil { if err != nil {
@@ -73,7 +105,7 @@ func (l *LoginServer) OnLoginStart(packet *v1_21_8.LoginToServerPacketLoginStart
func (l *LoginServer) OnLoginAcknowledged(_ *v1_21_8.LoginToServerPacketLoginAcknowledged) (err error) { func (l *LoginServer) OnLoginAcknowledged(_ *v1_21_8.LoginToServerPacketLoginAcknowledged) (err error) {
l.SetState(proto_base.Configuration) l.SetState(proto_base.Configuration)
err = event.ErrHandlerDone err = event.HandlerDoneErr{}
return return
} }
@@ -91,18 +123,59 @@ func (l *LoginServer) OnCycle(_ event.Tick) (err error) {
return return
} }
func ServeLogin(c *proto.Conn) (ret *LoginServer, err error) { type LoginServerSetting func(*LoginServer)
ret = &LoginServer{Conn: c}
ret.CompressionThreshold = 256 func WithOtherAccount(a *api.Account) LoginServerSetting {
err = ret.Start(ret) return func(s *LoginServer) {
return if s.Given == nil {
return
}
s.Given = &NameAndUUID{
Name: a.Name,
UUID: a.Uuid,
}
}
} }
func ServeLoginWithOtherAccount(c *proto.Conn, a *api.Account) (ret *LoginServer, err error) { func WithRawStatus(status []byte) LoginServerSetting {
ret = &LoginServer{Conn: c, Given: &NameAndUUID{ return func(s *LoginServer) {
Name: a.Name, s.Status = status
UUID: a.Uuid, }
}} }
func WithStatus(response StatusResponse) LoginServerSetting {
var status []byte
status, err := json.Marshal(response)
if err != nil {
panic(err)
}
slog.Debug("With status", "status", status)
return WithRawStatus(status)
}
func WithCompatibleVersion(versions int32) LoginServerSetting {
return WithCompatibleVersions([]int32{versions})
}
func WithCompatibleVersionsRange(start, end int32) LoginServerSetting {
var versions []int32
for i := start; i <= end; i++ {
versions = append(versions, i)
}
return WithCompatibleVersions(versions)
}
func WithCompatibleVersions(versions []int32) LoginServerSetting {
return func(s *LoginServer) {
s.CompatibleVersions = versions
}
}
func ServeLogin(c *proto.Conn, settings ...LoginServerSetting) (ret *LoginServer, err error) {
ret = &LoginServer{Conn: c}
for _, s := range settings {
s(ret)
}
ret.CompressionThreshold = 256 ret.CompressionThreshold = 256
err = ret.Start(ret) err = ret.Start(ret)
return return
+8 -9
View File
@@ -5,27 +5,26 @@ import (
"github.com/admin-else/strom/proto" "github.com/admin-else/strom/proto"
"github.com/admin-else/strom/proto_generated/v1_21_8" "github.com/admin-else/strom/proto_generated/v1_21_8"
"github.com/admin-else/strom/text"
) )
// StatusResponse here is the structure I used: https://minecraft.wiki/w/Java_Edition_protocol/Server_List_Ping#Status_Response // StatusResponse here is the structure I used: https://minecraft.wiki/w/Java_Edition_protocol/Server_List_Ping#Status_Response
type StatusResponse struct { type StatusResponse struct {
Version struct { Version struct {
Name string `json:"name"` Name *text.Component `json:"name"`
Protocol int `json:"protocol"` Protocol int `json:"protocol"`
} `json:"version"` } `json:"version"`
Players struct { Players struct {
Max int `json:"max"` Max int `json:"max"`
Online int `json:"online"` Online int `json:"online"`
Sample []struct { Sample []struct {
Name string `json:"name"` Name *text.Component `json:"name"`
ID string `json:"id"` ID string `json:"id"`
} `json:"sample"` } `json:"sample"`
} `json:"players"` } `json:"players"`
Description struct { Description *text.Component `json:"description"`
Text string `json:"text"` Favicon string `json:"favicon"`
} `json:"description"` EnforcesSecureChat bool `json:"enforcesSecureChat"`
Favicon string `json:"favicon"`
EnforcesSecureChat bool `json:"enforcesSecureChat"`
} }
type StatusServer struct { type StatusServer struct {
+23 -11
View File
@@ -1,8 +1,8 @@
// THIS THING IS BROKEN
package main package main
import ( import (
"crypto/sha256" "crypto/sha256"
"errors"
"fmt" "fmt"
"os" "os"
@@ -14,6 +14,7 @@ import (
"github.com/admin-else/strom/proto_generated/v1_21_8" "github.com/admin-else/strom/proto_generated/v1_21_8"
"github.com/admin-else/strom/server" "github.com/admin-else/strom/server"
"github.com/admin-else/strom/server/server_modules" "github.com/admin-else/strom/server/server_modules"
"github.com/admin-else/strom/text"
) )
type ProxyClient struct { type ProxyClient struct {
@@ -123,22 +124,33 @@ func SaveUnCodeAbleAsTest(d proto_base.Direction, packet proto.UnCodablePacket)
fmt.Println("Error", packet.Err, "saved to", f.Name(), "data:", packet.Data) fmt.Println("Error", packet.Err, "saved to", f.Name(), "data:", packet.Data)
} }
var StatusResponse = server_modules.StatusResponse{Description: struct { var StatusResponse = server_modules.StatusResponse{
Text string `json:"text"` Version: struct {
}{Text: "Un-code-able packet hunter proxy"}, Version: struct { Name *text.Component `json:"name"`
Name string `json:"name"` Protocol int `json:"protocol"`
Protocol int `json:"protocol"` }{
}{Name: "STROM", Protocol: 772}} Name: text.Pretty("STROM"),
Protocol: 772,
},
Players: struct {
Max int `json:"max"`
Online int `json:"online"`
Sample []struct {
Name *text.Component `json:"name"`
ID string `json:"id"`
} `json:"sample"`
}{},
Description: text.Pretty("Hunt the uncodeable packets"),
Favicon: "",
EnforcesSecureChat: false,
}
func main() { func main() {
err := server.StartServerWithOnConn(":25565", func(serveeConn *proto.Conn) (err error) { err := server.StartServerWithOnConn(":25565", func(serveeConn *proto.Conn) (err error) {
p := &Proxy{Conn: serveeConn, Client: nil} p := &Proxy{Conn: serveeConn, Client: nil}
acc := api.NewOfflineAccount("sigma") acc := api.NewOfflineAccount("sigma")
_, err = server_modules.ServeLoginWithOtherAccount(serveeConn, acc) _, err = server_modules.ServeLogin(serveeConn, server_modules.WithOtherAccount(acc), server_modules.WithStatus(StatusResponse))
if err != nil { if err != nil {
if errors.Is(err, server_modules.UnexpectedStatusRequest) {
err = server_modules.ServeStatus(serveeConn, StatusResponse)
}
return return
} }
c, err := modules.ConnectAndLogin("127.0.0.1:25566", acc) c, err := modules.ConnectAndLogin("127.0.0.1:25566", acc)