//////////////////////////////////////////////////////////////////////////////// // Scorched3D (c) 2000-2004 // // This file is part of Scorched3D. // // Scorched3D is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // Scorched3D is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Scorched3D; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include ServerBanned::ServerBanned() : lastReadTime_(0) { } ServerBanned::~ServerBanned() { } bool ServerBanned::load(bool force) { const char *filename = getSettingsFile(formatString("banned-%i.xml", ScorchedServer::instance()->getOptionsGame().getPortNo())); if (!s3d_fileExists(filename)) return true; time_t fileTime = s3d_fileModTime(filename); if (!force && fileTime == lastReadTime_) return true; XMLFile file; if (!file.readFile(filename)) { Logger::log(formatString("Failed to parse banned file \"%s\"\n%s", filename, file.getParserError())); return false; } Logger::log(formatString("Refreshing banned list %s", filename)); lastReadTime_ = fileTime; bannedIps_.clear(); bannedIds_.clear(); if (!file.getRootNode()) return true; // Empty File std::list::iterator childrenItor; std::list &children = file.getRootNode()->getChildren(); for (childrenItor = children.begin(); childrenItor != children.end(); childrenItor++) { XMLNode *currentNode = (*childrenItor); XMLNode *maskNode = 0, *nameNode = 0, *timeNode = 0, *typeNode = 0, *idNode = 0; // Read the mask unsigned int m = UINT_MAX; if (currentNode->getNamedParameter("mask", maskNode, false)) { unsigned int mask[4]; if (sscanf(maskNode->getContent(), "%u.%u.%u.%u", &mask[3], &mask[2], &mask[1], &mask[0]) != 4) { dialogMessage("ServerBanned", formatString("Failed to parse mask %s", maskNode->getContent())); return false; } m = mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]; } // Read name std::string name; if (currentNode->getNamedParameter("name", nameNode, false)) { name = nameNode->getContent(); } // Read unqiueid std::string uniqueid; if (currentNode->getNamedParameter("id", idNode, false)) { uniqueid = idNode->getContent(); } // Time time_t bantime = 0; if (currentNode->getNamedParameter("time", timeNode, false)) { sscanf(timeNode->getContent(), "%u", &bantime); } // Type BannedType type = Banned; if (currentNode->getNamedParameter("type", typeNode, false)) { if (0 == strcmp("banned", typeNode->getContent())) type = Banned; else if (0 == strcmp("muted", typeNode->getContent())) type = Muted; else if (0 == strcmp("flagged", typeNode->getContent())) type = Flagged; else { dialogMessage("ServerBanned", formatString("Failed to parse banned type %s", typeNode->getContent())); return false; } } // Read the ip address unsigned int address[4]; if (sscanf(currentNode->getContent(), "%u.%u.%u.%u", &address[3], &address[2], &address[1], &address[0]) != 4) { dialogMessage("ServerBanned", formatString("Failed to parse ip address %s", currentNode->getContent())); return false; } unsigned int ip = 0; ip = address[3] << 24 | address[2] << 16 | address[1] << 8 | address[0]; // Add the new entry addBannedEntry(ip, m, name.c_str(), uniqueid.c_str(), bantime, type); } return true; } std::list &ServerBanned::getBannedIps() { load(); return bannedIps_; } ServerBanned::BannedType ServerBanned::getBanned( unsigned int ip, const char *unqiueid) { load(); // Check if the unique id has been banned std::map::iterator findItor = bannedIds_.find(unqiueid); if (findItor != bannedIds_.end()) { BannedEntry &entry = (*findItor).second; return entry.type; } // Check if the ip address has been banned std::list::iterator itor; for (itor = bannedIps_.begin(); itor != bannedIps_.end(); itor++) { BannedRange &range = *itor; unsigned int newip = range.mask & ip; std::map::iterator findItor = range.ips.find(newip); if (findItor != range.ips.end()) { BannedEntry &entry = (*findItor).second; return entry.type; } } return NotBanned; } void ServerBanned::addBanned(unsigned int ip, const char *name, const char *uniqueId, BannedType type) { unsigned int t = time(0); addBannedEntry(ip, UINT_MAX, name, uniqueId, t, type); save(); } void ServerBanned::addBannedEntry(unsigned int ip, unsigned int mask, const char *name, const char *uniqueId, unsigned int bantime, BannedType type) { unsigned int newip = mask & ip; BannedEntry newEntry; newEntry.name = name; newEntry.bantime = bantime; newEntry.type = type; newEntry.uniqueid = uniqueId; BannedRange *found = 0; std::list::iterator itor; for (itor = bannedIps_.begin(); itor != bannedIps_.end(); itor++) { BannedRange &range = *itor; if (range.mask == mask) { found = ⦥ break; } } if (!found) { BannedRange range; range.mask = mask; bannedIps_.push_back(range); found = &bannedIps_.back(); } // Add ip to list of banned ips found->ips[newip] = newEntry; // Add id to list of banned ids if (uniqueId[0]) { std::map::iterator findItor = bannedIds_.find(uniqueId); if (findItor == bannedIds_.end()) { bannedIds_[uniqueId] = newEntry; } } } const char *ServerBanned::getBannedTypeStr(BannedType type) { const char *str = "error"; switch (type) { case Muted: str = "muted"; break; case Banned: str = "banned"; break; case NotBanned: str = "notbanned"; break; case Flagged: str = "flagged"; break; } return str; } bool ServerBanned::save() { const char *filename = getSettingsFile(formatString("banned-%i.xml", ScorchedServer::instance()->getOptionsGame().getPortNo())); XMLNode node("bannednodes"); std::list::iterator itor; for (itor = bannedIps_.begin(); itor != bannedIps_.end(); itor++) { BannedRange &range = *itor; unsigned int m = range.mask; std::map::iterator ipitor; for (ipitor = range.ips.begin(); ipitor != range.ips.end(); ipitor++) { // Add ip address unsigned int ip = (*ipitor).first; BannedEntry &entry = (*ipitor).second; XMLNode *optionNode = new XMLNode("ipaddress", NetInterface::getIpName(ip)); // Add the mask if (m != UINT_MAX) { optionNode->addParameter(new XMLNode("mask", NetInterface::getIpName(m), XMLNode::XMLParameterType)); } optionNode->addParameter(new XMLNode("name", entry.name.c_str(), XMLNode::XMLParameterType)); optionNode->addParameter(new XMLNode("time", formatString("%u", entry.bantime), XMLNode::XMLParameterType)); optionNode->addParameter(new XMLNode("type", getBannedTypeStr(entry.type), XMLNode::XMLParameterType)); optionNode->addParameter(new XMLNode("id", entry.uniqueid.c_str(), XMLNode::XMLParameterType)); // Add to file if (entry.type != NotBanned) { node.addChild(optionNode); } } } return node.writeToFile(filename); }