]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/ipban.qc
get rid of ServerConsoleEcho workaround; fix a remote DP-console command execution...
[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_Insert(string ip, float bantime)
120 {
121         float i;
122         float j;
123         float bestscore;
124         // already banned?
125         for(i = 0; i < ban_count; ++i)
126                 if(ban_ip[i] == ip)
127                         return FALSE;
128         // do we have a free slot?
129         for(i = 0; i < ban_count; ++i)
130                 if(time > ban_expire[i])
131                         break;
132         // no free slot? Then look for the one who would get unbanned next
133         if(i >= BAN_MAX)
134         {
135                 i = 0;
136                 bestscore = ban_expire[i];
137                 for(j = 1; j < ban_count; ++j)
138                 {
139                         if(ban_expire[j] < bestscore)
140                         {
141                                 i = j;
142                                 bestscore = ban_expire[i];
143                         }
144                 }
145         }
146         // if we replace someone, will we be banned longer than him (so long-term
147         // bans never get overridden by short-term bans)
148         if(ban_expire[i] > time + bantime)
149                 return FALSE;
150         // okay, insert our new victim as i
151         Ban_Delete(i);
152         print(ip, " has been banned for ", ftos(bantime), " seconds\n");
153         ban_expire[i] = time + bantime;
154         ban_ip[i] = strzone(ip);
155         ban_count = max(ban_count, i + 1);
156
157         Ban_SaveBans();
158
159         return TRUE;
160 }
161
162 void Ban_KickBanClient(entity client, float bantime, float masksize)
163 {
164         if(!Ban_GetClientIP(client))
165         {
166                 dropclient(client);
167                 return;
168         }
169         // now ban him
170         switch(masksize)
171         {
172                 case 1:
173                         Ban_Insert(ban_ip1, bantime);
174                         break;
175                 case 2:
176                         Ban_Insert(ban_ip2, bantime);
177                         break;
178                 case 3:
179                         Ban_Insert(ban_ip3, bantime);
180                         break;
181                 default:
182                         Ban_Insert(ban_ip4, bantime);
183                         break;
184         }
185         // and kick him
186         dropclient(client);
187 }
188
189 float GameCommand_Ban(string command)
190 {
191         float argc;
192         float bantime;
193         entity client;
194         float entno;
195         float masksize;
196
197         argc = tokenize(command);
198         if(argv(0) == "help")
199         {
200                 print("  kickban # n m p - kickban player n for m seconds, using mask size p (1 to 4)\n");
201                 print("  ban ip m - ban an IP or range (incomplete IP, like 1.2.3) for m seconds\n");
202                 print("  bans - list all existing bans\n");
203                 print("  unban n - delete the entry #n from the bans list\n");
204                 return TRUE;
205         }
206         if(argv(0) == "kickban")
207         {
208                 if(argc >= 3)
209                 {
210                         entno = stof(argv(2));
211                         if(entno > maxclients || entno < 1)
212                                 return TRUE;
213                         client = edict_num(entno);
214                         if(argc >= 4)
215                                 bantime = stof(argv(3));
216                         else
217                                 bantime = cvar("g_ban_default_bantime");
218                         if(argc >= 5)
219                                 masksize = stof(argv(4));
220                         else
221                                 masksize = cvar("g_ban_default_masksize");
222                         Ban_KickBanClient(client, bantime, masksize);
223                         return TRUE;
224                 }
225         }
226         else if(argv(0) == "ban")
227         {
228                 if(argc >= 2)
229                 {
230                         string ip;
231                         ip = argv(1);
232                         if(argc >= 3)
233                                 bantime = stof(argv(2));
234                         else
235                                 bantime = cvar("g_ban_default_bantime");
236                         Ban_Insert(ip, bantime);
237                         return TRUE;
238                 }
239         }
240         else if(argv(0) == "bans")
241         {
242                 Ban_View();
243                 return TRUE;
244         }
245         else if(argv(0) == "unban")
246         {
247                 if(argc >= 2)
248                 {
249                         float who;
250                         who = stof(argv(1));
251                         Ban_Delete(who);
252                         return TRUE;
253                 }
254         }
255         return FALSE;
256 }