summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorGluzskiy Alexandr <sss@sss.chaoslab.ru>2011-10-17 14:46:06 +0300
committerGluzskiy Alexandr <sss@sss.chaoslab.ru>2011-10-17 14:46:06 +0300
commit3d9612635ad9a74c66bf7b89952b184090da723e (patch)
tree9896cec5ca8f185cdab87eefd7a5258d6ffb32e4 /server
parent979a0c8eb8f7c4b2c1c8f0a95948278d0e682d49 (diff)
мой сервер от другого проекта, с ssl, логами и http клиентом, использует getopt и fork (нужно чуть переделать)
Diffstat (limited to 'server')
-rw-r--r--server/proxy_ui_server.workspace12
-rw-r--r--server/server/Makefile9
-rw-r--r--server/server/config.cpp105
-rw-r--r--server/server/config.h45
-rw-r--r--server/server/config_example17
-rw-r--r--server/server/headers.h24
-rw-r--r--server/server/log.cpp46
-rw-r--r--server/server/log.h29
-rw-r--r--server/server/main.cpp1184
-rw-r--r--server/server/main.h169
-rw-r--r--server/server/server.project113
-rw-r--r--server/server/utilities.cpp18
-rw-r--r--server/server/utilities.h7
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="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
+ <![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="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
+ <![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