multiserver/init.go

642 lines
14 KiB
Go
Raw Permalink Normal View History

2021-01-24 05:00:26 -08:00
package main
import (
2021-03-29 09:57:30 -07:00
"bytes"
"crypto/subtle"
"encoding/binary"
2021-03-02 08:47:07 -08:00
"errors"
2021-03-29 09:57:30 -07:00
"io"
"log"
2021-01-20 12:44:35 -08:00
"net"
2021-04-06 06:53:08 -07:00
"regexp"
"strings"
"time"
"github.com/HimbeerserverDE/srp"
"github.com/anon55555/mt/rudp"
)
// Init completes the initialisation of a connection to a server or client c2
2021-03-29 09:57:30 -07:00
func Init(c, c2 *Conn, ignMedia, noAccessDenied bool, fin chan *Conn) {
defer close(fin)
2021-03-29 09:57:30 -07:00
if c2.IsSrv() {
// We're trying to connect to a server
// INIT
2021-03-29 09:57:30 -07:00
data := make([]byte, 11+len(c.Username()))
data[0] = uint8(0x00)
2021-01-19 11:37:35 -08:00
data[1] = uint8(ToServerInit)
data[2] = uint8(0x1c)
binary.BigEndian.PutUint16(data[3:5], uint16(0x0000))
2021-03-13 08:15:07 -08:00
binary.BigEndian.PutUint16(data[5:7], uint16(ProtoMin))
binary.BigEndian.PutUint16(data[7:9], uint16(ProtoLatest))
2021-03-29 09:57:30 -07:00
binary.BigEndian.PutUint16(data[9:11], uint16(len(c.Username())))
copy(data[11:], []byte(c.Username()))
time.Sleep(250 * time.Millisecond)
2021-03-29 09:57:30 -07:00
if _, err := c2.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
Unrel: true,
},
}); err != nil {
log.Print(err)
}
for {
2021-03-29 09:57:30 -07:00
pkt, err := c2.Recv()
if err != nil {
2021-03-02 08:47:07 -08:00
if errors.Is(err, net.ErrClosed) {
2021-03-29 09:57:30 -07:00
if err = c2.WhyClosed(); err != nil {
log.Print(c2.Addr().String(), " disconnected with error: ", err)
} else {
log.Print(c2.Addr().String(), " disconnected")
}
return
}
log.Print(err)
continue
}
2021-03-29 09:57:30 -07:00
r := ByteReader(pkt)
switch cmd := ReadUint16(r); cmd {
2021-01-14 10:06:40 -08:00
case ToClientHello:
2021-03-29 09:57:30 -07:00
r.Seek(5, io.SeekStart)
c2.protoVer = ReadUint16(r)
2021-03-29 09:57:30 -07:00
r.Seek(10, io.SeekStart)
authMech := ReadUint8(r)
2021-03-13 08:15:07 -08:00
if authMech&AuthMechSRP > 0 {
// Compute and send SRP_BYTES_A
2021-03-29 09:57:30 -07:00
_, _, err := srp.NewClient([]byte(strings.ToLower(c.Username())), passPhrase)
if err != nil {
log.Print(err)
continue
}
A, a, err := srp.InitiateHandshake()
if err != nil {
log.Print(err)
continue
}
2021-03-29 09:57:30 -07:00
c.srp_A = A
c.srp_a = a
2021-04-02 05:19:11 -07:00
w := bytes.NewBuffer([]byte{0x00, ToServerSRPBytesA})
WriteBytes16(w, c.srp_A)
WriteUint8(w, 1)
2021-03-29 09:57:30 -07:00
ack, err := c2.Send(rudp.Pkt{
Reader: w,
2021-03-29 09:57:30 -07:00
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
log.Print(err)
continue
}
<-ack
} else {
// Compute and send s and v
2021-03-29 09:57:30 -07:00
s, v, err := srp.NewClient([]byte(strings.ToLower(c.Username())), passPhrase)
if err != nil {
log.Print(err)
continue
}
2021-04-02 05:19:11 -07:00
w := bytes.NewBuffer([]byte{0x00, ToServerFirstSRP})
WriteBytes16(w, s)
WriteBytes16(w, v)
WriteUint8(w, 0)
2021-03-29 09:57:30 -07:00
ack, err := c2.Send(rudp.Pkt{
2021-04-02 02:53:19 -07:00
Reader: w,
2021-03-29 09:57:30 -07:00
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
log.Print(err)
continue
}
<-ack
}
2021-01-14 10:06:40 -08:00
case ToClientSrpBytesSB:
// Compute and send SRP_BYTES_M
s := ReadBytes16(r)
2021-03-29 09:57:30 -07:00
r.Seek(2, io.SeekCurrent)
B := make([]byte, r.Len())
r.Read(B)
K, err := srp.CompleteHandshake(c.srp_A, c.srp_a, []byte(strings.ToLower(c.Username())), passPhrase, s, B)
if err != nil {
log.Print(err)
continue
}
2021-03-29 09:57:30 -07:00
c.srp_K = K
2021-03-31 10:27:50 -07:00
M := srp.ClientProof([]byte(c.Username()), s, c.srp_A, B, c.srp_K)
2021-04-02 05:19:11 -07:00
w := bytes.NewBuffer([]byte{0x00, ToServerSRPBytesM})
WriteBytes16(w, M)
2021-03-29 09:57:30 -07:00
ack, err := c2.Send(rudp.Pkt{
2021-04-02 02:53:19 -07:00
Reader: w,
2021-03-29 09:57:30 -07:00
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
log.Print(err)
continue
}
<-ack
2021-01-14 10:06:40 -08:00
case ToClientAccessDenied:
// Auth failed for some reason
2021-03-09 13:23:41 -08:00
servers := ConfKey("servers").(map[interface{}]interface{})
var srv string
for server := range servers {
2021-03-29 09:57:30 -07:00
if ConfKey("servers:"+server.(string)+":address") == c2.Addr().String() {
srv = server.(string)
break
}
}
2021-04-02 07:45:37 -07:00
log.Print("access denied by server " + srv)
2021-01-16 10:14:31 -08:00
if noAccessDenied {
return
}
2021-04-02 04:39:35 -07:00
c.CloseWith(AccessDeniedServerFail, "", false)
return
2021-01-14 10:06:40 -08:00
case ToClientAuthAccept:
// Auth succeeded
2021-03-14 05:52:31 -07:00
defer func() {
2021-03-29 09:57:30 -07:00
fin <- c2
2021-03-14 05:52:31 -07:00
}()
2021-03-29 09:57:30 -07:00
ack, err := c2.Send(rudp.Pkt{
Reader: bytes.NewReader([]byte{0, ToServerInit2, 0, 0}),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
log.Print(err)
continue
}
<-ack
if !ignMedia {
return
}
2021-04-02 05:19:11 -07:00
case ToClientCSMRestrictionFlags:
// Definitions sent (by server)
if !ignMedia {
continue
}
2021-05-02 03:20:52 -07:00
v := []byte("5.5.0-dev-83a7b48bb")
w := bytes.NewBuffer([]byte{0x00, ToServerClientReady})
w.Write([]byte{5, 4, 0, 0})
WriteBytes16(w, v)
2021-05-02 03:20:52 -07:00
if c.FormspecVer() != 1 {
WriteUint16(w, c.FormspecVer())
}
2021-03-29 09:57:30 -07:00
_, err := c2.Send(rudp.Pkt{
2021-04-02 03:38:46 -07:00
Reader: w,
2021-03-29 09:57:30 -07:00
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
if err != nil {
log.Print(err)
continue
}
return
}
}
} else {
// We're trying to initialize a client
for {
2021-03-29 09:57:30 -07:00
pkt, err := c2.Recv()
if err != nil {
2021-03-02 08:47:07 -08:00
if errors.Is(err, net.ErrClosed) {
2021-03-29 09:57:30 -07:00
if err = c2.WhyClosed(); err != nil {
log.Print(c2.Addr().String(), " disconnected with error: ", err)
} else {
log.Print(c2.Addr().String(), " disconnected")
}
2021-03-29 09:57:30 -07:00
connectedConnsMu.Lock()
connectedConns--
connectedConnsMu.Unlock()
2021-01-10 13:37:42 -08:00
2021-03-29 09:57:30 -07:00
processLeave(c2)
return
}
log.Print(err)
continue
}
2021-03-29 09:57:30 -07:00
r := ByteReader(pkt)
switch cmd := ReadUint16(r); cmd {
2021-01-14 10:06:40 -08:00
case ToServerInit:
// Process data
2021-04-02 03:38:46 -07:00
r.Seek(9, io.SeekStart)
c2.username = string(ReadBytes16(r))
2021-03-29 09:57:30 -07:00
r.Seek(5, io.SeekStart)
2021-03-13 08:15:07 -08:00
// Find protocol version
cliProtoMin := ReadUint16(r)
cliProtoMax := ReadUint16(r)
2021-03-29 09:57:30 -07:00
2021-03-13 08:15:07 -08:00
var protov uint16
if cliProtoMax >= ProtoMin || cliProtoMin <= ProtoLatest {
if cliProtoMax > ProtoLatest {
protov = ProtoLatest
} else {
protov = ProtoLatest
}
}
2021-03-29 09:57:30 -07:00
c2.protoVer = protov
2021-03-13 08:15:07 -08:00
if strict, ok := ConfKey("force_latest_proto").(bool); (ok && strict) && (protov != ProtoLatest) || protov < ProtoMin || protov > ProtoLatest {
2021-04-02 04:39:35 -07:00
c2.CloseWith(AccessDeniedWrongVersion, "", false)
2021-03-29 09:57:30 -07:00
fin <- c
2021-03-13 08:15:07 -08:00
return
}
2021-04-06 06:53:08 -07:00
msg := c2.Addr().String() + " tried to connect with "
if len(c2.Username()) == 0 {
c2.CloseWith(AccessDeniedWrongName, "", false)
fin <- c
log.Print(msg + "empty name")
return
} else if len(c2.Username()) > MaxPlayerNameLength {
c2.CloseWith(AccessDeniedWrongCharsInName, "", false)
fin <- c
log.Print(msg + "too long name")
return
}
ok, err := regexp.MatchString(PlayerNameChars, c2.Username())
if err != nil {
log.Print(err)
}
if !ok || err != nil {
c2.CloseWith(AccessDeniedWrongCharsInName, "", false)
fin <- c
log.Print(c2.Addr().String() + " tried to connect with invalid name")
return
}
// Send HELLO
2021-03-29 09:57:30 -07:00
data := make([]byte, 13+len(c2.Username()))
data[0] = uint8(0x00)
2021-01-14 10:06:40 -08:00
data[1] = uint8(ToClientHello)
data[2] = uint8(0x1c)
binary.BigEndian.PutUint16(data[3:5], uint16(0x0000))
2021-03-13 08:15:07 -08:00
binary.BigEndian.PutUint16(data[5:7], uint16(protov))
2021-02-28 04:12:28 -08:00
// Check if user is banned
2021-03-29 09:57:30 -07:00
banned, bname, err := c2.IsBanned()
2021-02-28 04:12:28 -08:00
if err != nil {
log.Print(err)
continue
}
if banned {
2021-03-29 09:57:30 -07:00
log.Print("Banned user " + bname + " at " + c2.Addr().String() + " tried to connect")
2021-04-02 04:39:35 -07:00
reason := "Your IP address is banned. Banned name is " + bname
c2.CloseWith(AccessDeniedCustomString, reason, false)
2021-03-29 09:57:30 -07:00
fin <- c
2021-02-28 04:12:28 -08:00
return
}
2021-01-14 10:06:40 -08:00
// Check if user is already connected
2021-03-29 09:57:30 -07:00
if IsOnline(c2.Username()) {
2021-04-02 04:39:35 -07:00
c2.CloseWith(AccessDeniedAlreadyConnected, "", false)
2021-03-29 09:57:30 -07:00
fin <- c
2021-01-14 10:06:40 -08:00
return
}
2021-01-29 07:21:43 -08:00
// Check if username is reserved for media or RPC
2021-03-29 09:57:30 -07:00
if c2.Username() == "media" || c2.Username() == "rpc" {
2021-04-02 04:39:35 -07:00
c2.CloseWith(AccessDeniedWrongName, "", false)
2021-03-29 09:57:30 -07:00
fin <- c
2021-01-29 07:21:43 -08:00
return
}
2021-04-22 03:33:50 -07:00
v, s, err := Password(c2.Username())
if err != nil {
log.Print(err)
continue
}
2021-04-22 03:33:50 -07:00
if v == nil || s == nil {
// New player
2021-03-29 09:57:30 -07:00
c2.authMech = AuthMechFirstSRP
binary.BigEndian.PutUint32(data[7:11], uint32(AuthMechFirstSRP))
} else {
// Existing player
2021-03-29 09:57:30 -07:00
c2.authMech = AuthMechSRP
binary.BigEndian.PutUint32(data[7:11], uint32(AuthMechSRP))
}
2021-03-29 09:57:30 -07:00
binary.BigEndian.PutUint16(data[11:13], uint16(len(c2.Username())))
copy(data[13:], []byte(c2.Username()))
2021-03-29 09:57:30 -07:00
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
}
<-ack
2021-04-02 05:19:11 -07:00
case ToServerFirstSRP:
// Process data
// Make sure the client is allowed to use AuthMechFirstSRP
2021-03-29 09:57:30 -07:00
if c2.authMech != AuthMechFirstSRP {
log.Print(c2.Addr().String() + " used unsupported AuthMechFirstSRP")
2021-04-02 04:39:35 -07:00
c2.CloseWith(AccessDeniedUnexpectedData, "", false)
2021-03-29 09:57:30 -07:00
fin <- c
return
}
// This is a new player, save verifier and salt
s := ReadBytes16(r)
v := ReadBytes16(r)
2021-03-29 09:57:30 -07:00
empty := ReadUint8(r)
2021-03-07 01:12:25 -08:00
// Also make sure to check for an empty password
2021-03-09 13:23:41 -08:00
disallow, ok := ConfKey("disallow_empty_passwords").(bool)
if ok && disallow && empty > 0 {
2021-03-29 09:57:30 -07:00
log.Print(c2.Addr().String() + " used an empty password but disallow_empty_passwords is true")
2021-03-07 01:12:25 -08:00
2021-04-02 04:39:35 -07:00
c2.CloseWith(AccessDeniedEmptyPassword, "", false)
2021-03-29 09:57:30 -07:00
fin <- c
2021-03-07 01:12:25 -08:00
return
}
2021-04-22 03:33:50 -07:00
if err := CreateUser(c2.Username(), v, s); err != nil {
log.Print(err)
continue
}
// Send AUTH_ACCEPT
data := []byte{
2021-01-19 11:37:35 -08:00
0, ToClientAuthAccept,
// Position stuff
2021-01-19 11:37:35 -08:00
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
// Map seed
2021-01-19 11:37:35 -08:00
0, 0, 0, 0,
0, 0, 0, 0,
// Send interval
2021-01-19 11:37:35 -08:00
0x3D, 0xB8, 0x51, 0xEC,
// Sudo mode mechs
2021-01-19 11:37:35 -08:00
0, 0, 0, AuthMechSRP,
}
2021-03-29 09:57:30 -07:00
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
}
<-ack
2021-04-02 05:19:11 -07:00
case ToServerSRPBytesA:
// Process data
// Make sure the client is allowed to use AuthMechSRP
2021-03-29 09:57:30 -07:00
if c2.authMech != AuthMechSRP {
log.Print(c2.Addr().String() + " used unsupported AuthMechSRP")
2021-04-02 04:39:35 -07:00
c2.CloseWith(AccessDeniedUnexpectedData, "", false)
return
}
A := ReadBytes16(r)
2021-04-22 03:33:50 -07:00
v, s, err := Password(c2.Username())
if err != nil {
log.Print(err)
continue
}
B, _, K, err := srp.Handshake(A, v)
if err != nil {
log.Print(err)
continue
}
2021-03-29 09:57:30 -07:00
c2.srp_s = s
c2.srp_A = A
c2.srp_B = B
c2.srp_K = K
// Send SRP_BYTES_S_B
data := make([]byte, 6+len(s)+len(B))
data[0] = uint8(0x00)
2021-01-14 10:06:40 -08:00
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)
ack, err := c2.Send(rudp.Pkt{Reader: w})
if err != nil {
log.Print(err)
continue
}
<-ack
2021-04-02 05:19:11 -07:00
case ToServerSRPBytesM:
// Process data
// Make sure the client is allowed to use AuthMechSRP
2021-03-29 09:57:30 -07:00
if c2.authMech != AuthMechSRP {
log.Print(c2.Addr().String() + " used unsupported AuthMechSRP")
2021-04-02 04:39:35 -07:00
c2.CloseWith(AccessDeniedUnexpectedData, "", false)
2021-03-29 09:57:30 -07:00
fin <- c
return
}
M := ReadBytes16(r)
2021-03-31 10:27:50 -07:00
M2 := srp.ClientProof([]byte(c2.Username()), c2.srp_s, c2.srp_A, c2.srp_B, c2.srp_K)
if subtle.ConstantTimeCompare(M, M2) == 1 {
// Password is correct
// Send AUTH_ACCEPT
data := []byte{
2021-01-19 11:37:35 -08:00
0, ToClientAuthAccept,
// Position stuff
2021-01-19 11:37:35 -08:00
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
// Map seed
2021-01-19 11:37:35 -08:00
0, 0, 0, 0,
0, 0, 0, 0,
// Send interval
2021-01-19 11:37:35 -08:00
0x3D, 0xB8, 0x51, 0xEC,
// Sudo mode mechs
2021-01-19 11:37:35 -08:00
0, 0, 0, AuthMechSRP,
}
2021-03-29 09:57:30 -07:00
ack, err := c2.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
continue
}
<-ack
} else {
// Client supplied wrong password
2021-03-29 09:57:30 -07:00
log.Print("User " + c2.Username() + " at " + c2.Addr().String() + " supplied wrong password")
2021-04-02 04:39:35 -07:00
c2.CloseWith(AccessDeniedWrongPassword, "", false)
2021-03-29 09:57:30 -07:00
fin <- c
return
}
2021-01-14 10:06:40 -08:00
case ToServerInit2:
2021-03-29 09:57:30 -07:00
c2.announceMedia()
2021-01-16 10:14:31 -08:00
case ToServerRequestMedia:
2021-04-01 11:27:58 -07:00
c2.sendMedia(r)
2021-01-16 10:14:31 -08:00
case ToServerClientReady:
2021-04-02 05:22:24 -07:00
// Second check if user is already connected
// This is needed because the INIT packet
// doesn't mark a player as online
if IsOnline(c2.Username()) {
c2.CloseWith(AccessDeniedAlreadyConnected, "", false)
fin <- c
return
}
2021-05-02 03:20:52 -07:00
r.Seek(4, io.SeekCurrent)
ReadBytes16(r)
if r.Len() >= 2 {
c2.formspecVer = ReadUint16(r) - 1
}
2021-03-13 09:58:51 -08:00
defaultSrv := ConfKey("default_server").(string)
2021-03-29 09:57:30 -07:00
defSrv := func() *Conn {
2021-03-13 09:58:51 -08:00
defaultSrvAddr := ConfKey("servers:" + defaultSrv + ":address").(string)
srvaddr, err := net.ResolveUDPAddr("udp", defaultSrvAddr)
if err != nil {
log.Print(err)
return nil
}
conn, err := net.DialUDP("udp", nil, srvaddr)
if err != nil {
log.Print(err)
return nil
}
2021-03-29 09:57:30 -07:00
srv, err := Connect(conn)
2021-03-13 09:58:51 -08:00
if err != nil {
log.Print(err)
return nil
}
2021-03-29 09:57:30 -07:00
fin2 := make(chan *Conn) // close-only
go Init(c2, srv, ignMedia, noAccessDenied, fin2)
2021-03-17 09:18:21 -07:00
<-fin2
2021-03-29 09:57:30 -07:00
go processJoin(c2)
2021-03-13 09:58:51 -08:00
return srv
}
2021-03-09 13:23:41 -08:00
if forceDefaultServer, ok := ConfKey("force_default_server").(bool); !forceDefaultServer || !ok {
2021-03-29 09:57:30 -07:00
srvname, err := StorageKey("server:" + c2.Username())
2021-01-20 12:44:35 -08:00
if err != nil {
2021-03-09 13:23:41 -08:00
srvname, ok = ConfKey("servers:" + ConfKey("default_server").(string) + ":address").(string)
2021-01-20 12:44:35 -08:00
if !ok {
2021-03-29 09:57:30 -07:00
go c2.SendChatMsg("Could not connect you to your last server!")
2021-01-20 12:44:35 -08:00
2021-03-13 09:58:51 -08:00
fin <- defSrv()
2021-01-20 12:44:35 -08:00
return
}
}
2021-03-09 13:23:41 -08:00
straddr, ok := ConfKey("servers:" + srvname + ":address").(string)
2021-01-20 12:44:35 -08:00
if !ok {
2021-03-29 09:57:30 -07:00
go c2.SendChatMsg("Could not connect you to your last server!")
2021-01-20 12:44:35 -08:00
2021-03-13 09:58:51 -08:00
fin <- defSrv()
2021-01-20 12:44:35 -08:00
return
}
srvaddr, err := net.ResolveUDPAddr("udp", straddr)
if err != nil {
2021-03-29 09:57:30 -07:00
go c2.SendChatMsg("Could not connect you to your last server!")
2021-01-20 12:44:35 -08:00
2021-03-13 09:58:51 -08:00
fin <- defSrv()
2021-01-20 12:44:35 -08:00
return
}
conn, err := net.DialUDP("udp", nil, srvaddr)
if err != nil {
2021-03-29 09:57:30 -07:00
go c2.SendChatMsg("Could not connect you to your last server!")
2021-01-20 12:44:35 -08:00
2021-03-13 09:58:51 -08:00
fin <- defSrv()
2021-01-20 12:44:35 -08:00
return
}
2021-03-13 09:58:51 -08:00
if srvname != defaultSrv {
2021-03-29 09:57:30 -07:00
srv, err := Connect(conn)
2021-01-20 12:44:35 -08:00
if err != nil {
2021-03-29 09:57:30 -07:00
go c2.SendChatMsg("Could not connect you to your last server!")
2021-01-20 12:44:35 -08:00
2021-03-13 09:58:51 -08:00
fin <- defSrv()
2021-01-20 12:44:35 -08:00
return
}
2021-03-29 09:57:30 -07:00
fin2 := make(chan *Conn) // close-only
go Init(c2, srv, ignMedia, noAccessDenied, fin2)
2021-03-14 05:52:31 -07:00
<-fin2
2021-03-29 09:57:30 -07:00
go c2.updateDetachedInvs(srvname)
go processJoin(c2)
2021-01-20 12:44:35 -08:00
fin <- srv
return
}
}
2021-03-13 09:58:51 -08:00
fin <- defSrv()
return
}
}
}
}