mirror of
https://git.code.sf.net/p/quake/newtree
synced 2024-11-22 12:11:34 +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
|
||||||
|
|
125
source/sv_main.c
125
source/sv_main.c
|
@ -62,10 +62,23 @@ 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
|
||||||
cvar_t *sv_maxtic; // physics time tic
|
cvar_t *sv_maxtic; // physics time tic
|
||||||
|
|
||||||
cvar_t *developer; // show extra messages
|
cvar_t *developer; // show extra messages
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -464,8 +557,8 @@ void SVC_Log (void)
|
||||||
|
|
||||||
//sprintf (data, "stdlog %i\n", svs.logsequence-1);
|
//sprintf (data, "stdlog %i\n", svs.logsequence-1);
|
||||||
//strcat (data, (char *)svs.log_buf[((svs.logsequence-1)&1)]);
|
//strcat (data, (char *)svs.log_buf[((svs.logsequence-1)&1)]);
|
||||||
snprintf (data, sizeof(data), "stdlog %i\n%s",
|
snprintf (data, sizeof(data), "stdlog %i\n%s",
|
||||||
svs.logsequence-1,
|
svs.logsequence-1,
|
||||||
(char *)svs.log_buf[((svs.logsequence-1)&1)]);
|
(char *)svs.log_buf[((svs.logsequence-1)&1)]);
|
||||||
|
|
||||||
NET_SendPacket (strlen(data)+1, data, net_from);
|
NET_SendPacket (strlen(data)+1, data, net_from);
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -705,7 +804,7 @@ void SVC_DirectConnect (void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// build a new connection
|
// build a new connection
|
||||||
// accept the new client
|
// accept the new client
|
||||||
// this is the only place a client_t is ever initialized
|
// this is the only place a client_t is ever initialized
|
||||||
|
@ -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"
|
||||||
|
@ -878,7 +978,7 @@ void SV_ConnectionlessPacket (void)
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
||||||
PACKET FILTERING
|
PACKET FILTERING
|
||||||
|
|
||||||
|
|
||||||
You can add or remove addresses from the filter list with:
|
You can add or remove addresses from the filter list with:
|
||||||
|
|
||||||
|
@ -1076,11 +1176,13 @@ 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;
|
||||||
strcat (data, "\nbanned.\n");
|
strcat (data, "\nbanned.\n");
|
||||||
|
|
||||||
NET_SendPacket (strlen(data), data, net_from);
|
NET_SendPacket (strlen(data), data, net_from);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1132,7 +1234,7 @@ void SV_ReadPackets (void)
|
||||||
SV_ConnectionlessPacket ();
|
SV_ConnectionlessPacket ();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the qport out of the message so we can fix up
|
// read the qport out of the message so we can fix up
|
||||||
// stupid address translating routers
|
// stupid address translating routers
|
||||||
MSG_BeginReading ();
|
MSG_BeginReading ();
|
||||||
|
@ -1207,7 +1309,7 @@ void SV_CheckTimeouts (void)
|
||||||
cl->state = cs_free; // don't bother with zombie state
|
cl->state = cs_free; // don't bother with zombie state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cl->state == cs_zombie &&
|
if (cl->state == cs_zombie &&
|
||||||
realtime - cl->connection_started > zombietime->value)
|
realtime - cl->connection_started > zombietime->value)
|
||||||
{
|
{
|
||||||
cl->state = cs_free; // can now be reused
|
cl->state = cs_free; // can now be reused
|
||||||
|
@ -1393,11 +1495,16 @@ 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");
|
||||||
|
|
||||||
filterban = Cvar_Get("filterban", "1", CVAR_NONE, "None");
|
filterban = Cvar_Get("filterban", "1", CVAR_NONE, "None");
|
||||||
|
|
||||||
allow_download = Cvar_Get("allow_download", "1", CVAR_NONE, "None");
|
allow_download = Cvar_Get("allow_download", "1", CVAR_NONE, "None");
|
||||||
allow_download_skins = Cvar_Get("allow_download_skins", "1", CVAR_NONE, "None");
|
allow_download_skins = Cvar_Get("allow_download_skins", "1", CVAR_NONE, "None");
|
||||||
allow_download_models = Cvar_Get("allow_download_models", "1", CVAR_NONE, "None");
|
allow_download_models = Cvar_Get("allow_download_models", "1", CVAR_NONE, "None");
|
||||||
|
|
Loading…
Reference in a new issue