00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "../log.hpp"
00016 #include "../config.hpp"
00017
00018 #include "ban.hpp"
00019 #include <sstream>
00020
00021 namespace wesnothd {
00022
00023 #define LOG_SERVER LOG_STREAM(info, mp_server)
00024 #define DBG_SERVER LOG_STREAM(debug, mp_server)
00025
00026 bool banned_compare::operator()(const banned* a, const banned* b) const
00027 {
00028 return (*a) > (*b);
00029 }
00030
00031 banned::banned(const std::string& ip, const time_t end_time, const std::string& reason) : ip_(ip), end_time_(end_time), reason_(reason), deleted_(false)
00032 {
00033 }
00034
00035 banned::banned(const config& cfg)
00036 {
00037 read(cfg);
00038 }
00039
00040 void banned::read(const config& cfg)
00041 {
00042 ip_ = cfg["ip"];
00043 end_time_ = lexical_cast<time_t>(cfg["end_time"]);
00044 reason_ = cfg["reason"];
00045 deleted_ = utils::string_bool(cfg["deleted"]);
00046 }
00047
00048 void banned::write(config& cfg) const
00049 {
00050 std::stringstream ss;
00051 cfg["ip"] = ip_;
00052 ss << end_time_;
00053 cfg["end_time"] = ss.str();
00054 cfg["reason"] = reason_;
00055 cfg["deleted"] = deleted_ ? "yes":"no";
00056 }
00057
00058 std::string banned::get_human_end_time() const
00059 {
00060 char buf[30];
00061 struct tm* local;
00062 local = localtime(&end_time_);
00063 strftime(buf,30,"%H:%M:%S %d.%m.%Y", local );
00064 return std::string(buf);
00065 }
00066
00067 bool banned::operator>(const banned& b) const
00068 {
00069 return end_time_ > b.get_end_time();
00070 }
00071
00072 void ban_manager::read(const config& cfg)
00073 {
00074 const config::child_list& bans = cfg.get_children("ban");
00075 for (config::child_list::const_iterator itor = bans.begin();
00076 itor != bans.end(); ++itor)
00077 {
00078 banned* new_ban = new banned(**itor);
00079 if (!new_ban->is_deleted())
00080 {
00081 bans_[new_ban->get_ip()] = new_ban;
00082 }
00083 time_queue_.push(new_ban);
00084 }
00085 }
00086
00087 void ban_manager::write(config& cfg) const
00088 {
00089 for (ban_map::const_iterator itor = bans_.begin();
00090 itor != bans_.end(); ++itor)
00091 {
00092 config& child = cfg.add_child("ban");
00093 itor->second->write(child);
00094 }
00095 }
00096
00097 time_t ban_manager::parse_time(std::string time_in) const
00098 {
00099 time_t ret;
00100 ret = time(NULL);
00101 if (time_in.substr(0,4) == "TIME")
00102 {
00103 struct tm* loc;
00104 loc = localtime(&ret);
00105
00106 std::string::iterator i = time_in.begin() + 4;
00107 size_t number = 0;
00108 for (; i != time_in.end(); ++i)
00109 {
00110 if (is_number(*i))
00111 {
00112 number = number*10 + to_number(*i);
00113 }
00114 else
00115 {
00116 switch(*i)
00117 {
00118 case 'Y':
00119 loc->tm_year = number;
00120 break;
00121 case 'M':
00122 loc->tm_mon = number;
00123 break;
00124 case 'D':
00125 loc->tm_mday = number;
00126 break;
00127 case 'h':
00128 loc->tm_hour = number;
00129 break;
00130 case 'm':
00131 loc->tm_min = number;
00132 break;
00133 case 's':
00134 loc->tm_sec = number;
00135 break;
00136 default:
00137 LOG_SERVER << "Wrong time code for ban: " << *i << "\n";
00138 break;
00139 }
00140 number = 0;
00141 }
00142 }
00143 return mktime(loc);
00144 }
00145 default_ban_times::const_iterator time_itor = ban_times_.find(time_in);
00146 if (time_itor != ban_times_.end())
00147 ret += time_itor->second;
00148 else
00149 {
00150 size_t multipler = 60;
00151 std::string::iterator i = time_in.begin();
00152 size_t number = 0;
00153 for (; i != time_in.end(); ++i)
00154 {
00155 if (is_number(*i))
00156 {
00157 number = number * 10 + to_number(*i);
00158 } else {
00159 switch(*i)
00160 {
00161 case 'Y':
00162 multipler = 365*24*60*60;
00163 break;
00164 case 'M':
00165 multipler = 30*24*60*60;
00166 break;
00167 case 'D':
00168 multipler = 24*60*60;
00169 break;
00170 case 'h':
00171 multipler = 60*60;
00172 break;
00173 case 'm':
00174 multipler = 60;
00175 break;
00176 case 's':
00177 multipler = 1;
00178 break;
00179 default:
00180 LOG_SERVER << "Wrong time multipler code given: " << *i << "\n";
00181 break;
00182 }
00183 ret += number * multipler;
00184 }
00185 }
00186 --i;
00187 if (is_number(*i))
00188 {
00189 ret += number * multipler;
00190 }
00191 }
00192 return ret;
00193 }
00194
00195 void ban_manager::ban(const std::string& ip, const time_t& end_time, const std::string& reason)
00196 {
00197 ban_map::iterator ban;
00198 if ((ban = bans_.find(ip)) != bans_.end())
00199 {
00200
00201 ban->second->remove_ban();
00202 bans_.erase(ban);
00203 }
00204 banned *new_ban = new banned(ip, end_time, reason);
00205 bans_.insert(ban_map::value_type(ip,new_ban));
00206 time_queue_.push(new_ban);
00207 }
00208
00209 void ban_manager::unban(std::ostringstream& os, const std::string& ip)
00210 {
00211 ban_map::iterator ban = bans_.find(ip);
00212 if (ban == bans_.end())
00213 {
00214 os << "There is no ban on '" << ip << "'.";
00215 return;
00216 }
00217 ban->second->remove_ban();
00218 bans_.erase(ban);
00219
00220 os << "Ban on '" << ip << "' removed.";
00221 }
00222
00223 void ban_manager::check_ban_times(time_t time_now)
00224 {
00225 while (!time_queue_.empty())
00226 {
00227 banned* ban = time_queue_.top();
00228
00229 if (ban->get_end_time() > time_now)
00230 {
00231
00232 LOG_SERVER << "ban " << ban->get_ip() << " not removed. time: " << time_now << " end_time " << ban->get_end_time() << "\n";
00233 break;
00234 }
00235
00236 if (ban->is_deleted())
00237 {
00238
00239 time_queue_.pop();
00240 delete ban;
00241 continue;
00242 }
00243
00244
00245 LOG_SERVER << "Remove a ban " << ban->get_ip() << ". time: " << time_now << " end_time " << ban->get_end_time() << "\n";
00246
00247 bans_.erase(bans_.find(ban->get_ip()));
00248 time_queue_.pop();
00249 delete ban;
00250
00251 }
00252 }
00253
00254 void ban_manager::list_bans(std::ostringstream& out) const
00255 {
00256 if (bans_.empty())
00257 {
00258 out << "No bans set.";
00259 return;
00260 }
00261
00262 out << "BAN LIST\n";
00263 for (ban_map::const_iterator i = bans_.begin();
00264 i != bans_.end(); ++i)
00265 {
00266 out << "IP: '" << i->second->get_ip() <<
00267 "' end_time: '" << i->second->get_human_end_time() <<
00268 "' reason: '" << i->second->get_reason() << "'\n";
00269 }
00270
00271 }
00272
00273
00274 bool ban_manager::is_ip_banned(std::string ip) const
00275 {
00276 for (ban_map::const_iterator i = bans_.begin(); i != bans_.end(); ++i) {
00277 if (utils::wildcard_string_match(ip, i->first)) {
00278 DBG_SERVER << "Comparing ban '" << i->first << "' vs '..." << ip << "'\t" << "banned.\n";
00279 return true;
00280 }
00281 DBG_SERVER << "Comparing ban '" << i->first << "' vs '..." << ip << "'\t" << "not banned.\n";
00282 }
00283 return false;
00284 }
00285
00286 void ban_manager::init_ban_help()
00287 {
00288 ban_help_ = "ban <ip|nickname> <time> [<reason>]\nTime is give in formar ‰d[‰s‰d‰s...] (where ‰s is s, m, h, D, M or Y).\nIf no time modifier is given minutes are used.\n";
00289 default_ban_times::iterator itor = ban_times_.begin();
00290 if (itor != ban_times_.end())
00291 {
00292 ban_help_ += "You can also use " + itor->first;
00293 ++itor;
00294 }
00295 for (; itor != ban_times_.end(); ++itor)
00296 {
00297 ban_help_ += std::string(", ") + itor->first;
00298 }
00299 if (!ban_times_.empty())
00300 {
00301 ban_help_ += " for standard ban times.\n";
00302 }
00303 ban_help_ += "ban 127.0.0.1 2H20m flooded lobby\nban 127.0.0.2 medium flooded lobby again\n";
00304 }
00305
00306 void ban_manager::set_default_ban_times(const config& cfg)
00307 {
00308 ban_times_.clear();
00309 const config::child_list& times = cfg.get_children("ban_time");
00310 for (config::child_list::const_iterator itor = times.begin();
00311 itor != times.end(); ++itor)
00312 {
00313 ban_times_.insert(default_ban_times::value_type((**itor)["name"],
00314 parse_time((**itor)["time"])-time(NULL)));
00315 }
00316 init_ban_help();
00317 }
00318
00319 ban_manager::~ban_manager()
00320 {
00321 bans_.clear();
00322 while(!time_queue_.empty())
00323 {
00324 banned* ban = time_queue_.top();
00325 delete ban;
00326 time_queue_.pop();
00327 }
00328 }
00329
00330 ban_manager::ban_manager() : bans_(), time_queue_(), ban_times_(), ban_help_()
00331 {
00332 init_ban_help();
00333 }
00334
00335
00336 }