yes a lot of stuff
This commit is contained in:
@@ -29,7 +29,7 @@ func (c *ConfigIgnorer) OnFinish(_ v1_21_8.ConfigurationToClientPacketFinishConf
|
||||
return
|
||||
}
|
||||
c.SetState(proto_base.Play)
|
||||
err = event.ErrHandlerDone
|
||||
err = event.HandlerDoneErr{}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ func (s *LoginClient) OnSuccess(success *v1_21_8.LoginToClientPacketSuccess) (er
|
||||
return
|
||||
}
|
||||
s.SetState(proto_base.Configuration)
|
||||
err = event.ErrHandlerDone
|
||||
err = event.HandlerDoneErr{}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,6 @@ func (s *StatusClient) OnStart(_ event.OnStart) (err error) {
|
||||
|
||||
func (s *StatusClient) OnStatus(p v1_21_8.StatusToClientPacketServerInfo) (err error) {
|
||||
s.Status = p.Response
|
||||
err = event.ErrHandlerDone
|
||||
err = event.HandlerDoneErr{}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -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
@@ -27,8 +27,18 @@ type (
|
||||
Tick struct{}
|
||||
)
|
||||
|
||||
// ErrHandlerDone will stop the event loop.
|
||||
var ErrHandlerDone = errors.New("handler done")
|
||||
// HandlerDoneErr will stop the event loop and return the error if provided.
|
||||
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.
|
||||
var ErrDontForward = errors.New("dont forward")
|
||||
@@ -101,8 +111,8 @@ func (l *Loop) Start() (err error) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if errors.Is(err, ErrHandlerDone) {
|
||||
err = nil
|
||||
if errors.Is(err, HandlerDoneErr{}) {
|
||||
err = errors.Unwrap(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ func NewStateFuzzer(state proto_base.State, actor proto_base.Actor) func(t *test
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -70,7 +70,7 @@ func FuzzConnHandshakingToClient(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) {
|
||||
@@ -78,7 +78,7 @@ func FuzzConnStatusToClient(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) {
|
||||
@@ -86,7 +86,7 @@ func FuzzConnLoginToClient(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) {
|
||||
@@ -94,7 +94,7 @@ func FuzzConnConfigToClient(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) {
|
||||
|
||||
@@ -41,13 +41,13 @@ const (
|
||||
type Actor int
|
||||
|
||||
const (
|
||||
Server Actor = iota
|
||||
Servee Actor = iota // Servee is the one being served
|
||||
Client
|
||||
)
|
||||
|
||||
func (a Actor) SendDirection() Direction {
|
||||
switch a {
|
||||
case Server:
|
||||
case Servee:
|
||||
return ToClient
|
||||
case Client:
|
||||
return ToServer
|
||||
@@ -58,7 +58,7 @@ func (a Actor) SendDirection() Direction {
|
||||
|
||||
func (a Actor) ReceiveDirection() Direction {
|
||||
switch a {
|
||||
case Server:
|
||||
case Servee:
|
||||
return ToServer
|
||||
case Client:
|
||||
return ToClient
|
||||
|
||||
+12
-4
@@ -1,11 +1,13 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"log"
|
||||
"log/slog"
|
||||
"net"
|
||||
|
||||
"github.com/admin-else/strom/proto"
|
||||
"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) {
|
||||
@@ -13,7 +15,7 @@ func Servee(c net.Conn) (ret *proto.Conn) {
|
||||
_ = ret.SetVersion("1.21.8") // cant fail
|
||||
ret.SetState(proto_base.Handshaking)
|
||||
ret.CompressionThreshold = -1
|
||||
ret.Actor = proto_base.Server
|
||||
ret.Actor = proto_base.Servee
|
||||
ret.Conn = c
|
||||
ret.R = c
|
||||
ret.W = c
|
||||
@@ -57,9 +59,15 @@ func StartServerWithOnConn(listenAddr string, onConn func(c *proto.Conn) (err er
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
connErr := onConn(Servee(cNet))
|
||||
c := Servee(cNet)
|
||||
defer c.Close()
|
||||
connErr := onConn(c)
|
||||
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())
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
package server_modules
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"slices"
|
||||
|
||||
"github.com/admin-else/strom/api"
|
||||
"github.com/admin-else/strom/event"
|
||||
@@ -11,6 +15,8 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
var StatusServedError = errors.New("status served")
|
||||
|
||||
var UnexpectedStatusRequest = UnexpectedNextStateError{proto_base.Status}
|
||||
|
||||
type NameAndUUID struct {
|
||||
@@ -26,25 +32,51 @@ func (u UnexpectedNextStateError) Error() string {
|
||||
return fmt.Sprintf("unexpected next state: %v", u.NextState)
|
||||
}
|
||||
|
||||
var IncompatibleProtocolVersionError = fmt.Errorf("incompatible protocol version")
|
||||
|
||||
type LoginServer struct {
|
||||
*proto.Conn
|
||||
//OnlineMode bool FIXME: implement this
|
||||
ServerHost string
|
||||
ServerPort uint16
|
||||
Requested NameAndUUID
|
||||
Given *NameAndUUID
|
||||
CompressionThreshold int32
|
||||
Status []byte
|
||||
CompatibleVersions []int32
|
||||
}
|
||||
|
||||
func (l *LoginServer) OnHandshake(packet *v1_21_8.HandshakingToServerPacketSetProtocol) (err error) {
|
||||
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)}
|
||||
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)}
|
||||
}
|
||||
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) {
|
||||
err = l.Send(&v1_21_8.LoginToClientPacketCompress{Threshold: threshold})
|
||||
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) {
|
||||
l.SetState(proto_base.Configuration)
|
||||
err = event.ErrHandlerDone
|
||||
err = event.HandlerDoneErr{}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -91,18 +123,59 @@ func (l *LoginServer) OnCycle(_ event.Tick) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func ServeLogin(c *proto.Conn) (ret *LoginServer, err error) {
|
||||
ret = &LoginServer{Conn: c}
|
||||
ret.CompressionThreshold = 256
|
||||
err = ret.Start(ret)
|
||||
type LoginServerSetting func(*LoginServer)
|
||||
|
||||
func WithOtherAccount(a *api.Account) LoginServerSetting {
|
||||
return func(s *LoginServer) {
|
||||
if s.Given == nil {
|
||||
return
|
||||
}
|
||||
|
||||
func ServeLoginWithOtherAccount(c *proto.Conn, a *api.Account) (ret *LoginServer, err error) {
|
||||
ret = &LoginServer{Conn: c, Given: &NameAndUUID{
|
||||
s.Given = &NameAndUUID{
|
||||
Name: a.Name,
|
||||
UUID: a.Uuid,
|
||||
}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithRawStatus(status []byte) LoginServerSetting {
|
||||
return func(s *LoginServer) {
|
||||
s.Status = status
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
err = ret.Start(ret)
|
||||
return
|
||||
|
||||
@@ -5,25 +5,24 @@ import (
|
||||
|
||||
"github.com/admin-else/strom/proto"
|
||||
"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
|
||||
type StatusResponse struct {
|
||||
Version struct {
|
||||
Name string `json:"name"`
|
||||
Name *text.Component `json:"name"`
|
||||
Protocol int `json:"protocol"`
|
||||
} `json:"version"`
|
||||
Players struct {
|
||||
Max int `json:"max"`
|
||||
Online int `json:"online"`
|
||||
Sample []struct {
|
||||
Name string `json:"name"`
|
||||
Name *text.Component `json:"name"`
|
||||
ID string `json:"id"`
|
||||
} `json:"sample"`
|
||||
} `json:"players"`
|
||||
Description struct {
|
||||
Text string `json:"text"`
|
||||
} `json:"description"`
|
||||
Description *text.Component `json:"description"`
|
||||
Favicon string `json:"favicon"`
|
||||
EnforcesSecureChat bool `json:"enforcesSecureChat"`
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// THIS THING IS BROKEN
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/admin-else/strom/proto_generated/v1_21_8"
|
||||
"github.com/admin-else/strom/server"
|
||||
"github.com/admin-else/strom/server/server_modules"
|
||||
"github.com/admin-else/strom/text"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
var StatusResponse = server_modules.StatusResponse{Description: struct {
|
||||
Text string `json:"text"`
|
||||
}{Text: "Un-code-able packet hunter proxy"}, Version: struct {
|
||||
Name string `json:"name"`
|
||||
var StatusResponse = server_modules.StatusResponse{
|
||||
Version: struct {
|
||||
Name *text.Component `json:"name"`
|
||||
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() {
|
||||
err := server.StartServerWithOnConn(":25565", func(serveeConn *proto.Conn) (err error) {
|
||||
p := &Proxy{Conn: serveeConn, Client: nil}
|
||||
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 errors.Is(err, server_modules.UnexpectedStatusRequest) {
|
||||
err = server_modules.ServeStatus(serveeConn, StatusResponse)
|
||||
}
|
||||
return
|
||||
}
|
||||
c, err := modules.ConnectAndLogin("127.0.0.1:25566", acc)
|
||||
|
||||
Reference in New Issue
Block a user