multiserver/init.go

689 lines
16 KiB
Go
Raw Normal View History

2021-01-24 05:00:26 -08:00
package main
import (
"crypto/subtle"
"encoding/binary"
2021-03-02 08:47:07 -08:00
"errors"
"log"
2021-01-20 12:44:35 -08:00
"net"
"strings"
"time"
"github.com/HimbeerserverDE/srp"
"github.com/anon55555/mt/rudp"
)
// Init authenticates to the server srv
// and finishes the initialisation process if ignMedia is true
2021-01-20 12:44:35 -08:00
func Init(p, p2 *Peer, ignMedia, noAccessDenied bool, fin chan *Peer) {
defer close(fin)
if p2.IsSrv() {
// We're trying to connect to a server
// INIT
2021-01-30 03:24:37 -08:00
data := make([]byte, 11+len(p.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))
binary.BigEndian.PutUint16(data[5:7], uint16(0x0025))
binary.BigEndian.PutUint16(data[7:9], uint16(0x0027))
2021-01-30 03:24:37 -08:00
binary.BigEndian.PutUint16(data[9:11], uint16(len(p.Username())))
copy(data[11:], []byte(p.Username()))
time.Sleep(250 * time.Millisecond)
if _, err := p2.Send(rudp.Pkt{Data: data, ChNo: 1, Unrel: true}); err != nil {
log.Print(err)
}
for {
pkt, err := p2.Recv()
if err != nil {
2021-03-02 08:47:07 -08:00
if errors.Is(err, net.ErrClosed) {
msg := p2.Addr().String() + " disconnected"
if p2.TimedOut() {
msg += " (timed out)"
}
log.Print(msg)
return
}
log.Print(err)
continue
}
switch cmd := binary.BigEndian.Uint16(pkt.Data[0:2]); cmd {
2021-01-14 10:06:40 -08:00
case ToClientHello:
2021-01-11 12:45:46 -08:00
if pkt.Data[10]&AuthMechSRP > 0 {
// Compute and send SRP_BYTES_A
2021-01-30 03:24:37 -08:00
_, _, err := srp.NewClient([]byte(strings.ToLower(p.Username())), passPhrase)
if err != nil {
log.Print(err)
continue
}
A, a, err := srp.InitiateHandshake()
if err != nil {
log.Print(err)
continue
}
p.srp_A = A
p.srp_a = a
data := make([]byte, 5+len(p.srp_A))
data[0] = uint8(0x00)
2021-01-14 10:06:40 -08:00
data[1] = uint8(ToServerSrpBytesA)
binary.BigEndian.PutUint16(data[2:4], uint16(len(p.srp_A)))
copy(data[4:4+len(p.srp_A)], p.srp_A)
data[4+len(p.srp_A)] = uint8(1)
ack, err := p2.Send(rudp.Pkt{Data: data, ChNo: 1})
if err != nil {
log.Print(err)
continue
}
<-ack
} else {
// Compute and send s and v
2021-01-30 03:24:37 -08:00
s, v, err := srp.NewClient([]byte(strings.ToLower(p.Username())), passPhrase)
if err != nil {
log.Print(err)
continue
}
data := make([]byte, 7+len(s)+len(v))
data[0] = uint8(0x00)
2021-01-14 10:06:40 -08:00
data[1] = uint8(ToServerFirstSrp)
binary.BigEndian.PutUint16(data[2:4], uint16(len(s)))
copy(data[4:4+len(s)], s)
2021-01-11 13:05:51 -08:00
binary.BigEndian.PutUint16(data[4+len(s):6+len(s)], uint16(len(v)))
copy(data[6+len(s):6+len(s)+len(v)], v)
data[6+len(s)+len(v)] = uint8(0)
ack, err := p2.Send(rudp.Pkt{Data: data, ChNo: 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
lenS := binary.BigEndian.Uint16(pkt.Data[2:4])
s := pkt.Data[4 : lenS+4]
B := pkt.Data[lenS+6:]
2021-01-30 03:24:37 -08:00
K, err := srp.CompleteHandshake(p.srp_A, p.srp_a, []byte(strings.ToLower(p.Username())), passPhrase, s, B)
if err != nil {
log.Print(err)
continue
}
p.srp_K = K
2021-01-30 03:24:37 -08:00
M := srp.CalculateM([]byte(p.Username()), s, p.srp_A, B, p.srp_K)
data := make([]byte, 4+len(M))
data[0] = uint8(0x00)
2021-01-14 10:06:40 -08:00
data[1] = uint8(ToServerSrpBytesM)
binary.BigEndian.PutUint16(data[2:4], uint16(len(M)))
copy(data[4:], M)
ack, err := p2.Send(rudp.Pkt{Data: data, ChNo: 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-09 13:23:41 -08:00
if ConfKey("servers:"+server.(string)+":address") == p2.Addr().String() {
srv = server.(string)
break
}
}
log.Print("authentication failed for server " + srv)
2021-01-16 10:14:31 -08:00
if noAccessDenied {
return
}
data := []byte{
2021-01-19 11:37:35 -08:00
0, ToClientAccessDenied,
AccessDeniedServerFail, 0, 0, 0, 0,
}
ack, err := p.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
}
<-ack
p.SendDisco(0, true)
p.Close()
return
2021-01-14 10:06:40 -08:00
case ToClientAuthAccept:
// Auth succeeded
2021-01-19 11:37:35 -08:00
ack, err := p2.Send(rudp.Pkt{Data: []byte{0, ToServerInit2, 0, 0}, ChNo: 1})
if err != nil {
log.Print(err)
continue
}
<-ack
if !ignMedia {
return
}
2021-01-14 10:06:40 -08:00
case ToClientCsmRestrictionFlags:
// Definitions sent (by server)
if !ignMedia {
continue
}
v := []byte("5.4.0-dev-dd5a732fa")
data := make([]byte, 8+len(v))
2021-01-14 10:06:40 -08:00
copy(data[0:6], []byte{uint8(0), uint8(ToServerClientReady), uint8(5), uint8(4), uint8(0), uint8(0)})
binary.BigEndian.PutUint16(data[6:8], uint16(len(v)))
copy(data[8:], v)
_, err := p2.Send(rudp.Pkt{Data: data, ChNo: 1})
if err != nil {
log.Print(err)
continue
}
return
}
}
} else {
for {
pkt, err := p2.Recv()
if err != nil {
2021-03-02 08:47:07 -08:00
if errors.Is(err, net.ErrClosed) {
msg := p2.Addr().String() + " disconnected"
if p2.TimedOut() {
msg += " (timed out)"
}
log.Print(msg)
connectedPeersMu.Lock()
connectedPeers--
connectedPeersMu.Unlock()
2021-01-10 13:37:42 -08:00
processLeave(p2)
return
}
log.Print(err)
continue
}
switch cmd := binary.BigEndian.Uint16(pkt.Data[0:2]); cmd {
2021-01-14 10:06:40 -08:00
case ToServerInit:
// Process data
2021-01-30 03:24:37 -08:00
p2.username = string(pkt.Data[11:])
// Send HELLO
2021-01-30 03:24:37 -08:00
data := make([]byte, 13+len(p2.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))
binary.BigEndian.PutUint16(data[5:7], uint16(0x0027))
2021-02-28 04:12:28 -08:00
// Check if user is banned
banned, bname, err := p2.IsBanned()
if err != nil {
log.Print(err)
continue
}
if banned {
log.Print("Banned user " + bname + " at " + p2.Addr().String() + " tried to connect")
2021-02-28 04:12:28 -08:00
reason := []byte("Your IP address is banned. Banned name is " + bname)
l := len(reason)
data := make([]byte, 7+l)
data[0] = uint8(0x00)
data[1] = uint8(ToClientAccessDenied)
data[2] = uint8(AccessDeniedCustomString)
binary.BigEndian.PutUint16(data[3:5], uint16(l))
copy(data[5:5+l], reason)
data[5+l] = uint8(0x00)
data[6+l] = uint8(0x00)
ack, err := p2.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
}
<-ack
p2.SendDisco(0, true)
p2.Close()
fin <- p
return
}
2021-01-14 10:06:40 -08:00
// Check if user is already connected
2021-01-30 03:24:37 -08:00
if IsOnline(p2.Username()) {
2021-01-14 10:06:40 -08:00
data := []byte{
2021-01-19 11:37:35 -08:00
0, ToClientAccessDenied,
AccessDeniedAlreadyConnected, 0, 0, 0, 0,
2021-01-14 10:06:40 -08:00
}
ack, err := p2.Send(rudp.Pkt{Data: data})
2021-01-14 10:06:40 -08:00
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
2021-01-21 05:35:48 -08:00
fin <- p
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-01-30 03:24:37 -08:00
if p2.Username() == "media" || p2.Username() == "rpc" {
2021-01-29 07:21:43 -08:00
data := []byte{
0, ToClientAccessDenied,
AccessDeniedWrongName, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
fin <- p
return
}
db, err := initAuthDB()
if err != nil {
log.Print(err)
continue
}
2021-01-30 03:24:37 -08:00
pwd, err := readAuthItem(db, p2.Username())
if err != nil {
log.Print(err)
continue
}
db.Close()
if pwd == "" {
// New player
p2.authMech = AuthMechFirstSRP
binary.BigEndian.PutUint32(data[7:11], uint32(AuthMechFirstSRP))
} else {
// Existing player
p2.authMech = AuthMechSRP
binary.BigEndian.PutUint32(data[7:11], uint32(AuthMechSRP))
}
2021-01-30 03:24:37 -08:00
binary.BigEndian.PutUint16(data[11:13], uint16(len(p2.Username())))
copy(data[13:], []byte(p2.Username()))
ack, err := p2.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
continue
}
<-ack
2021-01-14 10:06:40 -08:00
case ToServerFirstSrp:
// Process data
// Make sure the client is allowed to use AuthMechFirstSRP
if p2.authMech != AuthMechFirstSRP {
log.Print(p2.Addr().String() + " used unsupported AuthMechFirstSRP")
// Send ACCESS_DENIED
data := []byte{
2021-01-19 11:37:35 -08:00
0, ToClientAccessDenied,
AccessDeniedUnexpectedData, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
2021-01-21 05:35:48 -08:00
fin <- p
return
}
// This is a new player, save verifier and salt
lenS := binary.BigEndian.Uint16(pkt.Data[2:4])
s := pkt.Data[4 : 4+lenS]
lenV := binary.BigEndian.Uint16(pkt.Data[4+lenS : 6+lenS])
v := pkt.Data[6+lenS : 6+lenS+lenV]
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)
2021-03-07 01:12:25 -08:00
if ok && disallow && pkt.Data[6+lenS+lenV] == 1 {
log.Print(p2.Addr().String() + " used an empty password but disallow_empty_passwords is true")
// Send ACCESS_DENIED
data := []byte{
0, ToClientAccessDenied,
AccessDeniedEmptyPassword, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
fin <- p
return
}
pwd := encodeVerifierAndSalt(s, v)
db, err := initAuthDB()
if err != nil {
log.Print(err)
continue
}
2021-01-30 03:24:37 -08:00
err = addAuthItem(db, p2.Username(), pwd)
if err != nil {
log.Print(err)
continue
}
2021-01-30 03:24:37 -08:00
err = addPrivItem(db, p2.Username())
if err != nil {
log.Print(err)
continue
}
db.Close()
// 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,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
continue
}
<-ack
2021-01-14 10:06:40 -08:00
case ToServerSrpBytesA:
// Process data
// Make sure the client is allowed to use AuthMechSRP
if p2.authMech != AuthMechSRP {
log.Print(p2.Addr().String() + " used unsupported AuthMechSRP")
// Send ACCESS_DENIED
data := []byte{
2021-01-19 11:37:35 -08:00
0, ToClientAccessDenied,
AccessDeniedUnexpectedData, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data, ChNo: 0, Unrel: false})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
return
}
lenA := binary.BigEndian.Uint16(pkt.Data[2:4])
A := pkt.Data[4 : 4+lenA]
db, err := initAuthDB()
if err != nil {
log.Print(err)
continue
}
2021-01-30 03:24:37 -08:00
pwd, err := readAuthItem(db, p2.Username())
if err != nil {
log.Print(err)
continue
}
db.Close()
s, v, err := decodeVerifierAndSalt(pwd)
if err != nil {
log.Print(err)
continue
}
B, _, K, err := srp.Handshake(A, v)
if err != nil {
log.Print(err)
continue
}
p2.srp_s = s
p2.srp_A = A
p2.srp_B = B
p2.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)
ack, err := p2.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
continue
}
<-ack
2021-01-14 10:06:40 -08:00
case ToServerSrpBytesM:
// Process data
// Make sure the client is allowed to use AuthMechSRP
if p2.authMech != AuthMechSRP {
log.Print(p2.Addr().String() + " used unsupported AuthMechSRP")
// Send ACCESS_DENIED
data := []byte{
2021-01-19 11:37:35 -08:00
0, ToClientAccessDenied,
AccessDeniedUnexpectedData, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
2021-01-21 05:35:48 -08:00
fin <- p
return
}
lenM := binary.BigEndian.Uint16(pkt.Data[2:4])
M := pkt.Data[4 : 4+lenM]
2021-01-30 03:24:37 -08:00
M2 := srp.CalculateM([]byte(p2.Username()), p2.srp_s, p2.srp_A, p2.srp_B, p2.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,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
continue
}
<-ack
} else {
// Client supplied wrong password
2021-01-30 03:24:37 -08:00
log.Print("User " + p2.Username() + " at " + p2.Addr().String() + " supplied wrong password")
// Send ACCESS_DENIED
data := []byte{
2021-01-19 11:37:35 -08:00
0, ToClientAccessDenied,
AccessDeniedWrongPassword, 0, 0, 0, 0,
}
ack, err := p2.Send(rudp.Pkt{Data: data})
if err != nil {
log.Print(err)
continue
}
<-ack
p2.SendDisco(0, true)
p2.Close()
2021-01-21 05:35:48 -08:00
fin <- p
return
}
2021-01-14 10:06:40 -08:00
case ToServerInit2:
2021-01-16 10:14:31 -08:00
p2.announceMedia()
case ToServerRequestMedia:
p2.sendMedia(pkt.Data[2:])
case ToServerClientReady:
2021-03-09 13:23:41 -08:00
if forceDefaultServer, ok := ConfKey("force_default_server").(bool); !forceDefaultServer || !ok {
srvname, err := StorageKey("server:" + p2.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 {
go p2.SendChatMsg("Could not connect you to your last server!")
fin2 := make(chan *Peer) // close-only
Init(p2, p, ignMedia, noAccessDenied, fin2)
go processJoin(p2)
fin <- p
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 {
go p2.SendChatMsg("Could not connect you to your last server!")
fin2 := make(chan *Peer) // close-only
Init(p2, p, ignMedia, noAccessDenied, fin2)
go processJoin(p2)
fin <- p
return
}
srvaddr, err := net.ResolveUDPAddr("udp", straddr)
if err != nil {
go p2.SendChatMsg("Could not connect you to your last server!")
fin2 := make(chan *Peer) // close-only
Init(p2, p, ignMedia, noAccessDenied, fin2)
go processJoin(p2)
fin <- p
return
}
conn, err := net.DialUDP("udp", nil, srvaddr)
if err != nil {
go p2.SendChatMsg("Could not connect you to your last server!")
fin2 := make(chan *Peer) // close-only
Init(p2, p, ignMedia, noAccessDenied, fin2)
go processJoin(p2)
fin <- p
return
}
if straddr != p.Addr().String() {
srv, err := Connect(conn, conn.RemoteAddr())
if err != nil {
go p2.SendChatMsg("Could not connect you to your last server!")
fin2 := make(chan *Peer) // close-only
Init(p2, p, ignMedia, noAccessDenied, fin2)
go processJoin(p2)
fin <- p
return
}
fin2 := make(chan *Peer) // close-only
Init(p2, srv, ignMedia, noAccessDenied, fin2)
go p2.updateDetachedInvs(srvname)
go processJoin(p2)
fin <- srv
return
}
}
fin2 := make(chan *Peer) // close-only
2021-01-16 10:14:31 -08:00
Init(p2, p, ignMedia, noAccessDenied, fin2)
2021-01-17 12:43:23 -08:00
go processJoin(p2)
2021-01-20 12:44:35 -08:00
fin <- p
return
}
}
}
}