(svn r1389) -Add: [Network] Added packet protection. No longer a client or server
authortruelight
Wed, 05 Jan 2005 14:39:48 +0000
changeset 903 f860c7234167
parent 902 df8c96ee70d5
child 904 bff808a1c7f0
(svn r1389) -Add: [Network] Added packet protection. No longer a client or server
reads beyond the size of the packet
-Fix: [Network] A server no longer crashes when a client sends an
invalid DoCommand, but drops the client instead.
command.c
command.h
network.c
network_client.c
network_data.c
network_data.h
network_server.c
network_udp.c
--- a/command.c	Wed Jan 05 14:20:23 2005 +0000
+++ b/command.c	Wed Jan 05 14:39:48 2005 +0000
@@ -312,6 +312,17 @@
 	CmdReplaceVehicle,							/* 114 */
 };
 
+/* This function range-checks a cmd, and checks if the cmd is not NULL */
+bool IsValidCommand(int cmd)
+{
+	cmd = cmd & 0xFF;
+
+	if (cmd < 0 || cmd >= lengthof(_command_proc_table) || _command_proc_table[cmd] == NULL)
+		return false;
+
+	return true;
+}
+
 int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
 {
 	return DoCommand(GET_TILE_X(tile)*16, GET_TILE_Y(tile)*16, p1, p2, flags, procc);
--- a/command.h	Wed Jan 05 14:20:23 2005 +0000
+++ b/command.h	Wed Jan 05 14:39:48 2005 +0000
@@ -182,6 +182,7 @@
 int32 DoCommand(int x, int y, uint32 p1, uint32 p2, uint32 flags, uint procc);
 int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
 
+bool IsValidCommand(int cmd);
 int32 GetAvailableMoneyForCommand();
 
 #endif /* COMMAND_H */
--- a/network.c	Wed Jan 05 14:20:23 2005 +0000
+++ b/network.c	Wed Jan 05 14:39:48 2005 +0000
@@ -482,7 +482,10 @@
 {
 	NetworkClientInfo *ci;
 	// Socket is already dead
-	if (cs->socket == INVALID_SOCKET) return;
+	if (cs->socket == INVALID_SOCKET) {
+		cs->quited = true;
+		return;
+	}
 
 	DEBUG(net, 1) ("[NET] Closed client connection");
 
@@ -509,6 +512,7 @@
 
 	closesocket(cs->socket);
 	cs->writable = false;
+	cs->quited = true;
 
 	// Free all pending and partially received packets
 	while (cs->packet_queue != NULL) {
--- a/network_client.c	Wed Jan 05 14:20:23 2005 +0000
+++ b/network_client.c	Wed Jan 05 14:39:48 2005 +0000
@@ -22,7 +22,7 @@
 
 static uint32 last_ack_frame;
 
-void NetworkRecvPatchSettings(Packet *p);
+void NetworkRecvPatchSettings(NetworkClientState *cs, Packet *p);
 
 // **********
 // Sending functions
@@ -277,36 +277,36 @@
 	byte company_info_version;
 	int i;
 
-	company_info_version = NetworkRecv_uint8(p);
+	company_info_version = NetworkRecv_uint8(MY_CLIENT, p);
 
-	if (company_info_version == 1) {
+	if (!MY_CLIENT->quited && company_info_version == 1) {
 		byte total;
 		byte current;
 
-		total = NetworkRecv_uint8(p);
+		total = NetworkRecv_uint8(MY_CLIENT, p);
 
 		// There is no data at all..
 		if (total == 0)
 			return NETWORK_RECV_STATUS_CLOSE_QUERY;
 
-		current = NetworkRecv_uint8(p);
+		current = NetworkRecv_uint8(MY_CLIENT, p);
 		if (current >= MAX_PLAYERS)
 			return NETWORK_RECV_STATUS_CLOSE_QUERY;
 
 		_network_lobby_company_count++;
 
-		NetworkRecv_string(p, _network_player_info[current].company_name, sizeof(_network_player_info[current].company_name));
-		_network_player_info[current].inaugurated_year = NetworkRecv_uint8(p);
-		_network_player_info[current].company_value = NetworkRecv_uint64(p);
-		_network_player_info[current].money = NetworkRecv_uint64(p);
-		_network_player_info[current].income = NetworkRecv_uint64(p);
-		_network_player_info[current].performance = NetworkRecv_uint16(p);
+		NetworkRecv_string(MY_CLIENT, p, _network_player_info[current].company_name, sizeof(_network_player_info[current].company_name));
+		_network_player_info[current].inaugurated_year = NetworkRecv_uint8(MY_CLIENT, p);
+		_network_player_info[current].company_value = NetworkRecv_uint64(MY_CLIENT, p);
+		_network_player_info[current].money = NetworkRecv_uint64(MY_CLIENT, p);
+		_network_player_info[current].income = NetworkRecv_uint64(MY_CLIENT, p);
+		_network_player_info[current].performance = NetworkRecv_uint16(MY_CLIENT, p);
 		for (i = 0; i < NETWORK_VEHICLE_TYPES; i++)
-			_network_player_info[current].num_vehicle[i] = NetworkRecv_uint16(p);
+			_network_player_info[current].num_vehicle[i] = NetworkRecv_uint16(MY_CLIENT, p);
 		for (i = 0; i < NETWORK_STATION_TYPES; i++)
-			_network_player_info[current].num_station[i] = NetworkRecv_uint16(p);
+			_network_player_info[current].num_station[i] = NetworkRecv_uint16(MY_CLIENT, p);
 
-		NetworkRecv_string(p, _network_player_info[current].players, sizeof(_network_player_info[current].players));
+		NetworkRecv_string(MY_CLIENT, p, _network_player_info[current].players, sizeof(_network_player_info[current].players));
 
 		InvalidateWindow(WC_NETWORK_WINDOW, 0);
 
@@ -322,13 +322,16 @@
 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO)
 {
 	NetworkClientInfo *ci;
-	uint16 index = NetworkRecv_uint16(p);
-	byte playas = NetworkRecv_uint8(p);
+	uint16 index = NetworkRecv_uint16(MY_CLIENT, p);
+	byte playas = NetworkRecv_uint8(MY_CLIENT, p);
 	char name[NETWORK_NAME_LENGTH];
 	char unique_id[NETWORK_NAME_LENGTH];
 
-	NetworkRecv_string(p, name, sizeof(name));
-	NetworkRecv_string(p, unique_id, sizeof(unique_id));
+	NetworkRecv_string(MY_CLIENT, p, name, sizeof(name));
+	NetworkRecv_string(MY_CLIENT, p, unique_id, sizeof(unique_id));
+
+	if (MY_CLIENT->quited)
+		return NETWORK_RECV_STATUS_CONN_LOST;
 
 	/* Do we receive a change of data? Most likely we changed playas */
 	if (index == _network_own_client_index)
@@ -372,7 +375,7 @@
 
 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR)
 {
-	NetworkErrorCode error = NetworkRecv_uint8(p);
+	NetworkErrorCode error = NetworkRecv_uint8(MY_CLIENT, p);
 
 	if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED ||
 			error == NETWORK_ERROR_PLAYER_MISMATCH) {
@@ -398,7 +401,7 @@
 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD)
 {
 	NetworkPasswordType type;
-	type = NetworkRecv_uint8(p);
+	type = NetworkRecv_uint8(MY_CLIENT, p);
 
 	if (type == NETWORK_GAME_PASSWORD) {
 		ShowNetworkNeedGamePassword();
@@ -413,7 +416,7 @@
 
 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WELCOME)
 {
-	_network_own_client_index = NetworkRecv_uint16(p);
+	_network_own_client_index = NetworkRecv_uint16(MY_CLIENT, p);
 
 	// Start receiving the map
 	SEND_COMMAND(PACKET_CLIENT_GETMAP)();
@@ -423,7 +426,7 @@
 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WAIT)
 {
 	_network_join_status = NETWORK_JOIN_STATUS_WAITING;
-	_network_join_waiting = NetworkRecv_uint8(p);
+	_network_join_waiting = NetworkRecv_uint8(MY_CLIENT, p);
 	InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
 
 	// We are put on hold for receiving the map.. we need GUI for this ;)
@@ -440,7 +443,10 @@
 
 	byte maptype;
 
-	maptype = NetworkRecv_uint8(p);
+	maptype = NetworkRecv_uint8(MY_CLIENT, p);
+
+	if (MY_CLIENT->quited)
+		return NETWORK_RECV_STATUS_CONN_LOST;
 
 	// First packet, init some stuff
 	if (maptype == MAP_PACKET_START) {
@@ -453,11 +459,11 @@
 			return NETWORK_RECV_STATUS_SAVEGAME;
 		}
 
-		_frame_counter = _frame_counter_server = _frame_counter_max = NetworkRecv_uint32(p);
+		_frame_counter = _frame_counter_server = _frame_counter_max = NetworkRecv_uint32(MY_CLIENT, p);
 
 		_network_join_status = NETWORK_JOIN_STATUS_DOWNLOADING;
 		_network_join_kbytes = 0;
-		_network_join_kbytes_total = NetworkRecv_uint32(p) / 1024;
+		_network_join_kbytes_total = NetworkRecv_uint32(MY_CLIENT, p) / 1024;
 		InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
 
 		// The first packet does not contain any more data
@@ -473,7 +479,7 @@
 	}
 
 	if (maptype == MAP_PACKET_PATCH) {
-		NetworkRecvPatchSettings(p);
+		NetworkRecvPatchSettings(MY_CLIENT, p);
 	}
 
 	// Check if this was the last packet
@@ -481,8 +487,8 @@
 		// We also get, very nice, the player_seeds in this packet
 		int i;
 		for (i = 0; i < MAX_PLAYERS; i++) {
-			_player_seeds[i][0] = NetworkRecv_uint32(p);
-			_player_seeds[i][1] = NetworkRecv_uint32(p);
+			_player_seeds[i][0] = NetworkRecv_uint32(MY_CLIENT, p);
+			_player_seeds[i][1] = NetworkRecv_uint32(MY_CLIENT, p);
 		}
 
 		fclose(file_pointer);
@@ -527,16 +533,16 @@
 
 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FRAME)
 {
-	_frame_counter_server = NetworkRecv_uint32(p);
-	_frame_counter_max = NetworkRecv_uint32(p);
+	_frame_counter_server = NetworkRecv_uint32(MY_CLIENT, p);
+	_frame_counter_max = NetworkRecv_uint32(MY_CLIENT, p);
 #ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
 	// Test if the server supports this option
 	//  and if we are at the frame the server is
 	if (p->pos < p->size) {
 		_sync_frame = _frame_counter_server;
-		_sync_seed_1 = NetworkRecv_uint32(p);
+		_sync_seed_1 = NetworkRecv_uint32(MY_CLIENT, p);
 #ifdef NETWORK_SEND_DOUBLE_SEED
-		_sync_seed_2 = NetworkRecv_uint32(p);
+		_sync_seed_2 = NetworkRecv_uint32(MY_CLIENT, p);
 #endif
 	}
 #endif
@@ -555,10 +561,10 @@
 
 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_SYNC)
 {
-	_sync_frame = NetworkRecv_uint32(p);
-	_sync_seed_1 = NetworkRecv_uint32(p);
+	_sync_frame = NetworkRecv_uint32(MY_CLIENT, p);
+	_sync_seed_1 = NetworkRecv_uint32(MY_CLIENT, p);
 #ifdef NETWORK_SEND_DOUBLE_SEED
-	_sync_seed_2 = NetworkRecv_uint32(p);
+	_sync_seed_2 = NetworkRecv_uint32(MY_CLIENT, p);
 #endif
 
 	return NETWORK_RECV_STATUS_OKAY;
@@ -569,21 +575,21 @@
 	int i;
 	char *dparam_char;
 	CommandPacket *cp = malloc(sizeof(CommandPacket));
-	cp->player = NetworkRecv_uint8(p);
-	cp->cmd = NetworkRecv_uint32(p);
-	cp->p1 = NetworkRecv_uint32(p);
-	cp->p2 = NetworkRecv_uint32(p);
-	cp->tile = NetworkRecv_uint32(p);
+	cp->player = NetworkRecv_uint8(MY_CLIENT, p);
+	cp->cmd = NetworkRecv_uint32(MY_CLIENT, p);
+	cp->p1 = NetworkRecv_uint32(MY_CLIENT, p);
+	cp->p2 = NetworkRecv_uint32(MY_CLIENT, p);
+	cp->tile = NetworkRecv_uint32(MY_CLIENT, p);
 	/* We are going to send them byte by byte, because dparam is misused
 	    for chars (if it is used), and else we have a BigEndian / LittleEndian
 	    problem.. we should fix the misuse of dparam... -- TrueLight */
 	dparam_char = (char *)&cp->dp[0];
 	for (i = 0; i < lengthof(cp->dp) * 4; i++) {
-		*dparam_char = NetworkRecv_uint8(p);
+		*dparam_char = NetworkRecv_uint8(MY_CLIENT, p);
 		dparam_char++;
 	}
-	cp->callback = NetworkRecv_uint8(p);
-	cp->frame = NetworkRecv_uint32(p);
+	cp->callback = NetworkRecv_uint8(MY_CLIENT, p);
+	cp->frame = NetworkRecv_uint32(MY_CLIENT, p);
 	cp->next = NULL;
 
 	// The server did send us this command..
@@ -603,16 +609,16 @@
 
 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CHAT)
 {
-	NetworkAction action = NetworkRecv_uint8(p);
+	NetworkAction action = NetworkRecv_uint8(MY_CLIENT, p);
 	char msg[MAX_TEXT_MSG_LEN];
 	NetworkClientInfo *ci = NULL, *ci_to;
 	uint16 index;
 	char name[NETWORK_NAME_LENGTH];
 	bool self_send;
 
-	index = NetworkRecv_uint16(p);
-	self_send = NetworkRecv_uint8(p);
-	NetworkRecv_string(p, msg, MAX_TEXT_MSG_LEN);
+	index = NetworkRecv_uint16(MY_CLIENT, p);
+	self_send = NetworkRecv_uint8(MY_CLIENT, p);
+	NetworkRecv_string(MY_CLIENT, p, msg, MAX_TEXT_MSG_LEN);
 
 	ci_to = NetworkFindClientInfoFromIndex(index);
 	if (ci_to == NULL) return NETWORK_RECV_STATUS_OKAY;
@@ -656,8 +662,8 @@
 	uint16 index;
 	NetworkClientInfo *ci;
 
-	index = NetworkRecv_uint16(p);
-	errorno = NetworkRecv_uint8(p);
+	index = NetworkRecv_uint16(MY_CLIENT, p);
+	errorno = NetworkRecv_uint8(MY_CLIENT, p);
 
 	GetString(str, STR_NETWORK_ERR_CLIENT_GENERAL + errorno);
 
@@ -680,8 +686,8 @@
 	uint16 index;
 	NetworkClientInfo *ci;
 
-	index = NetworkRecv_uint16(p);
-	NetworkRecv_string(p, str, 100);
+	index = NetworkRecv_uint16(MY_CLIENT, p);
+	NetworkRecv_string(MY_CLIENT, p, str, 100);
 
 	ci = NetworkFindClientInfoFromIndex(index);
 	if (ci != NULL) {
@@ -704,7 +710,7 @@
 	uint16 index;
 	NetworkClientInfo *ci;
 
-	index = NetworkRecv_uint16(p);
+	index = NetworkRecv_uint16(MY_CLIENT, p);
 
 	ci = NetworkFindClientInfoFromIndex(index);
 	if (ci != NULL)
@@ -785,7 +791,7 @@
 // This is a TEMPORARY solution to get the patch-settings
 //  to the client. When the patch-settings are saved in the savegame
 //  this should be removed!!
-void NetworkRecvPatchSettings(Packet *p)
+void NetworkRecvPatchSettings(NetworkClientState *cs, Packet *p)
 {
 	const SettingDesc *item;
 
@@ -796,15 +802,15 @@
 			case SDT_BOOL:
 			case SDT_INT8:
 			case SDT_UINT8:
-				*(uint8 *)(item->ptr) = NetworkRecv_uint8(p);
+				*(uint8 *)(item->ptr) = NetworkRecv_uint8(cs, p);
 				break;
 			case SDT_INT16:
 			case SDT_UINT16:
-				*(uint16 *)(item->ptr) = NetworkRecv_uint16(p);
+				*(uint16 *)(item->ptr) = NetworkRecv_uint16(cs, p);
 				break;
 			case SDT_INT32:
 			case SDT_UINT32:
-				*(uint32 *)(item->ptr) = NetworkRecv_uint32(p);
+				*(uint32 *)(item->ptr) = NetworkRecv_uint32(cs, p);
 				break;
 		}
 		item++;
@@ -829,8 +835,8 @@
 	NetworkRecvStatus res = NETWORK_RECV_STATUS_OKAY;
 
 	while (res == NETWORK_RECV_STATUS_OKAY && (p = NetworkRecv_Packet(cs, &res)) != NULL) {
-		byte type = NetworkRecv_uint8(p);
-		if (type < PACKET_END && _network_client_packet[type] != NULL) {
+		byte type = NetworkRecv_uint8(MY_CLIENT, p);
+		if (type < PACKET_END && _network_client_packet[type] != NULL && !MY_CLIENT->quited) {
 			res = _network_client_packet[type](p);
 		}	else {
 			res = NETWORK_RECV_STATUS_MALFORMED_PACKET;
--- a/network_data.c	Wed Jan 05 14:20:23 2005 +0000
+++ b/network_data.c	Wed Jan 05 14:39:48 2005 +0000
@@ -183,22 +183,54 @@
 // Receiving commands
 // Again, the next couple of functions are endian-safe
 //  see the comment around NetworkSend_uint8 for more info.
-uint8 NetworkRecv_uint8(Packet *packet)
+uint8 NetworkRecv_uint8(NetworkClientState *cs, Packet *packet)
 {
+	/* Don't allow reading from a closed socket */
+	if (cs->quited)
+		return 0;
+
+	/* Check if variable is within packet-size */
+	if (packet->pos + 1 > packet->size) {
+		CloseConnection(cs);
+		return 0;
+	}
+
 	return packet->buffer[packet->pos++];
 }
 
-uint16 NetworkRecv_uint16(Packet *packet)
+uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet)
 {
 	uint16 n;
+
+	/* Don't allow reading from a closed socket */
+	if (cs->quited)
+		return 0;
+
+	/* Check if variable is within packet-size */
+	if (packet->pos + 2 > packet->size) {
+		CloseConnection(cs);
+		return 0;
+	}
+
 	n  = (uint16)packet->buffer[packet->pos++];
 	n += (uint16)packet->buffer[packet->pos++] << 8;
 	return n;
 }
 
-uint32 NetworkRecv_uint32(Packet *packet)
+uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet)
 {
 	uint32 n;
+
+	/* Don't allow reading from a closed socket */
+	if (cs->quited)
+		return 0;
+
+	/* Check if variable is within packet-size */
+	if (packet->pos + 4 > packet->size) {
+		CloseConnection(cs);
+		return 0;
+	}
+
 	n  = (uint32)packet->buffer[packet->pos++];
 	n += (uint32)packet->buffer[packet->pos++] << 8;
 	n += (uint32)packet->buffer[packet->pos++] << 16;
@@ -206,9 +238,20 @@
 	return n;
 }
 
-uint64 NetworkRecv_uint64(Packet *packet)
+uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet)
 {
 	uint64 n;
+
+	/* Don't allow reading from a closed socket */
+	if (cs->quited)
+		return 0;
+
+	/* Check if variable is within packet-size */
+	if (packet->pos + 8 > packet->size) {
+		CloseConnection(cs);
+		return 0;
+	}
+
 	n  = (uint64)packet->buffer[packet->pos++];
 	n += (uint64)packet->buffer[packet->pos++] << 8;
 	n += (uint64)packet->buffer[packet->pos++] << 16;
@@ -221,9 +264,14 @@
 }
 
 // Reads a string till it finds a '\0' in the stream
-void NetworkRecv_string(Packet *p, char* buffer, size_t size)
+void NetworkRecv_string(NetworkClientState *cs, Packet *p, char* buffer, size_t size)
 {
 	int pos;
+
+	/* Don't allow reading from a closed socket */
+	if (cs->quited)
+		return;
+
 	pos = p->pos;
 	while (--size > 0 && pos < p->size && (*buffer++ = p->buffer[pos++]) != '\0') {}
 	if (size == 0 || pos == p->size)
--- a/network_data.h	Wed Jan 05 14:20:23 2005 +0000
+++ b/network_data.h	Wed Jan 05 14:39:48 2005 +0000
@@ -203,11 +203,11 @@
 void NetworkSend_string(Packet *packet, const char* data);
 void NetworkSend_Packet(Packet *packet, NetworkClientState *cs);
 
-uint8 NetworkRecv_uint8(Packet *packet);
-uint16 NetworkRecv_uint16(Packet *packet);
-uint32 NetworkRecv_uint32(Packet *packet);
-uint64 NetworkRecv_uint64(Packet *packet);
-void NetworkRecv_string(Packet *packet, char* buffer, size_t size);
+uint8 NetworkRecv_uint8(NetworkClientState *cs, Packet *packet);
+uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet);
+uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet);
+uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet);
+void NetworkRecv_string(NetworkClientState *cs, Packet *packet, char* buffer, size_t size);
 Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status);
 
 bool NetworkSend_Packets(NetworkClientState *cs);
--- a/network_server.c	Wed Jan 05 14:20:23 2005 +0000
+++ b/network_server.c	Wed Jan 05 14:39:48 2005 +0000
@@ -580,7 +580,7 @@
 	char client_revision[NETWORK_REVISION_LENGTH];
 
 
-	NetworkRecv_string(p, client_revision, sizeof(client_revision));
+	NetworkRecv_string(cs, p, client_revision, sizeof(client_revision));
 
 #if defined(WITH_REV) || defined(WITH_REV_HACK)
 	// Check if the client has revision control enabled
@@ -594,10 +594,13 @@
 	}
 #endif
 
-	NetworkRecv_string(p, name, sizeof(name));
-	playas = NetworkRecv_uint8(p);
-	client_lang = NetworkRecv_uint8(p);
-	NetworkRecv_string(p, unique_id, sizeof(unique_id));
+	NetworkRecv_string(cs, p, name, sizeof(name));
+	playas = NetworkRecv_uint8(cs, p);
+	client_lang = NetworkRecv_uint8(cs, p);
+	NetworkRecv_string(cs, p, unique_id, sizeof(unique_id));
+
+	if (cs->quited)
+		return;
 
 	// Check if someone else already has that name
 	snprintf(test_name, sizeof(test_name), "%s", name);
@@ -644,8 +647,8 @@
 	char password[NETWORK_PASSWORD_LENGTH];
 	NetworkClientInfo *ci;
 
-	type = NetworkRecv_uint8(p);
-	NetworkRecv_string(p, password, sizeof(password));
+	type = NetworkRecv_uint8(cs, p);
+	NetworkRecv_string(cs, p, password, sizeof(password));
 
 	if (cs->status == STATUS_INACTIVE && type == NETWORK_GAME_PASSWORD) {
 		// Check game-password
@@ -761,21 +764,30 @@
 		return;
 	}
 
-	cp->player = NetworkRecv_uint8(p);
-	cp->cmd = NetworkRecv_uint32(p);
-	cp->p1 = NetworkRecv_uint32(p);
-	cp->p2 = NetworkRecv_uint32(p);
-	cp->tile = NetworkRecv_uint32(p);
+	cp->player = NetworkRecv_uint8(cs, p);
+	cp->cmd    = NetworkRecv_uint32(cs, p);
+	cp->p1     = NetworkRecv_uint32(cs, p);
+	cp->p2     = NetworkRecv_uint32(cs, p);
+	cp->tile   = NetworkRecv_uint32(cs, p);
 	/* We are going to send them byte by byte, because dparam is misused
 	    for chars (if it is used), and else we have a BigEndian / LittleEndian
 	    problem.. we should fix the misuse of dparam... -- TrueLight */
 	dparam_char = (char *)&cp->dp[0];
 	for (i = 0; i < lengthof(cp->dp) * 4; i++) {
-		*dparam_char = NetworkRecv_uint8(p);
+		*dparam_char = NetworkRecv_uint8(cs, p);
 		dparam_char++;
 	}
 
-	callback = NetworkRecv_uint8(p);
+	callback = NetworkRecv_uint8(cs, p);
+
+	if (cs->quited)
+		return;
+
+	/* Check if cp->cmd is valid */
+	if (!IsValidCommand(cp->cmd)) {
+		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
+		return;
+	}
 
 	ci = DEREF_CLIENT_INFO(cs);
 	// Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs
@@ -814,7 +826,7 @@
 	// The frame can be executed in the same frame as the next frame-packet
 	//  That frame just before that frame is saved in _frame_counter_max
 	cp->frame = _frame_counter_max + 1;
-	cp->next = NULL;
+	cp->next  = NULL;
 
 	// Queue the command for the clients (are send at the end of the frame
 	//   if they can handle it ;))
@@ -826,6 +838,7 @@
 				cp->callback = 0;
 			else
 				cp->callback = callback;
+
 			NetworkAddCommandQueue(new_cs, cp);
 		}
 	}
@@ -847,7 +860,7 @@
 	// This packets means a client noticed an error and is reporting this
 	//  to us. Display the error and report it to the other clients
 	NetworkClientState *new_cs;
-	byte errorno = NetworkRecv_uint8(p);
+	byte errorno = NetworkRecv_uint8(cs, p);
 	char str[100];
 	char client_name[NETWORK_CLIENT_NAME_LENGTH];
 
@@ -888,7 +901,7 @@
 		return;
 	}
 
-	NetworkRecv_string(p, str, 100);
+	NetworkRecv_string(cs, p, str, 100);
 
 	NetworkGetClientName(client_name, sizeof(client_name), cs);
 
@@ -906,7 +919,7 @@
 DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ACK)
 {
 	// The client received the frame, make note of it
-	cs->last_frame = NetworkRecv_uint32(p);
+	cs->last_frame = NetworkRecv_uint32(cs, p);
 	// With those 2 values we can calculate the lag realtime
 	cs->last_frame_server = _frame_counter;
 
@@ -1018,12 +1031,12 @@
 
 DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_CHAT)
 {
-	NetworkAction action = NetworkRecv_uint8(p);
-	DestType desttype = NetworkRecv_uint8(p);
-	int dest = NetworkRecv_uint8(p);
+	NetworkAction action = NetworkRecv_uint8(cs, p);
+	DestType desttype = NetworkRecv_uint8(cs, p);
+	int dest = NetworkRecv_uint8(cs, p);
 	char msg[MAX_TEXT_MSG_LEN];
 
-	NetworkRecv_string(p, msg, MAX_TEXT_MSG_LEN);
+	NetworkRecv_string(cs, p, msg, MAX_TEXT_MSG_LEN);
 
 	NetworkServer_HandleChat(action, desttype, dest, msg, cs->index);
 }
@@ -1033,7 +1046,7 @@
 	char password[NETWORK_PASSWORD_LENGTH];
 	NetworkClientInfo *ci;
 
-	NetworkRecv_string(p, password, sizeof(password));
+	NetworkRecv_string(cs, p, password, sizeof(password));
 	ci = DEREF_CLIENT_INFO(cs);
 
 	if (ci->client_playas <= MAX_PLAYERS) {
@@ -1046,9 +1059,12 @@
 	char client_name[NETWORK_CLIENT_NAME_LENGTH];
 	NetworkClientInfo *ci;
 
-	NetworkRecv_string(p, client_name, sizeof(client_name));
+	NetworkRecv_string(cs, p, client_name, sizeof(client_name));
 	ci = DEREF_CLIENT_INFO(cs);
 
+	if (cs->quited)
+		return;
+
 	if (ci != NULL) {
 		// Display change
 		if (NetworkFindName(client_name)) {
@@ -1388,8 +1404,8 @@
 	Packet *p;
 	NetworkRecvStatus res;
 	while((p = NetworkRecv_Packet(cs, &res)) != NULL) {
-		byte type = NetworkRecv_uint8(p);
-		if (type < PACKET_END && _network_server_packet[type] != NULL)
+		byte type = NetworkRecv_uint8(cs, p);
+		if (type < PACKET_END && _network_server_packet[type] != NULL && !cs->quited)
 			_network_server_packet[type](cs, p);
 		else
 			DEBUG(net, 0)("[NET][Server] Received invalid packet type %d", type);
--- a/network_udp.c	Wed Jan 05 14:20:23 2005 +0000
+++ b/network_udp.c	Wed Jan 05 14:39:48 2005 +0000
@@ -38,6 +38,8 @@
 #define DEF_UDP_RECEIVE_COMMAND(type) void NetworkPacketReceive_ ## type ## _command(Packet *p, struct sockaddr_in *client_addr)
 void NetworkSendUDP_Packet(SOCKET udp, Packet *p, struct sockaddr_in *recv);
 
+NetworkClientState _udp_cs;
+
 DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER)
 {
 	Packet *packet;
@@ -86,8 +88,10 @@
 	if (_network_udp_server)
 		return;
 
-	game_info_version = NetworkRecv_uint8(p);
+	game_info_version = NetworkRecv_uint8(&_udp_cs, p);
 
+	if (_udp_cs.quited)
+		return;
 
 	DEBUG(net, 6)("[NET][UDP] Server response from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port));
 
@@ -95,20 +99,20 @@
 	item = NetworkGameListAddItem(inet_addr(inet_ntoa(client_addr->sin_addr)), ntohs(client_addr->sin_port));
 
 	if (game_info_version == 1) {
-		NetworkRecv_string(p, item->info.server_name, sizeof(item->info.server_name));
-		NetworkRecv_string(p, item->info.server_revision, sizeof(item->info.server_revision));
-		item->info.server_lang = NetworkRecv_uint8(p);
-		item->info.use_password = NetworkRecv_uint8(p);
-		item->info.clients_max = NetworkRecv_uint8(p);
-		item->info.clients_on = NetworkRecv_uint8(p);
-		item->info.spectators_on = NetworkRecv_uint8(p);
-		item->info.game_date = NetworkRecv_uint16(p);
-		item->info.start_date = NetworkRecv_uint16(p);
-		NetworkRecv_string(p, item->info.map_name, sizeof(item->info.map_name));
-		item->info.map_width = NetworkRecv_uint16(p);
-		item->info.map_height = NetworkRecv_uint16(p);
-		item->info.map_set = NetworkRecv_uint8(p);
-		item->info.dedicated = NetworkRecv_uint8(p);
+		NetworkRecv_string(&_udp_cs, p, item->info.server_name, sizeof(item->info.server_name));
+		NetworkRecv_string(&_udp_cs, p, item->info.server_revision, sizeof(item->info.server_revision));
+		item->info.server_lang   = NetworkRecv_uint8(&_udp_cs, p);
+		item->info.use_password  = NetworkRecv_uint8(&_udp_cs, p);
+		item->info.clients_max   = NetworkRecv_uint8(&_udp_cs, p);
+		item->info.clients_on    = NetworkRecv_uint8(&_udp_cs, p);
+		item->info.spectators_on = NetworkRecv_uint8(&_udp_cs, p);
+		item->info.game_date     = NetworkRecv_uint16(&_udp_cs, p);
+		item->info.start_date    = NetworkRecv_uint16(&_udp_cs, p);
+		NetworkRecv_string(&_udp_cs, p, item->info.map_name, sizeof(item->info.map_name));
+		item->info.map_width     = NetworkRecv_uint16(&_udp_cs, p);
+		item->info.map_height    = NetworkRecv_uint16(&_udp_cs, p);
+		item->info.map_set       = NetworkRecv_uint8(&_udp_cs, p);
+		item->info.dedicated     = NetworkRecv_uint8(&_udp_cs, p);
 
 		if (item->info.hostname[0] == '\0')
 			snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr));
@@ -237,12 +241,15 @@
 	 * an uint32 (ip) and an uint16 (port) for each pair
 	 */
 
-	ver = NetworkRecv_uint8(p);
+	ver = NetworkRecv_uint8(&_udp_cs, p);
+
+	if (_udp_cs.quited)
+		return;
 
 	if (ver == 1) {
-		for (i = NetworkRecv_uint16(p); i != 0 ; i--) {
-			ip.s_addr = TO_LE32(NetworkRecv_uint32(p));
-			port = NetworkRecv_uint16(p);
+		for (i = NetworkRecv_uint16(&_udp_cs, p); i != 0 ; i--) {
+			ip.s_addr = TO_LE32(NetworkRecv_uint32(&_udp_cs, p));
+			port = NetworkRecv_uint16(&_udp_cs, p);
 			NetworkUDPQueryServer(inet_ntoa(ip), port);
 		}
 	}
@@ -282,9 +289,13 @@
 {
 	byte type;
 
-	type = NetworkRecv_uint8(p);
+	/* Fake a client, so we can see when there is an illegal packet */
+	_udp_cs.socket = INVALID_SOCKET;
+	_udp_cs.quited = false;
 
-	if (type < PACKET_UDP_END && _network_udp_packet[type] != NULL) {
+	type = NetworkRecv_uint8(&_udp_cs, p);
+
+	if (type < PACKET_UDP_END && _network_udp_packet[type] != NULL && !_udp_cs.quited) {
 		_network_udp_packet[type](p, client_addr);
 	}	else {
 		DEBUG(net, 0)("[NET][UDP] Received invalid packet type %d", type);