mirror of
https://git.code.sf.net/p/quake/newtree
synced 2024-11-10 06:42:26 +00:00
Basic DoS flood attack protections. Use sv_netdosprotect 1 to turn them on.
(quite experimental, these might break something...) Cvars added: sv_allow_log, sv_allow_status, sv_allow_ping, sv_netdosprotect Commands added: netdosexpire, netdosvalues
This commit is contained in:
parent
0bbc70dbd6
commit
afc467b84f
2 changed files with 133 additions and 9 deletions
|
@ -273,6 +273,23 @@ typedef struct
|
||||||
challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
|
challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
|
||||||
} server_static_t;
|
} server_static_t;
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// DoSflood protection
|
||||||
|
//=============================================================================
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
netadr_t adr;
|
||||||
|
double issued;
|
||||||
|
int floodcount;
|
||||||
|
int cmdcount;
|
||||||
|
double firstseen;
|
||||||
|
} flood_t;
|
||||||
|
|
||||||
|
enum {FLOOD_PING, FLOOD_LOG, FLOOD_CONNECT, FLOOD_STATUS, FLOOD_RCON, FLOOD_BAN};
|
||||||
|
|
||||||
|
#define DOSFLOODCMDS 6
|
||||||
|
#define DOSFLOODIP 64 // remember latest 64 IP's for each cmd.
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
// edict->movetype values
|
// edict->movetype values
|
||||||
|
|
107
source/sv_main.c
107
source/sv_main.c
|
@ -62,6 +62,19 @@ netadr_t master_adr[MAX_MASTERS]; // address of group servers
|
||||||
|
|
||||||
client_t *host_client; // current client
|
client_t *host_client; // current client
|
||||||
|
|
||||||
|
// DoS protection
|
||||||
|
// FLOOD_PING, FLOOD_LOG, FLOOD_CONNECT, FLOOD_STATUS, FLOOD_RCON, FLOOD_BAN
|
||||||
|
// fixme: these default values need to be tweaked after more testing
|
||||||
|
|
||||||
|
double netdosexpire[DOSFLOODCMDS] = {1,1,2,0.9,1,5};
|
||||||
|
double netdosvalues[DOSFLOODCMDS] = {12,1,3,2,1,1};
|
||||||
|
|
||||||
|
cvar_t *sv_netdosprotect; // tone down DoS from quake servers
|
||||||
|
|
||||||
|
cvar_t *sv_allow_status;
|
||||||
|
cvar_t *sv_allow_log;
|
||||||
|
cvar_t *sv_allow_ping;
|
||||||
|
|
||||||
cvar_t *fs_globalcfg;
|
cvar_t *fs_globalcfg;
|
||||||
|
|
||||||
cvar_t *sv_mintic; // bound the size of the
|
cvar_t *sv_mintic; // bound the size of the
|
||||||
|
@ -368,6 +381,79 @@ CONNECTIONLESS COMMANDS
|
||||||
==============================================================================
|
==============================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
CheckForFlood :: EXPERIMENTAL
|
||||||
|
|
||||||
|
Makes it more difficult to use Quake servers for DoS attacks against other sites.
|
||||||
|
|
||||||
|
Bad sides: affects gamespy and spytools somewhat...
|
||||||
|
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
|
||||||
|
int CheckForFlood(char cmdtype)
|
||||||
|
{
|
||||||
|
static qboolean firsttime=true;
|
||||||
|
static flood_t floodstatus[DOSFLOODCMDS][DOSFLOODIP];
|
||||||
|
|
||||||
|
int i;
|
||||||
|
double currenttime;
|
||||||
|
double oldestTime;
|
||||||
|
static double lastmessagetime=0;
|
||||||
|
int oldest;
|
||||||
|
|
||||||
|
if (!sv_netdosprotect->value) return 0;
|
||||||
|
|
||||||
|
oldestTime=0x7fffffff;
|
||||||
|
oldest=0;
|
||||||
|
|
||||||
|
if (firsttime) {
|
||||||
|
memset(floodstatus,sizeof(flood_t)*DOSFLOODCMDS*DOSFLOODIP,0);
|
||||||
|
firsttime=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
currenttime=Sys_DoubleTime();
|
||||||
|
|
||||||
|
for (i = 0 ; i < DOSFLOODIP ; i++)
|
||||||
|
{
|
||||||
|
if (NET_CompareBaseAdr (net_from, floodstatus[cmdtype][i].adr))
|
||||||
|
break;
|
||||||
|
if (floodstatus[cmdtype][i].issued < oldestTime)
|
||||||
|
{
|
||||||
|
oldestTime = floodstatus[cmdtype][i].issued;
|
||||||
|
oldest = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i<DOSFLOODIP && floodstatus[cmdtype][i].issued)
|
||||||
|
if(floodstatus[cmdtype][i].issued+netdosexpire[cmdtype]>currenttime)
|
||||||
|
{
|
||||||
|
floodstatus[cmdtype][i].floodcount+=1;
|
||||||
|
if (floodstatus[cmdtype][i].floodcount>netdosvalues[cmdtype])
|
||||||
|
{
|
||||||
|
if (lastmessagetime+5<currenttime)
|
||||||
|
Con_Printf("Blocking type %d flood from (or to) %s\n",cmdtype,NET_AdrToString(net_from));
|
||||||
|
Con_Printf("%f %f\n",currenttime,floodstatus[cmdtype][i].issued);
|
||||||
|
floodstatus[cmdtype][i].floodcount=0;
|
||||||
|
floodstatus[cmdtype][i].issued = currenttime;
|
||||||
|
floodstatus[cmdtype][i].cmdcount+=1;
|
||||||
|
lastmessagetime=currenttime;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else floodstatus[cmdtype][i].floodcount=0;
|
||||||
|
|
||||||
|
if (i == DOSFLOODIP)
|
||||||
|
{
|
||||||
|
i = oldest;
|
||||||
|
floodstatus[cmdtype][i].adr = net_from;
|
||||||
|
floodstatus[cmdtype][i].firstseen=currenttime;
|
||||||
|
}
|
||||||
|
floodstatus[cmdtype][i].issued = currenttime;
|
||||||
|
floodstatus[cmdtype][i].cmdcount+=1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
SVC_Status
|
SVC_Status
|
||||||
|
@ -383,6 +469,10 @@ void SVC_Status (void)
|
||||||
int ping;
|
int ping;
|
||||||
int top, bottom;
|
int top, bottom;
|
||||||
|
|
||||||
|
if (CheckForFlood(FLOOD_STATUS)) return;
|
||||||
|
|
||||||
|
if (!sv_allow_status->value) return;
|
||||||
|
|
||||||
Cmd_TokenizeString ("status");
|
Cmd_TokenizeString ("status");
|
||||||
SV_BeginRedirect (RD_PACKET);
|
SV_BeginRedirect (RD_PACKET);
|
||||||
Con_Printf ("%s\n", svs.info);
|
Con_Printf ("%s\n", svs.info);
|
||||||
|
@ -448,6 +538,9 @@ void SVC_Log (void)
|
||||||
int seq;
|
int seq;
|
||||||
char data[MAX_DATAGRAM+64];
|
char data[MAX_DATAGRAM+64];
|
||||||
|
|
||||||
|
if (sv_allow_log->value) return;
|
||||||
|
if (CheckForFlood(FLOOD_LOG)) return;
|
||||||
|
|
||||||
if (Cmd_Argc() == 2)
|
if (Cmd_Argc() == 2)
|
||||||
seq = atoi(Cmd_Argv(1));
|
seq = atoi(Cmd_Argv(1));
|
||||||
else
|
else
|
||||||
|
@ -482,6 +575,9 @@ void SVC_Ping (void)
|
||||||
{
|
{
|
||||||
char data;
|
char data;
|
||||||
|
|
||||||
|
if (!sv_allow_ping->value) return;
|
||||||
|
if (CheckForFlood(FLOOD_PING)) return;
|
||||||
|
|
||||||
data = A2A_ACK;
|
data = A2A_ACK;
|
||||||
|
|
||||||
NET_SendPacket (1, &data, net_from);
|
NET_SendPacket (1, &data, net_from);
|
||||||
|
@ -504,6 +600,7 @@ void SVC_GetChallenge (void)
|
||||||
int oldest;
|
int oldest;
|
||||||
int oldestTime;
|
int oldestTime;
|
||||||
|
|
||||||
|
// if (CheckForFlood(FLOOD_CHALLENGE)) return;
|
||||||
oldest = 0;
|
oldest = 0;
|
||||||
oldestTime = 0x7fffffff;
|
oldestTime = 0x7fffffff;
|
||||||
|
|
||||||
|
@ -557,6 +654,8 @@ void SVC_DirectConnect (void)
|
||||||
int version;
|
int version;
|
||||||
int challenge;
|
int challenge;
|
||||||
|
|
||||||
|
if (CheckForFlood(FLOOD_CONNECT)) return;
|
||||||
|
|
||||||
version = atoi(Cmd_Argv(1));
|
version = atoi(Cmd_Argv(1));
|
||||||
if (version != PROTOCOL_VERSION)
|
if (version != PROTOCOL_VERSION)
|
||||||
{
|
{
|
||||||
|
@ -781,6 +880,7 @@ void SVC_RemoteCommand (void)
|
||||||
int i;
|
int i;
|
||||||
char remaining[1024];
|
char remaining[1024];
|
||||||
|
|
||||||
|
if (CheckForFlood(FLOOD_RCON)) return;
|
||||||
|
|
||||||
if (!Rcon_Validate ()) {
|
if (!Rcon_Validate ()) {
|
||||||
Con_Printf ("Bad rcon from %s:\n%s\n"
|
Con_Printf ("Bad rcon from %s:\n%s\n"
|
||||||
|
@ -1076,6 +1176,8 @@ void SV_SendBan (void)
|
||||||
{
|
{
|
||||||
char data[128];
|
char data[128];
|
||||||
|
|
||||||
|
if (CheckForFlood(FLOOD_BAN)) return;
|
||||||
|
|
||||||
data[0] = data[1] = data[2] = data[3] = 0xff;
|
data[0] = data[1] = data[2] = data[3] = 0xff;
|
||||||
data[4] = A2C_PRINT;
|
data[4] = A2C_PRINT;
|
||||||
data[5] = 0;
|
data[5] = 0;
|
||||||
|
@ -1393,6 +1495,11 @@ void SV_InitLocal (void)
|
||||||
sv_timekick_fuzz = Cvar_Get("sv_timekick_fuzz", "15", CVAR_NONE, "Time cheat \"fuzz factor\"");
|
sv_timekick_fuzz = Cvar_Get("sv_timekick_fuzz", "15", CVAR_NONE, "Time cheat \"fuzz factor\"");
|
||||||
sv_timekick_interval = Cvar_Get("sv_timekick_interval", "30", CVAR_NONE, "Time cheat check interval");
|
sv_timekick_interval = Cvar_Get("sv_timekick_interval", "30", CVAR_NONE, "Time cheat check interval");
|
||||||
|
|
||||||
|
sv_allow_log = Cvar_Get("sv_allow_log", "1", CVAR_NONE, "Allow remote logging");
|
||||||
|
sv_allow_status = Cvar_Get("sv_allow_status","1", CVAR_NONE, "Allow remote status queries (gamespy etc)");
|
||||||
|
sv_allow_ping = Cvar_Get("sv_allow_pings","1", CVAR_NONE, "Allow remote pings (gamespy etc)");
|
||||||
|
sv_netdosprotect = Cvar_Get("sv_netdosprotect","0", CVAR_NONE, "DoS flood attack protection");
|
||||||
|
|
||||||
sv_timestamps = Cvar_Get ("sv_timestamps", "0", CVAR_NONE, "Time/date stamps in log entries");
|
sv_timestamps = Cvar_Get ("sv_timestamps", "0", CVAR_NONE, "Time/date stamps in log entries");
|
||||||
sv_timefmt = Cvar_Get ("sv_timefmt", "[%b %e %X] ", CVAR_NONE, "Time/date format to use");
|
sv_timefmt = Cvar_Get ("sv_timefmt", "[%b %e %X] ", CVAR_NONE, "Time/date format to use");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue