Author Topic: Subnet Bans.  (Read 11729 times)

==Troy==

  • Posts: 440
  • Turrets: +65/-67
Subnet Bans.
« 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.

Code: [Select]
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 );


« Last Edit: September 07, 2008, 02:46:41 pm by ==Troy== »

Rocinante

  • Posts: 642
  • Turrets: +252/-668
    • My Homepage
Re: Subnet Bans.
« Reply #1 on: September 05, 2008, 01:07:09 am »
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.
}MG{Mercenaries Guild
"On my ship, the Rocinante, wheeling through the galaxies, headed for the heart of Cygnus, headlong into mystery." -- Rush, "Cygnus X-1"

==Troy==

  • Posts: 440
  • Turrets: +65/-67
Re: Subnet Bans.
« Reply #2 on: September 05, 2008, 01:08:44 am »
Never liked the /XX subnet bans in any way :) Will fix in a moment

*fixed
« Last Edit: September 05, 2008, 01:13:39 am by ==Troy== »

Amanieu

  • Posts: 647
  • Turrets: +135/-83
    • Amanieu
Re: Subnet Bans.
« Reply #3 on: September 05, 2008, 02:50:04 am »
I was planning on doing that, but you beat me to it ;)
Quote
< kevlarman> zakk is getting his patches from shady frenchmen on irc
< kevlarman> this can't be a good sign :P

Undeference

  • Tremulous Developers
  • *
  • Posts: 1254
  • Turrets: +122/-45
Re: Subnet Bans.
« Reply #4 on: September 05, 2008, 10:02:00 am »
Already been done. 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, they have the potential to be more widely used.
Need help? Ask intelligently. Please share solutions you find.

Thats what we need, helpful players, not more powerful admins.

==Troy==

  • Posts: 440
  • Turrets: +65/-67
Re: Subnet Bans.
« Reply #5 on: September 05, 2008, 11:47:51 am »
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.
« Last Edit: September 05, 2008, 12:51:02 pm by ==Troy== »

Amanieu

  • Posts: 647
  • Turrets: +135/-83
    • Amanieu
Re: Subnet Bans.
« Reply #6 on: September 05, 2008, 01:48:07 pm »
Already been done.
That patch is broken and doesn't work.
Quote
< kevlarman> zakk is getting his patches from shady frenchmen on irc
< kevlarman> this can't be a good sign :P

Lakitu7

  • Tremulous Developers
  • *
  • Posts: 1002
  • Turrets: +120/-73
Re: Subnet Bans.
« Reply #7 on: September 05, 2008, 09:22:56 pm »

==Troy==

  • Posts: 440
  • Turrets: +65/-67
Re: Subnet Bans.
« Reply #8 on: September 06, 2008, 06:50:48 pm »
Updated the top post. Security issue fixed (thanks Lakitu). I strongly recommend to update if you were using the patch.

Lakitu7

  • Tremulous Developers
  • *
  • Posts: 1002
  • Turrets: +120/-73
Re: Subnet Bans.
« Reply #9 on: September 06, 2008, 06:52:59 pm »
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. :)

Lakitu7

  • Tremulous Developers
  • *
  • Posts: 1002
  • Turrets: +120/-73
Re: Subnet Bans.
« Reply #10 on: September 24, 2008, 11:29:07 pm »
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!