From c19474d27141e2f27b8838f159ec56d7d137c050 Mon Sep 17 00:00:00 2001 From: TimeServ Date: Mon, 22 May 2006 22:51:14 +0000 Subject: [PATCH] fixed sw build, fixed server banning, banip works properly and accepts the format x.x.x.x/n and x.x.x.x/x.x.x.x, added unban and banlist git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2294 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/renderer.c | 2 +- engine/common/net.h | 5 + engine/common/net_wins.c | 317 +++++++++++++++++++++++++++++++++++++++ engine/gl/gl_rmain.c | 1 - engine/server/server.h | 2 +- engine/server/sv_ccmds.c | 140 +++++++++++++---- engine/server/sv_main.c | 27 +--- 7 files changed, 440 insertions(+), 54 deletions(-) diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 3f0e3b78d..3d02c0dfd 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -210,7 +210,7 @@ extern cvar_t r_waterwarp; extern cvar_t r_fullbright; extern cvar_t r_shadows; extern cvar_t r_mirroralpha; -extern cvar_t r_wateralpha; +cvar_t r_wateralpha = SCVAR("r_wateralpha","1"); cvar_t r_dynamic = SCVARF("r_dynamic","1", CVAR_ARCHIVE); cvar_t r_flashblend = SCVARF("gl_flashblend","0", CVAR_ARCHIVE); cvar_t r_lightstylesmooth = SCVAR("r_lightstylesmooth", "0"); diff --git a/engine/common/net.h b/engine/common/net.h index e24cb0a3a..88f0b3474 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -84,6 +84,11 @@ qboolean NET_IsClientLegal(netadr_t *adr); qboolean NET_IsLoopBackAddress (netadr_t adr); +qboolean NET_StringToAdrMasked (char *s, netadr_t *a, netadr_t *amask); +char *NET_AdrToStringMasked (netadr_t a, netadr_t amask); +void NET_IntegerToMask (netadr_t *a, netadr_t *amask, int bits); +qboolean NET_CompareAdrMasked(netadr_t a, netadr_t b, netadr_t mask); + //============================================================================ #define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG) diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 075b6d182..e2ef97551 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -575,6 +575,323 @@ qboolean NET_StringToAdr (char *s, netadr_t *a) return true; } +// NET_IntegerToMask: given a source address pointer, a mask address pointer, and +// desired number of bits, fills the mask pointer with given bits +// (bits < 0 will always fill all bits) +void NET_IntegerToMask (netadr_t *a, netadr_t *amask, int bits) +{ + int i; + qbyte *n; + + memset (amask, 0, sizeof(*amask)); + amask->type = a->type; + + if (bits < 0) + i = 8000; // fill all bits + else + i = bits; + + switch (amask->type) + { +#ifdef USEIPX + case NA_IPX: + case NA_BROADCAST_IPX: + n = amask->address.ipx; + if (i > 80) + i = 80; + for (; i >= 8; i -= 8) + { + *n = 0xFF; + n++; + } + + // fill last bit + if (i) + { + i = (~((1 << i) - 1)) & 0xFF; + *n = i; + } + break; +#endif +#ifdef IPPROTO_IPV6 + case NA_IPV6: + case NA_BROADCAST_IP6: + n = amask->address.ip6; + if (i > 128) + i = 128; + for (; i >= 8; i -= 8) + { + *n = 0xFF; + n++; + } + + // fill last bit + if (i) + { + i = (~((1 << i) - 1)) & 0xFF; + *n = i; + } + break; +#endif + case NA_IP: + case NA_BROADCAST_IP: + n = amask->address.ip; + if (i > 32) + i = 32; + for (; i >= 8; i -= 8) + { + *n = 0xFF; + n++; + } + + // fill last bit + if (i) + { + i = (~((1 << i) - 1)) & 0xFF; + *n = i; + } + break; + } +} + +// NET_StringToAdrMasked: extension to NET_StringToAdr to handle IP addresses +// with masks or integers representing the bit masks +qboolean NET_StringToAdrMasked (char *s, netadr_t *a, netadr_t *amask) +{ + char t[64]; + char *spoint; + int i; + + spoint = strchr(s, '/'); + + if (spoint) + { + // we have a slash in the address so split and resolve separately + char *c; + + i = spoint - s; + if (i + 1 > sizeof(t)) + i = sizeof(t); + + Q_strncpyz(t, s, i); + if (!NET_StringToAdr(t, a)) + return false; + spoint++; + + c = spoint; + if (!*c) + return false; + + while (*c) // check for non-numeric characters + { + if (*c < '0' || *c > '9') + { + c = NULL; + break; + } + c++; + } + + if (c == NULL) // we have an address so resolve it and return + return NET_StringToAdr(spoint, amask); + + // otherwise generate mask for given bits + i = atoi(spoint); + NET_IntegerToMask(a, amask, i); + } + else + { + // we don't have a slash, resolve and fill with a full mask + if (!NET_StringToAdr(s, a)) + return false; + + memset (amask, 0, sizeof(*amask)); + amask->type = a->type; + + NET_IntegerToMask(a, amask, -1); + } + + return true; +} + +// NET_CompareAdrMasked: given 3 addresses, 2 to compare with a complimentary mask, +// returns true or false if they match +qboolean NET_CompareAdrMasked(netadr_t a, netadr_t b, netadr_t mask) +{ + int i; + + // check to make sure all types match + if (a.type != b.type || a.type != mask.type) + return false; + + // check port if both are non-zero + if (a.port && b.port && a.port != b.port) + return false; + + // match on protocol type and compare address + switch (a.type) + { + case NA_LOOPBACK: + return true; + case NA_BROADCAST_IP: + case NA_IP: + for (i = 0; i < 4; i++) + { + if ((a.address.ip[i] & mask.address.ip[i]) != (b.address.ip[i] & mask.address.ip[i])) + return false; + } + break; +#ifdef IPPROTO_IPV6 + case NA_BROADCAST_IP6: + case NA_IPV6: + for (i = 0; i < 16; i++) + { + if ((a.address.ip6[i] & mask.address.ip6[i]) != (b.address.ip6[i] & mask.address.ip6[i])) + return false; + } + break; +#endif +#ifdef USEIPX + case NA_BROADCAST_IPX: + case NA_IPX: + for (i = 0; i < 10; i++) + { + if ((a.address.ipx[i] & mask.address.ipx[i]) != (b.address.ipx[i] & mask.address.ipx[i])) + return false; + } + break; +#endif + default: + return false; // invalid protocol + } + + return true; // all checks passed +} + +// UniformMaskedBits: counts number of bits in an assumed uniform mask, returns +// -1 if not uniform +int UniformMaskedBits(netadr_t mask) +{ + int bits; + int b; + int bs; + qboolean bitenc = false; + + switch (mask.type) + { + case NA_BROADCAST_IP: + case NA_IP: + bits = 32; + for (b = 3; b >= 0; b--) + { + if (mask.address.ip[b] == 0xFF) + bitenc = true; + else if (mask.address.ip[b]) + { + bs = ~mask.address.ip[b]; + while (bs) + { + if (bs & 1) + { + bits -= 1; + if (bitenc) + return -1; + } + else + bitenc = true; + bs >>= 1; + } + } + else if (bitenc) + return -1; + else + bits -= 8; + } + break; +#ifdef IPPROTO_IPV6 + case NA_BROADCAST_IP6: + case NA_IPV6: + bits = 128; + for (b = 15; b >= 0; b--) + { + if (mask.address.ip6[b] == 0xFF) + bitenc = true; + else if (mask.address.ip6[b]) + { + bs = ~mask.address.ip6[b]; + while (bs) + { + if (bs & 1) + { + bits -= 1; + if (bitenc) + return -1; + } + else + bitenc = true; + bs >>= 1; + } + } + else if (bitenc) + return -1; + else + bits -= 8; + } + break; +#endif +#ifdef USEIPX + case NA_BROADCAST_IPX: + case NA_IPX: + bits = 80; + for (b = 9; b >= 0; b--) + { + if (mask.address.ipx[b] == 0xFF) + bitenc = true; + else if (mask.address.ipx[b]) + { + bs = ~mask.address.ipx[b]; + while (bs) + { + if (bs & 1) + { + bits -= 1; + if (bitenc) + return -1; + } + else + bitenc = true; + bs >>= 1; + } + } + else if (bitenc) + return -1; + else + bits -= 8; + } + break; +#endif + default: + return -1; // invalid protocol + } + + return bits; // all checks passed +} + +char *NET_AdrToStringMasked (netadr_t a, netadr_t amask) +{ + static char s[128]; + int i; + + i = UniformMaskedBits(amask); + + if (i >= 0) + sprintf(s, "%s/%i", NET_AdrToString(a), i); + else + sprintf(s, "%s/%s", NET_AdrToString(a), NET_AdrToString(amask)); + + return s; +} + // Returns true if we can't bind the address locally--in other words, // the IP is NOT one of our interfaces. qboolean NET_IsClientLegal(netadr_t *adr) diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index c497509c2..a27adc408 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -104,7 +104,6 @@ cvar_t r_norefresh = SCVAR("r_norefresh","0"); //cvar_t r_speeds = SCVAR("r_speeds","0"); //cvar_t r_fullbright = SCVAR("r_fullbright","0"); cvar_t r_mirroralpha = SCVARF("r_mirroralpha","1", CVAR_CHEAT); -cvar_t r_wateralpha = SCVAR("r_wateralpha","1"); //cvar_t r_waterwarp = SCVAR("r_waterwarp", "0"); cvar_t r_novis = SCVAR("r_novis","0"); //cvar_t r_netgraph = SCVAR("r_netgraph","0"); diff --git a/engine/server/server.h b/engine/server/server.h index 1bc2f8384..81be511d3 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -650,6 +650,7 @@ typedef struct typedef struct bannedips_s { struct bannedips_s *next; netadr_t adr; + netadr_t adrmask; } bannedips_t; typedef enum { @@ -1060,7 +1061,6 @@ void ClientReliableWrite_SZ(client_t *cl, void *data, int len); #ifdef SVRANKING //flags -#define RANK_BANNED 1 #define RANK_MUTED 2 #define RANK_CUFFED 4 #define RANK_CRIPPLED 8 //ha ha... get speed cheaters with this!... :o) diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 7790ffba3..ac89d381e 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -634,18 +634,32 @@ void SV_Kick_f (void) Con_TPrintf (STL_USERDOESNTEXIST, Cmd_Argv(1)); } -void SV_BanIP_f (void) +void SV_BanName_f (void) { client_t *cl; int clnum=-1; + if (Cmd_Argc() < 2) + { + Con_Printf("%s userid|nick\n", Cmd_Argv(0)); + return; + } + while((cl = SV_GetClientForString(Cmd_Argv(1), &clnum))) if (cl) { bannedips_t *nb; + + if (NET_IsLoopBackAddress(cl->netchan.remote_address)) + { + Con_Printf("You're not allowed to ban loopback!\n"); + continue; + } + nb = Z_Malloc(sizeof(bannedips_t)); nb->next = svs.bannedips; nb->adr = cl->netchan.remote_address; + NET_IntegerToMask(&nb->adr, &nb->adrmask, -1); // fill mask if (*Cmd_Argv(2)) //explicit blocking of all ports of a client ip nb->adr.port = 0; svs.bannedips = nb; @@ -661,38 +675,108 @@ void SV_BanIP_f (void) Con_TPrintf (STL_USERDOESNTEXIST, Cmd_Argv(1)); } -void SV_BanName_f (void) +void SV_BanIP_f (void) { + netadr_t banadr; + netadr_t banmask; + int i; client_t *cl; - int clnum=-1; -#ifdef SVRANKING - rankstats_t rs; -#endif + bannedips_t *nb; - - while((cl = SV_GetClientForString(Cmd_Argv(1), &clnum))) + if (Cmd_Argc() < 2) { - SV_BroadcastTPrintf (PRINT_HIGH, STL_CLIENTWASBANNED, cl->name); - // print directly, because the dropped client won't get the - // SV_BroadcastPrintf message - SV_ClientTPrintf (cl, PRINT_HIGH, STL_YOUWEREBANNED); -#ifdef SVRANKING - if (cl->rankid) - { - if (Rank_GetPlayerStats(cl->rankid, &rs)) - { - rs.flags1 |= RANK_BANNED; - Rank_SetPlayerStats(cl->rankid, &rs); - } - } - else - Con_Printf("User is not using an account\n"); -#endif - SV_DropClient (cl); + Con_Printf("%s address/mask|adress/maskbits\n", Cmd_Argv(0)); + return; } - if (clnum == -1) - Con_TPrintf (STL_USERDOESNTEXIST, Cmd_Argv(1)); + if (!NET_StringToAdrMasked(Cmd_Argv(1), &banadr, &banmask)) + { + Con_Printf("invalid address or mask\n"); + return; + } + + if (NET_IsLoopBackAddress(banadr)) + { + Con_Printf("You're not allowed to ban loopback!\n"); + return; + } + + // loop through clients and kick the ones that match + for (i = 0, cl = svs.clients; i < sv.allocated_client_slots; i++, cl++) + { + if (cl->state<=cs_zombie) + continue; + + if (NET_CompareAdrMasked(cl->netchan.remote_address, banadr, banmask)) + { + // match, so kick + SV_BroadcastTPrintf (PRINT_HIGH, STL_CLIENTWASBANNED, cl->name); + // print directly, because the dropped client won't get the + // SV_BroadcastPrintf message + SV_ClientTPrintf (cl, PRINT_HIGH, STL_YOUWEREBANNED); + SV_DropClient (cl); + } + } + + // add IP and mask to ban list + nb = Z_Malloc(sizeof(bannedips_t)); + nb->next = svs.bannedips; + nb->adr = banadr; + nb->adrmask = banmask; + svs.bannedips = nb; +} + +void SV_BanList_f (void) +{ + int bancount = 0; + bannedips_t *nb = svs.bannedips; + + while (nb) + { + Con_Printf("%s\n", NET_AdrToStringMasked(nb->adr, nb->adrmask)); + bancount++; + nb = nb->next; + } + + Con_Printf("%i total entries in ban list\n", bancount); +} + +void SV_Unban_f (void) +{ + qboolean all = false; + bannedips_t *nb = svs.bannedips; + bannedips_t *nbnext; + netadr_t unbanadr = {0}; + netadr_t unbanmask = {0}; + + if (Cmd_Argc() < 2) + { + Con_Printf("%s address/mask|address/maskbits|all\n", Cmd_Argv(0)); + return; + } + + if (!Q_strcasecmp(Cmd_Argv(1), "all")) + all = true; + else if (!NET_StringToAdrMasked(Cmd_Argv(1), &unbanadr, &unbanmask)) + { + Con_Printf("invalid address or mask\n"); + return; + } + + while (nb) + { + nbnext = nb->next; + if (NET_CompareAdrMasked(nb->adr, unbanadr, unbanmask)) + { + if (!all) + Con_Printf("unbanned %s\n", NET_AdrToStringMasked(nb->adr, nb->adrmask)); + if (svs.bannedips == nb) + svs.bannedips = nbnext; + Z_Free(nb); + } + + nb = nbnext; + } } void SV_ForceName_f (void) @@ -1717,7 +1801,9 @@ void SV_InitOperatorCommands (void) Cmd_AddCommand ("renameclient", SV_ForceName_f); Cmd_AddCommand ("cripple", SV_CripplePlayer_f); Cmd_AddCommand ("banname", SV_BanName_f); + Cmd_AddCommand ("banlist", SV_BanList_f); Cmd_AddCommand ("banip", SV_BanIP_f); + Cmd_AddCommand ("unban", SV_Unban_f); // Cmd_AddCommand ("ban", SV_BanName_f); Cmd_AddCommand ("status", SV_Status_f); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index ea063d7b9..4ad807f85 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -1762,21 +1762,10 @@ client_t *SVC_DirectConnect(void) bannedips_t *banip; for (banip = svs.bannedips; banip; banip=banip->next) { - if (banip->adr.port) + if (NET_CompareAdrMasked(adr, banip->adr, banip->adrmask)) { - if (NET_CompareAdr (adr, newcl->netchan.remote_address)) - { - SV_RejectMessage (protocol, "You were banned.\nContact the administrator to complain.\n"); - return NULL; - } - } - else - { - if (NET_CompareBaseAdr (adr, newcl->netchan.remote_address)) - { - SV_RejectMessage (protocol, "You were banned.\nContact the administrator to complain.\n"); - return NULL; - } + SV_RejectMessage (protocol, "You were banned.\nContact the administrator to complain.\n"); + return NULL; } } //yay, a legit client who we havn't banned yet. @@ -1917,16 +1906,6 @@ client_t *SVC_DirectConnect(void) return NULL; } - if (rs.flags1 & RANK_BANNED) - { - SV_RejectMessage (protocol, "You were banned.\nContact the administrator to complain.\n"); - Con_Printf("banned player %s is trying to connect\n", newcl->name); - newcl->name[0] = 0; - memset (newcl->userinfo, 0, sizeof(newcl->userinfo)); - newcl->state = cs_free; - return NULL; - } - if (rs.flags1 & RANK_MUTED) { SV_BroadcastTPrintf(PRINT_MEDIUM, STL_CLIENTISSTILLMUTED, newcl->name);