diff options
Diffstat (limited to 'src/game/g_utils.c')
-rw-r--r-- | src/game/g_utils.c | 189 |
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 ); +} |