Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added "rconwhitelist.dat" file for restricting RCON commands to fixed…

… IPs/CIDRs address.
  • Loading branch information...
commit ac5527cb3cb7ab7fadab783a62a2ba75a43739af 1 parent 99a5e00
@TheDushan authored
View
2  src/engine/qcommon/qcommon.h
@@ -203,7 +203,7 @@ void NET_FlushPacketQueue(void);
void NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t to );
void QDECL NET_OutOfBandPrint( netsrc_t net_socket, netadr_t adr, const char *format, ... ) __attribute__((format(printf, 3, 4)));
void QDECL NET_OutOfBandData( netsrc_t sock, netadr_t adr, byte *format, int len );
-
+qboolean NET_CompareBaseAdrMask(netadr_t a, netadr_t b, int netmask);
qboolean NET_CompareAdr( netadr_t a, netadr_t b );
qboolean NET_CompareBaseAdr( netadr_t a, netadr_t b );
qboolean NET_IsLocalAddress( netadr_t adr );
View
16 src/engine/server/server.h
@@ -364,6 +364,16 @@ typedef struct
int queryDone;
} serverStatic_t;
+// Structure for managing rcons
+typedef struct
+{
+ netadr_t ip;
+ // For a CIDR-Notation type suffix
+ int subnet;
+
+ qboolean isexception;
+} serverRcon_t;
+
#if defined (UPDATE_SERVER)
typedef struct {
@@ -428,6 +438,8 @@ extern convar_t *sv_showAverageBPS; // NERVE - SMF - net debugging
extern convar_t *sv_requireValidGuid;
+extern convar_t *sv_WhiteListRcon;
+
extern convar_t *sv_ircchannel;
extern convar_t *g_gameType;
@@ -464,6 +476,10 @@ extern convar_t *sv_voip;
extern convar_t *sv_IPmaxGetstatusPerSecond;
+#define MAX_RCON_WHITELIST 32
+extern serverRcon_t rconWhitelist[MAX_RCON_WHITELIST];
+extern int rconWhitelistCount;
+
//===========================================================
//
View
107 src/engine/server/sv_ccmds.cpp
@@ -510,6 +510,112 @@ static void SV_MapRestart_f(void) {
}
/*
+==================
+SV_RehashServerRconFile
+
+Helper to reload a "serverRcon_t" type of file
+Returns number of entries loaded
+==================
+*/
+static int SV_RehashServerRconFile(convar_t *fileName, int maxEntries, serverRcon_t buffer[])
+{
+ int index, filelen, numEntries = 0;
+ fileHandle_t readfrom;
+ char *textbuf, *curpos, *maskpos, *newlinepos, *endpos, filepath[MAX_QPATH];
+
+ if(!fileName->string || !*fileName->string)
+ {
+ goto exit;
+ }
+
+ if(!(curpos = Cvar_VariableString("fs_game")) || !*curpos)
+ {
+ curpos = BASEGAME;
+ }
+
+ Com_sprintf(filepath, sizeof(filepath), "%s/%s", curpos, fileName->string);
+
+ if((filelen = FS_SV_FOpenFileRead(filepath, &readfrom)) < 0)
+ {
+ Com_Printf("SV_RehashServerRconFile: failed to open %s\n", filepath);
+ goto exit;
+ }
+
+ if(filelen < 2)
+ {
+ // Don't bother if file is too short.
+ FS_FCloseFile(readfrom);
+ goto exit;
+ }
+
+ curpos = textbuf = (char*)Z_Malloc(filelen);
+
+ filelen = FS_Read(textbuf, filelen, readfrom);
+ FS_FCloseFile(readfrom);
+
+ endpos = textbuf + filelen;
+
+ for(index = 0; index < maxEntries && curpos + 2 < endpos; index++)
+ {
+ // find the end of the address string
+ for(maskpos = curpos + 2; maskpos < endpos && *maskpos != ' '; maskpos++);
+
+ if(maskpos + 1 >= endpos)
+ {
+ break;
+ }
+
+ *maskpos = '\0';
+ maskpos++;
+
+ // find the end of the subnet specifier
+ for(newlinepos = maskpos; newlinepos < endpos && *newlinepos != '\n'; newlinepos++);
+
+ if(newlinepos >= endpos)
+ {
+ break;
+ }
+
+ *newlinepos = '\0';
+
+ if(NET_StringToAdr(curpos + 2, &buffer[index].ip, NA_UNSPEC))
+ {
+ buffer[index].isexception = (qboolean)(curpos[0] != '0');
+ buffer[index].subnet = atoi(maskpos);
+
+ if(buffer[index].ip.type == NA_IP && (buffer[index].subnet < 1 || buffer[index].subnet > 32))
+ {
+ buffer[index].subnet = 32;
+ }
+ else if(buffer[index].ip.type == NA_IP6 && (buffer[index].subnet < 1 || buffer[index].subnet > 128))
+ {
+ buffer[index].subnet = 128;
+ }
+ }
+
+ curpos = newlinepos + 1;
+ }
+
+ Z_Free(textbuf);
+ numEntries = index;
+
+exit:
+ return numEntries;
+}
+
+/*
+==================
+SV_RehashRconWhitelist_f
+
+Load RCON whitelist from file.
+==================
+*/
+static void SV_RehashRconWhitelist_f(void)
+{
+ rconWhitelistCount = SV_RehashServerRconFile(sv_WhiteListRcon, MAX_RCON_WHITELIST, rconWhitelist);
+}
+
+/*
=================
SV_LoadGame_f
=================
@@ -895,4 +1001,5 @@ void SV_AddOperatorCommands(void) {
if(com_dedicated->integer) {
Cmd_AddCommand("say", SV_ConSay_f, "^1Say something to everyone on the server.");
}
+ Cmd_AddCommand("rehashrconwhitelist", SV_RehashRconWhitelist_f, "^1Load RCON whitelist from file.");
}
View
2  src/engine/server/sv_init.cpp
@@ -1052,6 +1052,8 @@ void SV_Init(void) {
sv_requireValidGuid = Cvar_Get ("sv_requireValidGuid", "0", CVAR_ARCHIVE, "test" );
+ sv_WhiteListRcon = Cvar_Get ("sv_WhiteListRcon", "rconwhitelist.dat", CVAR_ARCHIVE, "^1Restrict rcon commands to fixed IPs/CIDRs address." );
+
// initialize bot cvars so they arelisted and can be set before loading the botlib
SV_BotInitCvars();
View
63 src/engine/server/sv_main.cpp
@@ -107,6 +107,9 @@ convar_t *sv_wwwBaseURL; // base URL for redirect
convar_t *sv_wwwDlDisconnected;
convar_t *sv_wwwFallbackURL; // URL to send to if an http/ftp fails or is refused client side
+convar_t *sv_WhiteListRcon; // file containing IP addresses allowed to execute RCON commands, default
+ // "whitelist.dat" (use "" to disable)
+
//bani
convar_t *sv_cheats;
convar_t *sv_packetloss;
@@ -115,6 +118,9 @@ convar_t *sv_packetdelay;
// fretn
convar_t *sv_fullmsg;
+serverRcon_t rconWhitelist[MAX_RCON_WHITELIST];
+int rconWhitelistCount = 0;
+
void SVC_GameCompleteStatus(netadr_t from); // NERVE - SMF
#define LL( x ) x = LittleLong( x )
@@ -992,6 +998,50 @@ qboolean SV_CheckDRDoS(netadr_t from) {
}
/*
+==================
+SV_IsRconWhitelisted
+
+Check whether a certain address is RCON whitelisted
+==================
+*/
+
+static qboolean SV_IsRconWhitelisted(netadr_t *from)
+{
+ int index;
+ serverRcon_t *curban;
+
+ for(index = 0; index < rconWhitelistCount; index++)
+ {
+ curban = &rconWhitelist[index];
+
+ if(NET_CompareBaseAdrMask(curban->ip, *from, curban->subnet))
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+static void SV_DropClientsByAddress(netadr_t *drop, const char *reason)
+{
+ int i;
+ client_t *cl;
+
+ // for all clients
+ for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++) {
+ // skip free slots
+ if (cl->state == CS_FREE) {
+ continue;
+ }
+ // skip other addresses
+ if (!NET_CompareBaseAdr(*drop, cl->netchan.remoteAddress)) {
+ continue;
+ }
+ // address matches, drop this one
+ SV_DropClient(cl, reason);
+ }
+}
+
+/*
===============
SVC_RemoteCommand
@@ -1016,6 +1066,19 @@ void SVC_RemoteCommand(netadr_t from, msg_t * msg) {
// TTimo - show_bug.cgi?id=534
time = Com_Milliseconds();
+
+ // Do we have a whitelist for rcon?
+ if(sv_WhiteListRcon->string && *sv_WhiteListRcon->string) {
+ // Prevent use of rcon from addresses that have not been whitelisted
+ if(!SV_IsRconWhitelisted(&from))
+ {
+ Com_Printf( "SVC_RemoteCommand: attempt from %s who is not whitelisted\n", NET_AdrToString( from ) );
+ NET_OutOfBandPrint(NS_SERVER, from, "print\nClient not found whitelist data.\n");
+ SV_DropClientsByAddress(&from, "Client tried to access to RCON password.");
+ return;
+ }
+ }
+
if ( !strlen( sv_rconPassword->string ) || strcmp (Cmd_Argv(1), sv_rconPassword->string) ) {
// MaJ - If the rconpassword is bad and one just happned recently, don't spam the log file, just die.
if ( (unsigned)( time - lasttime ) < 500u ) {
Please sign in to comment.
Something went wrong with that request. Please try again.