Teeworlds 0.6

Teeworlds 0.6 sample traffic

In theory all 0.X releases are compatible. But for 0.6 there are 3 slightly different implementations for security tokens which have to be considered. There are the teeworlds 0.6.4 and older 0.6.x releases that have no security token at all. Then there is the fork of teeworlds called ddnet which is based on that teeworlds version which added

Teeworlds 0.6.5 sample traffic

[CLIENT->SERVER] Hello server this is my token

                
   10 00 00 01 00 00 00 00 4a 44 82 61 00 00 00 .. (501 more null bytes)
   ^        ^  ^           ^
   |        |  |           the client's 4 byte security token
   |        |  |           inside of the payload
   |        |  |           the payload is not parsed by 0.6.4
   |        |  |           servers anyways only the length is checked
   |        |  |           to protect against reflection attacks
   |        |  |
   |        |  connect message payload start
   |        |  the payload is 512 null bytes
   |        |
   |     control message id 1 (NET_CTRLMSG_CONNECT)
   |
   |
   flags (CONTROL)
   the token flag is NOT set yet, because the server
   might be 0.6.4 the client does not know it yet
                
            

[SERVER->CLIENT] Hello client this my token

                
   18 00 00 4a 44 82 61 02 07 ec ab 6c
   ^        ^           ^  ^
   |        |           |  |
   |     client token   | server token
   |                    | it will from now on used by both parties
   |                    | as the shared security token
   |                    |
   |     control message id 2 (NET_CTRLMSG_CONNECTACCEPT)
   |
  flags (CONTROL & TOKEN)
  the server knows the client supports tokens
  because the client already sent a token in the previous message
  so the server sets the token flag and places the client token
  in the packet header
                
            

[CLIENT->SERVER] Version and password

Now the client will inform the server about its version. This packet is defined in CClient::SendInfo() and contains the password, the network hash and the supported protocol version. The vanilla client always sends the password that was entered last by the user. No matter which server it is connecting to also if the server does not expect a password. This is nice since it minimizes user input even if the ip changes or multiple servers have the same password. But it is leaking the password you entered last to every server you connect to. That is why the ddnet client decided to only send the password after user confirmation.

If the server receives this packet it will log the following line.
[2022-10-25 14:22:25][connection]: connecting online

Since the packet payload now contains uncompressed printable ASCII characters those are included below. You can quickly identify this packet when running tcpdump with the -Xflag.
                
  [PACKET HEADER]
  08 00 01 07 ec ab 6c
  ^     ^  ^
  |     |  token
  |     |
  |     num chunks 1
  |     this is the first regular (non control) packet
  |     and it has one chunk/message as payload
  |
  flags (TOKEN)

  [PACKET PAYLOAD HEX]                 [PACKET PAYLOAD ASCII]
  41 07 01 03 30 2e 36 20 36 32 36     A...0.6 626
  66 63 65 39 61 37 37 38 64 66 34     fce9a778df4
  64 34 00 00                          d4..
        ^  ^
        |  empty password sent just as a single null byte
        |
     null terminating byte from the version hash string
                
            

[SERVER->CLIENT] Map info

Now the server is informing the client about the map. This is NOT the mapfile it self. Just its metadata. To see what exactly is being sent checkout the code of CServer::SendMap() it boils down to this:
                
  String GetMapName()
  Int    m_CurrentMapCrc
  Int    m_CurrentMapSize
                
            
In the ASCII representation of the packet you can spot the mapname.
In this case the map is called bridge.
                
  [PACKET HEADER]
  08 01 01 07 ec ab 6c
  ^  ^  ^  ^
  |  |  |  token
  |  |  |
  |  | num chunks 1
  |  | this packet contains one chunk/message in the payload
  |  |
  | Acknowledged sequence number 1
  | this is the server confirming that it
  | successfully received the first vital message from the client
  | which was the net info and password
  |
 flags (TOKEN)

  [PACKET PAYLOAD HEX]                       [PACKET PAYLOAD ASCII]
  40 0f 01 05 62 72 69 64 67 65 00           @...bridge.
  af cc 90 fb 0f a7 15                       .......
                
            

[CLIENT->SERVER] Ready

If the client already has the map or finished the download process it will respond with the ready packet. For more info on how the traffic would look like if the client did not know the map see the map_download section.

If the server gets this packet it will print the following log line.
[6a25182c][server]: player is ready. ClientID=2 addr=[0:0:0:0:0:0:0:1]:57620
                
  08 01 01 07 ec ab 6c 40 01 02 1d
  ^  ^  ^  ^           ^        ^
  |  |  |  |       chunk header |
  |  |  | token                 |
  |  | num chunks 1          NETMSG_READY with system bit
  |  ack 1
  flags (TOKEN)
                
            

[SERVER->CLIENT] Motd, Connection Ready

Now the server sends the first packet with more than one message in the payload: Read more about chunk queueing and flushing in the fundamentals if you want to understand why one packet contains 2 messages.
                
  08 02 02 07 ec ab 6c 40 02 02 02 00 40 01 03 09
  ^  ^  ^  ^           ^        ^  ^  ^        ^
  |  |  | token        |        |  |  |      msg id 4 NETMSG_CON_READY
  |  |  |              |        |  |  |      together in one byte with the game/system bit flag
  |  |  |              |        |  |  |      which is set so this a system message
  |  | num chunks 2    |        |  |  |
  |  |                 |        |  |  start of the second message
  | ack 2              |        |  |
  |                    |        | the message field of the "message of the day" motd
 flags (CONTROL)       |        | which is just 0x00 because the current message of the day is unset
                       |        | so it just sends an empty string
            start of the first  |
                 message        msg id 1 SV_MOTD
                                together in one byte with the game/system bit flag
                                which is unset so it is a game message
                
            

[CLIENT->SERVER] Start info (skin data)

Now the client calls CGameClient::SendInfo() which sends all the needed infos to render a tee in the world: Name, Clan, Country, Skin name.

You can see in the ASCII output that this client is connecting with the name 0.6 dragon and with an empty clantag. You can also identify the skin name greensward.

                
  [PACKET HEADER]
  08 03 01 07 ec ab 6c
  ^  ^  ^  ^
  |  |  | token
  |  | num chunks 1
  | ack 3
  flags (CONTROL)

  [PACKET PAYLOAD HEX]                       [PACKET PAYLOAD ASCII]
  42 00 03 28 30 2e 36 20 64 72 61 67        B..(0.6 drag
  6f 6e 00 00 40 67 72 65 65 6e 73 77        on..@greensw
  61 72 64 00 00 80 fe 07 80 fe 07           ard........
                
            

[SERVER->CLIENT] Vote Clear, Tune Params, Ready To Enter

Now the server sends another bigger packet with 3 messages as payload. With "ready to enter" being the most essential to progress the connection. No readable ascii strings this time so below we only look at the raw hex data.
                
  [PACKET HEADER]
  08 03 03 07 ec ab 6c
  ^  ^  ^  ^
  |  |  | token
  |  | num chunks 1
  | ack 3
  |
  flags (TOKEN)

  [PACKET PAYLOAD]
  40 01 04 16 44 07 05 0c a8 0f 88 03 32
  a8 14 b0 12 b4 07 96 02 9f 01 b0 d1 04
  80 7d ac 04 9c 17 32 98 db 06 80 b5 18
  8c 02 bd 01 a0 ed 1a 88 03 bd 01 b8 c8
  21 90 01 14 bc 0a a0 9a 0c 88 03 80 e2
  09 98 ea 01 a4 01 00 b4 07 a4 01 a4 01
  40 01 06 10
                
            

[CLIENT->SERVER] Enter game

Now the client sends NETMSG_ENTERGAME (15) using CClient::SendEnterGame() Keep in mind those net message ids are packed and mixed with the system flag. So hex 0x1f will be unpacked to the integer 15.

If the server gets this packet it will print the following log line.
[6a25182c][server]: player has entered the game. ClientID=2 addr=[0:0:0:0:0:0:0:1]:57620

                
  08 06 01 07 ec ab 6c 40 01 04 1f
  ^  ^  ^  ^           ^        ^
  |  |  | token     chunk header|
  |  |num chunks 1              |
  |ack 6                        |
  |                         message id 15
 flags (CONTROL)            together with the game/system bit
                            (0x1f >> 1 == 15)