Jump to content

[MaNGOS University] Login Walkthrough using MaNGOS and PseuWoW


Guest Shlainn_

Recommended Posts

DISCLAIMER: I posted this a while ago on the old forums, but I think this may help people. (http://getmangos.eu/community/viewtopic.php?id=16921)

While MaNGOS looks big and scary, it actually all boils down to a couple of files. I suggest you start at understanding WHAT MaNGOS is trying to emulate - in order of appearance:



    • [li]Realm Login (
https://github.com/mangos/mangos/blob/master/src/realmd/AuthSocket.cpp)[/li]
[li]World Login (https://github.com/mangos/mangos/blob/master/src/game/WorldSocket.cpp)[/li]
[li]Packet Handling (https://github.com/mangos/mangos/blob/master/src/game/Opcodes.cpp)[/li]
[li]Object system (https://github.com/mangos/mangos/blob/master/src/game/Object.h)[/li]
[li]Map/Grid system (https://github.com/mangos/mangos/blob/master/src/game/GridMap.cpp)[/li]
While this list is probably very incomplete, it should be enough to jumpstart your MaNGOS adventure. In parallel, it may help you to look at PseuWoW (http://mangosclient.org)(yes, shameless self-promo), which attempts to emulate the client part.

Let me walk you through how I would go about figuring out how the system works. This may or may not work for you.

1) Compile MaNGOS

2) Compile PseuWoW

3) Configure PseuWoW for the maximum debug output possible

Specifically this means in PseuWoW.conf:

debug=3 // Output every single piece of debug crap ever deposited in the source

showopcodes=3 // Show every single opcode that goes over the wire

hidefrequentopcodes=0 // REALLY every single opcode

HideDisabledOpcodes=0 // ...

showmyopcodes=1 // Also show what I am sending to the server

enablegui=0 // GUI adds unnecessary complexity, so no need for that

4) Now start up PseuWow and see what happens... OMG! It's full of crap!!! ...No, seriously:

2011-10-07 11:00:19 +----------------------------------+

2011-10-07 11:00:19 | © 2006-2010 Snowstorm Software |

2011-10-07 11:00:19 | http://www.mangosclient.org |

2011-10-07 11:00:19 +----------------------------------+

2011-10-07 11:00:19 Platform: Unix

2011-10-07 11:00:19 Compiler: GCC (40502)

2011-10-07 11:00:19 Compiled: Sep 22 2011 16:39:00

2011-10-07 11:00:19

2011-10-07 11:00:19 --- Initializing Instance ---

2011-10-07 11:00:19 *** DefScript StartUp [A13.51]...

2011-10-07 11:00:19 *** Loading 14 script files.

2011-10-07 11:00:19 * Loading script file [./scripts/__core_chat.def]

2011-10-07 11:00:19 * Loading script file [./scripts/__core_chatAI.def]

2011-10-07 11:00:19 * Loading script file [./scripts/__core_eventstubs.def]

2011-10-07 11:00:19 * Loading script file [./scripts/__core_func.def]

2011-10-07 11:00:19 * Loading core scripts...

2011-10-07 11:00:19 * Loading script file [./scripts/__core_funstuff.def]

2011-10-07 11:00:19 * Loading script file [./scripts/__core_hookHelper.def]

2011-10-07 11:00:19 * Loading script file [./scripts/__core_internal.def]

2011-10-07 11:00:19 * Loading core scripts (internal config)...

2011-10-07 11:00:19 ** Configuring PseuWoW...

2011-10-07 11:00:19 * Loading 1 conf files.

2011-10-07 11:00:19 * Loading conf file [ PseuWoW.conf ]

2011-10-07 11:00:19 MemoryDataHolder: Single-threaded mode.

2011-10-07 11:00:19 * Configuration applied.

2011-10-07 11:00:19 * Cleaning up variables...

2011-10-07 11:00:19 * Dangerous variables removed.

2011-10-07 11:00:19 * Assigning permissions for internal functions...

2011-10-07 11:00:19 ** All Config done.

2011-10-07 11:00:19 * Loading script file [./scripts/__core_list_extensions.def]

2011-10-07 11:00:19 * Loading script file [./scripts/__core_misc.def]

2011-10-07 11:00:19 * Loading script file [./scripts/__core_wrappers.def]

2011-10-07 11:00:19 * Loading script file [./scripts/autobroadcast.def]

2011-10-07 11:00:19 ** AutoBroadcast: skipped loading.

2011-10-07 11:00:19 * Loading script file [./scripts/database_loader.def]

2011-10-07 11:00:19 * Loading script file [./scripts/help.def]

2011-10-07 11:00:19 * Loading script file [./scripts/uptime.def]

2011-10-07 11:00:19 *** All files loaded without errors.

2011-10-07 11:00:19 *** StartUp complete!

2011-10-07 11:00:19 ** Loading / dyncompiling databases...

2011-10-07 11:00:19 Loading database 'race'

2011-10-07 11:00:19 File './data/scp/race.scp' matching database 'race', loading

2011-10-07 11:00:19 21 sections loaded

2011-10-07 11:00:19 Compacting database 'race' into file './cache/race.ccp'

2011-10-07 11:00:19 Database 'race' loaded from source and compacted with compression 6

--snip--

2011-10-07 11:00:19 ** Databases loaded.

2011-10-07 11:00:19 RemoteController: listening on port 8101

2011-10-07 11:00:19 Starting CLI...

2011-10-07 11:00:19 Init complete.

2011-10-07 11:00:19 PseuInstance: Initialized and running!

2011-10-07 11:00:19 GUI not active or Login data pre-entered, skipping Login GUI

2011-10-07 11:00:19 RealmSocket connected!

2011-10-07 11:00:19 Packet Sent

2011-10-07 11:00:19 RealmSocket::OnRead() 119 bytes

2011-10-07 11:00:19 RealmSocket: Got AUTH_LOGON_CHALLENGE [119 of 118 bytes]

2011-10-07 11:00:19 Login successful, now calculating proof packet...

2011-10-07 11:00:19 == Server Bignums ==

2011-10-07 11:00:19 --> B=2CEC5E45B34CB20CABC099088CCF3D6B315F12DCBE070CC2F563D5447884D917

2011-10-07 11:00:19 --> g=07

2011-10-07 11:00:19 --> N=894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7

2011-10-07 11:00:19 --> salt=B1CDCBFEE4C62F33D47D3A41DEE66E1667D487764058304BF1A70BB6C3557361

2011-10-07 11:00:19 --> unk=96C6A6BE2A589806B0B0070D852BBAC7

2011-10-07 11:00:19 == My Bignums ==

2011-10-07 11:00:19 --> a=A4722A2E0E9F1B9764E615034870B981569409

2011-10-07 11:00:19 --> x=36A15107ECF19C70E49EF4E5B42D36C7E3990B47

2011-10-07 11:00:19 --> v=77F37E45F8A88CDE9943038D4AE6C3292F407ED62D9B3DCC93E701E56E4D5228

2011-10-07 11:00:19 --> A=7BADE689AA63658C8DA684A78660BF1C62114269930D4141B9B30F75EDE466BB

2011-10-07 11:00:19 --> u=DBC0E8AE033ACA9A9066E583DC160CB741A39737

2011-10-07 11:00:19 --> S=1F9CC8F4E9F82C234427CAD5FBA670BB3F13E45369A9785278F248A7ED4A6A4D

2011-10-07 11:00:19 --> SessionKey=B950BE26E5472829B32D9BFCDD442A3C4D7D70A4DA6290E5C4F2ACC78D823BFB39F3B5E21342083A

2011-10-07 11:00:19 == Common Hashes ==

2011-10-07 11:00:19 --> M1=9BB22EF3A2E65D59F59A69AC526A0DE5D6EE0EE4

2011-10-07 11:00:19 --> M2=B128DC34B9061495325AECA7059D269386B4D46F

2011-10-07 11:00:19 --> CRC=0000000000000000000000000000000000000000

2011-10-07 11:00:19 Data left on RealmSocket, Hexdump:

2011-10-07 11:00:19 00

-- CUT --

An average PseuWoW login produces about 400 lines of logfile.

Obviously in the beginning you have some startup messages which say that some script files are loaded, some config is read, some databases are loaded, etc. If you would like to know specifics on how this is done, do a search over all files using some of the log output. For example if you would like to know how the databases are loaded, run "Loading databases" in your search, and you will find out that databases are loaded somewhere in PseuWoW/src/Client/DefScriptInterface.cpp.

Then it says "Init complete. PseuInstance: Initialized and running" - The fun starts. PseuWoW connects to the server...

I have to admit, that the realm socket code does not produce very nice output. But still. Every single line of log output can be found in the source, so you can follow the code execution. I will go through the next 5 lines:

11:00:19 RealmSocket connected!

This line is logged in PseuWoW/src/Client/Realm/RealmSocket.cpp RealmSocket::OnConnect(). When does this function get called? After some more searching we find out that RealmSocket is derived from TcpSocket (see PseuWoW/src/Client/Realm/RealmSocket.h) and TcpSocket calls OnConnect() when a connection is made (see PseuWoW/src/shared/Network/TcpSocket.cpp). Nice one!

11:00:19 Packet Sent

This line comes from PseuWoW/src/Client/Realm/RealmSession.cpp RealmSession::SendLogonChallenge() which gets called from PseuWoW/src/Client/PseuWoW.cpp PseuInstance::ConnectToRealm() which is called from PseuInstance::Update() which in turn gets called from PseuInstance::Run(). As you will also find out, Run() contains the main program loop. So after reading through some or all of these functions, you will see that SendLogonChallenge() puts together a data packet containing all kinds of logon data (I believe some of that is a bit hacky, now that I look at it...) (Client Version, account name, etc) and sends it off to the server.

This is the first contact. So what does the server do with it? (At this point you should take a look at server startup logs using the same strategy as before) The server (in this case realmd) gets this AUTH_LOGON_CHALLENGE packet. Searching mangos source for that string reveals that MaNGOS/src/realmd/AuthSocket.cpp handles it in AuthSocket::_HandleLogonChallenge. Reading through the code (and ignoring or looking up bits you don't understand right away) you will see that realmd checks if the packet is okay, if the account exists, is not banned, suspended, or any other bad thing and if it is not, it calculates some lovely bignumbers which are then used as logon challenge to the client. By following the pkt object throughout the function you can see the structure and order of data in the packet, just as before in PseuWoW. In the end, the packet is sent back to the client, which then says:

11:00:19 RealmSocket::OnRead() 119 bytes

By now you will not have any difficulties to find out that this is called from PseuWoW/src/Client/Realm/RealmSocket.cpp RealmSocket::OnRead(). It receives all data on the socket, and adds it to a packet queue for processing.

11:00:19 RealmSocket: Got AUTH_LOGON_CHALLENGE [119 of 118 bytes]

This message is reported from PseuWoW/src/Client/Realm/RealmSession.cpp RealmSession::_HandleLogonChallenge(). How the hell did we get from the packet queue to this function? Let's see. RealmSession::_GetAuthHandlerTable() has a mention of _HandleLogonChallenge() in a table of some sorts. _GetAuthHandlerTable() gets called from RealmSession::Update() and returns a pointer to the table. A bit into the Update() function (which presumably gets called from the main loop, I leave it to you to verify this) you will find that a for loop goes through the table and checks if the Opcode of the packet matches the one in the table. If it does, a magic called "function pointers" is used to call the associated handler function, which we already know is _HandleLogonChallenge().

11:00:19 Login successful, now calculating proof packet...

This line is also from _HandleLogonChallenge(), a bit further down. As you will have found out at this point, PseuWoW has checked if there were any errors, and found none. So now it will extract the data from the packet, calculate login proof data and send it off again, while outputting copious amounts of debug information.

I hope this starts your learning process. What you will see all the time it this ping-pong game between the server and the client throwing packets at each other in response to something happening on either side (movement, attacks, cooldowns, etc) and replying to those packets.

This is just a start, but I am very certain that only a handful of people on this planet have a complete in-depth understanding of every bit of code in the MaNGOS repository. It is also not necessary to understand the underlying network code to fix something in the spell handling (just as an example). So I would recommend you not to get lost in implementation details before you have the big picture. And by "big picture" I refer to the three classic things every program needs to do:

main()
{

Initialize();

while(running)
 DoStuff();

CleanUp();

}


  • Hope it helps,
    Shlainn

Link to comment
Share on other sites

  • 42 years later...

I'll second that, TheLuda! A BIG "thank you" for such a detailed guide, shlainn. :)

I especially like your in-depth look at the debug log output. It's a huge help with understanding what's happening "under the hood" when a client connects with the MANGOS server.

I hope all other devs follow your example of such completeness and clarity. It's just the thing many newbies need to make sense of things and find a place to begin unraveling the complex thread that's been woven to create all this great software.

We need more like you! :D

Link to comment
Share on other sites

  • 1 month later...

Thanks for the info.

In short, it looks like https://github.com/mangos/mangos/blob/master/src/realmd/AuthSocket.cpp is using an optimized SRP (Secure Remote Password) protocol http://srp.stanford.edu/ndss.html.

The message handling between client and server look like this.

1. Client sends CMD_AUTH_LOGON_CHALLENGE request

a. Username, client version, platform, OS, country, timezone, IP

2. Server receives CMD_AUTH_LOGON_CHALLENGE request

a. Handled by AuthSocket::_HandleLogonChallenge

3. Server Sends CMD_AUTH_LOGON_CHALLENGE response with following result

a. Banned? WOW_FAIL_BANNED

b. Suspended? WOW_FAIL_SUSPENDED

c. Unknown user? WOW_FAIL_UNKNOWN_ACCOUNT

d. Okay? WOW_SUCCESS

i. Send SRP6 values: B, g, N, s, unk3

4. Client receives CMD_AUTH_LOGON_CHALLENGE response

a. Client calculates SRP6 proof: M1

5. Client sends CMD_AUTH_LOGON_PROOF request

6. Server receives CMD_AUTH_LOGON_PROOF request

a. Handled by AuthSocket::_HandleLogonProof

7. Server responds with one of the following:

a. Wrong client version or not authenticated?

i. Send CMD_AUTH_LOGON_CHALLENGE response WOW_FAIL_VERSION_INVALID

b. Login okay?

i. Send CMD_AUTH_LOGON_PROOF response with SRP6 M2 value

I'm a bit stuck on how the rest of the logon messages (CMD_AUTH_RECONNECT_CHALLENGE, CMD_AUTH_RECONNECT_PROOF, CMD_REALM_LIST, CMD_XFER_ACCEPT, CMD_XFER_RESUME, CMD_XFER_CANCEL) are used.

I'm assuming the client initiates the RECONNECT_CHALLENGE, but when and why?

Is CMD_REALM_LIST sent by the server immediately after CMD_AUTH_LOGON_PROOF, or is it sent by the client first?

Looks like CMD_XFER_... is how the client connects to the world servers, but what does that series of messages look like?

Link to comment
Share on other sites

You are correct, it is a SRP6 protocol.

In an ideal case it is

Client creates a TCP connection to realmd

Client: AUTH_LOGON_CHALLENGE

Server: AUTH_LOGON_CHALLENGE

Client: AUTH_LOGON_PROOF

Server: AUTH_LOGON_PROOF

at this point the client and server have exchanged auth secrets. Next, client sends

Client:CMD_REALM_LIST (which is an empty packet) and receives

Server:CMD_REALM_LIST which contains a list of all world servers.

After that, the client creates a TCP connection to the selected world server. Now the server sends

SMSG_AUTH_CHALLENGE to which the client replies with

CMSG_AUTH_SESSION. After this point the packet headers are encrypted.

As far as I recall CMD_XFER_* are used for downloading patches inside the client.

I haven't seen CMD_AUTH_RECONNECT_CHALLENGE or CMD_AUTH_RECONNECT_PROOF so far, but I assume these are for going back from world server to realmd. This is pure speculation though.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. Privacy Policy Terms of Use