diff options
-rw-r--r-- | server/proxy_ui_server.workspace | 12 | ||||
-rw-r--r-- | server/server/Makefile | 9 | ||||
-rw-r--r-- | server/server/config.cpp | 105 | ||||
-rw-r--r-- | server/server/config.h | 45 | ||||
-rw-r--r-- | server/server/config_example | 17 | ||||
-rw-r--r-- | server/server/headers.h | 24 | ||||
-rw-r--r-- | server/server/log.cpp | 46 | ||||
-rw-r--r-- | server/server/log.h | 29 | ||||
-rw-r--r-- | server/server/main.cpp | 1184 | ||||
-rw-r--r-- | server/server/main.h | 169 | ||||
-rw-r--r-- | server/server/server.project | 113 | ||||
-rw-r--r-- | server/server/utilities.cpp | 18 | ||||
-rw-r--r-- | server/server/utilities.h | 7 |
13 files changed, 1778 insertions, 0 deletions
diff --git a/server/proxy_ui_server.workspace b/server/proxy_ui_server.workspace new file mode 100644 index 0000000..964a5cc --- /dev/null +++ b/server/proxy_ui_server.workspace @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<CodeLite_Workspace Name="proxy_ui_server" Database="./proxy_ui_server.tags"> + <Project Name="server" Path="server/server.project" Active="Yes"/> + <BuildMatrix> + <WorkspaceConfiguration Name="Debug" Selected="yes"> + <Project Name="server" ConfigName="Debug"/> + </WorkspaceConfiguration> + <WorkspaceConfiguration Name="Release" Selected="yes"> + <Project Name="server" ConfigName="Release"/> + </WorkspaceConfiguration> + </BuildMatrix> +</CodeLite_Workspace> diff --git a/server/server/Makefile b/server/server/Makefile new file mode 100644 index 0000000..d3aa807 --- /dev/null +++ b/server/server/Makefile @@ -0,0 +1,9 @@ +all: + g++ -c *.cpp -I/usr/include -O2 -pipe -march=i686 -msse -fomit-frame-pointer + g++ -o core *.o -lssl -lcrypto -ldl -lboost_system-mt -lboost_date_time-mt -lboost_thread-mt -lboost_random-mt -lboost_filesystem-mt -lpthread -Wl,-O1 -s +clean: + rm *.o + +clean-all: + rm *.o *.dll + diff --git a/server/server/config.cpp b/server/server/config.cpp new file mode 100644 index 0000000..e145b4a --- /dev/null +++ b/server/server/config.cpp @@ -0,0 +1,105 @@ +#include "headers.h" + +config::config(const char *pth) +{ + std::ifstream config; + if(!pth) + config.open("/etc/aion_otp", std::fstream::out); + else + config.open(pth, std::fstream::in); + std::string cfg_str((std::istreambuf_iterator<char>(config)), std::istreambuf_iterator<char>()); + config.close(); + vars.ban_time = get_int(cfg_str, "BanTime=", 60); + vars.check_interval = get_int(cfg_str, "ConnListCheckInterval=", 30); + vars.conn_count = get_int(cfg_str, "ConnectionCount=", 30); + vars.conn_time = get_int(cfg_str, "ConnectionTimeOut=", 60); + vars.dos_conn_count = get_int(cfg_str, "DosConnectionCount=", 200); + vars.invalid_ml_count = get_int(cfg_str, "MainAccountInvalidLoginCount=", 10); + vars.invalid_sub_count = get_int(cfg_str, "SubAccountInvalidLoginCount=", 3); + vars.ls_port = get_int(cfg_str, "LSServerPort=", 80); + vars.debug = get_int(cfg_str, "Debug=", 0); + vars.bind_ip = get_string(cfg_str, "BindAddress=", "0.0.0.0"); + vars.ls_host = get_string(cfg_str, "LSServerHost=", "ls.aionlegend.ru"); + vars.log_path = get_string(cfg_str, "LogPath=", "/var/log/aion_otp"); + vars.dos_log_path = get_string(cfg_str, "DosLogPath=", "/var/log/aion_otp_dos"); +} +const int config::get_int(const std::string& data, const char* var, int default_) +{ + std::string::size_type p1 = 0, p2 = 0; + p1 = data.find(var); + if(p1 != std::string::npos) + { + p2 = data.find(";", p1); + if(p2 == std::string::npos) + p2 = data.length(); + p1+=strlen(var); + return atoi(data.substr(p1, p2-p1).c_str()); + } + return default_; +} +const std::string config::get_string(const std::string& data, const char* var, const std::string& default_) +{ + std::string::size_type p1 = 0, p2 = 0; + p1 = data.find(var); + if(p1 != std::string::npos) + { + p2 = data.find(";", p1); + if(p2 == std::string::npos) + p2 = data.length(); + p1+=strlen(var); + return data.substr(p1, p2-p1).c_str(); + } + return default_; +} +const int config::ban_time() +{ + return vars.ban_time; +} +const int config::invalid_ml_count() +{ + return vars.invalid_ml_count; +} +const int config::conn_count() +{ + return vars.conn_count; +} +const int config::conn_time() +{ + return vars.conn_time; +} +const int config::check_interval() +{ + return vars.check_interval; +} +const int config::invalid_sub_count() +{ + return vars.invalid_sub_count; +} +const int config::ls_port() +{ + return vars.ls_port; +} +const int config::debug() +{ + return vars.debug; +} +const int config::dos_conn_count() +{ + return vars.dos_conn_count; +} +const std::string& config::ls_host() +{ + return vars.ls_host; +} +const std::string& config::bind_ip() +{ + return vars.bind_ip; +} +const std::string& config::log_path() +{ + return vars.log_path; +} +const std::string& config::dos_log_path() +{ + return vars.dos_log_path; +} diff --git a/server/server/config.h b/server/server/config.h new file mode 100644 index 0000000..0c8450c --- /dev/null +++ b/server/server/config.h @@ -0,0 +1,45 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include "headers.h" + +class config +{ +public: + config(const char *path); + const int ban_time(); + const int invalid_ml_count(); + const int conn_count(); + const int conn_time(); + const int check_interval(); + const int invalid_sub_count(); + const int ls_port(); + const int debug(); + const int dos_conn_count(); + const std::string& ls_host(); + const std::string& bind_ip(); + const std::string& log_path(); + const std::string& dos_log_path(); +private: + struct cfg_data + { + int ban_time, invalid_ml_count, conn_count, check_interval, invalid_sub_count, ls_port, debug, dos_conn_count, conn_time; + std::string ls_host, log_path, bind_ip, dos_log_path; + cfg_data() + { + ban_time = conn_time = 60; + invalid_ml_count = 10; + conn_count = 30; + check_interval = 30; + invalid_sub_count = 3; + ls_port = 80; + debug = 0; + dos_conn_count = 200; + } + }; + const int get_int(const std::string& data, const char* var, int default_); + const std::string get_string(const std::string& data, const char* var, const std::string& default_); + cfg_data vars; +}; + +#endif
\ No newline at end of file diff --git a/server/server/config_example b/server/server/config_example new file mode 100644 index 0000000..712ef6b --- /dev/null +++ b/server/server/config_example @@ -0,0 +1,17 @@ +BanTime=60; //minutes +ConnListCheckInterval=30; //seconds +ConnectionCount=30; //conection limit for ban +ConnectionTimeOut=60; //conection limit for ban +DosConnectionCount=200; //conections before adding to dos list +MainAccountInvalidLoginCount=10; //invalid logins to ban +SubAccountInvalidLoginCount=3; //subaccount invalid logins to disconnect +LSServerPort=80; //port for ls server http connection +LSServerHost=chat1.aionlegend.ru; //ls server host +BindAddress=0.0.0.0; //ip address to listen on, 0.0.0.0 - any +LogPath=/var/aion_otp; //auth system log file path, use /dev/null for disable +DosLogPath=/var/log/aion_otp_dos; // log path for dos ip list +Debug=0; //debug log + +//options name are case sensitive +//no spaces allowed in options +//; - end line character
\ No newline at end of file diff --git a/server/server/headers.h b/server/server/headers.h new file mode 100644 index 0000000..0d1867e --- /dev/null +++ b/server/server/headers.h @@ -0,0 +1,24 @@ +#ifndef HEADERS_H +#define HEADERS_H + +#include <unistd.h> +#include <iostream> +#include <fstream> +#include <vector> +#include <list> +#include <string> +#include <algorithm> +#include <boost/asio.hpp> +#include <boost/asio/ssl.hpp> +#include <boost/random.hpp> +#include <boost/nondet_random.hpp> +#include <boost/thread/thread.hpp> +#include <boost/date_time.hpp> +#include <boost/filesystem.hpp> + +#include "utilities.h" +#include "main.h" +#include "log.h" +#include "config.h" + +#endif diff --git a/server/server/log.cpp b/server/server/log.cpp new file mode 100644 index 0000000..41ef828 --- /dev/null +++ b/server/server/log.cpp @@ -0,0 +1,46 @@ +#include "headers.h" + +logtofile& logtofile::operator<<(const char *buf) +{ + log.open(path, std::ios::app | std::ios::out); + if(log.fail()) + std::cerr << "Failed to open log "<< path <<"\n"; + else + log<<buf; + log.close(); + return *this; +} +logtofile& logtofile::operator<<(std::string buf) +{ + log.open(path, std::ios::app | std::ios::out); + if(log.fail()) + std::cerr << "Failed to open log "<< path <<"\n"; + else + log<<buf; + log.close(); + return *this; +} +logtofile& logtofile::operator<<(int buf) +{ + log.open(path, std::ios::app | std::ios::out); + if(log.fail()) + std::cerr << "Failed to open log "<< path <<"\n"; + else + log<<buf; + log.close(); + return *this; +} + +logtofile::logtofile(const char *pth) +{ + if(pth) + path = strdup(pth); +} +logtofile::logtofile() +{ + path = strdup("/var/log/aion_otp"); +} +logtofile::~logtofile() +{ + free(path); +} diff --git a/server/server/log.h b/server/server/log.h new file mode 100644 index 0000000..9f35bc4 --- /dev/null +++ b/server/server/log.h @@ -0,0 +1,29 @@ +#ifndef LOG_H +#define LOG_H + +#include "headers.h" + +class logtofile +{ +public: + logtofile& operator<<(const char *buf); + logtofile& operator<<(std::string buf); + logtofile& operator<<(int buf); + ~logtofile(); + logtofile(const char *pth); + logtofile(); + void lock() + { + log_mutex2.lock(); + } + void unlock() + { + log_mutex2.unlock(); + } +private: + std::ofstream log; + char *path; + boost::mutex log_mutex2; +}; + +#endif
\ No newline at end of file diff --git a/server/server/main.cpp b/server/server/main.cpp new file mode 100644 index 0000000..30d6404 --- /dev/null +++ b/server/server/main.cpp @@ -0,0 +1,1184 @@ + +#include "main.h" +#include "headers.h" + +logtofile *logger, *dos_logger; +config *cfg; + +http_client::http_client(boost::asio::io_service& io_service, const std::string& new_server, const std::string& path, session* sess_, int request_type, server* serv_) : resolver_(io_service), socket_(io_service), io_service_(io_service) + { + // Form the request. We specify the "Connection: close" header so that the + // server will close the socket after transmitting the response. This will + // allow us to treat all data up until the EOF as the content. + session_ = sess_; + server_ = new_server; + serv = serv_; + std::ostream request_stream(&request_); + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": Requesting: " << path << "for client " << session_->get_ip() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + } + request_stream << "GET " << path << " HTTP/1.0\r\n"; + request_stream << "Host: " << new_server << "\r\n"; + request_stream << "User-Agent: Internal Auth Client v0.0.0.1\r\n"; + request_stream << "Accept: */*\r\n"; + request_stream << "Connection: close\r\n\r\n"; + + // Start an asynchronous resolve to translate the server and service names + // into a list of endpoints. + tcp::resolver::query query(new_server, "http"); + resolver_.async_resolve(query, + boost::bind(&http_client::handle_resolve, this, + boost::asio::placeholders::error, + boost::asio::placeholders::iterator, request_type)); + } + + + +void http_client::request(const std::string& path, int request_type) + { + + std::ostream request_stream(&request_); + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str()<< ": Requesting: " << path << "for client " << session_->get_ip() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + } + request_stream << "GET " << path << " HTTP/1.0\r\n"; + request_stream << "Host: " << server_ << "\r\n"; + request_stream << "User-Agent: Internal Auth Client v0.0.0.1\r\n"; + request_stream << "Accept: */*\r\n"; + request_stream << "Connection: close\r\n\r\n"; + + // Start an asynchronous resolve to translate the server and service names + // into a list of endpoints. + tcp::resolver::query query(server_, "http"); + resolver_.async_resolve(query, + boost::bind(&http_client::handle_resolve, this, + boost::asio::placeholders::error, + boost::asio::placeholders::iterator, request_type)); + } + + +void http_client::handle_resolve(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator, int request_type) + { + if (!err) + { + // Attempt a connection to the first endpoint in the list. Each endpoint + // will be tried until we successfully establish a connection. + tcp::endpoint endpoint = *endpoint_iterator; + endpoint.port(cfg->ls_port()); + socket_.async_connect(endpoint, + boost::bind(&http_client::handle_connect, this, + boost::asio::placeholders::error, ++endpoint_iterator, request_type)); + } + else + { + logger->lock(); + *logger << time_str() << ": Error: " << err.message() << " for client " << session_->get_ip() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + } + } + +void http_client::handle_connect(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator, int request_type) + { + if (!err) + { + // The connection was successful. Send the request. + boost::asio::async_write(socket_, request_, + boost::bind(&http_client::handle_write_request, this, + boost::asio::placeholders::error, request_type)); + } + else if (endpoint_iterator != tcp::resolver::iterator()) + { + // The connection failed. Try the next endpoint in the list. + socket_.close(); + tcp::endpoint endpoint = *endpoint_iterator; + socket_.async_connect(endpoint, + boost::bind(&http_client::handle_connect, this, + boost::asio::placeholders::error, ++endpoint_iterator, request_type)); + } + else + { + logger->lock(); + *logger << time_str() << ": Error: " << err.message() << " for client " << session_->get_ip() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + } + } + +void http_client::handle_write_request(const boost::system::error_code& err, int request_type) + { + if (!err) + { + // Read the response status line. The response_ streambuf will + // automatically grow to accommodate the entire line. The growth may be + // limited by passing a maximum size to the streambuf constructor. + if(socket_.is_open()) + boost::asio::async_read_until(socket_, response_, "\r\n", + boost::bind(&http_client::handle_read_status_line, this, + boost::asio::placeholders::error, request_type)); + } + else + { + logger->lock(); + *logger << time_str() << ": Error: " << err.message() << " for client " << session_->get_ip() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + } + } + +void http_client::handle_read_status_line(const boost::system::error_code& err, int request_type) + { + if (!err) + { + // Check that response is OK. + std::istream response_stream(&response_); + std::string http_version; + response_stream >> http_version; + unsigned int status_code; + response_stream >> status_code; + std::string status_message; + std::getline(response_stream, status_message); + if (!response_stream || http_version.substr(0, 5) != "HTTP/") + { + logger->lock(); + *logger << time_str() << ": Invalid response from LS" << "for client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + return; + } + if (status_code != 200) + { + logger->lock(); + *logger << time_str() << ": Response returned with status code " << status_code << " for client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + return; + } + + // Read the response headers, which are terminated by a blank line. + if(socket_.is_open()) + boost::asio::async_read_until(socket_, response_, "\r\n\r\n", + boost::bind(&http_client::handle_read_headers, this, + boost::asio::placeholders::error, request_type)); + } + else + { + logger->lock(); + *logger << time_str() << ": Error: " << err.message() << " for client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + } + } + +void http_client::handle_read_headers(const boost::system::error_code& err, int request_type) + { + if (!err) + { + // Process the response headers. + std::istream response_stream(&response_); + std::string header; + while (std::getline(response_stream, header) && header != "\r") + { + if(cfg->debug()) + { + logger->lock(); + *logger << header << "\n"; + logger->unlock(); + } + } + if(cfg->debug()) + { + logger->lock(); + *logger << "\nfor client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + } + + // Write whatever content we already have to output. + if (response_.size() > 0) + { +// response += boost::asio::buffer_cast<const char*>(response_.data()); + response_stream >> response; + if(cfg->debug()) + { + logger->lock(); + *logger << time_str() << ": have while processing headers: "<< response << " client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id()<< " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + } + } + + // Start reading remaining data until EOF. + if(socket_.is_open()) + boost::asio::async_read(socket_, response_, + boost::asio::transfer_at_least(1), + boost::bind(&http_client::handle_read_content, this, + boost::asio::placeholders::error, request_type)); + } + else + { + logger->lock(); + *logger << time_str() << ": Error: " << err.message() << " for client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + } + } +void http_client::proto_parser(int request_type) + { + if(!request_type) + { + std::string::size_type p1 = 0, p2 = 0; + p1 = response.find("0:"); + if(p1 != std::string::npos) + { // error + p1 += strlen("0:"); + const byte buf [] = {0x83, 0x83, 0xda, 0xb1, 0xdb, 0xaa, 0xab, 0x66, 0x66, 0xac, 0x84, 0x84}; //return failure to client + std::vector<byte> vec(buf, buf+sizeof(buf)); + session_->write_w_close(vec); + socket_.close(); + response.clear(); + logger->lock(); + *logger << time_str() << ": Master account auth fail for client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + serv->auth_fail_increment(session_->get_ip(), session_->get_this_sid()); + return; + } + p1 = response.find("1:"); + if(p1 != std::string::npos) + { + //login success, send sid before account list + const byte buf [] = {0x83, 0x83, 0xda, 0xb1, 0xdb, 0xaa, 0xab, 0x13, 0x13, 0xad}; + std::vector<byte> vec(buf, buf+sizeof(buf)); + std::string sid = get_random(12); + session_->set_sid(sid); + for(int i = 0; i < sid.length(); ++i) + vec.push_back(sid[i]); + vec.push_back(0xad); + p1 += 2; + std::list<account> local_accs; + std::string acc_str; + for(p2 = response.find("|", p1); p2 != std::string::npos;) + { + for(int i = 0; i < response.substr(p1, p2-p1).length(); ++i) + { + vec.push_back(response.substr(p1, p2-p1)[i]); + acc_str.push_back(response.substr(p1, p2-p1)[i]); + } + { + int access_level =0, ban_time = 0; + std::string name; + std::string::size_type p1 =0, p2 = 0; + p2 = acc_str.find(","); + if(p2 != std::string::npos) + name.append(acc_str.substr(0, p2)); + p1 = p2 + 1; + p2 = acc_str.find(",", p1); + if(p2 != std::string::npos) + access_level = atoi(acc_str.substr(p1, p2).c_str()); + p1 = p2 + 1; + p2 = acc_str.length(); + ban_time = atoi(acc_str.substr(p1, p2).c_str()); + local_accs.push_back(account(name, access_level, ban_time)); + } + acc_str.clear(); + vec.push_back(0xad); + p1 = p2+1; + p2 = response.find("|", p1); + } + p2 = response.length(); + for(int i = 0; i < response.substr(p1, p2-p1).length(); ++i) + { + vec.push_back(response.substr(p1, p2-p1)[i]); + acc_str.push_back(response.substr(p1, p2-p1)[i]); + } + { + int access_level =0, ban_time = 0; + std::string name; + std::string::size_type p1 =0, p2 = 0; + p2 = acc_str.find(","); + if(p2 != std::string::npos) + name.append(acc_str.substr(0, p2)); + p1 = p2 + 1; + p2 = acc_str.find(",", p1); + if(p2 != std::string::npos) + access_level = atoi(acc_str.substr(p1, p2).c_str()); + p1 = p2 + 1; + p2 = acc_str.length(); + ban_time = atoi(acc_str.substr(p1, p2).c_str()); + local_accs.push_back(account(name, access_level, ban_time)); + } + session_->set_accounts(local_accs); + const byte end [] = {0xac, 0x84, 0x84}; + for(int i = 0; i < sizeof(end); ++i) + vec.push_back(end[i]); + session_->write_w_response(vec); //send success notification, sid and account list + logger->lock(); + *logger << time_str() << ": Master account auth success for client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + socket_.close(); + response.clear(); + return; + } + } + if(request_type == 1) //subacc + { + std::string::size_type p1 = 0, p2 = 0; + p1 = response.find("0:"); + if(p1 != std::string::npos) + { // error +// p1 += strlen("0:"); + const byte buf [] = {0x83, 0x83, 0xda, 0xb2, 0xdb, 0xaa, 0xab, 0x66, 0x66, 0xac, 0x84, 0x84}; //return failure to client + std::vector<byte> vec(buf, buf+sizeof(buf)); + if(session_->get_fail_count() < cfg->invalid_sub_count()) + session_->write_w_response(vec); + else + session_->write_w_close(vec); + socket_.close(); + response.clear(); + logger->lock(); + *logger << time_str() << ": sub account auth fail for client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + session_->fail_count_increment(); + return; + } + p1 = response.find("1:"); + if(p1 != std::string::npos) + { + p1 +=2; + const byte buf [] = {0x83, 0x83, 0xda, 0xb2, 0xdb, 0xaa, 0xab, 0x13, 0x13, 0xad}; + std::vector<byte> vec(buf, buf+sizeof(buf)); + p2 = response.length(); + for(int i = 0; i < response.substr(p1, p2-p1).length(); ++i) + vec.push_back(response.substr(p1, p2-p1)[i]); + const byte end [] = {0xac, 0x84, 0x84}; + for(int i = 0; i < sizeof(end); ++i) + vec.push_back(end[i]); + logger->lock(); + *logger << time_str() << ": sub account auth success for client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + session_->write_w_response(vec); //send subacc access sid + socket_.close(); + response.clear(); + return; + } + } + } + +void http_client::handle_read_content(const boost::system::error_code& err, int request_type) + { + if (!err) + { + // Write all of the data that has been read so far. + if(cfg->debug()) + { + logger->lock(); + *logger << time_str() << ": Appending remain data... for client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + } + std::istream response_stream(&response_); + response_stream >> response; +// response += boost::asio::buffer_cast<const char*>(response_.data()); + + // Continue reading remaining data until EOF. + boost::asio::async_read(socket_, response_, + boost::asio::transfer_at_least(1), + boost::bind(&http_client::handle_read_content, this, + boost::asio::placeholders::error, request_type)); + } + else if (err != boost::asio::error::eof) + { + logger->lock(); + *logger << time_str() << ": Error: " << err.message() << " for client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id() << " session " << session_->get_this_sid() << "\n"; + logger->unlock(); + } + else + { + if(cfg->debug()) + { + logger->lock(); + *logger << "\n" << time_str()<< ": for client ip " << session_->get_ip()<< " login hash " << session_->get_lhash() << " Hardware ID " << session_->get_hardware_id() << " session " << session_->get_this_sid() <<": End of data.\n"; + logger->unlock(); + } + proto_parser(request_type); + } + } + +/*http_client::~http_client() +{ + try + { + socket_.close(); + } + catch (std::exception& e) + { + logger->lock(); + *logger << time_str() << ": session delete exception: " << e.what() << "\n"; + logger->unlock(); + } +}*/ + + +//session +session::session(boost::asio::io_service& io_service, boost::asio::ssl::context& context, server *serv) : socket_(io_service, context), io_service_(io_service) +{ + this_sid = get_random(8); + recv_data_[0] = 0; + snd_data_[0] = 0; + fail_count = 0; + http_client_ = NULL; + server_ = serv; + blacklisted = canceled = false; + hardware_id = "Not received yet"; +} +void session::cancel_thread(session *s, int minutes) +{ + if(s->get_ip().empty()) + return; + boost::this_thread::sleep(boost::posix_time::minutes(minutes)); + if(boost::this_thread::interruption_requested()) + return; + s->set_cancel(); +} + +ssl_socket::lowest_layer_type& session::socket() +{ + return socket_.lowest_layer(); +} +session::~session() +{ + if(http_client_) + delete http_client_; + if(killer) + { + killer->interrupt(); + delete killer; + } + logger->lock(); + *logger << time_str() << ": Connection with ip "<< remote_ip << " session " << this_sid << " closed\n"; + logger->unlock(); +} + +void session::set_cancel() +{ + canceled = true; +} + +void session::start() + { + remote_ip = socket_.lowest_layer().remote_endpoint().address().to_string(); + killer = new boost::thread(boost::bind(session::cancel_thread, this, cfg->conn_time())); + logger->lock(); + *logger << time_str() << ": New incomming connection from "<< remote_ip << " session " << this_sid << "\n"; + logger->unlock(); + std::list<std::string>* blacklist = server_->get_blacklist(); + std::list<conn_count>* list = server_->get_connections_list(); + if(!blacklist->empty()) + { + std::list<std::string>::iterator end = blacklist->end(); + for(std::list<std::string>::iterator i = blacklist->begin(); i != end; ++i) + { + if(*i == remote_ip) + { + logger->lock(); + *logger << time_str() << ": session " << this_sid << " ip " << remote_ip << " is in blacklist\n"; + logger->unlock(); + blacklisted = true; + break; + } + } + } + server_->connections_increment(remote_ip, this_sid); + socket_.async_handshake(boost::asio::ssl::stream_base::server, boost::bind(&session::handle_handshake, this, boost::asio::placeholders::error)); + } +const int session::get_fail_count() +{ + return fail_count; +} +void session::fail_count_increment() +{ + fail_count++; +} +const std::string& session::get_ip() +{ + return remote_ip; +} + + +void session::handle_handshake(const boost::system::error_code& error) + { +// if(blacklisted) +// delete this; + if(cfg->debug()) + { + logger->lock(); + *logger << time_str() << ": following handshake error occured: " << error.message() << " for client " << remote_ip << " session " << this_sid << "\n"; + logger->unlock(); + } + if (!error) + socket_.async_read_some(boost::asio::buffer(recv_data_, max_length), boost::bind(&session::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + else + delete this; + } +void session::handle_write(const boost::system::error_code& error, size_t bytes_transferred) +{ + if(cfg->debug()) + { + logger->lock(); + *logger << time_str() << ": following write error occured: " << error.message() << " for client " << remote_ip << " session " << this_sid << "\n"; + logger->unlock(); + } + if(!error) + socket_.async_read_some(boost::asio::buffer(recv_data_, max_length), boost::bind(&session::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + else + delete this; + } + void session::handle_write_close(const boost::system::error_code& error, size_t bytes_transferred) + { + if(cfg->debug()) + { + logger->lock(); + *logger << time_str() << ": following write error occured: " << error.message() << " for client " << remote_ip << " session " << this_sid << "\n"; + logger->unlock(); + } + delete this; + } +void session::handle_auth_server_reply(const boost::system::error_code& error, size_t bytes_transferred) + { + //parse auth server response here + } + +void session::proto_parser(std::vector<byte>& data) + { + if(!data.empty()) + { + if(cfg->debug()) + { + logger->lock(); + *logger << time_str() << ": Working with data size: " << data.size() << "\n"; + *logger << time_str() << ": Searching for " << (const char*)data_end << " for client " << remote_ip << " session " << this_sid << "\n"; + logger->unlock(); + } + std::vector<byte>::iterator end = std::search(data.begin(), data.end(), data_end, data_end + 2); + if(end != data.end()) + { + std::vector<byte>::iterator begin = std::search(data.begin(), data.end(), data_begin, data_begin + 2); + if(begin != data.end()) + { + std::vector<byte> local_data(begin, end); + std::vector<byte>::iterator it = std::find(local_data.begin(), local_data.end(), data_type_begin); + if(it != local_data.end()) + { + ++it; + switch(*it) + { + case 0xa0: //login request + { + logger->lock(); + *logger<< time_str() << ": recieved login request from "<<remote_ip << " session " << this_sid <<"\n"; + logger->unlock(); + //fill snd_data_ + if(!blacklisted) + { + logger->lock(); + *logger<< time_str() << ": login request from "<<remote_ip<< " session " << this_sid << " are permited \n"; + logger->unlock(); + std::vector<byte>::iterator p1 = std::search(local_data.begin(), local_data.end(), delim, delim + 2); + if(p1 != local_data.end()) + { + p1 +=2; + std::vector<byte>::iterator p2 = std::find(local_data.begin(), local_data.end(),data_c_end); + if(p2 == local_data.end()) + delete this; + std::vector<byte> tmp_vec(p1, p2); + if(tmp_vec[0] < proto_version) + { + logger->lock(); + *logger<< time_str() << ": old client version, login denied " << remote_ip <<" session " << this_sid << "\n"; + logger->unlock(); + const unsigned char buf [] = {0x83, 0x83, 0xDA, 0xB0, 0xDB, 0xAA, 0xAB, 0x15, 0x15, 0xAC, 0x84, 0x84}; //login not permited + memset(snd_data_, 0, 1024); + for(int i = 0; i < sizeof(buf); i++) + snd_data_[i] = buf[i]; + socket_.async_write_some(boost::asio::buffer(snd_data_, max_length), boost::bind(&session::handle_write_close, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + } + else + { + const unsigned char buf [] = {0x83, 0x83, 0xDA, 0xB0, 0xDB, 0xAA, 0xAB, 0x13, 0x13, 0xAC, 0x84, 0x84}; //login permited + memset(snd_data_, 0, 1024); + for(int i = 0; i < sizeof(buf); i++) + snd_data_[i] = buf[i]; + socket_.async_write_some(boost::asio::buffer(snd_data_, max_length), boost::bind(&session::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + } + } + else + { + logger->lock(); + *logger<< time_str() << ": WARNING old client version, allowed old clients for now " << remote_ip <<" session " << this_sid << "\n"; + logger->unlock(); + const unsigned char buf [] = {0x83, 0x83, 0xDA, 0xB0, 0xDB, 0xAA, 0xAB, 0x13, 0x13, 0xAC, 0x84, 0x84}; //login permited + memset(snd_data_, 0, 1024); + for(int i = 0; i < sizeof(buf); i++) + snd_data_[i] = buf[i]; + socket_.async_write_some(boost::asio::buffer(snd_data_, max_length), boost::bind(&session::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + } + } + else + { + logger->lock(); + *logger<< time_str() << ": login request from "<<remote_ip << " session " << this_sid <<" are denied \n"; + logger->unlock(); + const unsigned char buf [] = {0x83, 0x83, 0xDA, 0xB0, 0xDB, 0xAA, 0xAB, 0x66, 0x66, 0xAC, 0x84, 0x84}; //login denied + memset(snd_data_, 0, 1024); + for(int i = 0; i < sizeof(buf); i++) + snd_data_[i] = buf[i]; + socket_.async_write_some(boost::asio::buffer(snd_data_, max_length), boost::bind(&session::handle_write_close, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + } + } + break; + case 0xa1: //main acc login request + { + logger->lock(); + *logger<< time_str() << ": recieved main account login info from " << remote_ip <<" session " << this_sid << "\n"; + logger->unlock(); + std::vector<byte>::iterator p1 = std::search(local_data.begin(), local_data.end(), delim, delim + 2); + if(p1 != local_data.end()) + { + std::vector<byte>::iterator p2 = std::find(local_data.begin(), local_data.end(),data_c_delim); + if(p2 != local_data.end()) + { + p1 +=2; + std::vector<byte> tmp_vec(p1, p2); + std::string request = "/index.php?/8870ebc1484f13c87ce89f19a8cd1605/get_ga_list/lhash:"; + lhash.clear(); + for(int i = 0; i < tmp_vec.size(); i++) + { + request.push_back(tmp_vec[i]); + lhash.push_back(tmp_vec[i]); + } + request.append(",phash:"); + ++p2; + p1 = std::find(p2, local_data.end(),data_c_delim); + if(p1 == local_data.end()) + { + p1 = std::find(p2, local_data.end(),data_c_end); + if(p1 == local_data.end()) + delete this; + else + { + logger->lock(); + *logger<< time_str() << ": WARNING old client version, allowed old clients for now " << remote_ip <<" session " << this_sid << "\n"; + logger->unlock(); + } + } + tmp_vec.assign(p2, p1); + for(int i = 0; i < tmp_vec.size(); i++) + request.push_back(tmp_vec[i]); + hardware_id.clear(); + ++p1; + p2 = std::find(p1, local_data.end(),data_c_end); + if(p2 != local_data.end()) + { + tmp_vec.assign(p1, p2); + for(int i = 0; i < tmp_vec.size(); i++) + hardware_id.push_back(tmp_vec[i]); + } + request.append(",hwid:"); + request.append(hardware_id); + request.push_back('/'); + if(http_client_) + delete http_client_; + http_client_ = new http_client(io_service_, cfg->ls_host(), request, this, 0, server_); + } + } + else + delete this; + } + break; + case 0xa2: //subacc login request + { + if(canceled) + { + delete this; + break; + } + std::vector<byte>::iterator p1 = std::find(local_data.begin(), local_data.end(), sid_begin); + if(p1 != local_data.end()) + { + ++p1; + if(accounts.empty()) + { + delete this; + break; + } + ///index.php?/[key]/get_ls_sid/mname:[mname],lname:[lname],pass:[sha1(pass)] + std::string request = "/index.php?/8870ebc1484f13c87ce89f19a8cd1605/get_ga_sid/mname:", response_sid; + for(; *p1 != sid_end; ++p1) + response_sid.push_back(*p1); + if(response_sid != sid) + { + logger->lock(); + *logger<<time_str()<<": Invalid sid from ip "<<remote_ip << " login hash " << lhash << " Hardware ID " << hardware_id << " session " << this_sid <<"\n"; + logger->unlock(); + const unsigned char buf [] = {0x83, 0x83, 0xDA, 0xB2, 0xDB, 0xAA, 0xAB, 0x66, 0x66, 0xAC, 0x84, 0x84}; //login denied + memset(snd_data_, 0, 1024); + for(int i = 0; i < sizeof(buf); i++) + snd_data_[i] = buf[i]; + socket_.async_write_some(boost::asio::buffer(snd_data_, max_length), boost::bind(&session::handle_write_close, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + } + p1 = std::search(local_data.begin(), local_data.end(), delim, delim +2); + if(p1 == local_data.end()) + { + logger->lock(); + *logger<<time_str()<<": Data not found in request from ip "<<remote_ip << " login hash " << lhash << " Hardware ID " << hardware_id << " session " << this_sid<<"\n"; + logger->unlock(); + delete this; + break; + } + p1 +=2; + for(; *p1 != data_c_delim; ++p1) + request.push_back(*p1); + ++p1; + request += ",lname:"; + std::string recvd_acc; + for(; *p1 != data_c_delim; ++p1) + { + request.push_back(*p1); + recvd_acc.push_back(*p1); + } + logger->lock(); + *logger<< time_str() << ": recieved subacc login info from ip "<<remote_ip << " login hash " << lhash << " Hardware ID " << hardware_id << " game account " << recvd_acc << " session " << this_sid <<"\n"; + logger->unlock(); + std::list<account>::iterator t_acc = std::find(accounts.begin(), accounts.end(), recvd_acc); + if(t_acc == accounts.end() || t_acc->ban_time == -1) + { + logger->lock(); + *logger<<time_str()<<": account "<< recvd_acc << " not exist for ip " << remote_ip << " login hash " << lhash << " Hardware ID " << hardware_id << " session " << this_sid << "\n"; + logger->unlock(); + const byte buf [] = {0x83, 0x83, 0xda, 0xb2, 0xdb, 0xaa, 0xab, 0x66, 0x66, 0xac, 0x84, 0x84}; //return failure to client + std::vector<byte> vec(buf, buf+sizeof(buf)); + write_w_close(vec); + break; + } + ++p1; + request += ",pass:"; + for(; *p1 != data_c_end; ++p1) + request.push_back(*p1); + request += ",ip:"; + request += remote_ip; + request += ",hwid:"; + request += hardware_id; + request.push_back('/'); + http_client_->request(request, 1); //request subacc sid + } + else + delete this; + } + break; + case 0xa3: + { + if(canceled) + { + delete this; + break; + } + if(cfg->debug()) + { + logger->lock(); + *logger<<time_str() << ": recieved ping request from ip "<<remote_ip << " login hash " << lhash << " Hardware ID " << hardware_id << " session " << this_sid<<"\n"; + logger->unlock(); + } + std::vector<byte>::iterator p1 = std::search(local_data.begin(), local_data.end(), delim, delim + 2); + if(p1 != local_data.end()) + { + p1 +=2; + if(*p1 == 0x14) + { + ++p1; + if(*p1 == 0x14) + { + const unsigned char buf [] = {0x83, 0x83, 0xDA, 0xB3, 0xDB, 0xAA, 0xAB, 0x15, 0x15, 0xAC, 0x84, 0x84}; + memset(snd_data_, 0, 1024); + for(int i = 0; i < sizeof(buf); i++) + snd_data_[i] = buf[i]; + socket_.async_write_some(boost::asio::buffer(snd_data_, max_length), boost::bind(&session::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + } + } + else + delete this; + } + else + delete this; + } + break; + default: + socket_.async_read_some(boost::asio::buffer(recv_data_, max_length), boost::bind(&session::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + break; + } + } + //ok, our data found + } + } + } + } +void session::set_accounts(std::list<account>& accs) + { + accounts.assign(accs.begin(), accs.end()); + } +void session::set_sid(std::string _sid) + { + sid = _sid; + } +void session::write_w_close(std::vector<byte>& data) +{ + memset(snd_data_, 0, 1024); + for(int i = 0; i < data.size(); i++) + snd_data_[i] = data[i]; + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": Requested data write with socket close for " << remote_ip << " session " << this_sid << "\n"; + logger->unlock(); + } + socket_.async_write_some(boost::asio::buffer(snd_data_, max_length), boost::bind(&session::handle_write_close, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); +} + +void session::write_w_response(std::vector<byte>& data) + { + memset(snd_data_, 0, 1024); + for(int i = 0; i < data.size(); i++) + snd_data_[i] = data[i]; + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": Requested data write with response for " << remote_ip << " session " << this_sid << "\n"; + logger->unlock(); + } + socket_.async_write_some(boost::asio::buffer(snd_data_, max_length), boost::bind(&session::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + + } +void session::write_wo_response(std::vector<byte>& data) + { + memset(snd_data_, 0, 1024); + for(int i = 0; i < data.size(); i++) + snd_data_[i] = data[i]; + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": Requested data write with out response for " << remote_ip << " session " << this_sid << "\n"; + logger->unlock(); + } + socket_.async_write_some(boost::asio::buffer(snd_data_, max_length), boost::bind(&session::handle_operation, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + + } + +void session::handle_operation(const boost::system::error_code& error, size_t bytes_transferred) +{ + +} + +void session::handle_read(const boost::system::error_code& error, size_t bytes_transferred) + { + try{ + if(cfg->debug()) + { + logger->lock(); + *logger << time_str() << ": following read error occured: " << error.message() << " for client " << remote_ip << " session " << this_sid << "\n"; + logger->unlock(); + } + if (!error) + { + if(cfg->debug()) + { + logger->lock(); + *logger << time_str() << ": Recieved: " << (const char*)recv_data_ << "\n Data size: " << bytes_transferred << " from "<<remote_ip << " session " << this_sid << "\n"; + logger->unlock(); + } + std::vector<byte> copy(recv_data_, recv_data_ + bytes_transferred); + proto_parser(copy); + } + else + delete this; + } + catch (std::exception& e) + { + logger->lock(); + *logger << time_str() << ": read handler exception: " << e.what() << "\n"; + logger->unlock(); + } + } +//server + +server::server(boost::asio::io_service& io_service, unsigned short port) : io_service_(io_service), acceptor_(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4::from_string(cfg->bind_ip()), port)), context_(io_service, boost::asio::ssl::context::sslv3_server) + { + boost::system::error_code err; + std::string b_path = boost::filesystem::initial_path().string(), tmp_path; +// context_.set_password_callback(boost::bind(&server::get_password, this)); + context_.set_verify_mode(boost::asio::ssl::context::verify_peer | boost::asio::ssl::context::verify_fail_if_no_peer_cert); + tmp_path = b_path; + tmp_path.append("/ca.crt"); + context_.load_verify_file(tmp_path, err); + logger->lock(); + *logger << time_str()<<": Openning verify cert: " << tmp_path << " " << err.message()<<"\n"; + logger->unlock(); + tmp_path = b_path; + tmp_path.append("/server.crt"); + context_.use_certificate_file(tmp_path, boost::asio::ssl::context::pem, err); + logger->lock(); + *logger << time_str()<<": Openning server cert file: " << tmp_path << " " << err.message()<<"\n"; + logger->unlock(); + tmp_path.replace(tmp_path.length() - 3, 3, "key"); +// tmp_path = b_path; +// tmp_path.append("/server.key"); + context_.use_private_key_file(tmp_path, boost::asio::ssl::context::pem, err); + logger->lock(); + *logger << time_str()<<": Openning server key file: " << tmp_path << " " << err.message()<<"\n"; + logger->unlock(); + flood_chek = new boost::thread(boost::bind(flood_check_thread, &conns, &blacklist)); + blacklist_clean = new boost::thread(boost::bind(blacklist_clean_thread, &blacklist)); + + session* new_session = new session(io_service_, context_, this); + acceptor_.async_accept(new_session->socket(), + boost::bind(&server::handle_accept, this, new_session, + boost::asio::placeholders::error)); + } +server::~server() +{ + flood_chek->interrupt(); + blacklist_clean->interrupt(); + delete flood_chek; + delete blacklist_clean; +} +void server::connections_increment(std::string ip, const std::string& l_sid) +{ + if(!conns.empty()) + { + std::list<conn_count>::iterator p = std::find(conns.begin(), conns.end(), ip); + if(p != conns.end()) + { + p->connections++; + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": connections from " << ip << " incremented, current value " << p->connections << " session "<< l_sid << "\n"; + logger->unlock(); + } + } + } + else + { + conns.push_back(conn_count(ip, 1)); + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": connections from " << ip << " session "<< l_sid << " incremented, current value 1\n"; + logger->unlock(); + } + } +} +void server::auth_fail_increment(std::string ip, const std::string& l_sid) +{ + if(!conns.empty()) + { + std::list<conn_count>::iterator p = std::find(conns.begin(), conns.end(), ip); + if(p != conns.end()) + { + p->fail_count++; + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": auth fail count from " << ip << " incremented, current value " << p->fail_count << " session "<< l_sid << "\n"; + logger->unlock(); + } + } + } + else + { + conns.push_back(conn_count(ip, 1, 1)); + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": auth fail count from " << ip << " session "<< l_sid << " incremented, current value 1\n"; + logger->unlock(); + } + } +} +void server::flood_check_thread(std::list<conn_count> *list, std::list<std::string> *blacklist) //sort and clean blacklist ? +{ + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": flood check thread started\n"; + logger->unlock(); + } + while(true) + { + boost::this_thread::sleep(boost::posix_time::seconds(cfg->check_interval())); + if(boost::this_thread::interruption_requested()) + return; +// if(boost::this_thread::interruption_requested()) +// break; + if(!list->empty()) + { + std::list<conn_count>::iterator end = list->end(); + for(std::list<conn_count>::iterator i = list->begin(); i != end; ++i) + { + if((i->connections > cfg->conn_count()) || (i->fail_count > cfg->invalid_ml_count())) + { + blacklist->push_back(i->ip); + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": " << i->ip << " adding to ban list\n"; + logger->unlock(); + } + if(i->connections > cfg->dos_conn_count()) + { + *dos_logger << i->ip << "\n"; + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": " << i->ip << " adding to dos list\n"; + logger->unlock(); + } + } + } + } + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": cleaning connections list\n"; + logger->unlock(); + } + list->clear(); + } + else if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": connections list are empty\n"; + logger->unlock(); + } + } +} +void server::blacklist_clean_thread(std::list<std::string> *list) +{ + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << ": ban list cleaner thread started\n"; + logger->unlock(); + } + while(true) + { + boost::this_thread::sleep(boost::posix_time::minutes(cfg->ban_time())); + if(boost::this_thread::interruption_requested()) + return; +// if(boost::this_thread::interruption_requested()) +// break; + if(cfg->debug()) + { + logger->lock(); + *logger<< time_str() << " cleaning ban list\n"; + logger->unlock(); + } + list->clear(); + } +} +std::list<std::string>* server::get_blacklist() +{ + return &blacklist; +} +std::list<conn_count>* server::get_connections_list() +{ + return &conns; +} + +std::string server::get_password() const + { + return ""; + } + +void server::handle_accept(session* new_session, const boost::system::error_code& error) + { + if (!error) + { + new_session->start(); + new_session = new session(io_service_, context_, this); + acceptor_.async_accept(new_session->socket(), + boost::bind(&server::handle_accept, this, new_session, + boost::asio::placeholders::error)); + } + else + { + delete new_session; + } + } + +int main(int argc, char* argv[]) +{ + int opt = 0; + int daemon = 0; + std::string cfg_path; + while ((opt = getopt(argc, argv, (char*)"bhc:")) != -1) //getting options from command line + { + switch (opt) + { + case 'b': + daemon = 1; + break; + case 'h': + std::cout<<"Usage: "<<basename(argv[0])<<" -b -h -c\n-b - run in backgrounf \n-h - this info message\n-c /etc/config.cfg (use /etc/config.cfg as config file)\n\n"; + exit(EXIT_SUCCESS); + break; + case 'c': + if(optarg) + cfg_path = optarg; + break; + default: + break; + } + + } + if(daemon) //going to background (only for unix-like systems now) + { + pid_t pid; + pid = fork(); + if(pid < 0) + { + std::cout<<"main thread: error, failed to start background thread\n"; + exit(EXIT_FAILURE); + } + if(pid > 0) + { + std::cout<<"main thread: succesfully fork to background\n"; + exit(EXIT_SUCCESS); + } + } + + if (!cfg_path.empty()) + cfg = new config(cfg_path.c_str()); + else + cfg = new config("/etc/aion_otp"); + + logger = new logtofile(cfg->log_path().c_str()); + dos_logger = new logtofile(cfg->dos_log_path().c_str()); + while(true) + { + try + { + + boost::asio::io_service io_service; + + server s(io_service, 1025); + + io_service.run(); + } + catch (std::exception& e) + { + logger->lock(); + *logger << time_str() << ": main thread exception: " << e.what() << " (this is bad)\n"; + logger->unlock(); + } + sleep(2); + } + + return 0; +} + + diff --git a/server/server/main.h b/server/server/main.h new file mode 100644 index 0000000..dbcb178 --- /dev/null +++ b/server/server/main.h @@ -0,0 +1,169 @@ +#ifndef MAIN_H +#define MAIN_H + +#include "headers.h" + +typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket; +using boost::asio::ip::tcp; +typedef unsigned char byte; + +const byte proto_version = 0x01; + +const byte data_begin [] = {0x83, 0x83}; +const byte data_end [] = {0x84, 0x84}; +const byte data_type_begin = 0xda; +const byte data_type_end = 0xdb; +const byte _eq = 0xaa; +const byte data_c_begin = 0xab; +const byte delim [] = {0xaa, 0xab}; +const byte data_c_delim = 0xad; +const byte data_c_end = 0xac; +const byte sid_begin = 0xca; +const byte sid_end = 0xcb; +const byte reply_success [] = {0x13, 0x13}; +const byte reply_failure [] = {0x66, 0x66}; + +class session; +class server; + + +class http_client +{ +public: + http_client(boost::asio::io_service& io_service, const std::string& new_server, const std::string& path, session* sess_, int request_type, server *serv); +// ~http_client(); + void request(const std::string& path, int request_type); +private: + void handle_resolve(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator, int request_type); + void handle_connect(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator, int request_type); + void handle_write_request(const boost::system::error_code& err, int request_type); + void handle_read_status_line(const boost::system::error_code& err, int request_type); + void handle_read_headers(const boost::system::error_code& err, int request_type); + void proto_parser(int request_type); + void handle_read_content(const boost::system::error_code& err, int request_type); + + tcp::resolver resolver_; + tcp::socket socket_; + boost::asio::streambuf request_; + boost::asio::streambuf response_; + boost::asio::io_service& io_service_; + session *session_; + server *serv; + std::string response, server_; +}; +struct account +{ + std::string name; + int access_level, ban_time; + account(const std::string& n, int lvl, int bt) + { + name = n; + access_level = lvl; + ban_time = bt; + } + const bool operator==(const std::string& n) + { + return this->name == n; + } +}; + + +class session +{ +public: + session(boost::asio::io_service& io_service, boost::asio::ssl::context& context, server *serv); + ssl_socket::lowest_layer_type& socket(); + ~session(); + void start(); + void handle_handshake(const boost::system::error_code& error); + void handle_write(const boost::system::error_code& error, size_t bytes_transferred); + void handle_write_close(const boost::system::error_code& error, size_t bytes_transferred); + void handle_auth_server_reply(const boost::system::error_code& error, size_t bytes_transferred); + void proto_parser(std::vector<byte>& data); + void set_accounts(std::list<account>& accs); + void set_sid(std::string _sid); + void write_w_close(std::vector<byte>& data); + void write_w_response(std::vector<byte>& data); + void write_wo_response(std::vector<byte>& data); + static void cancel_thread(session *s, int minutes); + void set_cancel(); + const int get_fail_count(); + const std::string& get_ip(); + const std::string& get_lhash() + { + return lhash; + } + const std::string& get_this_sid() + { + return this_sid; + } + const std::string& get_hardware_id() + { + return hardware_id; + } + void fail_count_increment(); + void handle_operation(const boost::system::error_code& error, size_t bytes_transferred); + void handle_read(const boost::system::error_code& error, size_t bytes_transferred); +private: + ssl_socket socket_; + enum { max_length = 2048 }; + unsigned char recv_data_[max_length]; + unsigned char snd_data_[max_length]; + boost::asio::io_service& io_service_; + http_client *http_client_; + std::string sid, remote_ip, lhash, hardware_id, this_sid; + std::list<account> accounts; + server *server_; + bool blacklisted, canceled; + int fail_count; + boost::thread *killer; +}; +struct conn_count +{ + std::string ip; //use string for logs e.t.c., mayby replace this in future + int connections, fail_count; + conn_count(const std::string& str, int i) + { + ip = str; + connections = i; + fail_count = 0; + } + conn_count(const std::string& str, int i, int f) + { + ip = str; + connections = i; + fail_count = f; + } + const bool operator==(const conn_count& c) + { + return this->ip == c.ip; + } + const bool operator==(const std::string& c) + { + return this->ip == c; + } +}; + +class server +{ +public: + server(boost::asio::io_service& io_service, unsigned short port); + ~server(); + std::string get_password() const; + void handle_accept(session* new_session, const boost::system::error_code& error); + void connections_increment(std::string ip, const std::string& l_sid); + void auth_fail_increment(std::string ip, const std::string& l_sid); + static void flood_check_thread(std::list<conn_count> *list, std::list<std::string> *blacklist); + static void blacklist_clean_thread(std::list<std::string> *list); + std::list<std::string>* get_blacklist(); + std::list<conn_count>* get_connections_list(); +private: + boost::asio::io_service& io_service_; + boost::asio::ip::tcp::acceptor acceptor_; + boost::asio::ssl::context context_; + std::list<conn_count> conns; + std::list<std::string> blacklist; + boost::thread *flood_chek, *blacklist_clean; +}; + +#endif diff --git a/server/server/server.project b/server/server/server.project new file mode 100644 index 0000000..ad0c73d --- /dev/null +++ b/server/server/server.project @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="utf-8"?> +<CodeLite_Project Name="server" InternalType="Console"> + <Plugins> + <Plugin Name="qmake"> + <![CDATA[00010001N0005Debug000000000000]]> + </Plugin> + </Plugins> + <Description/> + <Dependencies/> + <VirtualDirectory Name="src"> + <File Name="main.cpp"/> + <File Name="config.cpp"/> + <File Name="config.h"/> + <File Name="headers.h"/> + <File Name="log.cpp"/> + <File Name="log.h"/> + <File Name="main.h"/> + <File Name="utilities.cpp"/> + <File Name="utilities.h"/> + </VirtualDirectory> + <Settings Type="Executable"> + <GlobalSettings> + <Compiler Options="" C_Options=""> + <IncludePath Value="."/> + </Compiler> + <Linker Options=""> + <LibraryPath Value="."/> + </Linker> + <ResourceCompiler Options=""/> + </GlobalSettings> + <Configuration Name="Debug" CompilerType="gnu g++" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append"> + <Compiler Options="-g" C_Options="-g" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags=""> + <IncludePath Value="."/> + </Compiler> + <Linker Options="" Required="yes"> + <Library Value="boost_system"/> + <Library Value="pthread"/> + <Library Value="ssl"/> + <Library Value="boost_random"/> + <Library Value="boost_thread"/> + <Library Value="boost_date_time"/> + <Library Value="boost_filesystem"/> + </Linker> + <ResourceCompiler Options="" Required="no"/> + <General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Debug" Command="./$(ProjectName)" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes"/> + <Environment EnvVarSetName="<Use Defaults>" DbgSetName="<Use Defaults>"> + <![CDATA[]]> + </Environment> + <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath=""> + <PostConnectCommands/> + <StartupCommands/> + </Debugger> + <PreBuild/> + <PostBuild/> + <CustomBuild Enabled="no"> + <RebuildCommand/> + <CleanCommand/> + <BuildCommand/> + <PreprocessFileCommand/> + <SingleFileCommand/> + <MakefileGenerationCommand/> + <ThirdPartyToolName>None</ThirdPartyToolName> + <WorkingDirectory/> + </CustomBuild> + <AdditionalRules> + <CustomPostBuild/> + <CustomPreBuild/> + </AdditionalRules> + <Completion> + <ClangCmpFlags/> + <ClangPP/> + <SearchPaths/> + </Completion> + </Configuration> + <Configuration Name="Release" CompilerType="gnu g++" DebuggerType="GNU gdb debugger" Type="" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append"> + <Compiler Options="" C_Options="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags=""> + <IncludePath Value="."/> + </Compiler> + <Linker Options="-O2" Required="yes"/> + <ResourceCompiler Options="" Required="no"/> + <General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Release" Command="./$(ProjectName)" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes"/> + <Environment EnvVarSetName="<Use Defaults>" DbgSetName="<Use Defaults>"> + <![CDATA[ + ]]> + </Environment> + <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath=""> + <PostConnectCommands/> + <StartupCommands/> + </Debugger> + <PreBuild/> + <PostBuild/> + <CustomBuild Enabled="no"> + <RebuildCommand/> + <CleanCommand/> + <BuildCommand/> + <PreprocessFileCommand/> + <SingleFileCommand/> + <MakefileGenerationCommand/> + <ThirdPartyToolName>None</ThirdPartyToolName> + <WorkingDirectory/> + </CustomBuild> + <AdditionalRules> + <CustomPostBuild/> + <CustomPreBuild/> + </AdditionalRules> + <Completion> + <ClangCmpFlags/> + <ClangPP/> + <SearchPaths/> + </Completion> + </Configuration> + </Settings> +</CodeLite_Project> diff --git a/server/server/utilities.cpp b/server/server/utilities.cpp new file mode 100644 index 0000000..70c2400 --- /dev/null +++ b/server/server/utilities.cpp @@ -0,0 +1,18 @@ +#include "headers.h" + +std::string get_random(int length) +{ + std::string chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); + std::string data; + boost::random_device rng; + boost::variate_generator<boost::random_device&, boost::uniform_int<> > gen(rng, boost::uniform_int<>(0, chars.length()-1)); + for(int i = 0; i < length; ++i) + data += chars[gen()]; + return data; +} + +std::string time_str() +{ + boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); + return (std::string)boost::posix_time::to_simple_string(now); +}
\ No newline at end of file diff --git a/server/server/utilities.h b/server/server/utilities.h new file mode 100644 index 0000000..ded609f --- /dev/null +++ b/server/server/utilities.h @@ -0,0 +1,7 @@ +#ifndef UTILITIES_H +#define UTILITIES_H + +std::string get_random(int length); +std::string time_str(); + +#endif
\ No newline at end of file |