diff --git a/client/handshake_packet.go b/client/handshake_packet.go index b09ddb8..20c1c2d 100644 --- a/client/handshake_packet.go +++ b/client/handshake_packet.go @@ -13,6 +13,7 @@ func MakeHandshakePacket(c *proto.Conn, nextState proto_base.State) (p *v1_21_8. return MakeHandshakePacketAddr(c, nextState, c.RemoteAddr().String()) } +// MakeHandshakePacketAddr gets a custom addr func MakeHandshakePacketAddr(s *proto.Conn, nextState proto_base.State, addr string) (p *v1_21_8.HandshakingToServerPacketSetProtocol, err error) { p = &v1_21_8.HandshakingToServerPacketSetProtocol{NextState: int32(nextState), ProtocolVersion: s.ProtocolVersion} var portStr string diff --git a/client/login.go b/client/login.go index b4f489a..bde3521 100644 --- a/client/login.go +++ b/client/login.go @@ -127,7 +127,7 @@ func (s *LoginClient) OnStart() (err error) { return } -func Login(c *proto.Conn, account *api.Account) (err error) { +func LoginRaw(c *proto.Conn, account *api.Account, addr string) (err error) { lc := &LoginClient{ Conn: c, Account: account, @@ -159,11 +159,24 @@ func Login(c *proto.Conn, account *api.Account) (err error) { return } -func ConnectAndLogin(connectTo string, account *api.Account) (c *proto.Conn, err error) { +func LoginNoSrv(connectTo string, account *api.Account) (c *proto.Conn, err error) { c, err = Connect(connectTo) if err != nil { return } - err = Login(c, account) + err = LoginRaw(c, account, connectTo) + return +} + +func Login(connectTo string, account *api.Account) (c *proto.Conn, err error) { + connectTo, err = DoDnsSimple(connectTo) + if err != nil { + return + } + c, err = Connect(connectTo) + if err != nil { + return + } + err = LoginRaw(c, account, connectTo) return } diff --git a/client/status.go b/client/status.go index f1ef7bd..1c04ee4 100644 --- a/client/status.go +++ b/client/status.go @@ -37,7 +37,8 @@ func (s *StatusClient) OnPong(p *v1_21_8.StatusToClientPacketPing) (err error) { } // StatusRaw returns a StatusClient that is not connected to a server. -// So ignore the resource leak warning. And maybe attach a warn ignore comment +// So ignore the resource leak warning. And maybe attach a warn ignore comment. +// It does not resolve SRV records. func StatusRaw(addr string) (s *StatusClient, err error) { c, err := ConnectVersionLess(addr) if err != nil { @@ -69,7 +70,8 @@ func StatusRaw(addr string) (s *StatusClient, err error) { return } -func Status(addr string) (status server.StatusResponse, err error) { +// StatusNoDns is like Status but does not resolve SRV records. +func StatusNoDns(addr string) (status server.StatusResponse, err error) { s, err := StatusRaw(addr) if err != nil { return @@ -77,3 +79,12 @@ func Status(addr string) (status server.StatusResponse, err error) { err = json.Unmarshal([]byte(s.Status), &status) return } + +// Status resolves the status of the minecraft server at the given address. +func Status(addr string) (status server.StatusResponse, err error) { + addr, err = DoDnsSimple(addr) + if err != nil { + return + } + return StatusNoDns(addr) +} diff --git a/cmd/strom/main.go b/cmd/strom/main.go index e312d37..d46ecce 100644 --- a/cmd/strom/main.go +++ b/cmd/strom/main.go @@ -9,6 +9,7 @@ import ( "slices" "github.com/admin-else/strom/cmd/strom/offline_uuid" + "github.com/admin-else/strom/cmd/strom/packet_inspector" "github.com/admin-else/strom/cmd/strom/print_nbt" "github.com/admin-else/strom/cmd/strom/status" ) @@ -20,6 +21,7 @@ var subcommands = map[string]func(args []string) error{ "offline-uuid": offline_uuid.Run, "print-nbt": print_nbt.Run, "status": status.Run, + "packet-spy": packet_inspector.Run, } func Help(args []string) (err error) { diff --git a/cmd/strom/packet_inspector/main.go b/cmd/strom/packet_inspector/main.go new file mode 100644 index 0000000..1cf7379 --- /dev/null +++ b/cmd/strom/packet_inspector/main.go @@ -0,0 +1,118 @@ +package packet_inspector + +import ( + "flag" + "log/slog" + + "github.com/admin-else/strom/api" + "github.com/admin-else/strom/client" + "github.com/admin-else/strom/event" + "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_11" + "github.com/admin-else/strom/server" + "github.com/admin-else/strom/text" +) + +var Cmd = flag.NewFlagSet("packet-inspector", flag.ContinueOnError) + +var OfflineNameFlag = Cmd.String("name", "packet_inspector", "offline player name") +var Token = Cmd.String("token", "", "token to use") + +var TargetAddr = Cmd.String("addr", "127.0.0.1:25565", "address to connect to") +var ListenAddr = Cmd.String("listen", "127.0.0.1:25566", "address to listen on") + +type Proxy struct { + Client, Servee *proto.Conn + Data nbt.Tag +} + +func (p *Proxy) Start() (err error) { + p.Client.RegisterCritical(p.OnAnything) + p.Servee.RegisterCritical(p.OnAnything) + + p.Servee.RegisterCriticalUntilLatest(p.OnFinishConfiguration) + + errChan := make(chan error) + go func() { + errChan <- p.Client.StartConn() + }() + go func() { + errChan <- p.Servee.StartConn() + }() + err = <-errChan + return +} + +func (p *Proxy) OnAnything(e event.Anything) (err error) { + packet, ok := e.Val.(proto_base.EncodeDecodeAble) + if !ok { + return + } + packetInfo, ok := proto.LookupPacketInfoByType(packet) + if !ok { + return + } + switch packetInfo.Direction { + case proto_base.ToServer: + err = p.Client.Send(packet) + case proto_base.ToClient: + err = p.Servee.Send(packet) + } + return +} + +func (p *Proxy) OnFinishConfiguration(packet *v1_21_11.ConfigurationToServerPacketFinishConfiguration) (err error) { + err = p.Client.Send(packet) + if err != nil { + return + } + p.Servee.SetState(proto_base.Play) + p.Client.SetState(proto_base.Play) + err = event.DontForwardErr + return +} + +var StatusResponse = server.StatusResponse{ + Version: server.StatusResponseVersion{ + Name: text.Pretty("STROM"), + Protocol: 772, + }, + Players: server.StatusResponsePlayers{}, + Description: text.Pretty("Packet spy forwards to " + *TargetAddr), + Favicon: "", + EnforcesSecureChat: false, +} + +func Run(args []string) (err error) { + err = Cmd.Parse(args) + if err != nil { + return + } + slog.SetLogLoggerLevel(slog.LevelDebug) + slog.Info("Starting packet inspector", "listen", *ListenAddr) + err = server.StartServerWithOnConn(*ListenAddr, func(serveeConn *proto.Conn) (err error) { + p := &Proxy{Servee: serveeConn, Client: nil} + var acc = api.NewOfflineAccount(*OfflineNameFlag) + if *Token != "" { + acc, err = api.NewAccountFromYGG(*Token) + if err != nil { + return + } + } + _, err = server.ServeLogin(serveeConn, server.WithOtherAccount(acc), server.WithStatus(StatusResponse)) + if err != nil { + return + } + c, err := client.Login(*TargetAddr, acc) + if err != nil { + return + } + defer c.Close() + p.Client = c + err = p.Start() + return + }) + return +} diff --git a/tools/uncodeable_packet_hunter_proxy/main.go b/tools/uncodeable_packet_hunter_proxy/main.go index e0bc508..179d1de 100644 --- a/tools/uncodeable_packet_hunter_proxy/main.go +++ b/tools/uncodeable_packet_hunter_proxy/main.go @@ -117,7 +117,7 @@ func main() { if err != nil { return } - c, err := client.ConnectAndLogin("127.0.0.1:25565", acc) + c, err := client.LoginNoSrv("127.0.0.1:25565", acc) if err != nil { return }