msnet

package module
v1.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 1, 2026 License: MIT Imports: 18 Imported by: 0

README

msnet

msnet is a pure Golang networking package for MapleStory

Installation

$ go get github.com/zhyonc/msnet@latest

Quick Start

package main

import (
	"log/slog"
	"net"

	"github.com/zhyonc/msnet"
)

type server struct {
	addr string
	lis  net.Listener
}

func NewServer(addr string) *server {
	s := &server{
		addr: addr,
	}
	return s
}

func (s *server) Run() {
	lis, err := net.Listen("tcp", s.addr)
	if err != nil {
		slog.Error("Failed to create tcp listener", "err", err)
		return
	}
	slog.Info("TCPListener is starting on " + s.addr)
	s.lis = lis
	var idCount int32 = 0
	for {
		if s.lis == nil {
			slog.Warn("TCPListener is nil")
			break
		}
		conn, err := s.lis.Accept()
		if err != nil {
			slog.Error("Failed to accept conn", "err", err)
			continue
		}
		slog.Info("New client connected", "addr", conn.RemoteAddr())
		cs := msnet.NewCClientSocket(s, conn, nil, nil)
		go cs.OnRead()
		cs.OnConnect()
		cs.SetID(idCount)
		idCount++
	}
}

func (s *server) Shutdown() {
	s.lis.Close()
	s.lis = nil
}

func main() {
	msnet.New(&msnet.Setting{
		MSRegion:       msnet.GMS,
		MSVersion:      95,
		MSMinorVersion: "1",
	})
	s := NewServer("127.0.0.1:8484")
	s.Run()
}

Setting

  • MSRegion: MapleStory Regions including GMSCW(1)/KMS(1)/KMST(2)/JMS(3)/CMS(4)/TMS(6)/MSEA(7)/GMS(8)/BMS(9)
  • MSVersion: MapleStory Client Version
  • MSMinorVersion: MapleStory Client Minor Version
  • CipherType:
    • AESCipher: Used for the majority of clients
    • XORCipher: Used in versions about 2004
    • LinearCipher: Used for GMS LP data since 2017 (excluding the login server)
    • NullCipher: Used for connect packet
  • DESKey (optional): A 16-byte string used for opcode encryption based on v193-encryption and opcode-encryption-fix
  • IsCycleAESKey (optional):
    • Default is false, old AES key will be used, which is compatible with most earlier versions
    • If set true, cycle AES key will be used, which is compatible with newer versions
  • CustomAESKey (optional): It's used to instead of old AES key and cycle AES key
    • Decrypt: A 32-byte array used for decrypting data in CInPacket::DecryptData
    • Encrypt: A 32-byte array used for encrypting data in COutPacket::MakeBufferList
  • RecvXOR (optional): The server must use the same XOR key to recover the original packet
  • SendXOR (optional): The client must use the same XOR key to recover the original packet
  • AliveAckMins (optional): Client heartbeat timeout minutes (0 to disable)
  • IsTypeHeader1Byte: Used in versions about 2004~2008
  • AESInitType (optional): Compatible with older versions based on AES encrypt
    • Default: Used in versions after about 2008
    • Duplicate: Used in versions about 2005~2007 (excluding TMS)
    • Shuffle: Used in TMS versions about 2005~2007

Packet

Header AESOFB Note
4 Bytes Any Bytes Except for the first packet
Decode

Decode packet length using XOR of two little-endian uint16 values from header
PacketLen = (Header[0]+Header[1]*0x100) ^ (Header[2]+Header[3]*0x100)

Encode

Encode packet length using little-endian XOR with sVersion and sendIV

  • sVersion = (^clientVer >> 8 & 0xFF) | ((^clientVer << 8) & 0xFF00)
  • a = int(sendIV[3])
  • a |= int(sendIV[2])<<8
  • a ^= sVersion
  • b = ((PacketLen << 8) & 0xFF00) | (PacketLen >> 8)
  • c = a ^ b
  • Header = [a>>8, a, c>>8, b]
Format
Opcode Data Note
2 Bytes Any Bytes Except for the connect packet
Connect Packet
Name PacketLen Version MinorVersionLen MinorVersion RecvIV SendIV Region Note
Connect 2 Bytes 2 Bytes 2 Bytes 1 Byte 4 Bytes 4 Bytes 1 Bytes The connect packet

Documentation

Index

Constants

View Source
const (
	SERVER_TYPE     string = "login"
	SERVER_ADDR     string = "127.0.0.1:8484"
	LOG_BACKUP_DIR  string = "./log"
	HEADER_LENGTH   int    = 4
	MAX_DATA_LENGTH int    = 1456
	FT_EPOCH_DIFF   int64  = 116444736000000000 // FileTime epoch is January 1, 1601
	GMSCW_DES_KEY   string = "G0dD@mnN#H@ckEr!"
	KMS_DES_KEY     string = "G0dD@mnN#H@ckEr!"
	JMS_DES_KEY     string = "M@pl3J@p@nH@ck3r"
	CMS_DES_KEY     string = "aVbTpJ5=ZjG&Db3$"
	TMS_DES_KEY     string = "BrN=r54jQp2@yP6G"
	GMS_DES_KEY     string = "N3x@nGLEUH@ckEr!"
)

Variables

This section is empty.

Functions

func GetLangBuf added in v1.0.2

func GetLangBuf(s string) []byte

func GetLangStr added in v1.0.2

func GetLangStr(buf []byte) string

func New

func New(setting *Setting)

func SetLogger

func SetLogger(backupDir string, filename string, level slog.Level, done chan bool)

Types

type AESInitType added in v1.1.3

type AESInitType uint8
const (
	Default AESInitType = iota
	Duplicate
	Shuffle
)

type CClientSocket

type CClientSocket interface {
	SetID(id int32)
	GetID() int32
	GetAddr() string
	XORRecv(buf []byte)
	XORSend(buf []byte)
	OnRead()
	OnConnect()
	OnAliveAck()
	OnOpcodeEncryption(LP_OpcodeEncryption uint16, startOpcode uint16, endOpcode uint16, isSplit bool)
	DecryptOpcode(randNum uint16) uint16
	SetLinearCipher(toggle bool)
	SendPacket(oPacket COutPacket)
	Stepping(iv []byte)
	Flush()
	OnError(err error)
	Close()
}

func NewCClientSocket

func NewCClientSocket(delegate CClientSocketDelegate, conn net.Conn, rcvIV []byte, sndIV []byte) CClientSocket

type CClientSocketDelegate added in v1.0.7

type CClientSocketDelegate interface {
	DebugInPacketLog(id int32, iPacket CInPacket)
	DebugOutPacketLog(id int32, oPacket COutPacket)
	NewConnectPacket(region Region, version uint16, minorVersion string, seqRcv [4]byte, seqSnd [4]byte) COutPacket
	ProcessPacket(cs CClientSocket, iPacket CInPacket)
	SocketClose(id int32)
}

type CInPacket

type CInPacket interface {
	DecryptHeader(pBuff []byte)
	DecryptData(dwKey []byte)
	GetType() uint16
	GetTypeByte() uint8
	GetRemain() int
	GetOffset() int
	GetLength() int
	DecodeBool() bool
	Decode1() int8
	Decode2() int16
	Decode4() int32
	Decode8() int64
	DecodeFT() time.Time
	DecodeStr() string
	DecodeLocalStr() string
	DecodeLocalName() string
	DecodeBuffer(uSize int) []byte
	DumpString(nSize int) string
	Clear()
}

func NewCInPacket

func NewCInPacket(buf []byte) CInPacket

type COutPacket

type COutPacket interface {
	GetType() uint16
	GetTypeByte() uint8
	GetSendBuffer() []byte
	GetOffset() int
	GetLength() int
	EncodeBool(b bool)
	Encode1(n int8)
	Encode2(n int16)
	Encode4(n int32)
	Encode8(n int64)
	EncodeFT(t time.Time)
	EncodeStr(s string)
	EncodeLocalStr(s string)
	EncodeLocalName(s string)
	EncodeBuffer(buf []byte)
	EncryptHeader(pBuff []byte, dataLen int, dwKey []byte)
	MakeBufferList(cipherType CipherType, dwKey []byte) []byte
	DumpString(nSize int) string
}

func NewCOutPacket

func NewCOutPacket(nType ...any) COutPacket

type CipherType added in v1.1.3

type CipherType uint8
const (
	AESCipher CipherType = iota
	XORCipher
	LinearCipher
	NullCipher
)

type Region added in v1.1.3

type Region uint8
const (
	GMSCW Region = 1
	KMS   Region = 1
	KMST  Region = 2
	JMS   Region = 3
	CMS   Region = 4
	CMST  Region = 5
	TMS   Region = 6
	MSEA  Region = 7
	GMS   Region = 8
	EMS   Region = 9
	BMS   Region = 9
)

type Setting

type Setting struct {
	MSRegion          Region
	MSVersion         uint16
	MSMinorVersion    string
	CipherType        CipherType
	DESKey            string
	IsCycleAESKey     bool
	AESKeyDecrypt     [32]byte
	AESKeyEncrypt     [32]byte
	RecvXOR           uint8
	SendXOR           uint8
	AliveAckMins      uint8
	IsTypeHeader1Byte bool
	AESInitType       AESInitType
}

Directories

Path Synopsis
internal
opcode
Code generated by opcode_test, DO NOT EDIT.
Code generated by opcode_test, DO NOT EDIT.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL