(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.
pull/155/head
truelight 20 years ago
parent 9545f8c19c
commit 503ccc81c9

@ -312,6 +312,17 @@ static CommandProc * const _command_proc_table[] = {
CmdReplaceVehicle, /* 114 */ 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) 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); return DoCommand(GET_TILE_X(tile)*16, GET_TILE_Y(tile)*16, p1, p2, flags, procc);

@ -182,6 +182,7 @@ enum {
int32 DoCommand(int x, int y, uint32 p1, uint32 p2, uint32 flags, uint procc); 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); int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
bool IsValidCommand(int cmd);
int32 GetAvailableMoneyForCommand(); int32 GetAvailableMoneyForCommand();
#endif /* COMMAND_H */ #endif /* COMMAND_H */

@ -482,7 +482,10 @@ void NetworkCloseClient(NetworkClientState *cs)
{ {
NetworkClientInfo *ci; NetworkClientInfo *ci;
// Socket is already dead // 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"); DEBUG(net, 1) ("[NET] Closed client connection");
@ -509,6 +512,7 @@ void NetworkCloseClient(NetworkClientState *cs)
closesocket(cs->socket); closesocket(cs->socket);
cs->writable = false; cs->writable = false;
cs->quited = true;
// Free all pending and partially received packets // Free all pending and partially received packets
while (cs->packet_queue != NULL) { while (cs->packet_queue != NULL) {

@ -22,7 +22,7 @@ extern const char _openttd_revision[];
static uint32 last_ack_frame; static uint32 last_ack_frame;
void NetworkRecvPatchSettings(Packet *p); void NetworkRecvPatchSettings(NetworkClientState *cs, Packet *p);
// ********** // **********
// Sending functions // Sending functions
@ -277,36 +277,36 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMPANY_INFO)
byte company_info_version; byte company_info_version;
int i; 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 total;
byte current; byte current;
total = NetworkRecv_uint8(p); total = NetworkRecv_uint8(MY_CLIENT, p);
// There is no data at all.. // There is no data at all..
if (total == 0) if (total == 0)
return NETWORK_RECV_STATUS_CLOSE_QUERY; return NETWORK_RECV_STATUS_CLOSE_QUERY;
current = NetworkRecv_uint8(p); current = NetworkRecv_uint8(MY_CLIENT, p);
if (current >= MAX_PLAYERS) if (current >= MAX_PLAYERS)
return NETWORK_RECV_STATUS_CLOSE_QUERY; return NETWORK_RECV_STATUS_CLOSE_QUERY;
_network_lobby_company_count++; _network_lobby_company_count++;
NetworkRecv_string(p, _network_player_info[current].company_name, sizeof(_network_player_info[current].company_name)); 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(p); _network_player_info[current].inaugurated_year = NetworkRecv_uint8(MY_CLIENT, p);
_network_player_info[current].company_value = NetworkRecv_uint64(p); _network_player_info[current].company_value = NetworkRecv_uint64(MY_CLIENT, p);
_network_player_info[current].money = NetworkRecv_uint64(p); _network_player_info[current].money = NetworkRecv_uint64(MY_CLIENT, p);
_network_player_info[current].income = NetworkRecv_uint64(p); _network_player_info[current].income = NetworkRecv_uint64(MY_CLIENT, p);
_network_player_info[current].performance = NetworkRecv_uint16(p); _network_player_info[current].performance = NetworkRecv_uint16(MY_CLIENT, p);
for (i = 0; i < NETWORK_VEHICLE_TYPES; i++) 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++) 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); InvalidateWindow(WC_NETWORK_WINDOW, 0);
@ -322,13 +322,16 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMPANY_INFO)
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO) DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO)
{ {
NetworkClientInfo *ci; NetworkClientInfo *ci;
uint16 index = NetworkRecv_uint16(p); uint16 index = NetworkRecv_uint16(MY_CLIENT, p);
byte playas = NetworkRecv_uint8(p); byte playas = NetworkRecv_uint8(MY_CLIENT, p);
char name[NETWORK_NAME_LENGTH]; char name[NETWORK_NAME_LENGTH];
char unique_id[NETWORK_NAME_LENGTH]; char unique_id[NETWORK_NAME_LENGTH];
NetworkRecv_string(p, name, sizeof(name)); NetworkRecv_string(MY_CLIENT, p, name, sizeof(name));
NetworkRecv_string(p, unique_id, sizeof(unique_id)); 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 */ /* Do we receive a change of data? Most likely we changed playas */
if (index == _network_own_client_index) if (index == _network_own_client_index)
@ -372,7 +375,7 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO)
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR) 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 || if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED ||
error == NETWORK_ERROR_PLAYER_MISMATCH) { error == NETWORK_ERROR_PLAYER_MISMATCH) {
@ -398,7 +401,7 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR)
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD) DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD)
{ {
NetworkPasswordType type; NetworkPasswordType type;
type = NetworkRecv_uint8(p); type = NetworkRecv_uint8(MY_CLIENT, p);
if (type == NETWORK_GAME_PASSWORD) { if (type == NETWORK_GAME_PASSWORD) {
ShowNetworkNeedGamePassword(); ShowNetworkNeedGamePassword();
@ -413,7 +416,7 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD)
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WELCOME) 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 // Start receiving the map
SEND_COMMAND(PACKET_CLIENT_GETMAP)(); SEND_COMMAND(PACKET_CLIENT_GETMAP)();
@ -423,7 +426,7 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WELCOME)
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WAIT) DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WAIT)
{ {
_network_join_status = NETWORK_JOIN_STATUS_WAITING; _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); InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
// We are put on hold for receiving the map.. we need GUI for this ;) // We are put on hold for receiving the map.. we need GUI for this ;)
@ -440,7 +443,10 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP)
byte maptype; 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 // First packet, init some stuff
if (maptype == MAP_PACKET_START) { if (maptype == MAP_PACKET_START) {
@ -453,11 +459,11 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP)
return NETWORK_RECV_STATUS_SAVEGAME; 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_status = NETWORK_JOIN_STATUS_DOWNLOADING;
_network_join_kbytes = 0; _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); InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
// The first packet does not contain any more data // The first packet does not contain any more data
@ -473,7 +479,7 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP)
} }
if (maptype == MAP_PACKET_PATCH) { if (maptype == MAP_PACKET_PATCH) {
NetworkRecvPatchSettings(p); NetworkRecvPatchSettings(MY_CLIENT, p);
} }
// Check if this was the last packet // Check if this was the last packet
@ -481,8 +487,8 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP)
// We also get, very nice, the player_seeds in this packet // We also get, very nice, the player_seeds in this packet
int i; int i;
for (i = 0; i < MAX_PLAYERS; i++) { for (i = 0; i < MAX_PLAYERS; i++) {
_player_seeds[i][0] = NetworkRecv_uint32(p); _player_seeds[i][0] = NetworkRecv_uint32(MY_CLIENT, p);
_player_seeds[i][1] = NetworkRecv_uint32(p); _player_seeds[i][1] = NetworkRecv_uint32(MY_CLIENT, p);
} }
fclose(file_pointer); fclose(file_pointer);
@ -527,16 +533,16 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP)
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FRAME) DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FRAME)
{ {
_frame_counter_server = NetworkRecv_uint32(p); _frame_counter_server = NetworkRecv_uint32(MY_CLIENT, p);
_frame_counter_max = NetworkRecv_uint32(p); _frame_counter_max = NetworkRecv_uint32(MY_CLIENT, p);
#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME #ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
// Test if the server supports this option // Test if the server supports this option
// and if we are at the frame the server is // and if we are at the frame the server is
if (p->pos < p->size) { if (p->pos < p->size) {
_sync_frame = _frame_counter_server; _sync_frame = _frame_counter_server;
_sync_seed_1 = NetworkRecv_uint32(p); _sync_seed_1 = NetworkRecv_uint32(MY_CLIENT, p);
#ifdef NETWORK_SEND_DOUBLE_SEED #ifdef NETWORK_SEND_DOUBLE_SEED
_sync_seed_2 = NetworkRecv_uint32(p); _sync_seed_2 = NetworkRecv_uint32(MY_CLIENT, p);
#endif #endif
} }
#endif #endif
@ -555,10 +561,10 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FRAME)
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_SYNC) DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_SYNC)
{ {
_sync_frame = NetworkRecv_uint32(p); _sync_frame = NetworkRecv_uint32(MY_CLIENT, p);
_sync_seed_1 = NetworkRecv_uint32(p); _sync_seed_1 = NetworkRecv_uint32(MY_CLIENT, p);
#ifdef NETWORK_SEND_DOUBLE_SEED #ifdef NETWORK_SEND_DOUBLE_SEED
_sync_seed_2 = NetworkRecv_uint32(p); _sync_seed_2 = NetworkRecv_uint32(MY_CLIENT, p);
#endif #endif
return NETWORK_RECV_STATUS_OKAY; return NETWORK_RECV_STATUS_OKAY;
@ -569,21 +575,21 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMMAND)
int i; int i;
char *dparam_char; char *dparam_char;
CommandPacket *cp = malloc(sizeof(CommandPacket)); CommandPacket *cp = malloc(sizeof(CommandPacket));
cp->player = NetworkRecv_uint8(p); cp->player = NetworkRecv_uint8(MY_CLIENT, p);
cp->cmd = NetworkRecv_uint32(p); cp->cmd = NetworkRecv_uint32(MY_CLIENT, p);
cp->p1 = NetworkRecv_uint32(p); cp->p1 = NetworkRecv_uint32(MY_CLIENT, p);
cp->p2 = NetworkRecv_uint32(p); cp->p2 = NetworkRecv_uint32(MY_CLIENT, p);
cp->tile = NetworkRecv_uint32(p); cp->tile = NetworkRecv_uint32(MY_CLIENT, p);
/* We are going to send them byte by byte, because dparam is misused /* 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 for chars (if it is used), and else we have a BigEndian / LittleEndian
problem.. we should fix the misuse of dparam... -- TrueLight */ problem.. we should fix the misuse of dparam... -- TrueLight */
dparam_char = (char *)&cp->dp[0]; dparam_char = (char *)&cp->dp[0];
for (i = 0; i < lengthof(cp->dp) * 4; i++) { for (i = 0; i < lengthof(cp->dp) * 4; i++) {
*dparam_char = NetworkRecv_uint8(p); *dparam_char = NetworkRecv_uint8(MY_CLIENT, p);
dparam_char++; dparam_char++;
} }
cp->callback = NetworkRecv_uint8(p); cp->callback = NetworkRecv_uint8(MY_CLIENT, p);
cp->frame = NetworkRecv_uint32(p); cp->frame = NetworkRecv_uint32(MY_CLIENT, p);
cp->next = NULL; cp->next = NULL;
// The server did send us this command.. // The server did send us this command..
@ -603,16 +609,16 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMMAND)
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CHAT) 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]; char msg[MAX_TEXT_MSG_LEN];
NetworkClientInfo *ci = NULL, *ci_to; NetworkClientInfo *ci = NULL, *ci_to;
uint16 index; uint16 index;
char name[NETWORK_NAME_LENGTH]; char name[NETWORK_NAME_LENGTH];
bool self_send; bool self_send;
index = NetworkRecv_uint16(p); index = NetworkRecv_uint16(MY_CLIENT, p);
self_send = NetworkRecv_uint8(p); self_send = NetworkRecv_uint8(MY_CLIENT, p);
NetworkRecv_string(p, msg, MAX_TEXT_MSG_LEN); NetworkRecv_string(MY_CLIENT, p, msg, MAX_TEXT_MSG_LEN);
ci_to = NetworkFindClientInfoFromIndex(index); ci_to = NetworkFindClientInfoFromIndex(index);
if (ci_to == NULL) return NETWORK_RECV_STATUS_OKAY; if (ci_to == NULL) return NETWORK_RECV_STATUS_OKAY;
@ -656,8 +662,8 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT)
uint16 index; uint16 index;
NetworkClientInfo *ci; NetworkClientInfo *ci;
index = NetworkRecv_uint16(p); index = NetworkRecv_uint16(MY_CLIENT, p);
errorno = NetworkRecv_uint8(p); errorno = NetworkRecv_uint8(MY_CLIENT, p);
GetString(str, STR_NETWORK_ERR_CLIENT_GENERAL + errorno); GetString(str, STR_NETWORK_ERR_CLIENT_GENERAL + errorno);
@ -680,8 +686,8 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_QUIT)
uint16 index; uint16 index;
NetworkClientInfo *ci; NetworkClientInfo *ci;
index = NetworkRecv_uint16(p); index = NetworkRecv_uint16(MY_CLIENT, p);
NetworkRecv_string(p, str, 100); NetworkRecv_string(MY_CLIENT, p, str, 100);
ci = NetworkFindClientInfoFromIndex(index); ci = NetworkFindClientInfoFromIndex(index);
if (ci != NULL) { if (ci != NULL) {
@ -704,7 +710,7 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_JOIN)
uint16 index; uint16 index;
NetworkClientInfo *ci; NetworkClientInfo *ci;
index = NetworkRecv_uint16(p); index = NetworkRecv_uint16(MY_CLIENT, p);
ci = NetworkFindClientInfoFromIndex(index); ci = NetworkFindClientInfoFromIndex(index);
if (ci != NULL) if (ci != NULL)
@ -785,7 +791,7 @@ extern const SettingDesc patch_settings[];
// This is a TEMPORARY solution to get the patch-settings // This is a TEMPORARY solution to get the patch-settings
// to the client. When the patch-settings are saved in the savegame // to the client. When the patch-settings are saved in the savegame
// this should be removed!! // this should be removed!!
void NetworkRecvPatchSettings(Packet *p) void NetworkRecvPatchSettings(NetworkClientState *cs, Packet *p)
{ {
const SettingDesc *item; const SettingDesc *item;
@ -796,15 +802,15 @@ void NetworkRecvPatchSettings(Packet *p)
case SDT_BOOL: case SDT_BOOL:
case SDT_INT8: case SDT_INT8:
case SDT_UINT8: case SDT_UINT8:
*(uint8 *)(item->ptr) = NetworkRecv_uint8(p); *(uint8 *)(item->ptr) = NetworkRecv_uint8(cs, p);
break; break;
case SDT_INT16: case SDT_INT16:
case SDT_UINT16: case SDT_UINT16:
*(uint16 *)(item->ptr) = NetworkRecv_uint16(p); *(uint16 *)(item->ptr) = NetworkRecv_uint16(cs, p);
break; break;
case SDT_INT32: case SDT_INT32:
case SDT_UINT32: case SDT_UINT32:
*(uint32 *)(item->ptr) = NetworkRecv_uint32(p); *(uint32 *)(item->ptr) = NetworkRecv_uint32(cs, p);
break; break;
} }
item++; item++;
@ -829,8 +835,8 @@ NetworkRecvStatus NetworkClient_ReadPackets(NetworkClientState *cs)
NetworkRecvStatus res = NETWORK_RECV_STATUS_OKAY; NetworkRecvStatus res = NETWORK_RECV_STATUS_OKAY;
while (res == NETWORK_RECV_STATUS_OKAY && (p = NetworkRecv_Packet(cs, &res)) != NULL) { while (res == NETWORK_RECV_STATUS_OKAY && (p = NetworkRecv_Packet(cs, &res)) != NULL) {
byte type = NetworkRecv_uint8(p); byte type = NetworkRecv_uint8(MY_CLIENT, p);
if (type < PACKET_END && _network_client_packet[type] != NULL) { if (type < PACKET_END && _network_client_packet[type] != NULL && !MY_CLIENT->quited) {
res = _network_client_packet[type](p); res = _network_client_packet[type](p);
} else { } else {
res = NETWORK_RECV_STATUS_MALFORMED_PACKET; res = NETWORK_RECV_STATUS_MALFORMED_PACKET;

@ -183,22 +183,54 @@ bool NetworkSend_Packets(NetworkClientState *cs)
// Receiving commands // Receiving commands
// Again, the next couple of functions are endian-safe // Again, the next couple of functions are endian-safe
// see the comment around NetworkSend_uint8 for more info. // 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++]; return packet->buffer[packet->pos++];
} }
uint16 NetworkRecv_uint16(Packet *packet) uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet)
{ {
uint16 n; 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++];
n += (uint16)packet->buffer[packet->pos++] << 8; n += (uint16)packet->buffer[packet->pos++] << 8;
return n; return n;
} }
uint32 NetworkRecv_uint32(Packet *packet) uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet)
{ {
uint32 n; 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++];
n += (uint32)packet->buffer[packet->pos++] << 8; n += (uint32)packet->buffer[packet->pos++] << 8;
n += (uint32)packet->buffer[packet->pos++] << 16; n += (uint32)packet->buffer[packet->pos++] << 16;
@ -206,9 +238,20 @@ uint32 NetworkRecv_uint32(Packet *packet)
return n; return n;
} }
uint64 NetworkRecv_uint64(Packet *packet) uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet)
{ {
uint64 n; 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++];
n += (uint64)packet->buffer[packet->pos++] << 8; n += (uint64)packet->buffer[packet->pos++] << 8;
n += (uint64)packet->buffer[packet->pos++] << 16; n += (uint64)packet->buffer[packet->pos++] << 16;
@ -221,9 +264,14 @@ uint64 NetworkRecv_uint64(Packet *packet)
} }
// Reads a string till it finds a '\0' in the stream // 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; int pos;
/* Don't allow reading from a closed socket */
if (cs->quited)
return;
pos = p->pos; pos = p->pos;
while (--size > 0 && pos < p->size && (*buffer++ = p->buffer[pos++]) != '\0') {} while (--size > 0 && pos < p->size && (*buffer++ = p->buffer[pos++]) != '\0') {}
if (size == 0 || pos == p->size) if (size == 0 || pos == p->size)

@ -203,11 +203,11 @@ void NetworkSend_uint64(Packet *packet, uint64 data);
void NetworkSend_string(Packet *packet, const char* data); void NetworkSend_string(Packet *packet, const char* data);
void NetworkSend_Packet(Packet *packet, NetworkClientState *cs); void NetworkSend_Packet(Packet *packet, NetworkClientState *cs);
uint8 NetworkRecv_uint8(Packet *packet); uint8 NetworkRecv_uint8(NetworkClientState *cs, Packet *packet);
uint16 NetworkRecv_uint16(Packet *packet); uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet);
uint32 NetworkRecv_uint32(Packet *packet); uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet);
uint64 NetworkRecv_uint64(Packet *packet); uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet);
void NetworkRecv_string(Packet *packet, char* buffer, size_t size); void NetworkRecv_string(NetworkClientState *cs, Packet *packet, char* buffer, size_t size);
Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status); Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status);
bool NetworkSend_Packets(NetworkClientState *cs); bool NetworkSend_Packets(NetworkClientState *cs);

@ -580,7 +580,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN)
char client_revision[NETWORK_REVISION_LENGTH]; 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) #if defined(WITH_REV) || defined(WITH_REV_HACK)
// Check if the client has revision control enabled // Check if the client has revision control enabled
@ -594,10 +594,13 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN)
} }
#endif #endif
NetworkRecv_string(p, name, sizeof(name)); NetworkRecv_string(cs, p, name, sizeof(name));
playas = NetworkRecv_uint8(p); playas = NetworkRecv_uint8(cs, p);
client_lang = NetworkRecv_uint8(p); client_lang = NetworkRecv_uint8(cs, p);
NetworkRecv_string(p, unique_id, sizeof(unique_id)); NetworkRecv_string(cs, p, unique_id, sizeof(unique_id));
if (cs->quited)
return;
// Check if someone else already has that name // Check if someone else already has that name
snprintf(test_name, sizeof(test_name), "%s", name); snprintf(test_name, sizeof(test_name), "%s", name);
@ -644,8 +647,8 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD)
char password[NETWORK_PASSWORD_LENGTH]; char password[NETWORK_PASSWORD_LENGTH];
NetworkClientInfo *ci; NetworkClientInfo *ci;
type = NetworkRecv_uint8(p); type = NetworkRecv_uint8(cs, p);
NetworkRecv_string(p, password, sizeof(password)); NetworkRecv_string(cs, p, password, sizeof(password));
if (cs->status == STATUS_INACTIVE && type == NETWORK_GAME_PASSWORD) { if (cs->status == STATUS_INACTIVE && type == NETWORK_GAME_PASSWORD) {
// Check game-password // Check game-password
@ -761,21 +764,30 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
return; return;
} }
cp->player = NetworkRecv_uint8(p); cp->player = NetworkRecv_uint8(cs, p);
cp->cmd = NetworkRecv_uint32(p); cp->cmd = NetworkRecv_uint32(cs, p);
cp->p1 = NetworkRecv_uint32(p); cp->p1 = NetworkRecv_uint32(cs, p);
cp->p2 = NetworkRecv_uint32(p); cp->p2 = NetworkRecv_uint32(cs, p);
cp->tile = NetworkRecv_uint32(p); cp->tile = NetworkRecv_uint32(cs, p);
/* We are going to send them byte by byte, because dparam is misused /* 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 for chars (if it is used), and else we have a BigEndian / LittleEndian
problem.. we should fix the misuse of dparam... -- TrueLight */ problem.. we should fix the misuse of dparam... -- TrueLight */
dparam_char = (char *)&cp->dp[0]; dparam_char = (char *)&cp->dp[0];
for (i = 0; i < lengthof(cp->dp) * 4; i++) { for (i = 0; i < lengthof(cp->dp) * 4; i++) {
*dparam_char = NetworkRecv_uint8(p); *dparam_char = NetworkRecv_uint8(cs, p);
dparam_char++; 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); ci = DEREF_CLIENT_INFO(cs);
// Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs // Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs
@ -814,7 +826,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
// The frame can be executed in the same frame as the next frame-packet // 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 // That frame just before that frame is saved in _frame_counter_max
cp->frame = _frame_counter_max + 1; 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 // Queue the command for the clients (are send at the end of the frame
// if they can handle it ;)) // if they can handle it ;))
@ -826,6 +838,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
cp->callback = 0; cp->callback = 0;
else else
cp->callback = callback; cp->callback = callback;
NetworkAddCommandQueue(new_cs, cp); NetworkAddCommandQueue(new_cs, cp);
} }
} }
@ -847,7 +860,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ERROR)
// This packets means a client noticed an error and is reporting this // This packets means a client noticed an error and is reporting this
// to us. Display the error and report it to the other clients // to us. Display the error and report it to the other clients
NetworkClientState *new_cs; NetworkClientState *new_cs;
byte errorno = NetworkRecv_uint8(p); byte errorno = NetworkRecv_uint8(cs, p);
char str[100]; char str[100];
char client_name[NETWORK_CLIENT_NAME_LENGTH]; char client_name[NETWORK_CLIENT_NAME_LENGTH];
@ -888,7 +901,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_QUIT)
return; return;
} }
NetworkRecv_string(p, str, 100); NetworkRecv_string(cs, p, str, 100);
NetworkGetClientName(client_name, sizeof(client_name), cs); NetworkGetClientName(client_name, sizeof(client_name), cs);
@ -906,7 +919,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_QUIT)
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ACK) DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ACK)
{ {
// The client received the frame, make note of it // 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 // With those 2 values we can calculate the lag realtime
cs->last_frame_server = _frame_counter; cs->last_frame_server = _frame_counter;
@ -1018,12 +1031,12 @@ void NetworkServer_HandleChat(NetworkAction action, DestType desttype, int dest,
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_CHAT) DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_CHAT)
{ {
NetworkAction action = NetworkRecv_uint8(p); NetworkAction action = NetworkRecv_uint8(cs, p);
DestType desttype = NetworkRecv_uint8(p); DestType desttype = NetworkRecv_uint8(cs, p);
int dest = NetworkRecv_uint8(p); int dest = NetworkRecv_uint8(cs, p);
char msg[MAX_TEXT_MSG_LEN]; 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); NetworkServer_HandleChat(action, desttype, dest, msg, cs->index);
} }
@ -1033,7 +1046,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD)
char password[NETWORK_PASSWORD_LENGTH]; char password[NETWORK_PASSWORD_LENGTH];
NetworkClientInfo *ci; NetworkClientInfo *ci;
NetworkRecv_string(p, password, sizeof(password)); NetworkRecv_string(cs, p, password, sizeof(password));
ci = DEREF_CLIENT_INFO(cs); ci = DEREF_CLIENT_INFO(cs);
if (ci->client_playas <= MAX_PLAYERS) { if (ci->client_playas <= MAX_PLAYERS) {
@ -1046,9 +1059,12 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_NAME)
char client_name[NETWORK_CLIENT_NAME_LENGTH]; char client_name[NETWORK_CLIENT_NAME_LENGTH];
NetworkClientInfo *ci; NetworkClientInfo *ci;
NetworkRecv_string(p, client_name, sizeof(client_name)); NetworkRecv_string(cs, p, client_name, sizeof(client_name));
ci = DEREF_CLIENT_INFO(cs); ci = DEREF_CLIENT_INFO(cs);
if (cs->quited)
return;
if (ci != NULL) { if (ci != NULL) {
// Display change // Display change
if (NetworkFindName(client_name)) { if (NetworkFindName(client_name)) {
@ -1388,8 +1404,8 @@ bool NetworkServer_ReadPackets(NetworkClientState *cs)
Packet *p; Packet *p;
NetworkRecvStatus res; NetworkRecvStatus res;
while((p = NetworkRecv_Packet(cs, &res)) != NULL) { while((p = NetworkRecv_Packet(cs, &res)) != NULL) {
byte type = NetworkRecv_uint8(p); byte type = NetworkRecv_uint8(cs, p);
if (type < PACKET_END && _network_server_packet[type] != NULL) if (type < PACKET_END && _network_server_packet[type] != NULL && !cs->quited)
_network_server_packet[type](cs, p); _network_server_packet[type](cs, p);
else else
DEBUG(net, 0)("[NET][Server] Received invalid packet type %d", type); DEBUG(net, 0)("[NET][Server] Received invalid packet type %d", type);

@ -38,6 +38,8 @@ enum {
#define DEF_UDP_RECEIVE_COMMAND(type) void NetworkPacketReceive_ ## type ## _command(Packet *p, struct sockaddr_in *client_addr) #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); void NetworkSendUDP_Packet(SOCKET udp, Packet *p, struct sockaddr_in *recv);
NetworkClientState _udp_cs;
DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER) DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER)
{ {
Packet *packet; Packet *packet;
@ -86,8 +88,10 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE)
if (_network_udp_server) if (_network_udp_server)
return; 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)); 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 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE)
item = NetworkGameListAddItem(inet_addr(inet_ntoa(client_addr->sin_addr)), ntohs(client_addr->sin_port)); item = NetworkGameListAddItem(inet_addr(inet_ntoa(client_addr->sin_addr)), ntohs(client_addr->sin_port));
if (game_info_version == 1) { if (game_info_version == 1) {
NetworkRecv_string(p, item->info.server_name, sizeof(item->info.server_name)); NetworkRecv_string(&_udp_cs, p, item->info.server_name, sizeof(item->info.server_name));
NetworkRecv_string(p, item->info.server_revision, sizeof(item->info.server_revision)); NetworkRecv_string(&_udp_cs, p, item->info.server_revision, sizeof(item->info.server_revision));
item->info.server_lang = NetworkRecv_uint8(p); item->info.server_lang = NetworkRecv_uint8(&_udp_cs, p);
item->info.use_password = NetworkRecv_uint8(p); item->info.use_password = NetworkRecv_uint8(&_udp_cs, p);
item->info.clients_max = NetworkRecv_uint8(p); item->info.clients_max = NetworkRecv_uint8(&_udp_cs, p);
item->info.clients_on = NetworkRecv_uint8(p); item->info.clients_on = NetworkRecv_uint8(&_udp_cs, p);
item->info.spectators_on = NetworkRecv_uint8(p); item->info.spectators_on = NetworkRecv_uint8(&_udp_cs, p);
item->info.game_date = NetworkRecv_uint16(p); item->info.game_date = NetworkRecv_uint16(&_udp_cs, p);
item->info.start_date = NetworkRecv_uint16(p); item->info.start_date = NetworkRecv_uint16(&_udp_cs, p);
NetworkRecv_string(p, item->info.map_name, sizeof(item->info.map_name)); NetworkRecv_string(&_udp_cs, p, item->info.map_name, sizeof(item->info.map_name));
item->info.map_width = NetworkRecv_uint16(p); item->info.map_width = NetworkRecv_uint16(&_udp_cs, p);
item->info.map_height = NetworkRecv_uint16(p); item->info.map_height = NetworkRecv_uint16(&_udp_cs, p);
item->info.map_set = NetworkRecv_uint8(p); item->info.map_set = NetworkRecv_uint8(&_udp_cs, p);
item->info.dedicated = NetworkRecv_uint8(p); item->info.dedicated = NetworkRecv_uint8(&_udp_cs, p);
if (item->info.hostname[0] == '\0') if (item->info.hostname[0] == '\0')
snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr)); snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr));
@ -237,12 +241,15 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST) {
* an uint32 (ip) and an uint16 (port) for each pair * 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) { if (ver == 1) {
for (i = NetworkRecv_uint16(p); i != 0 ; i--) { for (i = NetworkRecv_uint16(&_udp_cs, p); i != 0 ; i--) {
ip.s_addr = TO_LE32(NetworkRecv_uint32(p)); ip.s_addr = TO_LE32(NetworkRecv_uint32(&_udp_cs, p));
port = NetworkRecv_uint16(p); port = NetworkRecv_uint16(&_udp_cs, p);
NetworkUDPQueryServer(inet_ntoa(ip), port); NetworkUDPQueryServer(inet_ntoa(ip), port);
} }
} }
@ -282,9 +289,13 @@ void NetworkHandleUDPPacket(Packet *p, struct sockaddr_in *client_addr)
{ {
byte type; 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;
type = NetworkRecv_uint8(&_udp_cs, p);
if (type < PACKET_UDP_END && _network_udp_packet[type] != NULL) { if (type < PACKET_UDP_END && _network_udp_packet[type] != NULL && !_udp_cs.quited) {
_network_udp_packet[type](p, client_addr); _network_udp_packet[type](p, client_addr);
} else { } else {
DEBUG(net, 0)("[NET][UDP] Received invalid packet type %d", type); DEBUG(net, 0)("[NET][UDP] Received invalid packet type %d", type);

Loading…
Cancel
Save