tweaked download rules to match mvdsv, by adding an allow_download_other cvar.

added log_enable_rcon (and enabled it by default), for feature parity with mvdsv. invalid requests, valid requests, and redirected prints are all logged.
tweaked server-side download code to not bug out with downloads larger than 2gb.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4697 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-06-24 03:02:32 +00:00
parent 1908310788
commit b1e3060648
12 changed files with 163 additions and 77 deletions

View file

@ -26,6 +26,7 @@ cvar_t cmd_maxbuffersize = SCVAR("cmd_maxbuffersize", "65536");
cvar_t dpcompat_set = SCVAR("dpcompat_set", "0");
int Cmd_ExecLevel;
qboolean cmd_didwait;
qboolean cmd_blockwait;
void Cmd_ForwardToServer (void);
@ -161,6 +162,9 @@ bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
*/
void Cmd_Wait_f (void)
{
if (cmd_blockwait)
return;
#ifndef CLIENTONLY
if (cmd_didwait && sv.state)
Con_DPrintf("waits without server frames\n");

View file

@ -55,6 +55,7 @@ void Cbuf_Execute (void);
// Normally called once per frame, but may be explicitly invoked.
// Do not call inside a command function!
extern qboolean cmd_blockwait;
void Cbuf_ExecuteLevel(int level);
//executes only a single cbuf level. can be used to restrict cbuf execution to some 'safe' set of commands, so there are no surprise 'map' commands.
//will not magically make all commands safe to exec, but will prevent user commands slipping in too.

View file

@ -570,6 +570,7 @@ void PO_Close(struct po_s *po);
typedef enum {
LOG_CONSOLE,
LOG_PLAYER,
LOG_RCON,
LOG_TYPES
} logtype_t;
void Log_Dir_Callback (struct cvar_s *var, char *oldvalue);

View file

@ -1051,7 +1051,7 @@ qboolean FS_GetPackageDownloadable(const char *package)
for (search = com_searchpaths ; search ; search = search->next)
{
if (!strcmp(package, search->purepath))
if (!Q_strcasecmp(package, search->purepath))
return !(search->flags & SPF_COPYPROTECTED);
}
return false;
@ -3944,6 +3944,10 @@ void FS_ChangeGame_f(void)
int i;
char *arg = Cmd_Argv(1);
//don't execute this if we're executing rcon commands, as this can change game directories.
if (cmd_blockwait)
return;
if (!*arg)
{
Con_Printf("Valid games are:\n");

View file

@ -5691,6 +5691,10 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end,
if (0)
{ //treat *ALL* tests against the actual geometry instead of using any brushes.
//also ignores the bsp etc. not fast. testing only.
trace_ispoint = trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0
&& trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0;
for (i = 0; i < mod->numsurfaces; i++)
{
CM_ClipBoxToMesh(trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, mod->surfaces[i].mesh);
@ -5699,6 +5703,9 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end,
else
if (0)
{
trace_ispoint = trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0
&& trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0;
for (i = 0; i < mod->numleafs; i++)
CM_TraceToLeaf(&mod->leafs[i]);
}

View file

@ -9,9 +9,12 @@ void Log_Name_Callback (struct cvar_s *var, char *oldvalue);
// cvars
#define CONLOGGROUP "Console logging"
cvar_t log_enable[LOG_TYPES] = { CVARF("log_enable", "0", CVAR_NOTFROMSERVER),
CVARF("log_enable_players", "0", CVAR_NOTFROMSERVER)};
CVARF("log_enable_players", "0", CVAR_NOTFROMSERVER),
CVARF("log_enable_rcon", "1", CVAR_NOTFROMSERVER)
};
cvar_t log_name[LOG_TYPES] = { CVARFC("log_name", "", CVAR_NOTFROMSERVER, Log_Name_Callback),
CVARFC("log_name_players", "", CVAR_NOTFROMSERVER, Log_Name_Callback)};
CVARFC("log_name_players", "", CVAR_NOTFROMSERVER, Log_Name_Callback),
CVARFC("log_name_rcon", "", CVAR_NOTFROMSERVER, Log_Name_Callback)};
cvar_t log_dir = CVARFC("log_dir", "", CVAR_NOTFROMSERVER, Log_Dir_Callback);
cvar_t log_readable = CVARFD("log_readable", "7", CVAR_NOTFROMSERVER, "Bitfield describing what to convert/strip. If 0, exact byte representation will be used.\n&1: Dequakify text.\n&2: Strip special markup.\n&4: Strip ansi control codes.");
cvar_t log_developer = CVARF("log_developer", "0", CVAR_NOTFROMSERVER);
@ -88,6 +91,9 @@ void Log_String (logtype_t lognum, char *s)
case LOG_PLAYER:
f = "players";
break;
case LOG_RCON:
f = "rcon";
break;
default:
break;
}

View file

@ -19,8 +19,11 @@
#define FTE_WORDSIZE 64
#define quintptr_t unsigned qintptr_t
#elif defined(_WIN32)
typedef __int32 qintptr_t; //add __w64 if you need msvc to shut up about unsafe type conversions
typedef unsigned __int32 quintptr_t;
#ifndef _MSC_VER
#define __w64
#endif
typedef __int32 __w64 qintptr_t; //add __w64 if you need msvc to shut up about unsafe type conversions
typedef unsigned __int32 __w64 quintptr_t;
// #define qintptr_t __int32
// #define quintptr_t unsigned qintptr_t
#define FTE_WORDSIZE 32

View file

@ -8837,6 +8837,14 @@
<File
RelativePath="..\client\in_generic.c"
>
<FileConfiguration
Name="Release Dedicated Server|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug Dedicated Server|Win32"
ExcludedFromBuild="true"
@ -11183,6 +11191,14 @@
<File
RelativePath="..\client\pr_clcmd.c"
>
<FileConfiguration
Name="Release Dedicated Server|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug Dedicated Server|Win32"
ExcludedFromBuild="true"
@ -16807,6 +16823,7 @@
</FileConfiguration>
<FileConfiguration
Name="Release Dedicated Server|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
@ -21320,7 +21337,6 @@
</FileConfiguration>
<FileConfiguration
Name="Release Dedicated Server|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"

View file

@ -457,11 +457,11 @@ typedef struct client_s
char downloadfn[MAX_QPATH];
vfsfile_t *download; // file being downloaded
unsigned int downloadsize; // total bytes
unsigned int downloadcount; // bytes sent
qofs_t downloadsize; // total bytes
qofs_t downloadcount; // bytes sent
int downloadacked; //DP-specific
int downloadstarted; //DP-specific
qofs_t downloadacked; //DP-specific
qofs_t downloadstarted; //DP-specific
int spec_track; // entnum of player tracking
@ -1161,7 +1161,7 @@ void SVM_Think(int port);
//
// svonly.c
//
typedef enum {RD_NONE, RD_CLIENT, RD_PACKET, RD_OBLIVION, RD_MASTER} redirect_t; //oblivion is provided so people can read the output before the buffer is wiped.
typedef enum {RD_NONE, RD_CLIENT, RD_PACKET, RD_PACKET_LOG, RD_OBLIVION, RD_MASTER} redirect_t; //oblivion is provided so people can read the output before the buffer is wiped.
void SV_BeginRedirect (redirect_t rd, int lang);
void SV_EndRedirect (void);

View file

@ -124,6 +124,7 @@ cvar_t allow_download_refpackages = CVARD("allow_download_refpackages", "1", "If
cvar_t allow_download_wads = CVAR("allow_download_wads", "1");
cvar_t allow_download_configs = CVAR("allow_download_configs", "0");
cvar_t allow_download_copyrighted = CVAR("allow_download_copyrighted", "0");
cvar_t allow_download_other = CVAR("allow_download_other", "0");
cvar_t sv_serverip = CVARD("sv_serverip", "", "Set this cvar to the server's public ip address if the server is behind a firewall and cannot detect its own public address. Providing a port is required if the firewall/nat remaps it, but is otherwise optional.");
cvar_t sv_public = CVAR("sv_public", "0");
@ -3697,6 +3698,7 @@ void SVC_RemoteCommand (void)
if (!Rcon_Validate ())
{
/*
#ifdef SVRANKING
if (cmd_allowaccess.value) //try and find a username, match the numeric password
{
@ -3727,7 +3729,7 @@ void SVC_RemoteCommand (void)
Con_TPrintf ("Rcon from %s:\n%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4);
SV_BeginRedirect (RD_PACKET, svs.language);
SV_BeginRedirect (RD_PACKET_LOG, svs.language);
remaining[0] = 0;
@ -3753,22 +3755,32 @@ void SVC_RemoteCommand (void)
}
}
#endif
*/
Con_TPrintf ("Bad rcon from %s:\n%s\n"
Log_String(LOG_RCON, va("Bad rcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4));
Con_TPrintf ("Bad rcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4);
SV_BeginRedirect (RD_PACKET, svs.language);
Con_TPrintf ("Bad rcon_password.\n");
Con_TPrintf ("Bad rcon_password. Passwords might be logged. Be careful.\n");
}
else
{
//make sure stuff is flushed
cmd_blockwait = true;
Cbuf_ExecuteLevel(rcon_level.ival);
cmd_blockwait = false;
Con_TPrintf ("Rcon from %s:\n%s\n"
Log_String(LOG_RCON, va("\n\nRcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4));
Con_TPrintf ("Rcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4);
SV_BeginRedirect (RD_PACKET, svs.language);
SV_BeginRedirect (RD_PACKET_LOG, svs.language);
remaining[0] = 0;
@ -3778,16 +3790,19 @@ void SVC_RemoteCommand (void)
{
Con_TPrintf("Rcon was too long\n");
SV_EndRedirect ();
Con_TPrintf ("Rcon from %s:\n%s\n"
Con_TPrintf ("Rcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), "Was too long - possible buffer overflow attempt");
return;
}
strcat (remaining, Cmd_Argv(i) );
strcat (remaining, " ");
Q_strncatz(remaining, Cmd_Argv(i), sizeof(remaining));
Q_strncatz(remaining, " ", sizeof(remaining));
}
Cmd_ExecuteString (remaining, rcon_level.ival);
//make sure the wait command can't be used to fuck up our logs.
cmd_blockwait = true;
Cbuf_AddText(remaining, rcon_level.ival);
Cbuf_ExecuteLevel(rcon_level.ival);
cmd_blockwait = false;
}
SV_EndRedirect ();
@ -5278,6 +5293,7 @@ void SV_InitLocal (void)
Cvar_Register (&allow_download_wads, cvargroup_serverpermissions);
Cvar_Register (&allow_download_root, cvargroup_serverpermissions);
Cvar_Register (&allow_download_copyrighted, cvargroup_serverpermissions);
Cvar_Register (&allow_download_other, cvargroup_serverpermissions);
Cvar_Register (&secure, cvargroup_serverpermissions);
Cvar_Register (&sv_highchars, cvargroup_servercontrol);

View file

@ -62,8 +62,12 @@ void SV_FlushRedirect (void)
Log_String(LOG_CONSOLE, va("{\n%s}\n", outputbuf));
if (sv_redirected == RD_PACKET)
if (sv_redirected == RD_PACKET || sv_redirected == RD_PACKET_LOG)
{
//log it to the rcon log if its not just a status response
if (sv_redirected == RD_PACKET_LOG)
Log_String(LOG_RCON, outputbuf);
send[0] = 0xff;
send[1] = 0xff;
send[2] = 0xff;

View file

@ -2007,7 +2007,7 @@ void SV_DarkPlacesDownloadAck(client_t *cl)
}
}
void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezfilenum)
static void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezfilenum, int chunks)
{
#define CHUNKSIZE 1024
char buffer[CHUNKSIZE];
@ -2015,16 +2015,20 @@ void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezfilenum)
sizebuf_t *msg, msg_oob;
int i;
int error = false;
//can't support this yet. at least forcing to 1 avoids too bad infinite loops. this can be a nasty dos attack on a server. if (chunks < 1)
chunks = 1;
msg = &host_client->datagram;
if (chunknum*CHUNKSIZE > host_client->downloadsize)
if (chunknum == -1)
error = 2; //silent, don't report it
else if (chunknum*CHUNKSIZE > host_client->downloadsize)
{
SV_ClientTPrintf (host_client, PRINT_HIGH, "Warning: Invalid file chunk requested %u to %u of %u.\n", chunknum*CHUNKSIZE, (chunknum+1)*CHUNKSIZE, host_client->downloadsize);
error = 2;
}
if (!error && VFS_SEEK (host_client->download, chunknum*CHUNKSIZE) == false)
if (!error && VFS_SEEK (host_client->download, (qofs_t)chunknum*CHUNKSIZE) == false)
error = true;
else
{
@ -2032,58 +2036,63 @@ void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezfilenum)
host_client->downloadcount = chunknum*CHUNKSIZE;
}
if ((host_client->datagram.cursize + CHUNKSIZE+5+50 > host_client->datagram.maxsize) || (host_client->datagram.cursize + CHUNKSIZE+5 > 1400))
while (!error && chunks > 0)
{
//would overflow the packet, or result in (ethernet) fragmentation and high packet loss.
msg = &msg_oob;
if ((host_client->datagram.cursize + CHUNKSIZE+5+50 > host_client->datagram.maxsize) || (host_client->datagram.cursize + CHUNKSIZE+5 > 1400))
{
//would overflow the packet, or result in (ethernet) fragmentation and high packet loss.
msg = &msg_oob;
if (!ezfilenum)
return;
if (!ezfilenum) //can't oob it
return;
if (host_client->waschoked)
return; //don't let chunked downloads flood out the standard packets.
if (host_client->waschoked)
return; //don't let chunked downloads flood out the standard packets.
if (!Netchan_CanPacket(&host_client->netchan, SV_RateForClient(host_client)))
return;
}
if (!Netchan_CanPacket(&host_client->netchan, SV_RateForClient(host_client)))
return;
}
if (error)
i = 0;
else
i = VFS_READ (host_client->download, buffer, CHUNKSIZE);
if (i > 0)
{
if (msg == &msg_oob)
if (i > 0)
{
msg = &msg_oob;
msg->cursize = 0;
msg->maxsize = sizeof(oobdata);
msg->currentbit = 0;
msg->packing = SZ_RAWBYTES;
msg->allowoverflow = 0;
msg->overflowed = 0;
msg->data = oobdata;
MSG_WriteByte(msg, A2C_PRINT);
SZ_Write(msg, "\\chunk", 6);
MSG_WriteLong(msg, ezfilenum); //echoing the file num is used so the packets don't go out of sync.
if (msg == &msg_oob)
{
msg = &msg_oob;
msg->cursize = 0;
msg->maxsize = sizeof(oobdata);
msg->currentbit = 0;
msg->packing = SZ_RAWBYTES;
msg->allowoverflow = 0;
msg->overflowed = 0;
msg->data = oobdata;
MSG_WriteByte(msg, A2C_PRINT);
SZ_Write(msg, "\\chunk", 6);
MSG_WriteLong(msg, ezfilenum); //echoing the file num is used so the packets don't go out of sync.
}
if (i != CHUNKSIZE)
memset(buffer+i, 0, CHUNKSIZE-i);
MSG_WriteByte(msg, svc_download);
MSG_WriteLong(msg, chunknum);
SZ_Write(msg, buffer, CHUNKSIZE);
if (msg == &msg_oob)
{
Netchan_OutOfBand(NS_SERVER, &host_client->netchan.remote_address, msg_oob.cursize, msg_oob.data);
Netchan_Block(&host_client->netchan, msg_oob.cursize, SV_RateForClient(host_client));
host_client->netchan.bytesout += msg_oob.cursize;
}
}
else if (i < 0)
error = true;
if (i != CHUNKSIZE)
memset(buffer+i, 0, CHUNKSIZE-i);
MSG_WriteByte(msg, svc_download);
MSG_WriteLong(msg, chunknum);
SZ_Write(msg, buffer, CHUNKSIZE);
if (msg == &msg_oob)
{
Netchan_OutOfBand(NS_SERVER, &host_client->netchan.remote_address, msg_oob.cursize, msg_oob.data);
Netchan_Block(&host_client->netchan, msg_oob.cursize, SV_RateForClient(host_client));
}
chunks--;
chunknum++;
}
else if (i < 0)
error = true;
if (error)
{
@ -2122,9 +2131,9 @@ void SV_NextDownload_f (void)
if (host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS)
{
if (Cmd_Argc() < 2)
SV_NextChunkedDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)), atoi(Cmd_Argv(3)));
SV_NextChunkedDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)), atoi(Cmd_Argv(3)), atoi(Cmd_Argv(4)));
else
SV_NextChunkedDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)), atoi(Cmd_Argv(3)));
SV_NextChunkedDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)), atoi(Cmd_Argv(3)), atoi(Cmd_Argv(4)));
return;
}
#endif
@ -2596,6 +2605,7 @@ qboolean SV_AllowDownload (const char *name)
extern cvar_t allow_download_root;
extern cvar_t allow_download_configs;
extern cvar_t allow_download_copyrighted;
extern cvar_t allow_download_other;
char cleanname[MAX_QPATH];
int i=0;
if (strlen(name) >= MAX_QPATH)
@ -2620,6 +2630,9 @@ qboolean SV_AllowDownload (const char *name)
if (strchr(name, '\\')) //no windows paths - grow up lame windows users.
return false;
if (!Q_strcasecmp("log", COM_FileExtension(name)))
return false;
if (!strncmp(name, "package/", 8))
{
if (!strcmp("pk4", COM_FileExtension(name)) || !strcmp("pk3", COM_FileExtension(name)) || !strcmp("pak", COM_FileExtension(name)))
@ -2677,12 +2690,13 @@ qboolean SV_AllowDownload (const char *name)
//root of gamedir
if (!strchr(name, '/') && !allow_download_root.value)
{
if (strcmp(name, "csprogs.dat")) //we always allow csprogs.dat to be downloaded (if downloads are permitted).
return false;
if (!strcmp(name, "csprogs.dat")) //we always allow csprogs.dat to be downloaded (if downloads are permitted).
return true;
return false;
}
//any other subdirs are allowed
return true;
return !!allow_download_other.value;;
}
static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementname, qboolean redirectpaks)
@ -3036,9 +3050,16 @@ void SV_BeginDownload_f(void)
host_client->download = tmp;
}
ClientReliableWrite_Begin (host_client, svc_download, 10+strlen(host_client->downloadfn));
ClientReliableWrite_Begin (host_client, svc_download, 18+strlen(host_client->downloadfn));
ClientReliableWrite_Long (host_client, -1);
ClientReliableWrite_Long (host_client, host_client->downloadsize);
if (host_client->downloadsize >= 0x7fffffff)
{ //avoid unsigned values.
ClientReliableWrite_Long (host_client, 0x80000000); //signal that its 64bit
ClientReliableWrite_Long (host_client, qofs_Low(host_client->downloadsize));
ClientReliableWrite_Long (host_client, qofs_High(host_client->downloadsize));
}
else
ClientReliableWrite_Long (host_client, host_client->downloadsize);
ClientReliableWrite_String (host_client, host_client->downloadfn);
}
else
@ -5333,8 +5354,11 @@ void SV_ExecuteUserCommand (char *s, qboolean fromQC)
return;
}
Log_String(LOG_RCON, va("cmd from %s - %s:\n%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), host_client->name, s));
Con_TPrintf ("cmd from %s:\n%s\n"
, host_client->name, net_message.data+4);
, host_client->name, s);
SV_BeginRedirect (RD_CLIENT, host_client->language);
@ -5351,8 +5375,8 @@ void SV_ExecuteUserCommand (char *s, qboolean fromQC)
, NET_AdrToString (adr, sizeof(adr), &net_from), "Was too long - possible buffer overflow attempt");
return;
}
strcat (remaining, Cmd_Argv(i) );
strcat (remaining, " ");
Q_strncatz(remaining, Cmd_Argv(i), sizeof(remaining));
Q_strncatz(remaining, " ", sizeof(remaining));
}
Cmd_ExecuteString (remaining, stats.trustlevel);