Now gets ingame!

This commit is contained in:
Andrew Gutekanst
2019-12-24 16:06:40 +09:00
parent e5066d4f8b
commit 319cfcb2f7
9 changed files with 517 additions and 79 deletions

View File

@@ -3,28 +3,238 @@ package main
import ( import (
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"github.com/Andoryuuta/Erupe/network" "github.com/Andoryuuta/Erupe/network"
"github.com/Andoryuuta/byteframe" "github.com/Andoryuuta/byteframe"
) )
var loadDataCount int
var getPaperDataCount int
func handlePacket(cc *network.CryptConn, pkt []byte) {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic.")
}
}()
bf := byteframe.NewByteFrameFromBytes(pkt)
opcode := network.PacketID(bf.ReadUint16())
if opcode == network.MSG_SYS_EXTEND_THRESHOLD {
opcode = network.PacketID(bf.ReadUint16())
}
switch opcode {
case network.MSG_SYS_PING:
ackHandle := bf.ReadUint32()
_ = bf.ReadUint16()
bfw := byteframe.NewByteFrame()
bfw.WriteUint16(uint16(network.MSG_SYS_ACK))
bfw.WriteUint32(ackHandle)
bfw.WriteUint32(0)
bfw.WriteUint32(0)
cc.SendPacket(bfw.Data())
case network.MSG_SYS_TIME:
_ = bf.ReadUint8()
timestamp := bf.ReadUint32() // unix timestamp, e.g. 1577105879
bfw := byteframe.NewByteFrame()
bfw.WriteUint16(uint16(network.MSG_SYS_TIME))
bfw.WriteUint8(0)
bfw.WriteUint32(timestamp)
cc.SendPacket(bfw.Data())
case network.MSG_SYS_LOGIN:
ackHandle := bf.ReadUint32()
charID0 := bf.ReadUint32()
loginTokenNumber := bf.ReadUint32()
hardcodedZero0 := bf.ReadUint16()
requestVersion := bf.ReadUint16()
charID1 := bf.ReadUint32()
hardcodedZero1 := bf.ReadUint16()
loginTokenLength := bf.ReadUint16() // hardcoded to 0x11
loginTokenString := bf.ReadBytes(17)
_ = ackHandle
_ = charID0
_ = loginTokenNumber
_ = hardcodedZero0
_ = requestVersion
_ = charID1
_ = hardcodedZero1
_ = loginTokenLength
_ = loginTokenString
bfw := byteframe.NewByteFrame()
bfw.WriteUint16(uint16(network.MSG_SYS_ACK))
bfw.WriteUint32(ackHandle)
bfw.WriteUint64(0x000000005E00B9C2) // Timestamp?
cc.SendPacket(bfw.Data())
case network.MSG_MHF_ENUMERATE_EVENT:
fallthrough
case network.MSG_MHF_ENUMERATE_QUEST:
fallthrough
case network.MSG_MHF_ENUMERATE_RANKING:
fallthrough
case network.MSG_MHF_READ_MERCENARY_W:
fallthrough
case network.MSG_MHF_GET_ETC_POINTS:
fallthrough
case network.MSG_MHF_READ_GUILDCARD:
fallthrough
case network.MSG_MHF_READ_BEAT_LEVEL:
fallthrough
case network.MSG_MHF_GET_EARTH_STATUS:
fallthrough
case network.MSG_MHF_GET_EARTH_VALUE:
fallthrough
case network.MSG_MHF_GET_WEEKLY_SCHEDULE:
fallthrough
case network.MSG_MHF_LIST_MEMBER:
fallthrough
case network.MSG_MHF_LOAD_PLATE_DATA:
fallthrough
case network.MSG_MHF_LOAD_PLATE_BOX:
fallthrough
case network.MSG_MHF_LOAD_FAVORITE_QUEST:
fallthrough
case network.MSG_MHF_LOAD_PARTNER:
fallthrough
case network.MSG_MHF_GET_TOWER_INFO:
fallthrough
case network.MSG_MHF_LOAD_OTOMO_AIROU:
fallthrough
case network.MSG_MHF_LOAD_DECO_MYSET:
fallthrough
case network.MSG_MHF_LOAD_HUNTER_NAVI:
fallthrough
case network.MSG_MHF_GET_UD_SCHEDULE:
fallthrough
case network.MSG_MHF_GET_UD_INFO:
fallthrough
case network.MSG_MHF_GET_UD_MONSTER_POINT:
fallthrough
case network.MSG_MHF_GET_RAND_FROM_TABLE:
fallthrough
case network.MSG_MHF_ACQUIRE_MONTHLY_REWARD:
fallthrough
case network.MSG_MHF_GET_RENGOKU_RANKING_RANK:
fallthrough
case network.MSG_MHF_LOAD_PLATE_MYSET:
fallthrough
case network.MSG_MHF_LOAD_RENGOKU_DATA:
fallthrough
case network.MSG_MHF_ENUMERATE_SHOP:
fallthrough
case network.MSG_MHF_LOAD_SCENARIO_DATA:
fallthrough
case network.MSG_MHF_GET_BOOST_TIME_LIMIT:
fallthrough
case network.MSG_MHF_GET_BOOST_RIGHT:
fallthrough
case network.MSG_MHF_GET_REWARD_SONG:
fallthrough
case network.MSG_MHF_GET_GACHA_POINT:
fallthrough
case network.MSG_MHF_GET_KOURYOU_POINT:
fallthrough
case network.MSG_MHF_GET_ENHANCED_MINIDATA:
ackHandle := bf.ReadUint32()
data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp.bin", opcode.String()))
if err != nil {
panic(err)
}
bfw := byteframe.NewByteFrame()
bfw.WriteUint16(uint16(network.MSG_SYS_ACK))
bfw.WriteUint32(ackHandle)
bfw.WriteBytes(data)
cc.SendPacket(bfw.Data())
case network.MSG_MHF_INFO_FESTA:
ackHandle := bf.ReadUint32()
_ = bf.ReadUint32()
data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp.bin", opcode.String()))
if err != nil {
panic(err)
}
bfw := byteframe.NewByteFrame()
bfw.WriteUint16(uint16(network.MSG_SYS_ACK))
bfw.WriteUint32(ackHandle)
bfw.WriteBytes(data)
cc.SendPacket(bfw.Data())
case network.MSG_MHF_LOADDATA:
ackHandle := bf.ReadUint32()
data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp%d.bin", opcode.String(), loadDataCount))
if err != nil {
panic(err)
}
bfw := byteframe.NewByteFrame()
bfw.WriteUint16(uint16(network.MSG_SYS_ACK))
bfw.WriteUint32(ackHandle)
bfw.WriteBytes(data)
cc.SendPacket(bfw.Data())
loadDataCount++
if loadDataCount > 1 {
loadDataCount = 0
}
case network.MSG_MHF_GET_PAPER_DATA:
ackHandle := bf.ReadUint32()
data, err := ioutil.ReadFile(fmt.Sprintf("bin_resp/%s_resp%d.bin", opcode.String(), getPaperDataCount))
if err != nil {
panic(err)
}
bfw := byteframe.NewByteFrame()
bfw.WriteUint16(uint16(network.MSG_SYS_ACK))
bfw.WriteUint32(ackHandle)
bfw.WriteBytes(data)
cc.SendPacket(bfw.Data())
getPaperDataCount++
if getPaperDataCount > 7 {
getPaperDataCount = 0
}
default:
break
}
fmt.Printf("Opcode: %s\n", opcode)
fmt.Printf("Data:\n%s\n", hex.Dump(pkt))
remainingData := bf.DataFromCurrent()
if len(remainingData) >= 2 && (opcode == network.MSG_SYS_TIME || opcode == network.MSG_MHF_INFO_FESTA) {
handlePacket(cc, remainingData)
}
}
func handleChannelServerConnection(conn net.Conn) { func handleChannelServerConnection(conn net.Conn) {
fmt.Println("Channel server got connection!") fmt.Println("Channel server got connection!")
// Unlike the sign and entrance server, // Unlike the sign and entrance server,
// the client DOES NOT initalize the channel connection with 8 NULL bytes. // the client DOES NOT initalize the channel connection with 8 NULL bytes.
cc := network.NewCryptConn(conn) cc := network.NewCryptConn(conn)
for { for {
pkt, err := cc.ReadPacket() pkt, err := cc.ReadPacket()
if err != nil { if err != nil {
return return
} }
bf := byteframe.NewByteFrameFromBytes(pkt) handlePacket(cc, pkt)
opcode := network.PacketID(bf.ReadUint16())
fmt.Printf("Opcode: %s\n", opcode)
fmt.Printf("Data:\n%s\n", hex.Dump(pkt))
} }
} }

2
go.mod
View File

@@ -7,5 +7,7 @@ require (
github.com/Andoryuuta/byteframe v0.0.0-20191219124302-41f4085eb4c0 github.com/Andoryuuta/byteframe v0.0.0-20191219124302-41f4085eb4c0
github.com/BurntSushi/toml v0.3.1 github.com/BurntSushi/toml v0.3.1
github.com/golang-migrate/migrate v3.5.4+incompatible // indirect github.com/golang-migrate/migrate v3.5.4+incompatible // indirect
github.com/gorilla/handlers v1.4.2
github.com/julienschmidt/httprouter v1.3.0 github.com/julienschmidt/httprouter v1.3.0
github.com/lib/pq v1.3.0
) )

5
go.sum
View File

@@ -2,9 +2,14 @@ github.com/Andoryuuta/binio v0.0.0-20160731013325-2c89946fb8c3 h1:N8pCiqpJAHyOO8
github.com/Andoryuuta/binio v0.0.0-20160731013325-2c89946fb8c3/go.mod h1:4WK1jUpH8NFdDiv7IJcBfyCIOMqKjZ15kcw5eBKALvc= github.com/Andoryuuta/binio v0.0.0-20160731013325-2c89946fb8c3/go.mod h1:4WK1jUpH8NFdDiv7IJcBfyCIOMqKjZ15kcw5eBKALvc=
github.com/Andoryuuta/byteframe v0.0.0-20191219124302-41f4085eb4c0 h1:2pVgen9rh18IxSWxOa80bObcpyfrS6d5bJtZeCUN7rY= github.com/Andoryuuta/byteframe v0.0.0-20191219124302-41f4085eb4c0 h1:2pVgen9rh18IxSWxOa80bObcpyfrS6d5bJtZeCUN7rY=
github.com/Andoryuuta/byteframe v0.0.0-20191219124302-41f4085eb4c0/go.mod h1:koVyx+gN3TfE70rpOidywETVODk87304YpwW69Y27J4= github.com/Andoryuuta/byteframe v0.0.0-20191219124302-41f4085eb4c0/go.mod h1:koVyx+gN3TfE70rpOidywETVODk87304YpwW69Y27J4=
github.com/Andoryuuta/erupe v0.0.0-20191219210047-7aef17f7d946 h1:Z20gk8dvCNRZuHEdeEyGVwbMs9IxyGs5gGU4zFN3aTs=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/golang-migrate/migrate v3.5.4+incompatible h1:R7OzwvCJTCgwapPCiX6DyBiu2czIUMDCB118gFTKTUA= github.com/golang-migrate/migrate v3.5.4+incompatible h1:R7OzwvCJTCgwapPCiX6DyBiu2czIUMDCB118gFTKTUA=
github.com/golang-migrate/migrate v3.5.4+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk= github.com/golang-migrate/migrate v3.5.4+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk=
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=

View File

@@ -1,8 +1,12 @@
package main package main
import ( import (
"fmt"
"net/http" "net/http"
"net/http/httputil"
"os"
"github.com/gorilla/handlers"
"github.com/julienschmidt/httprouter" "github.com/julienschmidt/httprouter"
) )
@@ -11,15 +15,27 @@ func g6Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
} }
func serverUniqueName(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
dump, err := httputil.DumpRequest(r, true)
if err != nil {
http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
return
}
fmt.Println(string(dump))
fmt.Fprintf(w, `<?xml version="1.0" encoding="ISO-8859-1"?><uniq code="200">OK</uniq>`)
}
// serveLauncherHTML is responsible for serving the launcher HTML and (HACK) serverlist.xml. // serveLauncherHTML is responsible for serving the launcher HTML and (HACK) serverlist.xml.
func serveLauncherHTML(listenAddr string) { func serveLauncherHTML(listenAddr string) {
// Manually route the folder root to index.html? Is there a better way to do this? // Manually route the folder root to index.html? Is there a better way to do this?
router := httprouter.New() router := httprouter.New()
router.GET("/g6_launcher/", g6Index) router.GET("/g6_launcher/", g6Index)
router.GET("/server/unique.php", serverUniqueName)
static := httprouter.New() static := httprouter.New()
static.ServeFiles("/*filepath", http.Dir("www")) static.ServeFiles("/*filepath", http.Dir("www"))
router.NotFound = static router.NotFound = static
http.ListenAndServe(listenAddr, router) http.ListenAndServe(listenAddr, handlers.LoggingHandler(os.Stdout, router))
} }

29
main.go
View File

@@ -1,16 +1,43 @@
package main package main
import ( import (
"database/sql"
"fmt" "fmt"
"time" "time"
"github.com/Andoryuuta/Erupe/signserver"
_ "github.com/lib/pq"
) )
func main() { func main() {
fmt.Println("Starting!") fmt.Println("Starting!")
// Load the config.toml configuration.
// TODO(Andoryuuta): implement config loading.
// Create the postgres DB pool.
db, err := sql.Open("postgres", "host=localhost port=5432 user=postgres password=admin dbname=erupe sslmode=disable")
if err != nil {
panic(err)
}
// Test the DB connection.
err = db.Ping()
if err != nil {
panic(err)
}
// Finally start our server(s).
go serveLauncherHTML(":80") go serveLauncherHTML(":80")
go doEntranceServer(":53310") go doEntranceServer(":53310")
go doSignServer(":53312")
signServer := signserver.NewServer(
&signserver.Config{
DB: db,
ListenAddr: ":53312",
})
go signServer.Listen()
go doChannelServer(":54001") go doChannelServer(":54001")
for { for {

View File

@@ -1,27 +1,6 @@
package main package signserver
import ( import "github.com/Andoryuuta/byteframe"
"fmt"
"io"
"net"
"github.com/Andoryuuta/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
/*
var conf *config.Config
func init() {
c, err := config.LoadConfig("config.toml")
if err != nil {
panic(err)
}
conf = c
}
*/
func paddedString(x string, size uint) []byte { func paddedString(x string, size uint) []byte {
out := make([]byte, size) out := make([]byte, size)
@@ -42,6 +21,12 @@ func uint16PascalString(bf *byteframe.ByteFrame, x string) {
bf.WriteNullTerminatedBytes([]byte(x)) bf.WriteNullTerminatedBytes([]byte(x))
} }
func makeSignInFailureResp(respID RespID) []byte {
bf := byteframe.NewByteFrame()
bf.WriteUint8(uint8(respID))
return bf.Data()
}
func makeSignInResp(username string) []byte { func makeSignInResp(username string) []byte {
bf := byteframe.NewByteFrame() bf := byteframe.NewByteFrame()
@@ -51,7 +36,7 @@ func makeSignInResp(username string) []byte {
bf.WriteUint8(1) // resp_code bf.WriteUint8(1) // resp_code
bf.WriteUint8(0) // file/patch server count bf.WriteUint8(0) // file/patch server count
bf.WriteUint8(1) // entrance server count bf.WriteUint8(4) // entrance server count
bf.WriteUint8(1) // character count bf.WriteUint8(1) // character count
bf.WriteUint32(0xFFFFFFFF) // login_token_number bf.WriteUint32(0xFFFFFFFF) // login_token_number
bf.WriteBytes(paddedString("logintokenstrng", 16)) // login_token (16 byte padded string) bf.WriteBytes(paddedString("logintokenstrng", 16)) // login_token (16 byte padded string)
@@ -61,6 +46,9 @@ func makeSignInResp(username string) []byte {
// Array(this.entrance_server_count, PascalString(Byte, "utf8")), // Array(this.entrance_server_count, PascalString(Byte, "utf8")),
uint8PascalString(bf, "localhost:53310") uint8PascalString(bf, "localhost:53310")
uint8PascalString(bf, "")
uint8PascalString(bf, "")
uint8PascalString(bf, "mhf-n.capcom.com.tw")
/////////////////////////// ///////////////////////////
// Characters: // Characters:
@@ -87,6 +75,8 @@ func makeSignInResp(username string) []byte {
bf.WriteUint32(469153291) // character ID 469153291 bf.WriteUint32(469153291) // character ID 469153291
bf.WriteUint16(30) // Exp, HR[x] is split by 0, 1, 30, 50, 99, 299, 998, 999 bf.WriteUint16(30) // Exp, HR[x] is split by 0, 1, 30, 50, 99, 299, 998, 999
//44.204
/* /*
0=大劍/Big sword 0=大劍/Big sword
1=重弩/Heavy crossbow 1=重弩/Heavy crossbow
@@ -108,7 +98,7 @@ func makeSignInResp(username string) []byte {
bf.WriteUint32(1576761172) // Last login date, unix timestamp in seconds. bf.WriteUint32(1576761172) // Last login date, unix timestamp in seconds.
bf.WriteUint8(1) // Sex, 0=male, 1=female. bf.WriteUint8(1) // Sex, 0=male, 1=female.
bf.WriteUint8(0) // Is new character, 1 replaces character name with ?????. bf.WriteUint8(1) // Is new character, 1 replaces character name with ?????.
grMode := uint8(0) grMode := uint8(0)
bf.WriteUint8(1) // GR level if grMode == 0 bf.WriteUint8(1) // GR level if grMode == 0
bf.WriteUint8(grMode) // GR mode. bf.WriteUint8(grMode) // GR mode.
@@ -145,51 +135,3 @@ func makeSignInResp(username string) []byte {
return bf.Data() return bf.Data()
} }
func handleSignServerConnection(conn net.Conn) {
// Client initalizes the connection with a one-time buffer of 8 NULL bytes.
nullInit := make([]byte, 8)
n, err := io.ReadFull(conn, nullInit)
if err != nil {
fmt.Println(err)
return
} else if n != len(nullInit) {
fmt.Println("io.ReadFull couldn't read the full 8 byte init.")
return
}
cc := network.NewCryptConn(conn)
for {
pkt, err := cc.ReadPacket()
if err != nil {
return
}
bf := byteframe.NewByteFrameFromBytes(pkt)
loginType := string(bf.ReadNullTerminatedBytes())
username := string(bf.ReadNullTerminatedBytes())
password := string(bf.ReadNullTerminatedBytes())
unk := string(bf.ReadNullTerminatedBytes())
fmt.Printf("Got signin, type: %s, username: %s, password %s, unk: %s", loginType, username, password, unk)
resp := makeSignInResp(username)
cc.SendPacket(resp)
}
}
func doSignServer(listenAddr string) {
l, err := net.Listen("tcp", listenAddr)
if err != nil {
panic(err)
}
defer l.Close()
for {
conn, err := l.Accept()
if err != nil {
panic(err)
}
go handleSignServerConnection(conn)
}
}

50
signserver/respid.go Normal file
View File

@@ -0,0 +1,50 @@
package signserver
//revive:disable
type RespID uint16
//go:generate stringer -type=RespID
const (
SIGN_UNKNOWN RespID = iota
SIGN_SUCCESS
SIGN_EFAILED // Authentication server communication failed
SIGN_EILLEGAL // Incorrect input, authentication has been suspended
SIGN_EALERT // Authentication server process error
SIGN_EABORT // The internal procedure of the authentication server ended abnormally
SIGN_ERESPONSE // Procedure terminated due to abnormal certification report
SIGN_EDATABASE // Database connection failed
SIGN_EABSENCE
SIGN_ERESIGN
SIGN_ESUSPEND_D
SIGN_ELOCK
SIGN_EPASS
SIGN_ERIGHT
SIGN_EAUTH
SIGN_ESUSPEND // This account is temporarily suspended. Please contact customer service for details
SIGN_EELIMINATE // This account is permanently suspended. Please contact customer service for details
SIGN_ECLOSE
SIGN_ECLOSE_EX // Login process is congested. <br> Please try to sign in again later
SIGN_EINTERVAL
SIGN_EMOVED
SIGN_ENOTREADY
SIGN_EALREADY
SIGN_EIPADDR // Region block because of IP address.
SIGN_EHANGAME
SIGN_UPD_ONLY
SIGN_EMBID
SIGN_ECOGCODE
SIGN_ETOKEN
SIGN_ECOGLINK
SIGN_EMAINTE
SIGN_EMAINTE_NOUPDATE
// Couldn't find names for the following:
UNK_32
UNK_33
UNK_34
UNK_35
SIGN_XBRESPONSE
SIGN_EPSI
SIGN_EMBID_PSI
)

107
signserver/session.go Normal file
View File

@@ -0,0 +1,107 @@
package signserver
import (
"database/sql"
"encoding/hex"
"fmt"
"net"
"sync"
"github.com/Andoryuuta/Erupe/network"
"github.com/Andoryuuta/byteframe"
)
// Session holds state for the sign server connection.
type Session struct {
sync.Mutex
sid int
server *Server
rawConn *net.Conn
cryptConn *network.CryptConn
}
func (session *Session) fail() {
session.server.Lock()
delete(session.server.sessions, session.sid)
session.server.Unlock()
}
func (session *Session) work() {
for {
pkt, err := session.cryptConn.ReadPacket()
if err != nil {
session.fail()
return
}
err = session.handlePacket(pkt)
if err != nil {
session.fail()
return
}
}
}
func (session *Session) handlePacket(pkt []byte) error {
bf := byteframe.NewByteFrameFromBytes(pkt)
reqType := string(bf.ReadNullTerminatedBytes())
switch reqType {
case "DSGN:100":
session.handleDSGNRequest(bf)
break
case "DELETE:100":
loginTokenString := string(bf.ReadNullTerminatedBytes())
_ = loginTokenString
characterID := bf.ReadUint32()
fmt.Printf("Got delete request for character ID: %v\n", characterID)
fmt.Printf("remaining unknown data:\n%s\n", hex.Dump(bf.DataFromCurrent()))
default:
fmt.Printf("Got unknown request type %s, data:\n%s\n", reqType, hex.Dump(bf.DataFromCurrent()))
}
return nil
}
func (session *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error {
reqUsername := string(bf.ReadNullTerminatedBytes())
reqPassword := string(bf.ReadNullTerminatedBytes())
reqUnk := string(bf.ReadNullTerminatedBytes())
fmt.Printf("Got sign in request:\n\tUsername: %s\n\tPassword %s\n\tUnk: %s\n", reqUsername, reqPassword, reqUnk)
// TODO(Andoryuuta): remove plaintext password storage if this ever becomes more than a toy project.
var (
id int
password string
)
err := session.server.db.QueryRow("SELECT id, password FROM users WHERE username = $1", reqUsername).Scan(&id, &password)
var serverRespBytes []byte
switch {
case err == sql.ErrNoRows:
fmt.Printf("No rows for username %s\n", reqUsername)
serverRespBytes = makeSignInFailureResp(SIGN_EAUTH)
break
case err != nil:
serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
fmt.Println("Got error on SQL query!")
fmt.Println(err)
break
default:
if reqPassword == password {
fmt.Println("Passwords match!")
serverRespBytes = makeSignInResp(reqUsername)
} else {
fmt.Println("Passwords don't match!")
serverRespBytes = makeSignInFailureResp(SIGN_EPASS)
}
}
err = session.cryptConn.SendPacket(serverRespBytes)
if err != nil {
return err
}
return nil
}

79
signserver/sign_server.go Normal file
View File

@@ -0,0 +1,79 @@
package signserver
import (
"database/sql"
"fmt"
"io"
"net"
"sync"
"github.com/Andoryuuta/Erupe/network"
)
// Config struct allows configuring the server.
type Config struct {
DB *sql.DB
ListenAddr string
}
// Server is a MHF sign server.
type Server struct {
sync.Mutex
sid int
sessions map[int]*Session
db *sql.DB
listenAddr string
}
// NewServer creates a new Server type.
func NewServer(config *Config) *Server {
s := &Server{
sid: 0,
sessions: make(map[int]*Session),
db: config.DB,
listenAddr: config.ListenAddr,
}
return s
}
// Listen listens for new connections and accepts/serves them.
func (s *Server) Listen() {
l, err := net.Listen("tcp", s.listenAddr)
if err != nil {
panic(err)
}
defer l.Close()
for {
conn, err := l.Accept()
if err != nil {
panic(err)
}
go s.handleConnection(s.sid, conn)
s.sid++
}
}
func (s *Server) handleConnection(sid int, conn net.Conn) {
// Client initalizes the connection with a one-time buffer of 8 NULL bytes.
nullInit := make([]byte, 8)
_, err := io.ReadFull(conn, nullInit)
if err != nil {
fmt.Println(err)
conn.Close()
return
}
session := &Session{
server: s,
rawConn: &conn,
cryptConn: network.NewCryptConn(conn),
}
s.Lock()
s.sessions[sid] = session
s.Unlock()
session.work()
}