]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/ipban.qc
now REALLY remove dead players
[divverent/nexuiz.git] / data / qcsrc / server / ipban.qc
1 #define BAN_MAX 64
2 float ban_loaded;
3 string ban_ip[BAN_MAX];
4 float ban_expire[BAN_MAX];
5 float ban_count;
6
7 string ban_ip1;
8 string ban_ip2;
9 string ban_ip3;
10 string ban_ip4;
11
12 void Ban_SaveBans()
13 {
14         string out;
15         float i;
16
17         if(!ban_loaded)
18                 return;
19
20         // version of list
21         out = "1";
22         for(i = 0; i < ban_count; ++i)
23         {
24                 if(time > ban_expire[i])
25                         continue;
26                 out = strcat(out, " ", ban_ip[i]);
27                 out = strcat(out, " ", ftos(ban_expire[i] - time));
28         }
29         if(strlen(out) <= 1) // no real entries
30                 cvar_set("g_banned_list", "");
31         else
32                 cvar_set("g_banned_list", out);
33 }
34
35 float Ban_Delete(float i)
36 {
37         if(i < 0)
38                 return FALSE;
39         if(i >= ban_count)
40                 return FALSE;
41         if(ban_expire[i] == 0)
42                 return FALSE;
43         if(ban_expire[i] > 0)
44                 strunzone(ban_ip[i]);
45         ban_expire[i] = 0;
46         ban_ip[i] = "";
47         Ban_SaveBans();
48         return TRUE;
49 }
50
51 void Ban_LoadBans()
52 {
53         float i, n;
54         for(i = 0; i < ban_count; ++i)
55                 Ban_Delete(i);
56         ban_count = 0;
57         ban_loaded = TRUE;
58         n = tokenize(cvar_string("g_banned_list"));
59         if(stof(argv(0)) == 1)
60         {
61                 ban_count = (n - 1) / 2;
62                 for(i = 0; i < ban_count; ++i)
63                 {
64                         ban_ip[i] = strzone(argv(2*i+1));
65                         ban_expire[i] = time + stof(argv(2*i+2));
66                 }
67         }
68 }
69
70 void Ban_View()
71 {
72         float i;
73         string msg;
74         for(i = 0; i < ban_count; ++i)
75         {
76                 if(time > ban_expire[i])
77                         continue;
78                 msg = strcat("#", ftos(i), ": ");
79                 msg = strcat(msg, ban_ip[i], " is still banned for ");
80                 msg = strcat(msg, ftos(ban_expire[i] - time), " seconds");
81                 print(msg, "\n");
82         }
83 }
84
85 float Ban_GetClientIP(entity client)
86 {
87         float n;
88         n = tokenizebyseparator(client.netaddress, ".");
89         if(n != 4)
90                 return FALSE;
91         ban_ip1 = strcat1(argv(0));
92         ban_ip2 = strcat(ban_ip1, ".", argv(1));
93         ban_ip3 = strcat(ban_ip2, ".", argv(2));
94         ban_ip4 = strcat(ban_ip3, ".", argv(3));
95         return TRUE;
96 }
97
98 float Ban_IsClientBanned(entity client)
99 {
100         float i;
101         if(!ban_loaded)
102                 Ban_LoadBans();
103         if(!Ban_GetClientIP(client))
104                 return FALSE;
105         for(i = 0; i < ban_count; ++i)
106         {
107                 string s;
108                 if(time > ban_expire[i])
109                         continue;
110                 s = ban_ip[i];
111                 if(ban_ip1 == s) return TRUE;
112                 if(ban_ip2 == s) return TRUE;
113                 if(ban_ip3 == s) return TRUE;
114                 if(ban_ip4 == s) return TRUE;
115         }
116         return FALSE;
117 }
118
119 float Ban_MaybeEnforceBan(entity client)
120 {
121         if(Ban_IsClientBanned(client))
122         {
123                 string s;
124                 s = strcat("^1NOTE:^7 banned client ", client.netaddress, " just tried to enter\n");
125                 dropclient(client);
126                 bprint(s);
127                 return TRUE;
128         }
129         return FALSE;
130 }
131
132 float Ban_Insert(string ip, float bantime)
133 {
134         float i;
135         float j;
136         float bestscore;
137         // already banned?
138         for(i = 0; i < ban_count; ++i)
139                 if(ban_ip[i] == ip)
140                         return FALSE;
141         // do we have a free slot?
142         for(i = 0; i < ban_count; ++i)
143                 if(time > ban_expire[i])
144                         break;
145         // no free slot? Then look for the one who would get unbanned next
146         if(i >= BAN_MAX)
147         {
148                 i = 0;
149                 bestscore = ban_expire[i];
150                 for(j = 1; j < ban_count; ++j)
151                 {
152                         if(ban_expire[j] < bestscore)
153                         {
154                                 i = j;
155                                 bestscore = ban_expire[i];
156                         }
157                 }
158         }
159         // if we replace someone, will we be banned longer than him (so long-term
160         // bans never get overridden by short-term bans)
161         if(ban_expire[i] > time + bantime)
162                 return FALSE;
163         // okay, insert our new victim as i
164         Ban_Delete(i);
165         print(ip, " has been banned for ", ftos(bantime), " seconds\n");
166         ban_expire[i] = time + bantime;
167         ban_ip[i] = strzone(ip);
168         ban_count = max(ban_count, i + 1);
169
170         Ban_SaveBans();
171
172         return TRUE;
173 }
174
175 void Ban_KickBanClient(entity client, float bantime, float masksize)
176 {
177         if(!Ban_GetClientIP(client))
178         {
179                 dropclient(client);
180                 return;
181         }
182         // now ban him
183         switch(masksize)
184         {
185                 case 1:
186                         Ban_Insert(ban_ip1, bantime);
187                         break;
188                 case 2:
189                         Ban_Insert(ban_ip2, bantime);
190                         break;
191                 case 3:
192                         Ban_Insert(ban_ip3, bantime);
193                         break;
194                 default:
195                         Ban_Insert(ban_ip4, bantime);
196                         break;
197         }
198         // and kick him
199         dropclient(client);
200 }
201
202 float GameCommand_Ban(string command)
203 {
204         float argc;
205         float bantime;
206         entity client;
207         float entno;
208         float masksize;
209
210         argc = tokenize(command);
211         if(argv(0) == "help")
212         {
213                 print("  kickban # n m p - kickban player n for m seconds, using mask size p (1 to 4)\n");
214                 print("  ban ip m - ban an IP or range (incomplete IP, like 1.2.3) for m seconds\n");
215                 print("  bans - list all existing bans\n");
216                 print("  unban n - delete the entry #n from the bans list\n");
217                 return TRUE;
218         }
219         if(argv(0) == "kickban")
220         {
221                 if(argc >= 3)
222                 {
223                         entno = stof(argv(2));
224                         if(entno > maxclients || entno < 1)
225                                 return TRUE;
226                         client = edict_num(entno);
227                         if(argc >= 4)
228                                 bantime = stof(argv(3));
229                         else
230                                 bantime = cvar("g_ban_default_bantime");
231                         if(argc >= 5)
232                                 masksize = stof(argv(4));
233                         else
234                                 masksize = cvar("g_ban_default_masksize");
235                         Ban_KickBanClient(client, bantime, masksize);
236                         return TRUE;
237                 }
238         }
239         else if(argv(0) == "ban")
240         {
241                 if(argc >= 2)
242                 {
243                         string ip;
244                         ip = argv(1);
245                         if(argc >= 3)
246                                 bantime = stof(argv(2));
247                         else
248                                 bantime = cvar("g_ban_default_bantime");
249                         Ban_Insert(ip, bantime);
250                         return TRUE;
251                 }
252         }
253         else if(argv(0) == "bans")
254         {
255                 Ban_View();
256                 return TRUE;
257         }
258         else if(argv(0) == "unban")
259         {
260                 if(argc >= 2)
261                 {
262                         float who;
263                         who = stof(argv(1));
264                         Ban_Delete(who);
265                         return TRUE;
266                 }
267         }
268         return FALSE;
269 }