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- official teeworlds 0.6.4 and older has no security tokens at all
- official teeworlds 0.6.5 introduced security tokens in the packet header in a backwards compatible way using a token flag
- community fork ddnet based on older teeworlds 0.6 introduced own security tokens at the very end of the packet after the payload
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:- NETMSGTYPE_SV_MOTD - the message of the day
- NETMSG_CON_READY - telling the client he can send his startinfo
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.- NETMSGTYPE_SV_VOTECLEAROPTIONS - tell the client to reset the vote menu
- NETMSGTYPE_SV_TUNEPARAMS - sends the current servers gameplay affecting tunes
- NETMSGTYPE_SV_READYTOENTER - telling the client he can join the game (spawn a tee)
[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 sendsNETMSG_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)