multiserver/command.go

489 lines
12 KiB
Go
Raw Normal View History

2021-01-24 05:00:26 -08:00
package main
2021-01-14 04:40:31 -08:00
2021-01-16 12:48:21 -08:00
import (
2021-02-23 11:09:00 -08:00
"bytes"
2021-01-16 12:48:21 -08:00
"crypto/subtle"
"encoding/binary"
2021-03-29 09:57:30 -07:00
"io"
2021-01-16 12:48:21 -08:00
"log"
"github.com/HimbeerserverDE/srp"
"github.com/anon55555/mt/rudp"
2021-01-16 12:48:21 -08:00
)
2021-01-14 04:40:31 -08:00
const (
2021-01-14 08:09:06 -08:00
ToClientHello = 0x02
ToClientAuthAccept = 0x03
ToClientAcceptSudoMode = 0x04
ToClientDenySudoMode = 0x05
ToClientAccessDenied = 0x0A
ToClientBlockdata = 0x20
ToClientAddNode = 0x21
ToClientRemoveNode = 0x22
ToClientInventory = 0x27
ToClientTimeOfDay = 0x29
2021-04-02 05:19:11 -07:00
ToClientCSMRestrictionFlags = 0x2A
2021-01-14 08:09:06 -08:00
ToClientPlayerSpeed = 0x2B
ToClientMediaPush = 0x2C
ToClientChatMessage = 0x2F
2021-01-14 04:40:31 -08:00
ToClientActiveObjectRemoveAdd = 0x31
2021-01-14 08:09:06 -08:00
ToClientActiveObjectMessages = 0x32
2021-04-02 05:19:11 -07:00
ToClientHP = 0x33
2021-01-14 08:09:06 -08:00
ToClientMovePlayer = 0x34
2021-04-02 05:19:11 -07:00
ToClientFOV = 0x36
2021-01-14 08:09:06 -08:00
ToClientDeathscreen = 0x37
ToClientMedia = 0x38
2021-04-02 05:19:11 -07:00
ToClientToolDef = 0x39
ToClientNodeDef = 0x3A
ToClientCraftItemDef = 0x3B
2021-01-14 08:09:06 -08:00
ToClientAnnounceMedia = 0x3C
2021-04-02 05:19:11 -07:00
ToClientItemDef = 0x3D
2021-01-14 08:09:06 -08:00
ToClientPlaySound = 0x3F
ToClientStopSound = 0x40
ToClientPrivileges = 0x41
ToClientInventoryFormspec = 0x42
ToClientDetachedInventory = 0x43
ToClientShowFormspec = 0x44
ToClientMovement = 0x45
ToClientSpawnParticle = 0x46
2021-04-02 05:19:11 -07:00
ToClientAddParticleSpawner = 0x47
2021-01-14 08:09:06 -08:00
ToClientHudAdd = 0x49
2021-04-02 05:19:11 -07:00
ToClientHudRM = 0x4A
2021-01-14 08:09:06 -08:00
ToClientHudChange = 0x4B
ToClientHudSetFlags = 0x4C
ToClientHudSetParam = 0x4D
ToClientBreath = 0x4E
ToClientSetSky = 0x4F
2021-01-14 04:40:31 -08:00
ToClientOverrideDayNightRatio = 0x50
ToClientLocalPlayerAnimations = 0x51
2021-01-14 08:09:06 -08:00
ToClientEyeOffset = 0x52
2021-04-02 05:19:11 -07:00
ToClientDeleteParticleSpawner = 0x53
2021-01-14 08:09:06 -08:00
ToClientCloudParams = 0x54
ToClientFadeSound = 0x55
ToClientUpdatePlayerList = 0x56
2021-04-02 05:19:11 -07:00
ToClientModChannelMSG = 0x57
ToClientModChannelSignal = 0x58
2021-01-14 08:09:06 -08:00
ToClientNodeMetaChanged = 0x59
ToClientSetSun = 0x5A
ToClientSetMoon = 0x5B
ToClientSetStars = 0x5C
ToClientSrpBytesSB = 0x60
ToClientFormspecPrepend = 0x61
ToClientMinimapModes = 0x62
2021-01-14 04:40:31 -08:00
)
const (
2021-01-14 08:09:06 -08:00
ToServerInit = 0x02
ToServerInit2 = 0x11
ToServerModChannelJoin = 0x17
ToServerModChannelLeave = 0x18
ToServerModChannelMsg = 0x19
2021-01-14 08:09:06 -08:00
ToServerPlayerPos = 0x23
2021-04-02 05:19:11 -07:00
ToServerGotBlocks = 0x24
ToServerDeletedBlocks = 0x25
2021-01-14 04:40:31 -08:00
ToServerInventoryAction = 0x31
2021-01-14 08:09:06 -08:00
ToServerChatMessage = 0x32
ToServerDamage = 0x35
ToServerPlayerItem = 0x37
ToServerRespawn = 0x38
ToServerInteract = 0x39
ToServerRemovedSounds = 0x3A
ToServerNodeMetaFields = 0x3B
2021-01-14 04:40:31 -08:00
ToServerInventoryFields = 0x3C
2021-01-14 08:09:06 -08:00
ToServerRequestMedia = 0x40
ToServerClientReady = 0x43
2021-04-02 05:19:11 -07:00
ToServerFirstSRP = 0x50
ToServerSRPBytesA = 0x51
ToServerSRPBytesM = 0x52
2021-01-14 04:40:31 -08:00
)
const (
AccessDeniedWrongPassword = iota
AccessDeniedUnexpectedData
AccessDeniedSingleplayer
AccessDeniedWrongVersion
AccessDeniedWrongCharsInName
AccessDeniedWrongName
AccessDeniedTooManyUsers
AccessDeniedEmptyPassword
AccessDeniedAlreadyConnected
AccessDeniedServerFail
AccessDeniedCustomString
AccessDeniedShutdown
AccessDeniedCrash
)
2021-03-29 09:57:30 -07:00
func processPktCommand(src, dst *Conn, pkt *rudp.Pkt) bool {
r := ByteReader(*pkt)
origReader := *r
pkt.Reader = &origReader
cmdBytes := make([]byte, 2)
r.Read(cmdBytes)
2021-01-14 08:09:06 -08:00
if src.IsSrv() {
2021-03-29 09:57:30 -07:00
switch cmd := binary.BigEndian.Uint16(cmdBytes); cmd {
2021-01-14 08:09:06 -08:00
case ToClientActiveObjectRemoveAdd:
2021-03-29 09:57:30 -07:00
pkt.Reader = bytes.NewReader(append(cmdBytes, processAoRmAdd(dst, r)...))
2021-01-14 08:09:06 -08:00
return false
2021-02-20 04:17:52 -08:00
case ToClientActiveObjectMessages:
2021-03-29 09:57:30 -07:00
pkt.Reader = bytes.NewReader(append(cmdBytes, processAoMsgs(dst, r)...))
2021-02-20 04:17:52 -08:00
return false
2021-01-17 02:08:34 -08:00
case ToClientChatMessage:
2021-03-29 09:57:30 -07:00
r.Seek(2, io.SeekCurrent)
ReadBytes16(r)
msg := ReadBytes16(r)
2021-03-29 09:57:30 -07:00
w := bytes.NewBuffer([]byte{0x00, ToServerChatMessage})
WriteBytes16(w, msg)
2021-01-17 02:08:34 -08:00
2021-03-29 09:57:30 -07:00
return processServerChatMessage(dst, rudp.Pkt{
Reader: w,
2021-03-29 09:57:30 -07:00
PktInfo: rudp.PktInfo{
Channel: pkt.Channel,
},
})
case ToClientModChannelSignal:
2021-03-29 09:57:30 -07:00
r.Seek(1, io.SeekCurrent)
ch := string(ReadBytes16(r))
2021-03-29 09:57:30 -07:00
state := ReadUint8(r)
2021-03-29 09:57:30 -07:00
r.Seek(2, io.SeekStart)
if ch == rpcCh {
switch sig := ReadUint8(r); sig {
case ModChSigJoinOk:
2021-05-02 04:12:24 -07:00
src.SetUseRPC(true)
case ModChSigSetState:
if state == ModChStateRO {
2021-05-02 04:12:24 -07:00
src.SetUseRPC(false)
}
}
return true
}
2021-03-29 09:57:30 -07:00
return false
2021-04-02 05:19:11 -07:00
case ToClientModChannelMSG:
2021-05-02 04:12:24 -07:00
return processRPC(src, r)
2021-02-09 23:35:14 -08:00
case ToClientBlockdata:
2021-03-29 09:57:30 -07:00
data, drop := processBlockdata(dst, r)
if drop {
return true
}
pkt.Reader = bytes.NewReader(append(cmdBytes, data...))
return false
2021-02-10 22:40:42 -08:00
case ToClientAddNode:
2021-03-29 09:57:30 -07:00
pkt.Reader = bytes.NewReader(append(cmdBytes, processAddnode(dst, r)...))
return false
2021-02-13 10:52:41 -08:00
case ToClientHudAdd:
id := ReadUint32(r)
2021-02-13 10:52:41 -08:00
dst.huds[id] = true
return false
2021-04-02 05:19:11 -07:00
case ToClientHudRM:
id := ReadUint32(r)
2021-02-13 10:52:41 -08:00
dst.huds[id] = false
return false
2021-02-21 03:04:54 -08:00
case ToClientPlaySound:
id := int32(ReadUint32(r))
namelen := ReadUint16(r)
2021-03-29 09:57:30 -07:00
r.Seek(int64(17+namelen), io.SeekStart)
objID := ReadUint16(r)
2021-03-29 09:57:30 -07:00
2021-02-21 03:04:54 -08:00
if objID == dst.currentPlayerCao {
objID = dst.localPlayerCao
} else if objID == dst.localPlayerCao {
objID = dst.currentPlayerCao
}
2021-03-29 09:57:30 -07:00
r.Seek(2, io.SeekStart)
data := make([]byte, r.Len())
r.Read(data)
binary.BigEndian.PutUint16(data[17+namelen:19+namelen], objID)
pkt.Reader = bytes.NewReader(append(cmdBytes, data...))
if loop := ReadUint8(r); loop > 0 {
2021-02-21 03:04:54 -08:00
dst.sounds[id] = true
}
case ToClientStopSound:
id := int32(ReadUint32(r))
2021-02-21 03:04:54 -08:00
dst.sounds[id] = false
2021-04-02 05:19:11 -07:00
case ToClientAddParticleSpawner:
2021-03-29 09:57:30 -07:00
r.Seek(97, io.SeekStart)
texturelen := ReadUint32(r)
2021-03-29 09:57:30 -07:00
r.Seek(int64(6+texturelen), io.SeekCurrent)
id := ReadUint16(r)
2021-03-29 09:57:30 -07:00
2021-02-21 03:24:07 -08:00
if id == dst.currentPlayerCao {
id = dst.localPlayerCao
} else if id == dst.localPlayerCao {
id = dst.currentPlayerCao
}
2021-03-29 09:57:30 -07:00
r.Seek(2, io.SeekStart)
data := make([]byte, r.Len())
r.Read(data)
binary.BigEndian.PutUint16(data[107+texturelen:109+texturelen], id)
pkt.Reader = bytes.NewReader(append(cmdBytes, data...))
2021-02-23 11:09:00 -08:00
case ToClientInventory:
2021-04-02 02:15:44 -07:00
old := *dst.Inv()
2021-03-29 09:57:30 -07:00
if err := dst.Inv().Deserialize(r); err != nil {
2021-02-23 11:09:00 -08:00
return true
}
2021-02-25 00:11:37 -08:00
dst.UpdateHandCapabs()
2021-02-23 11:09:00 -08:00
buf := &bytes.Buffer{}
2021-04-02 02:15:44 -07:00
dst.Inv().SerializeKeep(buf, old)
2021-02-23 11:11:01 -08:00
2021-03-29 09:57:30 -07:00
pkt.Reader = bytes.NewReader(append(cmdBytes, buf.Bytes()...))
2021-02-23 11:09:00 -08:00
return false
2021-03-02 09:30:59 -08:00
case ToClientAccessDenied:
2021-03-09 13:23:41 -08:00
doFallback, ok := ConfKey("do_fallback").(bool)
2021-03-02 09:30:59 -08:00
if ok && !doFallback {
return false
}
reason := ReadUint8(r)
2021-03-29 09:57:30 -07:00
if reason != uint8(AccessDeniedShutdown) && reason != uint8(AccessDeniedCrash) {
2021-03-02 09:30:59 -08:00
return false
}
msg := "shut down"
if reason == uint8(AccessDeniedCrash) {
2021-03-02 09:30:59 -08:00
msg = "crashed"
}
2021-03-09 13:23:41 -08:00
defsrv, ok := ConfKey("default_server").(string)
2021-03-02 09:30:59 -08:00
if !ok {
log.Print("Default server name not set or not a string")
return false
}
if dst.ServerName() == defsrv {
return false
}
dst.SendChatMsg("The minetest server has " + msg + ", connecting you to the default server...")
go dst.Redirect(defsrv)
for src.Forward() {
}
2021-03-10 10:36:37 -08:00
return true
case ToClientMediaPush:
digest := ReadBytes16(r)
name := string(ReadBytes16(r))
cacheByte := ReadUint8(r)
2021-03-29 09:57:30 -07:00
cache := cacheByte == uint8(1)
r.Seek(5, io.SeekCurrent)
data := make([]byte, r.Len())
r.Read(data)
2021-03-10 10:36:37 -08:00
media[string(name)] = &mediaFile{
digest: digest,
data: data,
noCache: !cache,
}
2021-03-29 09:57:30 -07:00
for _, conn := range Conns() {
ack, err := conn.Send(*pkt)
2021-03-10 10:36:37 -08:00
if err != nil {
log.Print(err)
}
<-ack
}
updateMediaCache()
2021-03-02 09:30:59 -08:00
return true
2021-01-14 04:40:31 -08:00
default:
return false
}
} else {
2021-03-29 09:57:30 -07:00
switch cmd := binary.BigEndian.Uint16(cmdBytes); cmd {
2021-01-14 04:40:31 -08:00
case ToServerChatMessage:
return processChatMessage(src, r)
2021-04-02 05:19:11 -07:00
case ToServerFirstSRP:
2021-01-16 12:48:21 -08:00
if src.sudoMode {
src.sudoMode = false
// This is a password change, save verifier and salt
s := ReadBytes16(r)
v := ReadBytes16(r)
2021-01-16 12:48:21 -08:00
2021-04-22 03:33:50 -07:00
SetPassword(src.Username(), v, s)
2021-01-16 12:48:21 -08:00
} else {
2021-01-30 03:24:37 -08:00
log.Print("User " + src.Username() + " at " + src.Addr().String() + " did not enter sudo mode before attempting to change the password")
2021-01-16 12:48:21 -08:00
}
2021-03-29 09:57:30 -07:00
2021-01-16 12:48:21 -08:00
return true
2021-04-02 05:19:11 -07:00
case ToServerSRPBytesA:
2021-01-16 12:48:21 -08:00
if !src.sudoMode {
A := ReadBytes16(r)
2021-01-16 12:48:21 -08:00
2021-04-22 03:33:50 -07:00
v, s, err := Password(src.Username())
2021-01-16 12:48:21 -08:00
if err != nil {
log.Print(err)
return true
}
B, _, K, err := srp.Handshake(A, v)
if err != nil {
log.Print(err)
return true
}
src.srp_s = s
src.srp_A = A
src.srp_B = B
src.srp_K = K
// Send SRP_BYTES_S_B
data := make([]byte, 6+len(s)+len(B))
data[0] = uint8(0x00)
data[1] = uint8(ToClientSrpBytesSB)
binary.BigEndian.PutUint16(data[2:4], uint16(len(s)))
copy(data[4:4+len(s)], s)
binary.BigEndian.PutUint16(data[4+len(s):6+len(s)], uint16(len(B)))
copy(data[6+len(s):6+len(s)+len(B)], B)
w := bytes.NewBuffer([]byte{0x00, ToClientSrpBytesSB})
WriteBytes16(w, s)
WriteBytes16(w, B)
2021-03-29 09:57:30 -07:00
ack, err := src.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-01-16 12:48:21 -08:00
if err != nil {
log.Print(err)
return true
}
<-ack
}
return true
2021-04-02 05:19:11 -07:00
case ToServerSRPBytesM:
2021-01-16 12:48:21 -08:00
if !src.sudoMode {
M := ReadBytes16(r)
2021-03-31 10:27:50 -07:00
M2 := srp.ClientProof([]byte(src.Username()), src.srp_s, src.srp_A, src.srp_B, src.srp_K)
2021-01-16 12:48:21 -08:00
if subtle.ConstantTimeCompare(M, M2) == 1 {
// Password is correct
// Enter sudo mode
src.sudoMode = true
// Send ACCEPT_SUDO_MODE
2021-01-19 11:37:35 -08:00
data := []byte{0, ToClientAcceptSudoMode}
2021-01-16 12:48:21 -08:00
2021-03-29 09:57:30 -07:00
ack, err := src.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-01-16 12:48:21 -08:00
if err != nil {
log.Print(err)
return true
}
<-ack
} else {
// Client supplied wrong password
2021-01-30 03:24:37 -08:00
log.Print("User " + src.Username() + " at " + src.Addr().String() + " supplied wrong password for sudo mode")
2021-01-16 12:48:21 -08:00
// Send DENY_SUDO_MODE
2021-01-19 11:37:35 -08:00
data := []byte{0, ToClientDenySudoMode}
2021-01-16 12:48:21 -08:00
2021-03-29 09:57:30 -07:00
ack, err := src.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-01-16 12:48:21 -08:00
if err != nil {
log.Print(err)
return true
}
<-ack
}
}
return true
case ToServerModChannelJoin:
2021-03-20 11:38:57 -07:00
deny := func() {
data := make([]byte, 5+len(rpcCh))
data[0] = uint8(0x00)
data[1] = uint8(ToClientModChannelSignal)
data[2] = uint8(ModChSigJoinFail)
binary.BigEndian.PutUint16(data[3:5], uint16(len(rpcCh)))
copy(data[5:], []byte(rpcCh))
2021-03-29 09:57:30 -07:00
ack, err := src.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
<-ack
2021-03-20 11:38:57 -07:00
}
chAllowed, ok := ConfKey("modchannels").(bool)
if ok && !chAllowed {
deny()
return true
}
ch := string(ReadBytes16(r))
2021-03-20 11:38:57 -07:00
if ch == rpcCh {
deny()
return true
}
src.modChs[ch] = true
return false
case ToServerModChannelLeave:
2021-03-20 11:38:57 -07:00
deny := func() {
data := make([]byte, 5+len(rpcCh))
data[0] = uint8(0x00)
data[1] = uint8(ToClientModChannelSignal)
data[2] = uint8(ModChSigLeaveFail)
binary.BigEndian.PutUint16(data[3:5], uint16(len(rpcCh)))
copy(data[5:], []byte(rpcCh))
2021-03-29 09:57:30 -07:00
ack, err := src.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
<-ack
2021-03-20 11:38:57 -07:00
}
2021-03-20 11:38:57 -07:00
chAllowed, ok := ConfKey("modchannels").(bool)
if ok && !chAllowed {
deny()
return true
}
ch := string(ReadBytes16(r))
2021-03-20 11:38:57 -07:00
if ch == rpcCh {
deny()
return true
}
src.modChs[ch] = false
return false
case ToServerModChannelMsg:
2021-03-20 11:38:57 -07:00
chAllowed, ok := ConfKey("modchannels").(bool)
if ok && !chAllowed {
return true
}
ch := string(ReadBytes16(r))
if ch == rpcCh {
return true
}
return false
2021-01-14 04:40:31 -08:00
default:
return false
}
}
2021-01-16 12:48:21 -08:00
return false
2021-01-14 04:40:31 -08:00
}