Tremulous Forum
Mods => Mod Releases => Non-Gameplay Changing => Topic started by: ==Troy== on September 05, 2008, 01:02:17 am
-
A diff from latest Lakitu.
This tiny patch enables proper subnet bans for the admin.dat
As you know that IP adress is made out of 4 bytes, each byte has 8 bits, making a total of 32 bits of the IP adress.
The subnet mask is the number of non-variable bits from the start of the IP adress, so mask /30 will mean that 2 last bits vary.
The patch is compatable will earlier admin.dat structure.
At the moment I am wroking on in-game interface for the subnet bans. And currently you have to edit the admin.dat manually.
To ban a subnet add /number to the IP adress in the admin.dat
1.2.3.4/24 will ban IP range 1.2.3.0 - 1.2.3.255
Update :
!subnetban is used in the similar way as !adjustban and can add subnetmask to the banned IP adress. You are required to have flag "E" to be able to operate the function.
Whitelist, ANY admin with a flag "W" will be able to connect to the server, even if his IP/IPrange is banned. On the other hand, if his guid is specifically banned, the whitelist flag will not help.
Edit : as I said, the patch is 100% forward compatable. But of course there is no backward compatability (other than manually removing /XX mask from IP adresses). Make backup of the admin.dat before installing.
Index: src/game/g_admin.c
===================================================================
--- src/game/g_admin.c (revision 97)
+++ src/game/g_admin.c (working copy)
@@ -44,7 +44,13 @@
" or seconds if no units are specified",
"[^3ban#^7] (^5time^7) (^5reason^7)"
},
-
+
+ {"subnetban", G_admin_subnetban, "E",
+ "Add the subnet mask to the ban "
+ "[^3ban#^7] (^5mask^7)"
+ "mask values 0 or 32 remove the subnet"
+ },
+
{"admintest", G_admin_admintest, "a",
"display your current admin level",
""
@@ -288,19 +294,17 @@
g_admin_command_t *g_admin_commands[ MAX_ADMIN_COMMANDS ];
g_admin_namelog_t *g_admin_namelog[ MAX_ADMIN_NAMELOGS ];
-qboolean G_admin_permission( gentity_t *ent, char flag )
+qboolean G_admin_permission_guid( char *guid, char flag )
{
int i;
int l = 0;
char *flags;
- // console always wins
- if( !ent )
- return qtrue;
+ if(!guid) return qfalse; // since there is a different check for console, here we are just returning false.
for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ )
{
- if( !Q_stricmp( ent->client->pers.guid, g_admin_admins[ i ]->guid ) )
+ if( !Q_stricmp( guid, g_admin_admins[ i ]->guid ) )
{
flags = g_admin_admins[ i ]->flags;
while( *flags )
@@ -378,6 +382,15 @@
return qfalse;
}
+
+qboolean G_admin_permission( gentity_t *ent, char flag )
+{
+ if(!ent) return qtrue; //console always wins
+ if(!ent->client->pers.guid) return qfalse; //if we have no guid, and we are not console, we lose.
+
+ return G_admin_permission_guid(ent->client->pers.guid, flag);
+}
+
qboolean G_admin_name_check( gentity_t *ent, char *name, char *err, int len )
{
int i;
@@ -1115,8 +1128,10 @@
char ip[ 16 ];
char *value;
int i;
+ int userIP = 0, intIP = 0, IP[5], k, tempIP, mask;
int t;
char notice[51];
+ qboolean ignoreIP = qfalse;
trap_Cvar_VariableStringBuffer( "g_banNotice", notice, sizeof( notice ) );
@@ -1137,49 +1152,76 @@
value = Info_ValueForKey( userinfo, "cl_guid" );
Q_strncpyz( guid, value, sizeof( guid ) );
-
+
t = trap_RealTime( NULL );
+ sscanf(ip, "%i.%i.%i.%i", &IP[4], &IP[3], &IP[2], &IP[1]);
+ for(k = 4; k >= 1; k--)
+ {
+ if(!IP[k]) continue;
+ userIP |= IP[k] << 8*(k-1);
+ }
+ ignoreIP = G_admin_permission_guid( guid , 'W');
for( i = 0; i < MAX_ADMIN_BANS && g_admin_bans[ i ]; i++ )
{
// 0 is for perm ban
if( g_admin_bans[ i ]->expires != 0 &&
( g_admin_bans[ i ]->expires - t ) < 1 )
continue;
- if( strstr( ip, g_admin_bans[ i ]->ip ) == ip )
- {
- char duration[ 32 ];
- G_admin_duration( ( g_admin_bans[ i ]->expires - t ),
- duration, sizeof( duration ) );
+ if( !ignoreIP )
+ {
+ tempIP = userIP;
+ intIP = 0;
+ mask = 0;
+ sscanf(g_admin_bans[ i ]->ip, "%i.%i.%i.%i/%i", &IP[4], &IP[3], &IP[2], &IP[1], &IP[0]);
+ if(IP[0]) mask = IP[0]; else mask = 0;
+ for(k = 4; k >= 1; k--)
+ {
+ if(!IP[k]) continue;
+ intIP |= IP[k] << 8*(k-1);
+ }
- // flood protected
- if( t - lastConnectTime >= 300 ||
- Q_stricmp( lastConnectIP, ip ) )
- {
- lastConnectTime = t;
- Q_strncpyz( lastConnectIP, ip, sizeof( lastConnectIP ) );
+ if(mask > 0 && mask <= 32)
+ {
+ tempIP &= ~((1 << (32-mask)) - 1); // fixme can overflow
+ intIP &= ~((1 << (32-mask)) - 1);
+ }
- G_AdminsPrintf(
- "Banned player %s^7 (%s^7) tried to connect (ban #%i by %s^7 expires %s reason: %s^7 )\n",
- Info_ValueForKey( userinfo, "name" ),
- g_admin_bans[ i ]->name,
- i+1,
- g_admin_bans[ i ]->banner,
- duration,
- g_admin_bans[ i ]->reason );
- }
-
- Com_sprintf(
- reason,
- rlen,
- "You have been banned by %s^7 reason: %s^7 expires: %s %s",
- g_admin_bans[ i ]->banner,
- g_admin_bans[ i ]->reason,
- duration,
- notice
- );
- G_LogPrintf("Banned player tried to connect from IP %s\n", ip);
- return qtrue;
- }
+ if( intIP == tempIP )
+ {
+ char duration[ 32 ];
+ G_admin_duration( ( g_admin_bans[ i ]->expires - t ),
+ duration, sizeof( duration ) );
+
+ // flood protected
+ if( t - lastConnectTime >= 300 ||
+ Q_stricmp( lastConnectIP, ip ) )
+ {
+ lastConnectTime = t;
+ Q_strncpyz( lastConnectIP, ip, sizeof( lastConnectIP ) );
+
+ G_AdminsPrintf(
+ "Banned player %s^7 (%s^7) tried to connect (ban #%i by %s^7 expires %s reason: %s^7 )\n",
+ Info_ValueForKey( userinfo, "name" ),
+ g_admin_bans[ i ]->name,
+ i+1,
+ g_admin_bans[ i ]->banner,
+ duration,
+ g_admin_bans[ i ]->reason );
+ }
+
+ Com_sprintf(
+ reason,
+ rlen,
+ "You have been banned by %s^7 reason: %s^7 expires: %s %s",
+ g_admin_bans[ i ]->banner,
+ g_admin_bans[ i ]->reason,
+ duration,
+ notice
+ );
+ G_LogPrintf("Banned player tried to connect from IP %s\n", ip);
+ return qtrue;
+ }
+ }
if( *guid && !Q_stricmp( g_admin_bans[ i ]->guid, guid ) )
{
char duration[ 32 ];
@@ -2245,6 +2287,97 @@
return qtrue;
}
+
+qboolean G_admin_subnetban( gentity_t *ent, int skiparg )
+{
+ int bnum;
+ int mask;
+ int IPRlow = 0, IPRhigh = 0;
+ char cIPRlow[ 32 ], cIPRhigh[ 32 ];
+ char bs[ 5 ];
+ char strmask[ 5 ];
+ char exl[2];
+ int k, IP[5];
+
+ if( G_SayArgc() < 3 + skiparg )
+ {
+ ADMP( "^3!subnetban: ^7usage: !subnetban [ban#] [mask]\n" );
+ return qfalse;
+ }
+ G_SayArgv( 1 + skiparg, bs, sizeof( bs ) );
+ bnum = atoi( bs );
+ if( bnum < 1 || bnum > MAX_ADMIN_BANS || !g_admin_bans[ bnum - 1] )
+ {
+ ADMP( "^3!adjustban: ^7invalid ban#\n" );
+ return qfalse;
+ }
+
+ G_SayArgv( 2 + skiparg, strmask, sizeof( strmask ) );
+ mask = atoi( strmask );
+
+ if( mask >= 0 && mask <= 32)
+ {
+ G_SayArgv( 3 + skiparg, exl, sizeof( exl ) );
+ if(mask > 0 && mask <= 16 && strcmp(exl, "!"))
+ {
+ ADMP( "^3!subnetban: ^1WARNING :^2 you are about to ban a large network, use !subnetban [ban] [mask] ! to force^7\n" );
+ return qfalse;
+ }
+ else
+ {
+ sscanf(g_admin_bans[ bnum - 1 ]->ip, "%i.%i.%i.%i/%i", &IP[4], &IP[3], &IP[2], &IP[1], &IP[0]);
+ for(k = 4; k >= 1; k--)
+ {
+ if(!IP[k]) IP[k] = 0;
+ IPRlow |= IP[k] << 8*(k-1);
+ }
+ IPRhigh = IPRlow;
+ if( mask == 0 || mask == 32)
+ {
+ Q_strncpyz( g_admin_bans[ bnum - 1 ]->ip,
+ va("%i.%i.%i.%i", IP[4], IP[3], IP[2], IP[1]),
+ sizeof( g_admin_bans[ bnum - 1 ]->ip ) );
+ }
+ else
+ {
+
+ Q_strncpyz( g_admin_bans[ bnum - 1 ]->ip,
+ va("%i.%i.%i.%i/%i", IP[4], IP[3], IP[2], IP[1], mask ),
+ sizeof( g_admin_bans[ bnum - 1 ]->ip ) );
+ IPRlow &= ~((1 << (32-mask)) - 1);
+ IPRhigh |= ((1 << (32-mask)) - 1);
+ }
+ }
+ }
+ else
+ {
+ ADMP( "^3!subnetban: ^7mask is out of range, please use 0-32 including\n" );
+ return qfalse;
+ }
+ Q_strncpyz( cIPRlow,
+ va("%i.%i.%i.%i", (IPRlow & (255 << 24)) >> 24, (IPRlow & (255 << 16)) >> 16, (IPRlow & (255 << 8)) >> 8, IPRlow & 255),
+ sizeof( cIPRlow ) );
+ Q_strncpyz( cIPRhigh,
+ va("%i.%i.%i.%i", (IPRhigh & (255 << 24)) >> 24, (IPRhigh & (255 << 16)) >> 16, (IPRhigh & (255 << 8)) >> 8, IPRhigh & 255),
+ sizeof( cIPRhigh ) );
+
+ AP( va( "print \"^3!subnetban: ^7ban #%d for %s^7 has been updated by %s^7 "
+ "%s (%s - %s)\n\"",
+ bnum,
+ g_admin_bans[ bnum - 1 ]->name,
+ ( ent ) ? G_admin_adminPrintName( ent ) : "console",
+ g_admin_bans[ bnum - 1 ]->ip,
+ cIPRlow,
+ cIPRhigh) );
+ if( ent )
+ Q_strncpyz( g_admin_bans[ bnum - 1 ]->banner, ent->client->pers.netname,
+ sizeof( g_admin_bans[ bnum - 1 ]->banner ) );
+ if( g_admin.string[ 0 ] )
+ admin_writeconfig();
+ return qtrue;
+}
+
+
qboolean G_admin_unban( gentity_t *ent, int skiparg )
{
int bnum;
Index: src/game/g_admin.h
===================================================================
--- src/game/g_admin.h (revision 97)
+++ src/game/g_admin.h (working copy)
@@ -159,6 +159,7 @@
qboolean G_admin_setlevel( gentity_t *ent, int skiparg );
qboolean G_admin_kick( gentity_t *ent, int skiparg );
qboolean G_admin_adjustban( gentity_t *ent, int skiparg );
+qboolean G_admin_subnetban( gentity_t *ent, int skiparg );
qboolean G_admin_ban( gentity_t *ent, int skiparg );
qboolean G_admin_unban( gentity_t *ent, int skiparg );
qboolean G_admin_putteam( gentity_t *ent, int skiparg );
-
1.2.3.4/8 will ban IP range 1.2.3.0 - 1.2.3.255
Uh.. if you're aiming for CIDR format, 1.2.3.0 - 1.2.3.255 would be 1.2.3.0/24. 1.2.3.0/8 would be 1.0.0.0 - 1.255.255.255.
-
Never liked the /XX subnet bans in any way :) Will fix in a moment
*fixed
-
I was planning on doing that, but you beat me to it ;)
-
Already been done (http://patches.mercenariesguild.net/index.php?do=details&task_id=136). Make it support IPv6 addresses as well and it will be more useful.
By the way, if you make patches against upstream revisions and put them in a useful place (http://bugzilla.icculus.org/), they have the potential to be more widely used.
-
To be honest this place is much better for normal discussion. I never knew that it was implemented, as most of other people here (otherwise it would have been noticed). And subnet bans is a DO WANT thing.
TODO:
IPv6
Edit : whitelist/!subnetban updated in the top post.
Edit2 : I am not a fan of reworking someone else's patch, and moreover I prefer sscanf, since it will be easier to add IPv6 with it.
-
Already been done (http://patches.mercenariesguild.net/index.php?do=details&task_id=136).
That patch is broken and doesn't work.
-
Already been done (http://patches.mercenariesguild.net/index.php?do=details&task_id=136).
That patch is broken and doesn't work.
Confirming.
-
Updated the top post. Security issue fixed (thanks Lakitu). I strongly recommend to update if you were using the patch.
-
Updated the top post. Security issue fixed (thanks Lakitu). I strongly recommend to update if you were using the patch.
Well, I was just forwarding things from kevlarman. :)
-
http://source.mercenariesguild.net/lakitu7-qvm?view=rev&revision=106
After some major formatting changes and minor functionality changes, I have integrated this into the development versions of my game.qvm. Please read all of the above release notes if you plan to beta test it. Enjoy!