summaryrefslogtreecommitdiff
path: root/src/game/g_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/g_utils.c')
-rw-r--r--src/game/g_utils.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/src/game/g_utils.c b/src/game/g_utils.c
index 62fcc2a4..8b76704b 100644
--- a/src/game/g_utils.c
+++ b/src/game/g_utils.c
@@ -857,3 +857,192 @@ void G_CloseMenus( int clientNum )
Com_sprintf( buffer, 32, "serverclosemenus" );
trap_SendServerCommand( clientNum, buffer );
}
+
+
+/*
+===============
+G_AddressParse
+
+Make an IP address more usable
+===============
+*/
+static const char *addr4parse( const char *str, addr_t *addr )
+{
+ int i;
+ int octet = 0;
+ int num = 0;
+ memset( addr, 0, sizeof( addr_t ) );
+ addr->type = IPv4;
+ for( i = 0; octet < 4; i++ )
+ {
+ if( isdigit( str[ i ] ) )
+ num = num * 10 + str[ i ] - '0';
+ else
+ {
+ if( num < 0 || num > 255 )
+ return NULL;
+ addr->addr[ octet ] = (byte)num;
+ octet++;
+ if( str[ i ] != '.' || str[ i + 1 ] == '.' )
+ break;
+ num = 0;
+ }
+ }
+ if( octet < 1 )
+ return NULL;
+ return str + i;
+}
+
+static const char *addr6parse( const char *str, addr_t *addr )
+{
+ int i;
+ qboolean seen = qfalse;
+ /* keep track of the parts before and after the ::
+ it's either this or even uglier hacks */
+ byte a[ ADDRLEN ], b[ ADDRLEN ];
+ size_t before = 0, after = 0;
+ int num = 0;
+ /* 8 hexadectets unless :: is present */
+ for( i = 0; before + after <= 8; i++ )
+ {
+ //num = num << 4 | str[ i ] - '0';
+ if( isdigit( str[ i ] ) )
+ num = num * 16 + str[ i ] - '0';
+ else if( str[ i ] >= 'A' && str[ i ] <= 'F' )
+ num = num * 16 + 10 + str[ i ] - 'A';
+ else if( str[ i ] >= 'a' && str[ i ] <= 'f' )
+ num = num * 16 + 10 + str[ i ] - 'a';
+ else
+ {
+ if( num < 0 || num > 65535 )
+ return NULL;
+ if( i == 0 )
+ {
+ //
+ }
+ else if( seen ) // :: has been seen already
+ {
+ b[ after * 2 ] = num >> 8;
+ b[ after * 2 + 1 ] = num & 0xff;
+ after++;
+ }
+ else
+ {
+ a[ before * 2 ] = num >> 8;
+ a[ before * 2 + 1 ] = num & 0xff;
+ before++;
+ }
+ if( !str[ i ] )
+ break;
+ if( str[ i ] != ':' || i == 8 )
+ break;
+ if( str[ i + 1 ] == ':' )
+ {
+ // ::: or multiple ::
+ if( seen || str[ i + 2 ] == ':' )
+ break;
+ seen = qtrue;
+ i++;
+ }
+ else if( i == 0 ) // starts with : but not ::
+ return NULL;
+ num = 0;
+ }
+ }
+ if( seen )
+ {
+ // there have to be fewer than 8 hexadectets when :: is present
+ if( before + after == 8 )
+ return NULL;
+ }
+ else if( before + after < 8 ) // require exactly 8 hexadectets
+ return NULL;
+ memset( addr, 0, sizeof( addr_t ) );
+ addr->type = IPv6;
+ if( before )
+ memcpy( addr->addr, a, before * 2 );
+ if( after )
+ memcpy( addr->addr + ADDRLEN - 2 * after, b, after * 2 );
+ return str + i;
+}
+
+qboolean G_AddressParse( const char *str, addr_t *addr, int *netmask )
+{
+ const char *p;
+ int max;
+ if( strchr( str, ':' ) )
+ {
+ p = addr6parse( str, addr );
+ max = 128;
+ }
+ else
+ {
+ p = addr4parse( str, addr );
+ max = 32;
+ }
+ if( !p )
+ return qfalse;
+ if( *p == '/' )
+ {
+ if( netmask )
+ {
+ *netmask = atoi( p + 1 );
+ if( *netmask < 1 || *netmask > max )
+ *netmask = max;
+ }
+ }
+ else if( *p )
+ return qfalse;
+ return qtrue;
+}
+
+/*
+===============
+G_AddressCompare
+
+Based largely on NET_CompareBaseAdrMask from ioq3 revision 1557
+===============
+*/
+qboolean G_AddressCompare( const addr_t *a, const addr_t *b, int netmask )
+{
+ int i;
+ if( a->type != b->type )
+ return qfalse;
+ if( a->type == IPv4 )
+ {
+ if( netmask < 1 || netmask > 32 )
+ netmask = 32;
+ }
+ else if( a->type == IPv6 )
+ {
+ if( netmask < 1 || netmask > 128 )
+ netmask = 128;
+ }
+ for( i = 0; netmask > 7; i++, netmask -= 8 )
+ if( a->addr[ i ] != b->addr[ i ] )
+ return qfalse;
+ if( netmask )
+ {
+ netmask = ( ( 1 << netmask ) - 1 ) << ( 8 - netmask );
+ return ( a->addr[ i ] & netmask ) == ( b->addr[ i ] & netmask );
+ }
+ return qtrue;
+}
+
+/*
+===============
+G_AdrCmpStr
+
+The first argument may be in CIDR notation
+===============
+*/
+qboolean G_AdrCmpStr( const char *a, const char *b )
+{
+ int netmask = -1;
+ addr_t cmpa, cmpb;
+ if( !G_AddressParse( a, &cmpa, &netmask ) )
+ return qfalse;
+ if( !G_AddressParse( b, &cmpb, NULL ) )
+ return qfalse;
+ return G_AddressCompare( &cmpa, &cmpb, netmask );
+}