mirror of
https://github.com/rehlds/rehlds.git
synced 2025-01-12 14:48:00 +03:00
Added new CVARs for improved handling of decompression failures:
- `sv_net_incoming_decompression_min_failures`: Min failures required to flag a player - `sv_net_incoming_decompression_max_failures`: max failures allowed before punishment - `sv_net_incoming_decompression_min_failuretime`: Time window for failure tracking
This commit is contained in:
parent
e54adb089c
commit
64c684af4a
@ -63,9 +63,12 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
|
|||||||
<li>sv_rehlds_local_gametime <1|0> // A feature of local gametime which decrease "lags" if you run same map for a long time. Default: 0
|
<li>sv_rehlds_local_gametime <1|0> // A feature of local gametime which decrease "lags" if you run same map for a long time. Default: 0
|
||||||
<li>sv_use_entity_file // Use custom entity file for a map. Path to an entity file will be "maps/[map name].ent". 0 - use original entities. 1 - use .ent files from maps directory. 2 - use .ent files from maps directory and create new .ent file if not exist.
|
<li>sv_use_entity_file // Use custom entity file for a map. Path to an entity file will be "maps/[map name].ent". 0 - use original entities. 1 - use .ent files from maps directory. 2 - use .ent files from maps directory and create new .ent file if not exist.
|
||||||
<li>sv_usercmd_custom_random_seed // When enabled server will populate an additional random seed independent of the client. Default: 0
|
<li>sv_usercmd_custom_random_seed // When enabled server will populate an additional random seed independent of the client. Default: 0
|
||||||
<li>sv_net_incoming_decompression <1|0> // When enabled server will decompress of incoming compressed file transfer payloads. Default: 1
|
<li>sv_net_incoming_decompression <1|0> // When enabled server will decompress of incoming compressed file transfer payloads. Default: 1
|
||||||
<li>sv_net_incoming_decompression_max_ratio <0|100> // Sets the max allowed ratio between compressed and uncompressed data for file transfer. (A ratio close to 90 indicates large uncompressed data with low entropy) Default: 80.0
|
<li>sv_net_incoming_decompression_max_ratio <0|100> // Sets the max allowed ratio between compressed and uncompressed data for file transfer. (A ratio close to 90 indicates large uncompressed data with low entropy) Default: 80.0
|
||||||
<li>sv_net_incoming_decompression_max_size <16|65536> // Sets the max allowed size for decompressed file transfer data. Default: 65536 bytes
|
<li>sv_net_incoming_decompression_max_size <16|65536> // Sets the max allowed size for decompressed file transfer data. Default: 65536 bytes
|
||||||
|
<li>sv_net_incoming_decompression_min_failures <0|10> // Sets the min number of decompression failures required before a player's connection is flagged for potential punishment. Default: 4
|
||||||
|
<li>sv_net_incoming_decompression_max_failures <0|10> // Sets the max number of decompression failures allowed within a specified time window before action is taken against the player. Default: 10
|
||||||
|
<li>sv_net_incoming_decompression_min_failuretime: <0.1|10.0> // Sets the min time in secs within which decompression failures are tracked to determine if the player exceeds the failure thresholds. Default: 0.1
|
||||||
<li>sv_net_incoming_decompression_punish // Time in minutes for which the player will be banned for malformed/abnormal bzip2 fragments (0 - Permanent, use a negative number for a kick). Default: -1
|
<li>sv_net_incoming_decompression_punish // Time in minutes for which the player will be banned for malformed/abnormal bzip2 fragments (0 - Permanent, use a negative number for a kick). Default: -1
|
||||||
<li>sv_tags <comma-delimited string list of tags> // Sets a string defining the "gametags" for this server, this is optional, but if it is set it allows users/scripts to filter in the matchmaking/server-browser interfaces based on the value. Default: ""
|
<li>sv_tags <comma-delimited string list of tags> // Sets a string defining the "gametags" for this server, this is optional, but if it is set it allows users/scripts to filter in the matchmaking/server-browser interfaces based on the value. Default: ""
|
||||||
<li>sv_filterban <-1|0|1>// Set packet filtering by IP mode. -1 - All players will be rejected without any exceptions. 0 - No checks will happen. 1 - All incoming players will be checked if they're IP banned (if they have an IP filter entry), if they are, they will be kicked. Default: 1
|
<li>sv_filterban <-1|0|1>// Set packet filtering by IP mode. -1 - All players will be rejected without any exceptions. 0 - No checks will happen. 1 - All incoming players will be checked if they're IP banned (if they have an IP filter entry), if they are, they will be kicked. Default: 1
|
||||||
|
@ -276,6 +276,15 @@ typedef struct flow_s
|
|||||||
float avgkbytespersec;
|
float avgkbytespersec;
|
||||||
} flow_t;
|
} flow_t;
|
||||||
|
|
||||||
|
const int NET_DECOMPRESS_MAX_TIMES = 10;
|
||||||
|
|
||||||
|
typedef struct frag_decomp_failure_s
|
||||||
|
{
|
||||||
|
float failure_times[NET_DECOMPRESS_MAX_TIMES];
|
||||||
|
// Count of abnormal fragment decompressions in a time window
|
||||||
|
int num_failures;
|
||||||
|
} frag_decomp_failure_t;
|
||||||
|
|
||||||
const int FRAGMENT_C2S_MIN_SIZE = 16;
|
const int FRAGMENT_C2S_MIN_SIZE = 16;
|
||||||
const int FRAGMENT_S2C_MIN_SIZE = 256;
|
const int FRAGMENT_S2C_MIN_SIZE = 256;
|
||||||
const int FRAGMENT_S2C_MAX_SIZE = 1024;
|
const int FRAGMENT_S2C_MAX_SIZE = 1024;
|
||||||
@ -422,6 +431,10 @@ typedef struct netchan_s
|
|||||||
|
|
||||||
// Incoming and outgoing flow metrics
|
// Incoming and outgoing flow metrics
|
||||||
flow_t flow[MAX_FLOWS];
|
flow_t flow[MAX_FLOWS];
|
||||||
|
|
||||||
|
// Stats for decompression of incoming fragments
|
||||||
|
frag_decomp_failure_t frag_decompress[MAX_STREAMS];
|
||||||
|
|
||||||
} netchan_t;
|
} netchan_t;
|
||||||
|
|
||||||
#ifdef REHLDS_FIXES
|
#ifdef REHLDS_FIXES
|
||||||
|
@ -40,7 +40,10 @@ cvar_t net_chokeloopback = { "net_chokeloop", "0", 0, 0.0f, nullptr};
|
|||||||
cvar_t sv_net_incoming_decompression = { "sv_net_incoming_decompression", "1", 0, 1.0f, nullptr };
|
cvar_t sv_net_incoming_decompression = { "sv_net_incoming_decompression", "1", 0, 1.0f, nullptr };
|
||||||
cvar_t sv_net_incoming_decompression_max_ratio = { "sv_net_incoming_decompression_max_ratio", "80.0", 0, 80.0f, nullptr };
|
cvar_t sv_net_incoming_decompression_max_ratio = { "sv_net_incoming_decompression_max_ratio", "80.0", 0, 80.0f, nullptr };
|
||||||
cvar_t sv_net_incoming_decompression_max_size = { "sv_net_incoming_decompression_max_size", "65536", 0, 65536.0f, nullptr };
|
cvar_t sv_net_incoming_decompression_max_size = { "sv_net_incoming_decompression_max_size", "65536", 0, 65536.0f, nullptr };
|
||||||
cvar_t sv_net_incoming_decompression_punish = { "sv_net_incoming_decompression_punish", "-1", 0, -1.0f, NULL };
|
cvar_t sv_net_incoming_decompression_min_failures = { "sv_net_incoming_decompression_min_failures", "4", 0, 4.0f, nullptr };
|
||||||
|
cvar_t sv_net_incoming_decompression_max_failures = { "sv_net_incoming_decompression_max_failures", "10", 0, 10.0f, nullptr };
|
||||||
|
cvar_t sv_net_incoming_decompression_min_failuretime = { "sv_net_incoming_decompression_min_failuretime", "0.1", 0, 0.1f, nullptr };
|
||||||
|
cvar_t sv_net_incoming_decompression_punish = { "sv_net_incoming_decompression_punish", "-1", 0, -1.0f, nullptr };
|
||||||
|
|
||||||
cvar_t sv_filetransfercompression = { "sv_filetransfercompression", "1", 0, 0.0f, nullptr};
|
cvar_t sv_filetransfercompression = { "sv_filetransfercompression", "1", 0, 0.0f, nullptr};
|
||||||
cvar_t sv_filetransfermaxsize = { "sv_filetransfermaxsize", "10485760", 0, 0.0f, nullptr};
|
cvar_t sv_filetransfermaxsize = { "sv_filetransfermaxsize", "10485760", 0, 0.0f, nullptr};
|
||||||
@ -171,6 +174,10 @@ void Netchan_Clear(netchan_t *chan)
|
|||||||
chan->frag_startpos[i] = 0;
|
chan->frag_startpos[i] = 0;
|
||||||
chan->frag_length[i] = 0;
|
chan->frag_length[i] = 0;
|
||||||
chan->incomingready[i] = FALSE;
|
chan->incomingready[i] = FALSE;
|
||||||
|
|
||||||
|
for (int j = 0; j < NET_DECOMPRESS_MAX_TIMES; j++)
|
||||||
|
chan->frag_decompress[i].failure_times[j] = 0;
|
||||||
|
chan->frag_decompress[i].num_failures = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan->tempbuffer)
|
if (chan->tempbuffer)
|
||||||
@ -1423,6 +1430,94 @@ void Netchan_FlushIncoming(netchan_t *chan, int stream)
|
|||||||
chan->incomingready[stream] = FALSE;
|
chan->incomingready[stream] = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Netchan_DecompressionCvarsBounds()
|
||||||
|
{
|
||||||
|
if (sv_net_incoming_decompression_min_failures.value < 1)
|
||||||
|
Cvar_SetValue("sv_net_incoming_decompression_min_failures", 1);
|
||||||
|
|
||||||
|
else if (sv_net_incoming_decompression_min_failures.value > NET_DECOMPRESS_MAX_TIMES)
|
||||||
|
Cvar_SetValue("sv_net_incoming_decompression_min_failures", NET_DECOMPRESS_MAX_TIMES);
|
||||||
|
|
||||||
|
if (sv_net_incoming_decompression_max_failures.value < 1)
|
||||||
|
Cvar_SetValue("sv_net_incoming_decompression_max_failures", 1);
|
||||||
|
|
||||||
|
else if (sv_net_incoming_decompression_max_failures.value > NET_DECOMPRESS_MAX_TIMES)
|
||||||
|
Cvar_SetValue("sv_net_incoming_decompression_max_failures", NET_DECOMPRESS_MAX_TIMES);
|
||||||
|
|
||||||
|
if (sv_net_incoming_decompression_max_failures.value < sv_net_incoming_decompression_min_failures.value)
|
||||||
|
{
|
||||||
|
int iTemp = sv_net_incoming_decompression_max_failures.value;
|
||||||
|
Cvar_SetValue("sv_net_incoming_decompression_max_failures", sv_net_incoming_decompression_min_failures.value);
|
||||||
|
Cvar_SetValue("sv_net_incoming_decompression_min_failures", iTemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sv_net_incoming_decompression_min_failuretime.value <= 0.0f)
|
||||||
|
Cvar_SetValue("sv_net_incoming_decompression_min_failuretime", 0.1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for an abnormal size ratio between compressed and uncompressed data
|
||||||
|
qboolean Netchan_ValidateDecompress(netchan_t *chan, int stream, unsigned int compressedSize, unsigned int uncompressedSize)
|
||||||
|
{
|
||||||
|
#ifdef REHLDS_FIXES
|
||||||
|
int i;
|
||||||
|
frag_decomp_failure_t *decomp;
|
||||||
|
|
||||||
|
if (sv_net_incoming_decompression_max_ratio.value <= 0)
|
||||||
|
return TRUE; // validation is disabled
|
||||||
|
|
||||||
|
if (compressedSize >= uncompressedSize)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
float ratio = ((float)(uncompressedSize - compressedSize) / uncompressedSize) * 100.0f;
|
||||||
|
if (ratio < sv_net_incoming_decompression_max_ratio.value)
|
||||||
|
return TRUE; // no low entropy for uncompressed data
|
||||||
|
|
||||||
|
if ((chan->player_slot - 1) != host_client - g_psvs.clients)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
Netchan_DecompressionCvarsBounds();
|
||||||
|
|
||||||
|
decomp = &chan->frag_decompress[stream];
|
||||||
|
|
||||||
|
// check if the client should be rejected based on total failed decompress
|
||||||
|
if (decomp->num_failures >= sv_net_incoming_decompression_max_failures.value)
|
||||||
|
{
|
||||||
|
for (i = 0; i < sv_net_incoming_decompression_max_failures.value - 1; i++)
|
||||||
|
decomp->failure_times[i] = decomp->failure_times[i + 1];
|
||||||
|
|
||||||
|
decomp->num_failures = sv_net_incoming_decompression_max_failures.value - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
decomp->failure_times[decomp->num_failures++] = realtime;
|
||||||
|
|
||||||
|
// check if the client should be rejected based on recent failed decompress
|
||||||
|
int recent_failures = 0;
|
||||||
|
for (i = 0; i < decomp->num_failures; i++)
|
||||||
|
{
|
||||||
|
if ((realtime - decomp->failure_times[i]) <= sv_net_incoming_decompression_min_failuretime.value)
|
||||||
|
recent_failures++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recent_failures >= sv_net_incoming_decompression_min_failures.value)
|
||||||
|
{
|
||||||
|
if (chan->player_slot == 0)
|
||||||
|
Con_DPrintf("Incoming abnormal uncompressed size with ratio %.2f\n", ratio);
|
||||||
|
else
|
||||||
|
Con_DPrintf("%s:Incoming abnormal uncompressed size with ratio %.2f from %s\n", NET_AdrToString(chan->remote_address), ratio, host_client->name);
|
||||||
|
|
||||||
|
if (sv_net_incoming_decompression_punish.value >= 0)
|
||||||
|
{
|
||||||
|
Con_DPrintf("%s:Banned for malformed/abnormal bzip2 fragments from %s\n", NET_AdrToString(chan->remote_address), host_client->name);
|
||||||
|
Cbuf_AddText(va("addip %.1f %s\n", sv_net_incoming_decompression_punish.value, NET_BaseAdrToString(chan->remote_address)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
qboolean Netchan_CopyNormalFragments(netchan_t *chan)
|
qboolean Netchan_CopyNormalFragments(netchan_t *chan)
|
||||||
{
|
{
|
||||||
fragbuf_t *p, *n;
|
fragbuf_t *p, *n;
|
||||||
@ -1483,8 +1578,6 @@ qboolean Netchan_CopyNormalFragments(netchan_t *chan)
|
|||||||
}
|
}
|
||||||
#endif // REHLDS_FIXES
|
#endif // REHLDS_FIXES
|
||||||
|
|
||||||
qboolean success = TRUE;
|
|
||||||
|
|
||||||
if (*(uint32 *)net_message.data == MAKEID('B', 'Z', '2', '\0'))
|
if (*(uint32 *)net_message.data == MAKEID('B', 'Z', '2', '\0'))
|
||||||
{
|
{
|
||||||
// Determine whether decompression of compressed data is allowed
|
// Determine whether decompression of compressed data is allowed
|
||||||
@ -1493,13 +1586,13 @@ qboolean Netchan_CopyNormalFragments(netchan_t *chan)
|
|||||||
{
|
{
|
||||||
if (chan->player_slot == 0)
|
if (chan->player_slot == 0)
|
||||||
{
|
{
|
||||||
Con_DPrintf("Incoming compressed data disallowed from\n");
|
Con_DPrintf("Incoming compressed normal fragment disallowed from\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
// compressed data is expected only after requesting resource list
|
// compressed data is expected only after requesting resource list
|
||||||
else if (host_client->m_sendrescount == 0)
|
else if (host_client->m_sendrescount == 0)
|
||||||
{
|
{
|
||||||
Con_DPrintf("%s:Incoming compressed data disallowed from %s\n", NET_AdrToString(chan->remote_address), host_client->name);
|
Con_DPrintf("%s:Incoming compressed normal fragment disallowed from %s\n", NET_AdrToString(chan->remote_address), host_client->name);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1510,22 +1603,25 @@ qboolean Netchan_CopyNormalFragments(netchan_t *chan)
|
|||||||
unsigned int compressedSize = net_message.cursize - 4;
|
unsigned int compressedSize = net_message.cursize - 4;
|
||||||
|
|
||||||
// Decompress net buffer data
|
// Decompress net buffer data
|
||||||
if (success && (BZ2_bzBuffToBuffDecompress(uncompressed, &uncompressedSize, (char *)net_message.data + 4, compressedSize, 1, 0) == BZ_OK))
|
qboolean success = TRUE;
|
||||||
{
|
|
||||||
#ifdef REHLDS_FIXES
|
|
||||||
// Check for an abnormal size ratio between compressed and uncompressed data
|
|
||||||
if (sv_net_incoming_decompression_max_ratio.value > 0 && compressedSize < uncompressedSize)
|
|
||||||
{
|
|
||||||
float ratio = ((float)(uncompressedSize - compressedSize) / uncompressedSize) * 100.0f;
|
|
||||||
if (ratio >= sv_net_incoming_decompression_max_ratio.value)
|
|
||||||
{
|
|
||||||
if (chan->player_slot == 0)
|
|
||||||
Con_DPrintf("Incoming abnormal uncompressed size with ratio %.2f\n", ratio);
|
|
||||||
else
|
|
||||||
Con_DPrintf("%s:Incoming abnormal uncompressed size with ratio %.2f from %s\n", NET_AdrToString(chan->remote_address), ratio, host_client->name);
|
|
||||||
|
|
||||||
|
if (BZ2_bzBuffToBuffDecompress(uncompressed, &uncompressedSize, (char *)net_message.data + 4, compressedSize, 1, 0) != BZ_OK)
|
||||||
|
{
|
||||||
|
// malformed data or compressed data exceeding sv_net_incoming_decompression_max_size
|
||||||
success = FALSE;
|
success = FALSE;
|
||||||
}
|
}
|
||||||
|
else if (!Netchan_ValidateDecompress(chan, FRAG_NORMAL_STREAM, compressedSize, uncompressedSize))
|
||||||
|
{
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef REHLDS_FIXES
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
// Drop client if decompression was unsuccessful
|
||||||
|
SV_DropClient(host_client, FALSE, "Malformed/abnormal compressed data");
|
||||||
|
SZ_Clear(&net_message);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1533,33 +1629,8 @@ qboolean Netchan_CopyNormalFragments(netchan_t *chan)
|
|||||||
Q_memcpy(net_message.data, uncompressed, uncompressedSize);
|
Q_memcpy(net_message.data, uncompressed, uncompressedSize);
|
||||||
net_message.cursize = uncompressedSize;
|
net_message.cursize = uncompressedSize;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// malformed data or compressed data exceeding sv_net_incoming_decompression_max_size
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drop client if decompression was unsuccessful
|
return TRUE;
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
if ((chan->player_slot - 1) == host_client - g_psvs.clients)
|
|
||||||
{
|
|
||||||
#ifdef REHLDS_FIXES
|
|
||||||
if (sv_net_incoming_decompression_punish.value >= 0)
|
|
||||||
{
|
|
||||||
Con_DPrintf("%s:Banned for malformed/abnormal bzip2 fragments from %s\n", NET_AdrToString(chan->remote_address), host_client->name);
|
|
||||||
Cbuf_AddText(va("addip %.1f %s\n", sv_net_incoming_decompression_punish.value, NET_BaseAdrToString(chan->remote_address)));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SV_DropClient(host_client, FALSE, "Malformed/abnormal compressed data");
|
|
||||||
}
|
|
||||||
|
|
||||||
SZ_Clear(&net_message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qboolean Netchan_CopyFileFragments(netchan_t *chan)
|
qboolean Netchan_CopyFileFragments(netchan_t *chan)
|
||||||
@ -1575,7 +1646,6 @@ qboolean Netchan_CopyFileFragments(netchan_t *chan)
|
|||||||
qboolean bCompressed;
|
qboolean bCompressed;
|
||||||
unsigned int uncompressedSize;
|
unsigned int uncompressedSize;
|
||||||
|
|
||||||
|
|
||||||
if (!chan->incomingready[FRAG_FILE_STREAM])
|
if (!chan->incomingready[FRAG_FILE_STREAM])
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
@ -1587,6 +1657,19 @@ qboolean Netchan_CopyFileFragments(netchan_t *chan)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef REHLDS_FIXES
|
||||||
|
if (chan->player_slot > 0 && (chan->player_slot - 1) == host_client - g_psvs.clients)
|
||||||
|
{
|
||||||
|
// customization already uploaded with request by operator,
|
||||||
|
// do not accept any other customization
|
||||||
|
if (host_client->uploaddoneregistering)
|
||||||
|
{
|
||||||
|
SV_DropClient(host_client, FALSE, "Too many customization have been uploaded (unrequested customization)");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bCompressed = FALSE;
|
bCompressed = FALSE;
|
||||||
SZ_Clear(&net_message);
|
SZ_Clear(&net_message);
|
||||||
MSG_BeginReading();
|
MSG_BeginReading();
|
||||||
@ -1701,10 +1784,53 @@ qboolean Netchan_CopyFileFragments(netchan_t *chan)
|
|||||||
|
|
||||||
if (bCompressed)
|
if (bCompressed)
|
||||||
{
|
{
|
||||||
unsigned char* uncompressedBuffer = (unsigned char*)Mem_Malloc(uncompressedSize);
|
// Determine whether decompression of compressed data is allowed
|
||||||
Con_DPrintf("Decompressing file %s (%d -> %d)\n", filename, nsize, uncompressedSize);
|
#ifdef REHLDS_FIXES
|
||||||
BZ2_bzBuffToBuffDecompress((char*)uncompressedBuffer, &uncompressedSize, (char*)buffer, nsize, 1, 0);
|
if (!sv_net_incoming_decompression.value)
|
||||||
|
{
|
||||||
|
if (chan->player_slot == 0)
|
||||||
|
{
|
||||||
|
Con_DPrintf("Incoming compressed file fragment disallowed from\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
// compressed data is expected only after requesting resource list
|
||||||
|
else if (host_client->m_sendrescount == 0)
|
||||||
|
{
|
||||||
|
Con_DPrintf("%s:Incoming compressed file fragment disallowed from %s\n", NET_AdrToString(chan->remote_address), host_client->name);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uncompressedSize = clamp(uncompressedSize, 16u, (unsigned)sv_net_incoming_decompression_max_size.value); // valid range (16 - 65536) bytes
|
||||||
|
|
||||||
|
qboolean success = TRUE;
|
||||||
|
unsigned char *uncompressedBuffer = (unsigned char *)Mem_Malloc(uncompressedSize);
|
||||||
|
unsigned int compressedSize = nsize;
|
||||||
|
|
||||||
|
// Decompress net buffer data
|
||||||
|
if (BZ2_bzBuffToBuffDecompress((char *)uncompressedBuffer, &uncompressedSize, (char *)buffer, compressedSize, 1, 0) != BZ_OK)
|
||||||
|
{
|
||||||
|
// malformed data or compressed data exceeding sv_net_incoming_decompression_max_size
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
else if (!Netchan_ValidateDecompress(chan, FRAG_NORMAL_STREAM, compressedSize, uncompressedSize))
|
||||||
|
{
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
Mem_Free(buffer);
|
Mem_Free(buffer);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
// Drop client if decompression was unsuccessful
|
||||||
|
SV_DropClient(host_client, FALSE, "Malformed/abnormal compressed data");
|
||||||
|
SZ_Clear(&net_message);
|
||||||
|
Mem_Free(uncompressedBuffer);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Con_DPrintf("Decompressing file %s (%d -> %d)\n", filename, compressedSize, uncompressedSize);
|
||||||
pos = uncompressedSize;
|
pos = uncompressedSize;
|
||||||
buffer = uncompressedBuffer;
|
buffer = uncompressedBuffer;
|
||||||
}
|
}
|
||||||
@ -1899,6 +2025,9 @@ void Netchan_Init(void)
|
|||||||
Cvar_RegisterVariable(&sv_net_incoming_decompression);
|
Cvar_RegisterVariable(&sv_net_incoming_decompression);
|
||||||
Cvar_RegisterVariable(&sv_net_incoming_decompression_max_ratio);
|
Cvar_RegisterVariable(&sv_net_incoming_decompression_max_ratio);
|
||||||
Cvar_RegisterVariable(&sv_net_incoming_decompression_max_size);
|
Cvar_RegisterVariable(&sv_net_incoming_decompression_max_size);
|
||||||
|
Cvar_RegisterVariable(&sv_net_incoming_decompression_min_failures);
|
||||||
|
Cvar_RegisterVariable(&sv_net_incoming_decompression_max_failures);
|
||||||
|
Cvar_RegisterVariable(&sv_net_incoming_decompression_min_failuretime);
|
||||||
Cvar_RegisterVariable(&sv_net_incoming_decompression_punish);
|
Cvar_RegisterVariable(&sv_net_incoming_decompression_punish);
|
||||||
#endif
|
#endif
|
||||||
Cvar_RegisterVariable(&sv_filetransfermaxsize);
|
Cvar_RegisterVariable(&sv_filetransfermaxsize);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user