teeworlds/teeworlds — pull request #986 by heinrich5991 (2012-07-27 18:20:01+00:00)
Title: Added tokens to the network and refactored master server code (please don't merge yet)

Summary
-------

Prevents ip spoofing of (hopefully) any kind:
* master server attack (see mailinglist)
* server flood attack
* session hijacking
* faking server info

Protocol change
---------------

The new network protocol header looks as follows:

packet header: 11 bytes (15 bytes for connless)
unsigned char padding[3]; // 24bit extra (must be 0x000000) to ensure compatiblity with the 0.5/0.6 protocol
unsigned char version; // 8bit version (must be 0x01)
unsigned char token[4]; // 32bit token (0xffffffff means none)
unsigned char flags_ack; // 4bit flags, 4bit ack (0xff for connless packets)
unsigned char ack; // 8bit ack (0xff for connless packets)
unsigned char num_chunks; // 8bit chunks (0xff for connless packets)

(unsigned char response_token[4];) // 32bit response token (only in case it's a connless packet)

Old packet header:

legacy packet header: 3 bytes (6 bytes for connless)
unsigned char flags_ack; // 4bit flags, 4bit ack
unsigned char ack; // 8bit ack
unsigned char num_chunks; // 8bit chunks

(unsigned char padding[3];) // 24bit extra incase it's a connection less packet
// this is to make sure that it's compatible with the
// old protocol

Connection set up
-----------------
1. `CNetClient::Connect` is called
This generates a client-side token which is only used for this connection.
Then it sends a `NET_CTRLMSG_TOKEN` with its own token to the server in order to request a connection token.
2. The server receives a `NET_CTRLMSG_TOKEN`
It uses `CNetTokenManager` to a create server-side connection token based on a salt which is changed every ten seconds and the client address.
Then it sends this token with a `NET_CTRLMSG_TOKEN` message (which also includes the client connection token for authentication) to the client.
3. The client receives a valid `NET_CTRLMSG_TOKEN` with the server connection token and its own token. Because it gets the own token back, the client knows that no one spoofed the `NET_CTRLMSG_TOKEN` packet.
It then proceeds in the normal connection process, sending the `NET_CTRLMSG_CONNECT` with both tokens and further packets with the own token, to verify that no one spoofed a client packet (might particulary be important for rcon commands).
4. The server can reconstruct the token it sent to the client, so it can verify the client. Since the seed changes every 10 seconds, the server compares the token it gets from the client with both the tokens generated from the current and the last seed.

Connless packet
---------------
1. `CNet*::Send` is called with an connless packet (NETSENDFLAG_CONNLESS).
The Net* calls its `CNetTokenCache` which stores the packet and sends a token request (`NET_CTRLMSG_TOKEN`) to the server.
2. The server receives the token requests, and uses `CTokenManager` to create a IP-specific token, which it sends back to the client.
3. The client receives the token from the server, now `CTokenCache` sends the stored packet with the token to the server.
4. The server receives a connless packet with a token, now knowing that it comes from an IP which isn't spoofed.

Stateless packet
----------------
`CNet*::Send` is called with an stateless packet (NETSENDFLAG_CONNLESS|NETSENDFLAG_STATELESS). It just sends the packet, this behaves like the old connless packets.

Please do not merge yet
-----------------------

However please do not merge this yet, as there are still some things missing:
* mastersrv support for 0.6 and 0.5
* versionsrv support

See also #915.

Posted this to get some suggestions.