r2779 - in branches/nexuiz-2.0/data: . gfx qcsrc/server
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Wed Jul 4 08:45:56 EDT 2007
Author: div0
Date: 2007-07-04 08:45:56 -0400 (Wed, 04 Jul 2007)
New Revision: 2779
Added:
branches/nexuiz-2.0/data/gfx/num_colon.tga
branches/nexuiz-2.0/data/qcsrc/server/ipban.qc
branches/nexuiz-2.0/data/qcsrc/server/ipban.qh
Modified:
branches/nexuiz-2.0/data/default.cfg
branches/nexuiz-2.0/data/qcsrc/server/cl_client.qc
branches/nexuiz-2.0/data/qcsrc/server/clientcommands.qc
branches/nexuiz-2.0/data/qcsrc/server/defs.qh
branches/nexuiz-2.0/data/qcsrc/server/extensions.qh
branches/nexuiz-2.0/data/qcsrc/server/g_world.qc
branches/nexuiz-2.0/data/qcsrc/server/gamecommand.qc
branches/nexuiz-2.0/data/qcsrc/server/progs.src
Log:
IP banning!
Voting now displays who is going to be kicked/banned.
Voting now allows leaving out the space between # and the status number.
Modified: branches/nexuiz-2.0/data/default.cfg
===================================================================
--- branches/nexuiz-2.0/data/default.cfg 2007-06-30 21:20:08 UTC (rev 2778)
+++ branches/nexuiz-2.0/data/default.cfg 2007-07-04 12:45:56 UTC (rev 2779)
@@ -670,7 +670,7 @@
con_chatwidth 0.6
con_chat 5
-con_chatpos -7
+con_chatpos -8
sbar_alpha_bg 0.4
net_banlist ""
@@ -761,3 +761,11 @@
// so it can be stuffcmd-ed still
set cl_gravity 800 // but ignored anyway
+
+set g_ban_default_bantime 5400 // 90 minutes
+set g_ban_default_masksize 3 // whole 255.255.255.0 networks (set to 4 for single IPs)
+set g_banned_list "" // format: 1 ip remainingtime ip remainingtime ...
+alias bans "sv_cmd bans $*"
+alias ban "sv_cmd ban $*" // usage: ban address(maybe incomplete, like 1.2.3) bantime(seconds)
+alias kickban "sv_cmd kickban $*" // usage: kickban # playerno bantime(seconds) masksize(bytes)
+alias unban "sv_cmd unban $*" // usage: unban 3 (number from bans)
Copied: branches/nexuiz-2.0/data/gfx/num_colon.tga (from rev 2773, trunk/data/gfx/num_colon.tga)
===================================================================
(Binary files differ)
Modified: branches/nexuiz-2.0/data/qcsrc/server/cl_client.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/cl_client.qc 2007-06-30 21:20:08 UTC (rev 2778)
+++ branches/nexuiz-2.0/data/qcsrc/server/cl_client.qc 2007-07-04 12:45:56 UTC (rev 2779)
@@ -605,6 +605,14 @@
{
local string s;
+ if(Ban_IsClientBanned(self))
+ {
+ s = strcat("^1NOTE:^7 banned client ", self.netaddress, " just tried to enter\n");
+ dropclient(self);
+ bprint(s);
+ return;
+ }
+
self.classname = "player_joining";
self.flags = self.flags | FL_CLIENT;
self.version_nagtime = time + 10 + random() * 10;
Modified: branches/nexuiz-2.0/data/qcsrc/server/clientcommands.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/clientcommands.qc 2007-06-30 21:20:08 UTC (rev 2778)
+++ branches/nexuiz-2.0/data/qcsrc/server/clientcommands.qc 2007-07-04 12:45:56 UTC (rev 2779)
@@ -120,8 +120,47 @@
strunzone(msgstr);
}
+string GetKickVoteVictim_newcommand;
+entity GetKickVoteVictim(string vote, string cmd)
+{
+ float tokens;
+ float i, n;
+ string ns;
+ entity e;
+
+ tokens = tokenize(vote);
+ ns = "";
+
+ if(tokens == 2)
+ if(substring(argv(1), 0, 1) == "#")
+ ns = substring(argv(1), 1, 999);
+
+ if(tokens == 3)
+ if(argv(1) == "#")
+ ns = argv(2);
+
+ if(ns != "")
+ {
+ n = stof(ns);
+ if(ns == ftos(n)) if(n >= 1) if(n <= maxclients)
+ {
+ for((e = world), (i = 0); i < n; ++i, (e = nextent(e)))
+ ;
+ if(clienttype(e) == CLIENTTYPE_REAL)
+ {
+ GetKickVoteVictim_newcommand = strcat(argv(0), " # ", ns);
+ return e;
+ }
+ }
+ }
+
+ sprint(self, strcat("Usage: ", cmd, " ", argv(0), " #playernumber (as in \"status\")\n"));
+ return world;
+}
+
void SV_ParseClientCommand(string s) {
local string cmd;
+ local entity e;
tokenize(s);
@@ -151,7 +190,7 @@
sprint(self, strcat("^3", cvar_string("sv_vote_commands"), "^7 and maybe further ^3arguments^7\n"));
} else if(argv(1) == "status") {
if(votecalled) {
- sprint(self, strcat("^7Vote for \"^1", votecalledvote, "^7\" called by \"^7", votecaller.netname, "^7\".\n"));
+ sprint(self, strcat("^7Vote for ", votecalledvote_display, "^7 called by ^7", votecaller.netname, "^7.\n"));
} else {
sprint(self, "^1No vote called.\n");
}
@@ -169,18 +208,29 @@
} else if(VoteAllowed(strcat1(argv(2)))) { // strcat seems to be necessary
if(!ValidateMap(vote))
return;
+ // remap chmap to gotomap (forces intermission)
+ if(substring(vote, 0, 6) == "chmap ")
+ vote = strcat("gotomap ", substring(vote, 6, strlen(vote) - 6));
+ // make kick and kickban votes a bit nicer (and reject them if formatted badly)
+ if(substring(vote, 0, 5) == "kick " || substring(vote, 0, 8) == "kickban ")
+ {
+ if(!(e = GetKickVoteVictim(vote, "vcall")))
+ return;
+ votecalledvote_display = strzone(strcat("^1", vote, " (^7", e.netname, "^1)"));
+ vote = GetKickVoteVictim_newcommand;
+ }
+ else
+ {
+ votecalledvote_display = strzone(strcat("^1", vote));
+ }
+ votecalledvote = strzone(vote);
votecalled = TRUE;
votecalledmaster = FALSE;
- // remap chmap to gotomap (forces intermission)
- if(strlen(vote) >= 6)
- if(substring(vote, 0, 6) == "chmap ")
- vote = strcat("gotomap ", substring(vote, 6, strlen(vote) - 6));
- votecalledvote = strzone(vote);
votecaller = self; // remember who called the vote
votefinished = time + cvar("sv_vote_timeout");
votecaller.vote_vote = 1; // of course you vote yes
votecaller.vote_next = time + cvar("sv_vote_wait");
- bprint("\{1}^2* ^3", votecaller.netname, "^2 calls a vote for ^1", votecalledvote, "\n");
+ bprint("\{1}^2* ^3", votecaller.netname, "^2 calls a vote for ", votecalledvote_display, "\n");
VoteCount(); // needed if you are the only one
} else {
sprint(self, "^1This vote is not ok. See help for more info.\n");
@@ -194,6 +244,8 @@
sprint(self, "^1No vote called.\n");
} else if(self == votecaller) { // the votecaller can stop a vote
VoteStop(self);
+ } else if(self.vote_master) { // masters can, too
+ VoteStop(self);
} else {
sprint(self, "^1You are not allowed to stop that Vote.\n");
}
@@ -204,7 +256,8 @@
} else {
votecalled = TRUE;
votecalledmaster = TRUE;
- votecalledvote = strzone("^3master");
+ votecalledvote = strzone("XXX");
+ votecalledvote_display = strzone("^3master");
votecaller = self; // remember who called the vote
votefinished = time + cvar("sv_vote_timeout");
votecaller.vote_vote = 1; // of course you vote yes
@@ -231,7 +284,7 @@
else
sprint(self, "^1You are NOT a master.\n");
} else if(self.vote_master) {
- local string dovote;
+ local string dovote, dovote_display;
dovote = VoteParse();
if(dovote == "") {
sprint(self, "^1Your command was empty. See help for more info.\n");
@@ -241,8 +294,16 @@
// remap chmap to gotomap (forces intermission)
if(strlen(dovote) >= 6)
if(substring(dovote, 0, 6) == "chmap ")
- vote = strcat("gotomap ", substring(dovote, 6, strlen(dovote) - 6));
- bprint("\{1}^2* ^3", self.netname, "^2 used his ^3master^2 status to do \"^2", dovote, "^2\".\n");
+ dovote = strcat("gotomap ", substring(dovote, 6, strlen(dovote) - 6));
+ dovote_display = dovote;
+ if(substring(dovote, 0, 5) == "kick " || substring(dovote, 0, 8) == "kickban ")
+ {
+ if(!(e = GetKickVoteVictim(dovote, "vdo")))
+ return;
+ dovote_display = strzone(strcat("^1", dovote, " (^7", e.netname, "^1)"));
+ dovote = GetKickVoteVictim_newcommand;
+ }
+ bprint("\{1}^2* ^3", self.netname, "^2 used his ^3master^2 status to do \"^2", dovote_display, "^2\".\n");
localcmd(strcat(dovote, "\n"));
} else {
sprint(self, "^1This command is not ok. See help for more info.\n");
@@ -519,13 +580,19 @@
centerprint_expire(player, CENTERPRIO_VOTE);
}
+ if(votecalled)
+ {
+ strunzone(votecalledvote);
+ strunzone(votecalledvote_display);
+ }
+
votecalled = FALSE;
votecalledmaster = FALSE;
votefinished = 0;
}
void VoteAccept() {
- bprint("\{1}^2* ^3", votecaller.netname, "^2's vote for ^1", votecalledvote, "^2 was accepted\n");
+ bprint("\{1}^2* ^3", votecaller.netname, "^2's vote for ^1", votecalledvote_display, "^2 was accepted\n");
if(votecalledmaster)
{
votecaller.vote_master = 1;
@@ -537,12 +604,12 @@
}
void VoteReject() {
- bprint("\{1}^2* ^3", votecaller.netname, "^2's vote for ^1", votecalledvote, "^2 was rejected\n");
+ bprint("\{1}^2* ^3", votecaller.netname, "^2's vote for ", votecalledvote_display, "^2 was rejected\n");
VoteReset();
}
void VoteTimeout() {
- bprint("\{1}^2* ^3", votecaller.netname, "^2's vote for ^1", votecalledvote, "^2 timed out\n");
+ bprint("\{1}^2* ^3", votecaller.netname, "^2's vote for ", votecalledvote_display, "^2 timed out\n");
VoteReset();
}
@@ -558,7 +625,7 @@
void VoteNag() {
if(votecalled)
if(self.vote_vote == 0)
- centerprint_atprio(self, CENTERPRIO_VOTE, strcat("^7^3", votecaller.netname, "^2 called a vote for ^1", votecalledvote, "\n\n^2You have not voted yet!\n^2HINT: By default, F1 is yes and F2 is no."));
+ centerprint_atprio(self, CENTERPRIO_VOTE, strcat("^7^3", votecaller.netname, "^2 called a vote for ", votecalledvote_display, "\n\n^2You have not voted yet!\n^2HINT: By default, F1 is yes and F2 is no."));
}
void VoteCount() {
Modified: branches/nexuiz-2.0/data/qcsrc/server/defs.qh
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/defs.qh 2007-06-30 21:20:08 UTC (rev 2778)
+++ branches/nexuiz-2.0/data/qcsrc/server/defs.qh 2007-07-04 12:45:56 UTC (rev 2779)
@@ -186,6 +186,7 @@
// stahl's voting
float votecalled;
string votecalledvote;
+string votecalledvote_display;
float votecalledmaster;
entity votecaller;
float votefinished;
Modified: branches/nexuiz-2.0/data/qcsrc/server/extensions.qh
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/extensions.qh 2007-06-30 21:20:08 UTC (rev 2778)
+++ branches/nexuiz-2.0/data/qcsrc/server/extensions.qh 2007-07-04 12:45:56 UTC (rev 2779)
@@ -1455,3 +1455,5 @@
//sv_stepheight (default 18)
//description:
//sv_jumpstep allows stepping up onto stairs while airborn, sv_stepheight controls how high a single step can be.
+
+.string netaddress; // TODO make this a full block
Modified: branches/nexuiz-2.0/data/qcsrc/server/g_world.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/g_world.qc 2007-06-30 21:20:08 UTC (rev 2778)
+++ branches/nexuiz-2.0/data/qcsrc/server/g_world.qc 2007-07-04 12:45:56 UTC (rev 2779)
@@ -345,6 +345,8 @@
fteqcc_testbugs();
readlevelcvars();
+
+ Ban_LoadBans();
}
void light (void)
@@ -511,6 +513,8 @@
localcmd(strcat("exec \"", exit_cfg, "\"\n"));
localcmd("exec game_reset.cfg\n");
+
+ Ban_SaveBans();
};
void() Map_Goto =
@@ -653,6 +657,8 @@
float() DoNextMapOverride =
{
+ Ban_SaveBans();
+
if(cvar("g_campaign"))
{
CampaignPostIntermission();
Modified: branches/nexuiz-2.0/data/qcsrc/server/gamecommand.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/gamecommand.qc 2007-06-30 21:20:08 UTC (rev 2778)
+++ branches/nexuiz-2.0/data/qcsrc/server/gamecommand.qc 2007-07-04 12:45:56 UTC (rev 2779)
@@ -9,10 +9,14 @@
print(" adminmsg clientnumber \"message\"\n");
print(" teamstatus\n");
print(" printstats\n");
+ GameCommand_Ban("help");
GameCommand_Generic("help");
return;
}
+ if(GameCommand_Ban(command))
+ return;
+
if(GameCommand_Generic(command))
return;
Copied: branches/nexuiz-2.0/data/qcsrc/server/ipban.qc (from rev 2774, trunk/data/qcsrc/server/ipban.qc)
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/ipban.qc (rev 0)
+++ branches/nexuiz-2.0/data/qcsrc/server/ipban.qc 2007-07-04 12:45:56 UTC (rev 2779)
@@ -0,0 +1,257 @@
+#define BAN_MAX 64
+float ban_loaded;
+string ban_ip[BAN_MAX];
+float ban_expire[BAN_MAX];
+float ban_count;
+
+string ban_ip1;
+string ban_ip2;
+string ban_ip3;
+string ban_ip4;
+
+void Ban_SaveBans()
+{
+ string out;
+ float i;
+
+ if(!ban_loaded)
+ return;
+
+ // version of list
+ out = "1";
+ for(i = 0; i < ban_count; ++i)
+ {
+ if(time > ban_expire[i])
+ continue;
+ out = strcat(out, " ", ban_ip[i]);
+ out = strcat(out, " ", ftos(ban_expire[i] - time));
+ }
+ if(strlen(out) <= 1) // no real entries
+ cvar_set("g_banned_list", "");
+ else
+ cvar_set("g_banned_list", out);
+}
+
+float Ban_Delete(float i)
+{
+ if(i < 0)
+ return FALSE;
+ if(i >= ban_count)
+ return FALSE;
+ if(ban_expire[i] == 0)
+ return FALSE;
+ if(ban_expire[i] > 0)
+ strunzone(ban_ip[i]);
+ ban_expire[i] = 0;
+ ban_ip[i] = "";
+ Ban_SaveBans();
+ return TRUE;
+}
+
+void Ban_LoadBans()
+{
+ float i, n;
+ for(i = 0; i < ban_count; ++i)
+ Ban_Delete(i);
+ ban_count = 0;
+ ban_loaded = TRUE;
+ n = tokenize(cvar_string("g_banned_list"));
+ if(stof(argv(0)) == 1)
+ {
+ ban_count = (n - 1) / 2;
+ for(i = 0; i < ban_count; ++i)
+ {
+ ban_ip[i] = strzone(argv(2*i+1));
+ ban_expire[i] = time + stof(argv(2*i+2));
+ }
+ }
+}
+
+void Ban_View()
+{
+ float i;
+ string msg;
+ for(i = 0; i < ban_count; ++i)
+ {
+ if(time > ban_expire[i])
+ continue;
+ msg = strcat("#", ftos(i), ": ");
+ msg = strcat(msg, ban_ip[i], " is still banned for ");
+ msg = strcat(msg, ftos(ban_expire[i] - time), " seconds");
+ ServerConsoleEcho(msg, FALSE);
+ }
+}
+
+float Ban_GetClientIP(entity client)
+{
+ float n;
+ n = tokenizebyseparator(client.netaddress, ".");
+ if(n != 4)
+ return FALSE;
+ ban_ip1 = strcat1(argv(0));
+ ban_ip2 = strcat(ban_ip1, ".", argv(1));
+ ban_ip3 = strcat(ban_ip2, ".", argv(2));
+ ban_ip4 = strcat(ban_ip3, ".", argv(3));
+ return TRUE;
+}
+
+float Ban_IsClientBanned(entity client)
+{
+ float i;
+ if(!ban_loaded)
+ Ban_LoadBans();
+ if(!Ban_GetClientIP(client))
+ return FALSE;
+ for(i = 0; i < ban_count; ++i)
+ {
+ string s;
+ if(time > ban_expire[i])
+ continue;
+ s = ban_ip[i];
+ if(ban_ip1 == s) return TRUE;
+ if(ban_ip2 == s) return TRUE;
+ if(ban_ip3 == s) return TRUE;
+ if(ban_ip4 == s) return TRUE;
+ }
+ return FALSE;
+}
+
+float Ban_Insert(string ip, float bantime)
+{
+ float i;
+ float j;
+ float bestscore;
+ // already banned?
+ for(i = 0; i < ban_count; ++i)
+ if(ban_ip[i] == ip)
+ return FALSE;
+ // do we have a free slot?
+ for(i = 0; i < ban_count; ++i)
+ if(time > ban_expire[i])
+ break;
+ // no free slot? Then look for the one who would get unbanned next
+ if(i >= BAN_MAX)
+ {
+ i = 0;
+ bestscore = ban_expire[i];
+ for(j = 1; j < ban_count; ++j)
+ {
+ if(ban_expire[j] < bestscore)
+ {
+ i = j;
+ bestscore = ban_expire[i];
+ }
+ }
+ }
+ // if we replace someone, will we be banned longer than him (so long-term
+ // bans never get overridden by short-term bans)
+ if(ban_expire[i] > time + bantime)
+ return FALSE;
+ // okay, insert our new victim as i
+ Ban_Delete(i);
+ ServerConsoleEcho(strcat(ip, " has been banned for ", ftos(bantime), " seconds"), FALSE);
+ ban_expire[i] = time + bantime;
+ ban_ip[i] = strzone(ip);
+ ban_count = max(ban_count, i + 1);
+
+ Ban_SaveBans();
+
+ return TRUE;
+}
+
+void Ban_KickBanClient(entity client, float bantime, float masksize)
+{
+ if(!Ban_GetClientIP(client))
+ {
+ dropclient(client);
+ return;
+ }
+ // now ban him
+ switch(masksize)
+ {
+ case 1:
+ Ban_Insert(ban_ip1, bantime);
+ break;
+ case 2:
+ Ban_Insert(ban_ip2, bantime);
+ break;
+ case 3:
+ Ban_Insert(ban_ip3, bantime);
+ break;
+ default:
+ Ban_Insert(ban_ip4, bantime);
+ break;
+ }
+ // and kick him
+ dropclient(client);
+}
+
+float GameCommand_Ban(string command)
+{
+ float argc;
+ float bantime;
+ entity client;
+ float entno;
+ float masksize;
+
+ argc = tokenize(command);
+ if(argv(0) == "help")
+ {
+ print(" kickban # n m p - kickban player n for m seconds, using mask size p (1 to 4)\n");
+ print(" ban ip m - ban an IP or range (incomplete IP, like 1.2.3) for m seconds\n");
+ print(" bans - list all existing bans\n");
+ print(" unban n - delete the entry #n from the bans list\n");
+ return TRUE;
+ }
+ if(argv(0) == "kickban")
+ {
+ if(argc >= 3)
+ {
+ entno = stof(argv(2));
+ if(entno > maxclients || entno < 1)
+ return TRUE;
+ for(client = world; entno > 0; --entno, client = nextent(client))
+ ;
+ if(argc >= 4)
+ bantime = stof(argv(3));
+ else
+ bantime = cvar("g_ban_default_bantime");
+ if(argc >= 5)
+ masksize = stof(argv(4));
+ else
+ masksize = cvar("g_ban_default_masksize");
+ Ban_KickBanClient(client, bantime, masksize);
+ return TRUE;
+ }
+ }
+ else if(argv(0) == "ban")
+ {
+ if(argc >= 2)
+ {
+ string ip;
+ ip = argv(1);
+ if(argc >= 3)
+ bantime = stof(argv(2));
+ else
+ bantime = cvar("g_ban_default_bantime");
+ Ban_Insert(ip, bantime);
+ return TRUE;
+ }
+ }
+ else if(argv(0) == "bans")
+ {
+ Ban_View();
+ return TRUE;
+ }
+ else if(argv(0) == "unban")
+ {
+ if(argc >= 2)
+ {
+ float who;
+ who = stof(argv(1));
+ Ban_Delete(who);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
Copied: branches/nexuiz-2.0/data/qcsrc/server/ipban.qh (from rev 2774, trunk/data/qcsrc/server/ipban.qh)
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/ipban.qh (rev 0)
+++ branches/nexuiz-2.0/data/qcsrc/server/ipban.qh 2007-07-04 12:45:56 UTC (rev 2779)
@@ -0,0 +1,4 @@
+void Ban_SaveBans();
+void Ban_LoadBans();
+float Ban_IsClientBanned(entity client);
+float GameCommand_Ban(string command);
Modified: branches/nexuiz-2.0/data/qcsrc/server/progs.src
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/progs.src 2007-06-30 21:20:08 UTC (rev 2778)
+++ branches/nexuiz-2.0/data/qcsrc/server/progs.src 2007-07-04 12:45:56 UTC (rev 2779)
@@ -12,6 +12,8 @@
../common/util.qh
../common/util.qc
+ipban.qh
+
keyhunt.qh
miscfunctions.qc
@@ -88,3 +90,5 @@
gamecommand.qc
keyhunt.qc
+
+ipban.qc
More information about the nexuiz-commits
mailing list