Code:
#include <direct.h>#include <conio.h>
#include <cstdlib>
#include <cstddef>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#define CONFIG_FILE "PacketFilterConfig.ini"
#define SILENT_MODE 0
#define PRINT_MODE 1
#define FILE_MODE 2
static int LOG_MEMORY_BUFFER;
static int LOG_MODE;
std::vector<unsigned char> Packet_Header_Filter;
std::vector<int> Packet_Size_Filter;
std::vector<std::vector<unsigned char>> Packet_Content_Filter;
std::string buffer;
namespace tcp_proxy
{
namespace ip = boost::asio::ip;
class bridge : public boost::enable_shared_from_this<bridge>
{
public:
typedef ip::tcp::socket socket_type;
typedef boost::shared_ptr<bridge> ptr_type;
bridge(boost::asio::io_service& ios)
: downstream_socket_(ios),
upstream_socket_(ios)
{}
socket_type& downstream_socket()
{
return downstream_socket_;
}
socket_type& upstream_socket()
{
return upstream_socket_;
}
void start(const std::string& upstream_host, unsigned short upstream_port)
{
upstream_socket_.async_connect(
ip::tcp::endpoint(
boost::asio::ip::address::from_string(upstream_host),
upstream_port),
boost::bind(&bridge::handle_upstream_connect,
shared_from_this(),
boost::asio::placeholders::error));
}
void handle_upstream_connect(const boost::system::error_code& error)
{
if (!error)
{
std::string datetime = format_datetime(boost::posix_time::microsec_clock::universal_time());
std::string upstream_file_name = "us_" + upstream_socket_.remote_endpoint().address().to_string()+ "_" + datetime + ".log";
std::string downstream_file_name = "ds_" + downstream_socket_.remote_endpoint().address().to_string()+ "_" + datetime + ".log";
upstream_log.open(upstream_file_name.c_str(),std::ios::hex);
downstream_log.open(downstream_file_name.c_str(),std::ios::hex);
upstream_socket_.async_read_some(
boost::asio::buffer(upstream_data_,max_data_length),
boost::bind(&bridge::handle_upstream_read,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
downstream_socket_.async_read_some(
boost::asio::buffer(downstream_data_,max_data_length),
boost::bind(&bridge::handle_downstream_read,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
close();
}
private:
void handle_downstream_write(const boost::system::error_code& error)
{
if (!error)
{
upstream_socket_.async_read_some(
boost::asio::buffer(upstream_data_,max_data_length),
boost::bind(&bridge::handle_upstream_read,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
close();
}
void log_bytes(const void *object, size_t size, std::string ip)
{
switch (LOG_MODE)
{
case SILENT_MODE:
break;
case PRINT_MODE:
print_bytes(object,size,ip);
break;
case FILE_MODE:
write_to_file(object,size,ip);
break;
default:
break;
}
}
bool check_bytes(const void *object, size_t size)
{
for (int i=0;i < Packet_Size_Filter.size();i++)
{
if (size >= Packet_Size_Filter.at(i))
return FALSE;
}
for (int i=0;i < Packet_Header_Filter.size();i++)
{
if (((const unsigned char *) object)[0] == Packet_Header_Filter.at(i))
return FALSE;
}
for (int i=0;i < Packet_Content_Filter.size();i++)
{
int x = 0;
for(x;x<size && x<Packet_Content_Filter.at(i).size();x++)
{
if ( Packet_Content_Filter.at(i).at(x) != 0x00)
if (((const unsigned char *) object)[x] != Packet_Content_Filter.at(i).at(x))
break;
}
if (x == Packet_Content_Filter.at(i).size())
return FALSE;
}
return TRUE;
}
std::string get_hex_stream(const void *object, size_t size)
{
char bytesBuffer[16];
size_t i;
std::stringstream msg (std::stringstream::in | std::stringstream::out);
msg << "[ ";
for(i = 0; i < size; i++)
{
sprintf_s(bytesBuffer, sizeof(bytesBuffer),"%02x ", ((const unsigned char *) object)[i] & 0xff);
msg << bytesBuffer;
}
msg << "] Size: " << size;
return msg.str();
}
void print_bytes(const void *object, size_t size, std::string ip)
{
std::cout << "--- Packet from " << ip << " ---" << std::endl;
std::cout << get_hex_stream(object,size) << std::endl << std::endl;
}
void write_to_file(const void *object, size_t size, std::string ip)
{
std::stringstream msg (std::stringstream::in | std::stringstream::out);
msg << "--- Packet from " << ip << " ---" << std::endl << get_hex_stream(object,size) << std::endl << std::endl;
buffer.append(msg.str());
if (buffer.size() > LOG_MEMORY_BUFFER)
{
time_t t = time(0);
struct tm * now = localtime(&t);
FILE* pSendLogFile;
char filename[500];
sprintf_s(filename, sizeof(filename),"Log\\MadPacketLog_%04d_%02d_%02d_%02d_%02d.txt", now->tm_year+1900, now->tm_mon+1,
now->tm_mday, now->tm_hour, now->tm_min);
pSendLogFile = fopen(filename, "a+");
fprintf(pSendLogFile, "Timestamp %04d/%02d/%02d %02d:%02d:%02d \n %s \n",now->tm_year+1900, now->tm_mon+1,
now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec , buffer);
fclose(pSendLogFile);
buffer.clear();
}
}
void handle_downstream_read(const boost::system::error_code& error,
const size_t& bytes_transferred)
{
if (!error)
{
log_bytes(&downstream_data_[0],static_cast<std::streamsize>(bytes_transferred),
downstream_socket_.remote_endpoint().address().to_string());
if (check_bytes(&downstream_data_[0],static_cast<std::streamsize>(bytes_transferred)))
async_write(upstream_socket_,
boost::asio::buffer(downstream_data_,bytes_transferred),
boost::bind(&bridge::handle_upstream_write,
shared_from_this(),
boost::asio::placeholders::error));
else
std::cout << "Packet successfully filtered!" << std::endl;
}
else
close();
}
void handle_upstream_write(const boost::system::error_code& error)
{
if (!error)
{
downstream_socket_.async_read_some(
boost::asio::buffer(downstream_data_,max_data_length),
boost::bind(&bridge::handle_downstream_read,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
close();
}
void handle_upstream_read(const boost::system::error_code& error,
const size_t& bytes_transferred)
{
if (!error)
{
async_write(downstream_socket_,
boost::asio::buffer(upstream_data_,bytes_transferred),
boost::bind(&bridge::handle_downstream_write,
shared_from_this(),
boost::asio::placeholders::error));
}
else
close();
}
void close()
{
boost::mutex::scoped_lock lock(mutex_);
if (downstream_socket_.is_open())
downstream_socket_.close();
if (upstream_socket_.is_open())
upstream_socket_.close();
downstream_log.close();
upstream_log.close();
}
std::string format_datetime(boost::posix_time::ptime pt)
{
std::string s;
std::ostringstream datetime_ss;
boost::posix_time::time_facet * p_time_output = new boost::posix_time::time_facet;
std::locale special_locale (std::locale(""), p_time_output);
datetime_ss.imbue (special_locale);
(*p_time_output).format("%Y%m%d%H%M%S.%f");
datetime_ss << pt;
s = datetime_ss.str().c_str();
return s;
}
socket_type downstream_socket_;
socket_type upstream_socket_;
enum { max_data_length = 8192 }; //8KB
unsigned char downstream_data_[max_data_length];
unsigned char upstream_data_[max_data_length];
boost::mutex mutex_;
std::ofstream downstream_log;
std::ofstream upstream_log;
public:
class acceptor
{
public:
acceptor(boost::asio::io_service& io_service,
const std::string& local_host, unsigned short local_port,
const std::string& upstream_host, unsigned short upstream_port)
: io_service_(io_service),
localhost_address(boost::asio::ip::address_v4::from_string(local_host)),
acceptor_(io_service_,ip::tcp::endpoint(localhost_address,local_port)),
upstream_port_(upstream_port),
upstream_host_(upstream_host)
{}
bool accept_connections()
{
try
{
session_ = boost::shared_ptr<bridge>(new bridge(io_service_));
acceptor_.async_accept(session_->downstream_socket(),
boost::bind(&acceptor::handle_accept,
this,
boost::asio::placeholders::error));
}
catch(std::exception& e)
{
std::cerr << "acceptor exception: " << e.what() << std::endl;
return false;
}
return true;
}
private:
void handle_accept(const boost::system::error_code& error)
{
if (!error)
{
session_->start(upstream_host_,upstream_port_);
if (!accept_connections())
{
std::cerr << "Failure during call to accept." << std::endl;
}
}
else
{
std::cerr << "Error: " << error.message() << std::endl;
}
}
boost::asio::io_service& io_service_;
ip::address_v4 localhost_address;
ip::tcp::acceptor acceptor_;
ptr_type session_;
unsigned short upstream_port_;
std::string upstream_host_;
};
};
}
char m_szFileName[MAX_PATH];
char *bindAddress;
u_short bindPort;
char *redirectAddress;
u_short redirectPort;
void load_packet_filter()
{
char sMessage[255];
std::string prefix_size = "[PACKET_SIZE_FILTER]";
std::string prefix_header = "[PACKET_HEADER_FILTER]";
std::string prefix_content = "[PACKET_CONTENT_FILTER]";
std::ifstream f;
std::string s;
std::string t;
std::ifstream ifile(CONFIG_FILE);
if (ifile)
{
f.open(CONFIG_FILE, std::ios::in);
while (!f.eof())
{
getline(f, s);
if (s.substr(0, prefix_size.size()) == prefix_size)
{
getline(f, s);
t = (s.substr(0,30));
sprintf_s(sMessage, sizeof(sMessage), " [PACKET_SIZE_FILTER] -> %i installed", atoi( t.c_str()));
std::cout << sMessage << std::endl;
Packet_Size_Filter.push_back( atoi( t.c_str()) );
}
if (s.substr(0, prefix_header.size()) == prefix_header)
{
getline(f, s);
t = (s.substr(0,30));
sprintf_s(sMessage, sizeof(sMessage), " [PACKET_HEADER_FILTER] -> %s installed", t.c_str());
std::cout << sMessage << std::endl;
std::istringstream hex_chars_stream(t);
unsigned int c;
while (hex_chars_stream >> std::hex >> c)
{
Packet_Header_Filter.push_back(c);
}
}
if (s.substr(0, prefix_content.size()) == prefix_content)
{
getline(f, s);
t = (s.substr(0,1024));
sprintf_s(sMessage, sizeof(sMessage), " [PACKET_CONTENT_FILTER] -> %s installed", t.c_str());
std::cout << sMessage << std::endl;
std::vector<unsigned char> temp;
std::istringstream hex_chars_stream(t);
unsigned int c;
while (hex_chars_stream >> std::hex >> c)
{
temp.push_back(c);
}
Packet_Content_Filter.push_back(temp);
}
}
}
f.close();
}
char* get_config_val(char* szSection, char* szKey)
{
char *szResult = new char[255];
memset(szResult, 0x00, 255);
GetPrivateProfileStringA(szSection, szKey, "", szResult, 255, m_szFileName);
return szResult;
}
void load_config()
{
char szSelfPath[MAX_PATH];
char *szData[2];
getcwd(szSelfPath, sizeof(szSelfPath));
sprintf_s(m_szFileName, sizeof(m_szFileName), "%s\\%s", szSelfPath, CONFIG_FILE);
szData[0] = get_config_val("SERVER", "SERVER_BIND_IP");
szData[1] = get_config_val("SERVER", "SERVER_BIND_PORT");
szData[2] = get_config_val("REDIRECT", "REDIRECT_IP");
szData[3] = get_config_val("REDIRECT", "REDIRECT_PORT");
szData[4] = get_config_val("MODE", "MODE");
szData[5] = get_config_val("BUFFER", "LOG_MEMORY_BUFFER");
if (strlen(szData[0]) <= 0 || strlen(szData[1]) <= 0 ||
strlen(szData[2]) <= 0 || strlen(szData[3]) <= 0 ||
strlen(szData[4]) <= 0 || strlen(szData[5]) <= 0)
{
std::cout << "Reading Config File failed" << std::endl;
exit(EXIT_SUCCESS);
}
else
{
load_packet_filter();
bindAddress = (char *)szData[0];
bindPort = (u_short)atoi(szData[1]);
redirectAddress = (char *)szData[2];
redirectPort = (u_short)atoi(szData[3]);
LOG_MODE = ((u_short)atoi(szData[4]));
LOG_MEMORY_BUFFER= (atoi(szData[5]));
}
}
void Thread( void* pParams )
{
while(1)
{
Sleep(10);
unsigned char key;
key = getch();
switch(key)
{
case 'f':
load_packet_filter();
std::cout << "Filter Reloaded" << std::endl;
break;
case 's':
if (LOG_MODE != 0) {
LOG_MODE = 0; std::cout << "Silent Mode activated" << std::endl;
} else {
LOG_MODE = 1; std::cout << "Silent Mode deactivated" << std::endl; }
break;
case 'l':
if (LOG_MODE != 2) {
LOG_MODE = 2; std::cout << "Log Mode activated" << std::endl;
} else {
LOG_MODE = 1; std::cout << "Log Mode deactivated" << std::endl; }
break;
default:
break;
}
}
}
int main(int argc, char* argv[])
{
load_config();
_beginthread( Thread, 0, NULL );
boost::asio::io_service ios;
std::cout << "MadKnight Packet Filter Version 2.0" << std::endl;
try
{
tcp_proxy::bridge::acceptor acceptor(ios,
bindAddress, bindPort,
redirectAddress, redirectPort);
acceptor.accept_connections();
ios.run();
}
catch(std::exception& e)
{
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}