From 4de697cf9a6b8c0795d26ebf4d577470a17ac22f Mon Sep 17 00:00:00 2001 From: flswld Date: Tue, 14 Feb 2023 17:20:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=BA=E5=99=A8=E4=BA=BAgate=E7=99=BB?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dispatch/controller/dispatch_controller.go | 4 - pkg/httpclient/http_client.go | 8 ++ robot/cmd/dpdk_test.go | 14 +++ robot/cmd/main.go | 73 ++++++++------ robot/login/gate_login.go | 106 +++++++++++++++++++++ robot/login/http_login.go | 53 +++++++++-- robot/net/session.go | 58 ++++------- 7 files changed, 236 insertions(+), 80 deletions(-) create mode 100644 robot/cmd/dpdk_test.go create mode 100644 robot/login/gate_login.go diff --git a/dispatch/controller/dispatch_controller.go b/dispatch/controller/dispatch_controller.go index fb7eacdb..b9a58203 100644 --- a/dispatch/controller/dispatch_controller.go +++ b/dispatch/controller/dispatch_controller.go @@ -101,10 +101,6 @@ func (c *Controller) queryCurRegion(context *gin.Context) { return } logger.Debug("do hk4e 2.8 rsa logic") - if context.Query("dispatchSeed") == "" { - rspError() - return - } keyId := context.Query("key_id") encPubPrivKey, exist := c.encRsaKeyMap[keyId] if !exist { diff --git a/pkg/httpclient/http_client.go b/pkg/httpclient/http_client.go index a1fe7205..16f6f6a8 100644 --- a/pkg/httpclient/http_client.go +++ b/pkg/httpclient/http_client.go @@ -2,11 +2,14 @@ package httpclient import ( "bytes" + "crypto/tls" "encoding/json" "io" "net/http" "strings" "time" + + "hk4e/pkg/logger" ) var httpClient http.Client @@ -14,6 +17,9 @@ var httpClient http.Client func init() { httpClient = http.Client{ Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, DisableKeepAlives: true, }, Timeout: time.Second * 10, @@ -37,6 +43,7 @@ func GetJson[T any](url string, authToken string) (*T, error) { if err != nil { return nil, err } + logger.Debug("http get rsp data: %v", string(data)) responseData := new(T) err = json.Unmarshal(data, responseData) if err != nil { @@ -87,6 +94,7 @@ func PostJson[T any](url string, body any, authToken string) (*T, error) { if err != nil { return nil, err } + logger.Debug("http post rsp data: %v", string(rspData)) responseData := new(T) err = json.Unmarshal(rspData, responseData) if err != nil { diff --git a/robot/cmd/dpdk_test.go b/robot/cmd/dpdk_test.go new file mode 100644 index 00000000..38a814dc --- /dev/null +++ b/robot/cmd/dpdk_test.go @@ -0,0 +1,14 @@ +//go:build linux +// +build linux + +package main + +import ( + "testing" + + "github.com/FlourishingWorld/dpdk-go/engine" +) + +func TestDpdk(t *testing.T) { + _ = engine.InitEngine("00:0C:29:3E:3E:DF", "192.168.199.199", "255.255.255.0", "192.168.199.1") +} diff --git a/robot/cmd/main.go b/robot/cmd/main.go index b54a1f21..6b39e16e 100644 --- a/robot/cmd/main.go +++ b/robot/cmd/main.go @@ -1,9 +1,9 @@ package main import ( + "encoding/base64" "os" "os/signal" - "strconv" "syscall" "time" @@ -13,51 +13,59 @@ import ( "hk4e/protocol/cmd" "hk4e/protocol/proto" "hk4e/robot/login" - "hk4e/robot/net" - - "github.com/FlourishingWorld/dpdk-go/engine" ) func main() { config.InitConfig("application.toml") logger.InitLogger("robot") - err := engine.InitEngine("00:0C:29:3E:3E:DF", "192.168.199.199", "255.255.255.0", "192.168.199.1") - if err != nil { - panic(err) - } - engine.RunEngine([]int{0, 1, 2, 3}, 4, 1, "0.0.0.0") + // // DPDK模式需开启 + // err := engine.InitEngine("00:0C:29:3E:3E:DF", "192.168.199.199", "255.255.255.0", "192.168.199.1") + // if err != nil { + // panic(err) + // } + // engine.RunEngine([]int{0, 1, 2, 3}, 4, 1, "0.0.0.0") + // time.Sleep(time.Second * 30) - time.Sleep(time.Second * 30) - - dispatchInfo, err := login.GetDispatchInfo("https://hk4e.flswld.com", "?version=OSRELWin3.2.0") + dispatchInfo, err := login.GetDispatchInfo("https://hk4e.flswld.com", + "https://hk4e.flswld.com/query_cur_region", + "", + "?version=OSRELWin3.2.0&key_id=5", + "5") if err != nil { panic(err) } - accountInfo, err := login.AccountLogin("https://hk4e.flswld.com", "flswld", "123456") + accountInfo, err := login.AccountLogin("https://hk4e.flswld.com", "test123@@12345678", base64.StdEncoding.EncodeToString([]byte{0x00})) + if err != nil { + panic(err) + } + session, err := login.GateLogin(dispatchInfo, accountInfo, "5") if err != nil { panic(err) } - gateAddr := dispatchInfo.GateIp + strconv.Itoa(int(dispatchInfo.GatePort)) - session := net.NewSession(gateAddr, dispatchInfo.DispatchKey, 30000) go func() { - protoMsg := <-session.RecvChan - logger.Debug("protoMsg: %v", protoMsg) + for { + // 从这个管道接收服务器发来的消息 + protoMsg := <-session.RecvChan + logger.Debug("recv protoMsg: %v", protoMsg) + } }() go func() { - session.SendChan <- &hk4egatenet.ProtoMsg{ - ConvId: 0, - CmdId: cmd.GetPlayerTokenReq, - HeadMessage: &proto.PacketHead{ - ClientSequenceId: 1, - SentMs: uint64(time.Now().UnixMilli()), - }, - PayloadMessage: &proto.GetPlayerTokenReq{ - AccountToken: accountInfo.ComboToken, - AccountUid: strconv.Itoa(int(accountInfo.AccountId)), - KeyId: 5, - ClientRandKey: "", - }, + for { + time.Sleep(time.Second) + // 通过这个管道发消息给服务器 + session.SendChan <- &hk4egatenet.ProtoMsg{ + ConvId: 0, + CmdId: cmd.PingReq, + HeadMessage: &proto.PacketHead{ + ClientSequenceId: 0, + SentMs: uint64(time.Now().UnixMilli()), + }, + PayloadMessage: &proto.PingReq{ + ClientTime: uint32(time.Now().UnixMilli()), + Seq: 0, + }, + } } }() @@ -67,7 +75,10 @@ func main() { s := <-c switch s { case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT: - engine.StopEngine() + + // // DPDK模式需开启 + // engine.StopEngine() + time.Sleep(time.Second) return case syscall.SIGHUP: diff --git a/robot/login/gate_login.go b/robot/login/gate_login.go new file mode 100644 index 00000000..ee071da4 --- /dev/null +++ b/robot/login/gate_login.go @@ -0,0 +1,106 @@ +package login + +import ( + "bytes" + "encoding/base64" + "encoding/binary" + "errors" + "strconv" + "time" + + "hk4e/common/region" + hk4egatenet "hk4e/gate/net" + "hk4e/pkg/endec" + "hk4e/pkg/logger" + "hk4e/pkg/random" + "hk4e/protocol/cmd" + "hk4e/protocol/proto" + "hk4e/robot/net" +) + +func GateLogin(dispatchInfo *DispatchInfo, accountInfo *AccountInfo, keyId string) (*net.Session, error) { + gateAddr := dispatchInfo.GateIp + ":" + strconv.Itoa(int(dispatchInfo.GatePort)) + session, err := net.NewSession(gateAddr, dispatchInfo.DispatchKey, 30000) + if err != nil { + return nil, err + } + timeRand := random.GetTimeRand() + clientSeedUint64 := timeRand.Uint64() + clientSeedBuf := new(bytes.Buffer) + err = binary.Write(clientSeedBuf, binary.BigEndian, &clientSeedUint64) + if err != nil { + return nil, err + } + clientSeed := clientSeedBuf.Bytes() + signRsaKey, encRsaKeyMap, _ := region.LoadRsaKey() + signPubkey, err := endec.RsaParsePubKeyByPrivKey(signRsaKey) + if err != nil { + logger.Error("parse rsa pub key error: %v", err) + return nil, err + } + clientSeedEnc, err := endec.RsaEncrypt(clientSeed, signPubkey) + if err != nil { + logger.Error("rsa dec error: %v", err) + return nil, err + } + clientSeedBase64 := base64.StdEncoding.EncodeToString(clientSeedEnc) + keyIdInt, err := strconv.Atoi(keyId) + if err != nil { + logger.Error("parse key id error: %v", err) + return nil, err + } + session.SendChan <- &hk4egatenet.ProtoMsg{ + ConvId: 0, + CmdId: cmd.GetPlayerTokenReq, + HeadMessage: &proto.PacketHead{ + ClientSequenceId: 0, + SentMs: uint64(time.Now().UnixMilli()), + }, + PayloadMessage: &proto.GetPlayerTokenReq{ + AccountToken: accountInfo.ComboToken, + AccountUid: strconv.Itoa(int(accountInfo.AccountId)), + KeyId: uint32(keyIdInt), + ClientRandKey: clientSeedBase64, + }, + } + protoMsg := <-session.RecvChan + if protoMsg.CmdId != cmd.GetPlayerTokenRsp { + return nil, errors.New("recv pkt is not GetPlayerTokenRsp") + } + // XOR密钥切换 + getPlayerTokenRsp := protoMsg.PayloadMessage.(*proto.GetPlayerTokenRsp) + seedEnc, err := base64.StdEncoding.DecodeString(getPlayerTokenRsp.ServerRandKey) + if err != nil { + logger.Error("base64 decode error: %v", err) + return nil, err + } + encPubPrivKey, exist := encRsaKeyMap[keyId] + if !exist { + logger.Error("can not found key id: %v", keyId) + return nil, err + } + privKey, err := endec.RsaParsePrivKey(encPubPrivKey) + if err != nil { + logger.Error("parse rsa pub key error: %v", err) + return nil, err + } + seed, err := endec.RsaDecrypt(seedEnc, privKey) + if err != nil { + logger.Error("rsa enc error: %v", err) + return nil, err + } + seedUint64 := uint64(0) + err = binary.Read(bytes.NewReader(seed), binary.BigEndian, &seedUint64) + if err != nil { + logger.Error("parse seed error: %v", err) + return nil, err + } + serverSeedUint64 := seedUint64 ^ clientSeedUint64 + logger.Info("change session xor key") + keyBlock := random.NewKeyBlock(serverSeedUint64, true) + xorKey := keyBlock.XorKey() + key := make([]byte, 4096) + copy(key, xorKey[:]) + session.XorKey = key + return session, nil +} diff --git a/robot/login/http_login.go b/robot/login/http_login.go index 61e5e217..cb19a36b 100644 --- a/robot/login/http_login.go +++ b/robot/login/http_login.go @@ -3,9 +3,12 @@ package login import ( "encoding/base64" "encoding/json" + "math" "strconv" + "hk4e/common/region" "hk4e/dispatch/api" + "hk4e/pkg/endec" "hk4e/pkg/httpclient" "hk4e/pkg/logger" "hk4e/pkg/random" @@ -21,9 +24,9 @@ type DispatchInfo struct { DispatchKey []byte } -func GetDispatchInfo(url string, clientParam string) (*DispatchInfo, error) { - logger.Info("http get url: %v", url+"/query_region_list"+clientParam) - regionListBase64, err := httpclient.GetRaw(url+"/query_region_list"+clientParam, "") +func GetDispatchInfo(regionListUrl string, curRegionUrl string, regionListParam string, curRegionParam string, keyId string) (*DispatchInfo, error) { + logger.Info("http get url: %v", regionListUrl+"/query_region_list"+regionListParam) + regionListBase64, err := httpclient.GetRaw(regionListUrl+"/query_region_list"+regionListParam, "") if err != nil { return nil, err } @@ -40,17 +43,51 @@ func GetDispatchInfo(url string, clientParam string) (*DispatchInfo, error) { if len(queryRegionListHttpRsp.RegionList) == 0 { return nil, errors.New("no region found") } - selectRegion := queryRegionListHttpRsp.RegionList[0] - logger.Info("select region: %v", selectRegion) - logger.Info("http get url: %v", selectRegion.DispatchUrl+clientParam) - regionCurrBase64, err := httpclient.GetRaw(selectRegion.DispatchUrl+clientParam, "") + if curRegionUrl == "" { + selectRegion := queryRegionListHttpRsp.RegionList[0] + logger.Info("select region: %v", selectRegion) + curRegionUrl = selectRegion.DispatchUrl + } + logger.Info("http get url: %v", curRegionUrl+curRegionParam) + regionCurrJson, err := httpclient.GetRaw(curRegionUrl+curRegionParam, "") if err != nil { return nil, err } - regionCurrData, err := base64.StdEncoding.DecodeString(regionCurrBase64) + queryCurRegionRspJson := new(api.QueryCurRegionRspJson) + err = json.Unmarshal([]byte(regionCurrJson), queryCurRegionRspJson) if err != nil { return nil, err } + encryptedRegionInfo, err := base64.StdEncoding.DecodeString(queryCurRegionRspJson.Content) + if err != nil { + return nil, err + } + chunkSize := 256 + regionInfoLength := len(encryptedRegionInfo) + numChunks := int(math.Ceil(float64(regionInfoLength) / float64(chunkSize))) + regionCurrData := make([]byte, 0) + _, encRsaKeyMap, _ := region.LoadRsaKey() + encPubPrivKey, exist := encRsaKeyMap[keyId] + if !exist { + logger.Error("can not found key id: %v", keyId) + return nil, err + } + for i := 0; i < numChunks; i++ { + from := i * chunkSize + to := int(math.Min(float64((i+1)*chunkSize), float64(regionInfoLength))) + chunk := encryptedRegionInfo[from:to] + privKey, err := endec.RsaParsePrivKey(encPubPrivKey) + if err != nil { + logger.Error("parse rsa priv key error: %v", err) + return nil, err + } + decrypt, err := endec.RsaDecrypt(chunk, privKey) + if err != nil { + logger.Error("rsa dec error: %v", err) + return nil, err + } + regionCurrData = append(regionCurrData, decrypt...) + } queryCurrRegionHttpRsp := new(proto.QueryCurrRegionHttpRsp) err = pb.Unmarshal(regionCurrData, queryCurrRegionHttpRsp) if err != nil { diff --git a/robot/net/session.go b/robot/net/session.go index b6c35be1..d077e457 100644 --- a/robot/net/session.go +++ b/robot/net/session.go @@ -1,54 +1,48 @@ package net import ( - "strconv" "time" + "hk4e/gate/kcp" hk4egatenet "hk4e/gate/net" "hk4e/pkg/logger" - "hk4e/pkg/random" "hk4e/protocol/cmd" - - "github.com/FlourishingWorld/dpdk-go/protocol/kcp" ) type Session struct { - SendChan chan *hk4egatenet.ProtoMsg - RecvChan chan *hk4egatenet.ProtoMsg - conn *kcp.UDPSession - seed uint64 // TODO 密钥交换后收到的服务器生成的seed - xorKey []byte - changeXorKeyFin bool - useMagicSeed bool + Conn *kcp.UDPSession + XorKey []byte + SendChan chan *hk4egatenet.ProtoMsg + RecvChan chan *hk4egatenet.ProtoMsg } -func NewSession(gateAddr string, dispatchKey []byte, localPort int) (r *Session) { - conn, err := kcp.DialWithOptions(gateAddr, "0.0.0.0:"+strconv.Itoa(localPort)) +func NewSession(gateAddr string, dispatchKey []byte, localPort int) (*Session, error) { + // // DPDK模式需开启 + // conn, err := kcp.DialWithOptions(gateAddr, "0.0.0.0:"+strconv.Itoa(localPort)) + + conn, err := kcp.DialWithOptions(gateAddr) if err != nil { logger.Error("kcp client conn to server error: %v", err) - return + return nil, err } conn.SetACKNoDelay(true) conn.SetWriteDelay(false) sendChan := make(chan *hk4egatenet.ProtoMsg, 1000) recvChan := make(chan *hk4egatenet.ProtoMsg, 1000) - r = &Session{ - SendChan: sendChan, - RecvChan: recvChan, - conn: conn, - seed: 0, - xorKey: dispatchKey, - changeXorKeyFin: false, - useMagicSeed: true, + r := &Session{ + Conn: conn, + XorKey: dispatchKey, + SendChan: sendChan, + RecvChan: recvChan, } go r.recvHandle() go r.sendHandle() - return r + return r, nil } func (s *Session) recvHandle() { logger.Info("recv handle start") - conn := s.conn + conn := s.Conn convId := conn.GetConv() recvBuf := make([]byte, hk4egatenet.PacketMaxLen) dataBuf := make([]byte, 0, 1500) @@ -62,21 +56,11 @@ func (s *Session) recvHandle() { } recvData := recvBuf[:recvLen] kcpMsgList := make([]*hk4egatenet.KcpMsg, 0) - hk4egatenet.DecodeBinToPayload(recvData, &dataBuf, convId, &kcpMsgList, s.xorKey) + hk4egatenet.DecodeBinToPayload(recvData, &dataBuf, convId, &kcpMsgList, s.XorKey) for _, v := range kcpMsgList { protoMsgList := hk4egatenet.ProtoDecode(v, cmd.NewCmdProtoMap(), nil) for _, vv := range protoMsgList { s.RecvChan <- vv - if s.changeXorKeyFin == false && vv.CmdId == cmd.GetPlayerTokenRsp { - // XOR密钥切换 - logger.Info("change session xor key, convId: %v", convId) - s.changeXorKeyFin = true - keyBlock := random.NewKeyBlock(s.seed, s.useMagicSeed) - xorKey := keyBlock.XorKey() - key := make([]byte, 4096) - copy(key, xorKey[:]) - s.xorKey = key - } } } } @@ -84,7 +68,7 @@ func (s *Session) recvHandle() { func (s *Session) sendHandle() { logger.Info("send handle start") - conn := s.conn + conn := s.Conn convId := conn.GetConv() for { protoMsg, ok := <-s.SendChan @@ -98,7 +82,7 @@ func (s *Session) sendHandle() { logger.Error("decode kcp msg is nil, convId: %v", convId) continue } - bin := hk4egatenet.EncodePayloadToBin(kcpMsg, s.xorKey) + bin := hk4egatenet.EncodePayloadToBin(kcpMsg, s.XorKey) _ = conn.SetWriteDeadline(time.Now().Add(time.Second * hk4egatenet.ConnSendTimeout)) _, err := conn.Write(bin) if err != nil {