1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2011
3 //
4 // This file is part of Scorched3D.
5 //
6 // Scorched3D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20
21 #include <server/ServerBanned.h>
22 #include <server/ScorchedServer.h>
23 #include <common/OptionsScorched.h>
24 #include <common/Defines.h>
25 #include <common/Logger.h>
26 #include <net/NetInterface.h>
27 #include <XML/XMLFile.h>
28 #include <limits.h>
29
ServerBanned()30 ServerBanned::ServerBanned() : lastReadTime_(0)
31 {
32 }
33
~ServerBanned()34 ServerBanned::~ServerBanned()
35 {
36 }
37
load(bool force)38 bool ServerBanned::load(bool force)
39 {
40 std::string filename =
41 S3D::getSettingsFile(S3D::formatStringBuffer("banned-%i.xml",
42 ScorchedServer::instance()->getOptionsGame().getPortNo()));
43 if (!S3D::fileExists(filename)) return true;
44
45 time_t fileTime = S3D::fileModTime(filename);
46 if (!force && fileTime == lastReadTime_) return true;
47
48 XMLFile file;
49 if (!file.readFile(filename))
50 {
51 Logger::log(S3D::formatStringBuffer("Failed to parse banned file \"%s\"\n%s",
52 filename.c_str(), file.getParserError()));
53 return false;
54 }
55
56 Logger::log(S3D::formatStringBuffer("Refreshing banned list %s", filename.c_str()));
57 lastReadTime_ = fileTime;
58 bannedIps_.clear();
59 bannedIds_.clear();
60 bannedSUIs_.clear();
61 if (!file.getRootNode()) return true; // Empty File
62
63 std::list<XMLNode *>::iterator childrenItor;
64 std::list<XMLNode *> &children = file.getRootNode()->getChildren();
65 for (childrenItor = children.begin();
66 childrenItor != children.end();
67 ++childrenItor)
68 {
69 XMLNode *currentNode = (*childrenItor);
70 XMLNode *maskNode = 0, *timeNode = 0, *typeNode = 0;
71
72 // Read the mask
73 unsigned int m = UINT_MAX;
74 if (currentNode->getNamedParameter("mask", maskNode, false))
75 {
76 unsigned int mask[4];
77 if (sscanf(maskNode->getContent(), "%u.%u.%u.%u",
78 &mask[3], &mask[2], &mask[1], &mask[0]) != 4)
79 {
80 S3D::dialogMessage("ServerBanned",
81 S3D::formatStringBuffer("Failed to parse mask %s",
82 maskNode->getContent()));
83 return false;
84 }
85 m = mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0];
86 }
87
88 LangString name;
89 std::string adminname, uniqueid, reason, SUI;
90 currentNode->getNamedParameter("name", name, false);
91 currentNode->getNamedParameter("adminname", adminname, false);
92 currentNode->getNamedParameter("reason", reason, false);
93 currentNode->getNamedParameter("id", uniqueid, false);
94 currentNode->getNamedParameter("SUI", SUI, false);
95
96 // Time
97 time_t bantime = 0;
98 if (currentNode->getNamedParameter("time", timeNode, false))
99 {
100 sscanf(timeNode->getContent(), "%u", &bantime);
101 }
102
103 // Type
104 BannedType type = Banned;
105 if (currentNode->getNamedParameter("type", typeNode, false))
106 {
107 if (0 == strcmp("banned", typeNode->getContent())) type = Banned;
108 else if (0 == strcmp("muted", typeNode->getContent())) type = Muted;
109 else if (0 == strcmp("flagged", typeNode->getContent())) type = Flagged;
110 else
111 {
112 S3D::dialogMessage("ServerBanned",
113 S3D::formatStringBuffer("Failed to parse banned type %s",
114 typeNode->getContent()));
115 return false;
116 }
117 }
118
119 // Read the ip address
120 unsigned int address[4];
121 if (sscanf(currentNode->getContent(), "%u.%u.%u.%u",
122 &address[3], &address[2], &address[1], &address[0]) != 4)
123 {
124 S3D::dialogMessage("ServerBanned",
125 S3D::formatStringBuffer("Failed to parse ip address %s",
126 currentNode->getContent()));
127 return false;
128 }
129
130 unsigned int ip = 0;
131 ip = address[3] << 24 | address[2] << 16 | address[1] << 8 | address[0];
132
133 // Add the new entry
134 addBannedEntry(ip, m, name, uniqueid.c_str(), SUI.c_str(),
135 (unsigned int) bantime, type,
136 adminname.c_str(), reason.c_str());
137 }
138 return true;
139 }
140
getBannedIps()141 std::list<ServerBanned::BannedRange> &ServerBanned::getBannedIps()
142 {
143 load();
144 return bannedIps_;
145 }
146
getBanned(const char * unqiueid,const char * SUI)147 ServerBanned::BannedType ServerBanned::getBanned(
148 const char *unqiueid, const char *SUI)
149 {
150 load();
151
152 // Check if the unique id has been banned
153 std::map<std::string, BannedEntry>::iterator findItor =
154 bannedIds_.find(unqiueid);
155 if (findItor != bannedIds_.end())
156 {
157 BannedEntry &entry = (*findItor).second;
158 return entry.type;
159 }
160
161 // Check if the SUI has been banned
162 std::map<std::string, BannedEntry>::iterator findItor2 =
163 bannedSUIs_.find(SUI);
164 if (findItor2 != bannedSUIs_.end())
165 {
166 BannedEntry &entry = (*findItor2).second;
167 return entry.type;
168 }
169 return NotBanned;
170 }
171
getBanned(unsigned int ip)172 ServerBanned::BannedType ServerBanned::getBanned(
173 unsigned int ip)
174 {
175 load();
176
177 // Check if the ip address has been banned
178 std::list<BannedRange>::iterator itor;
179 for (itor = bannedIps_.begin();
180 itor != bannedIps_.end();
181 ++itor)
182 {
183 BannedRange &range = *itor;
184 unsigned int newip = range.mask & ip;
185 std::map<unsigned int, BannedEntry>::iterator findItor =
186 range.ips.find(newip);
187 if (findItor != range.ips.end())
188 {
189 BannedEntry &entry = (*findItor).second;
190 return entry.type;
191 }
192 }
193 return NotBanned;
194 }
195
addBanned(unsigned int ip,const LangString & name,const char * uniqueId,const char * SUI,BannedType type,const char * adminname,const char * reason)196 void ServerBanned::addBanned(unsigned int ip, const LangString &name,
197 const char *uniqueId, const char *SUI, BannedType type,
198 const char *adminname, const char *reason)
199 {
200 unsigned int t = (unsigned int) time(0);
201 addBannedEntry(ip, UINT_MAX, name, uniqueId, SUI, t, type, adminname, reason);
202 save();
203 }
204
addBannedEntry(unsigned int ip,unsigned int mask,const LangString & name,const char * uniqueId,const char * SUid,unsigned int bantime,BannedType type,const char * adminname,const char * reason)205 void ServerBanned::addBannedEntry(unsigned int ip, unsigned int mask,
206 const LangString &name, const char *uniqueId, const char *SUid, unsigned int bantime, BannedType type,
207 const char *adminname, const char *reason)
208 {
209 unsigned int newip = mask & ip;
210 BannedEntry newEntry;
211 newEntry.name = name;
212 newEntry.bantime = bantime;
213 newEntry.type = type;
214 newEntry.uniqueid = uniqueId;
215 newEntry.SUI = SUid;
216 newEntry.adminname = adminname;
217 newEntry.reason = reason;
218
219 BannedRange *found = 0;
220 std::list<BannedRange>::iterator itor;
221 for (itor = bannedIps_.begin();
222 itor != bannedIps_.end();
223 ++itor)
224 {
225 BannedRange &range = *itor;
226 if (range.mask == mask)
227 {
228 found = ⦥
229 break;
230 }
231 }
232 if (!found)
233 {
234 BannedRange range;
235 range.mask = mask;
236 bannedIps_.push_back(range);
237 found = &bannedIps_.back();
238 }
239
240 // Add ip to list of banned ips
241 found->ips[newip] = newEntry;
242
243 // Add id to list of banned ids
244 if (uniqueId[0])
245 {
246 std::map<std::string, BannedEntry>::iterator findItor =
247 bannedIds_.find(uniqueId);
248 if (findItor == bannedIds_.end())
249 {
250 bannedIds_[uniqueId] = newEntry;
251 }
252 }
253
254 // Add SUI to list of banned SUIs
255 if (SUid[0])
256 {
257 std::map<std::string, BannedEntry>::iterator findItor2 =
258 bannedSUIs_.find(SUid);
259 if (findItor2 == bannedSUIs_.end())
260 {
261 bannedSUIs_[SUid] = newEntry;
262 }
263 }
264 }
265
getBannedTypeStr(BannedType type)266 const char *ServerBanned::getBannedTypeStr(BannedType type)
267 {
268 const char *str = "error";
269 switch (type)
270 {
271 case Muted:
272 str = "muted";
273 break;
274 case Banned:
275 str = "banned";
276 break;
277 case NotBanned:
278 str = "notbanned";
279 break;
280 case Flagged:
281 str = "flagged";
282 break;
283 }
284 return str;
285 }
286
save()287 bool ServerBanned::save()
288 {
289 std::string filename =
290 S3D::getSettingsFile(S3D::formatStringBuffer("banned-%i.xml",
291 ScorchedServer::instance()->getOptionsGame().getPortNo()));
292
293 XMLNode node("bannednodes");
294 std::list<BannedRange>::iterator itor;
295 for (itor = bannedIps_.begin();
296 itor != bannedIps_.end();
297 ++itor)
298 {
299 BannedRange &range = *itor;
300 unsigned int m = range.mask;
301 std::map<unsigned int, BannedEntry>::iterator ipitor;
302 for (ipitor = range.ips.begin();
303 ipitor != range.ips.end();
304 ++ipitor)
305 {
306 // Add ip address
307 unsigned int ip = (*ipitor).first;
308 BannedEntry &entry = (*ipitor).second;
309 XMLNode *optionNode =
310 new XMLNode("ipaddress", NetInterface::getIpName(ip));
311
312 // Add the mask
313 if (m != UINT_MAX)
314 {
315 optionNode->addParameter(new XMLNode("mask", NetInterface::getIpName(m),
316 XMLNode::XMLParameterType));
317 }
318 optionNode->addParameter(new XMLNode("name",
319 entry.name,
320 XMLNode::XMLParameterType));
321 optionNode->addParameter(new XMLNode("time",
322 S3D::formatStringBuffer("%u", (unsigned int) entry.bantime),
323 XMLNode::XMLParameterType));
324 optionNode->addParameter(new XMLNode("type",
325 getBannedTypeStr(entry.type),
326 XMLNode::XMLParameterType));
327 optionNode->addParameter(new XMLNode("id",
328 entry.uniqueid,
329 XMLNode::XMLParameterType));
330 optionNode->addParameter(new XMLNode("SUI",
331 entry.SUI,
332 XMLNode::XMLParameterType));
333 optionNode->addParameter(new XMLNode("adminname",
334 entry.adminname,
335 XMLNode::XMLParameterType));
336 optionNode->addParameter(new XMLNode("reason",
337 entry.reason,
338 XMLNode::XMLParameterType));
339
340 // Add to file
341 if (entry.type != NotBanned)
342 {
343 node.addChild(optionNode);
344 }
345 }
346 }
347 return node.writeToFile(filename);
348 }
349
350