proxyTest/main.cpp

521 lines
12 KiB
C++
Executable File

#include <iostream>
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <thread>
#include <array>
#include <iomanip>
#include <boost/bind.hpp>
#define SSL_R_SHORT_READ 219
#include "ssl/ssl_locl.h"
#include <boost/asio/ssl.hpp>
#if defined(close)
#undef close
#endif
enum AddressType
{
AT_IPV4 = 0,
AT_HOST = 3,
AT_IPV6 = 4
};
class ConnectResponseRecord
{
public:
std::vector<unsigned char> rawData;
enum ConnectResponseType
{
CRT_SUCCESS = 0,
CRT_GENERAL_SOCKS_SERVER_FAILURE = 1,
CRT_CONNECTION_NOT_ALLOWED_BY_RULESET = 2,
CRT_NETWORK_UNREACHABLE = 3,
CRT_HOST_UNREACHABLE = 4,
CRT_CONNECTION_REFUSED = 5,
CRT_TTL_EXPIRED = 6,
CRT_COMMAND_NOT_SUPPORTED = 7,
CRT_ADDRESS_TYPE_NOT_SUPPORTED = 8,
CRT_TO_FF_UNASSIGNED = 9
};
ConnectResponseType connectResponseType;
AddressType addressType;
std::string address;
uint16_t port;
};
class ConnectRequestRecord
{
public:
std::string address;
uint16_t port;
std::string getRequestData();
};
std::string ConnectRequestRecord::getRequestData()
{
std::string data = "";
data += 0x05;
data += 0x01;
data += char(0x00);
data += 0x03;
data += static_cast<unsigned char>(address.size());
data += address;
data += port / 256;
data += port % 256;
return data;
}
class proxyClient
{
public:
proxyClient(boost::asio::io_service& ioServiceIn, boost::asio::ssl::context& context, boost::asio::ip::tcp::resolver::iterator endpointIn)
: ioService(ioServiceIn)
, socket(ioServiceIn, context)
{
socket.set_verify_mode(boost::asio::ssl::verify_peer);
socket.set_verify_callback(
std::bind(&proxyClient::verify_certificate, this, std::placeholders::_1, std::placeholders::_2));
doConnect(endpointIn);
}
void close()
{
ioService.post([this]() { lowerSocket().close(); });
}
private:
boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::lowest_layer_type& lowerSocket()
{
return socket.lowest_layer();
}
void doConnect(boost::asio::ip::tcp::resolver::iterator endpointIterator)
{
boost::asio::async_connect(lowerSocket(), endpointIterator,
[this](boost::system::error_code ec, boost::asio::ip::tcp::resolver::iterator)
{
if (!ec)
{
//sendVersion();
doHandshake();
}
});
}
void doHandshake()
{
socket.async_handshake(boost::asio::ssl::stream_base::client,
[this](const boost::system::error_code& error) {
if (!error)
{
sendVersion();
}
else
{
std::cout << "Handshake failed: " << error.message() << "\n";
lowerSocket().close();
}
});
}
bool verify_certificate(bool preverified,
boost::asio::ssl::verify_context& ctx)
{
// The verify callback can be used to check whether the certificate that is
// being presented is valid for the peer. For example, RFC 2818 describes
// the steps involved in doing this for HTTPS. Consult the OpenSSL
// documentation for more details. Note that the callback is called once
// for each certificate in the certificate chain, starting from the root
// certificate authority.
// In this example we will simply print the certificate's subject name.
char subject_name[256];
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
std::cout << "Verifying " << subject_name << "\n";
return preverified;
}
void sendVersion()
{
std::array<char, 3> version = {0x05, 0x01, 0x02};
boost::asio::async_write(socket,
boost::asio::buffer(version.data(),
version.size()),
[this](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
doReadServerVersion();
}
else
{
lowerSocket().close();
}
});
}
std::array<unsigned char, 2> serverVersionMethod;
std::array<unsigned char, 2> serverAuthStatus;
std::vector<ConnectRequestRecord> connectRequestArr;
void doReadServerVersion()
{
boost::asio::async_read(socket,
boost::asio::buffer(serverVersionMethod.data(), serverVersionMethod.size()),
[this](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
if (serverVersionMethod[0] == 5 && serverVersionMethod[1] == 2)
{
doWriteLoginPassword();
}
else
{
//Others not supported
lowerSocket().close();
}
}
else
{
lowerSocket().close();
}
});
}
void doWriteLoginPassword()
{
std::string login = "telegram-proxy-user";
std::string password = "telegram-telegram-999112";
std::string data = "";
data += 0x01;
data += static_cast<unsigned char>(login.size());
data += login;
data += static_cast<unsigned char>(password.size());
data += password;
boost::asio::async_write(socket,
boost::asio::buffer(data.data(),
data.size()),
[this](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
doReadAuthStatus();
}
else
{
lowerSocket().close();
}
});
}
void connectToWebAddress(std::string address)
{
ConnectRequestRecord record = { address, 80 };
connectRequestArr.push_back(record);
auto data = record.getRequestData();
boost::asio::async_write(socket,
boost::asio::buffer(data.data(),
data.size()),
[this](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
doReadConnectToWebAddressResponse();
}
else
{
lowerSocket().close();
}
});
}
void doWriteSomething()
{
//std::array<char, 100> something = { 0x05, 0x01, 0x00, 0x03 };
std::string data = "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n";
boost::asio::async_write(socket,
boost::asio::buffer(data.data(),
data.size()),
[this](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
doReadSomethingText();
}
else
{
lowerSocket().close();
}
});
}
void doReadAuthStatus()
{
boost::asio::async_read(socket,
boost::asio::buffer(serverAuthStatus.data(), serverAuthStatus.size()),
[this](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
if (serverAuthStatus[0] == 1 && serverAuthStatus[1] == 0)
{
//doWriteSomething();
connectToWebAddress("www.google.com");
}
else
{
//Authorization is not succeed
lowerSocket().close();
}
}
else
{
lowerSocket().close();
}
});
}
void doReadConnectToWebAddressResponse()
{
std::shared_ptr<std::array<unsigned char, 5>> firstPartPtr = std::make_shared<std::array<unsigned char, 5>>();
boost::asio::async_read(socket,
boost::asio::buffer(firstPartPtr->data(), firstPartPtr->size()),
[this, firstPartPtr](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
doReadConnectToWebAddressResponsePart2(firstPartPtr);
}
else
{
lowerSocket().close();
}
});
}
void doReadConnectToWebAddressResponsePart2(std::shared_ptr<std::array<unsigned char, 5>> firstPartPtr)
{
unsigned int size = 3;
if ((*firstPartPtr)[3] == AddressType::AT_IPV4) {
size = 3;
}
if ((*firstPartPtr)[3] == AddressType::AT_HOST) {
size = (*firstPartPtr)[4];
}
if ((*firstPartPtr)[3] == AddressType::AT_IPV6) {
size = 15;
}
size += 2; //add port
std::shared_ptr<std::vector<char>> secondPartPtr = std::make_shared<std::vector<char>>();
secondPartPtr->resize(size);
boost::asio::async_read(socket,
boost::asio::buffer(secondPartPtr->data(), secondPartPtr->size()),
[this, firstPartPtr, secondPartPtr](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
ConnectResponseRecord connectResponseRecord;
connectResponseRecord.rawData.clear();
for (unsigned char c : *firstPartPtr)
{
connectResponseRecord.rawData.push_back(c);
}
for (unsigned char c : *secondPartPtr)
{
connectResponseRecord.rawData.push_back(c);
}
connectResponseRecord.connectResponseType = static_cast<ConnectResponseRecord::ConnectResponseType>(connectResponseRecord.rawData[1]);
connectResponseRecord.addressType = static_cast<AddressType>(connectResponseRecord.rawData[3]);
size_t portOffset = 8;
if (connectResponseRecord.addressType == AddressType::AT_IPV4)
{
connectResponseRecord.address = boost::lexical_cast<std::string>(static_cast<unsigned int>(connectResponseRecord.rawData[4]))
+ "." + boost::lexical_cast<std::string>(static_cast<unsigned int>(connectResponseRecord.rawData[5]))
+ "." + boost::lexical_cast<std::string>(static_cast<unsigned int>(connectResponseRecord.rawData[6]))
+ "." + boost::lexical_cast<std::string>(static_cast<unsigned int>(connectResponseRecord.rawData[7]));
portOffset = 8;
}
if (connectResponseRecord.addressType == AddressType::AT_HOST)
{
size_t count = connectResponseRecord.rawData[4];
for (size_t i = 0; i < count; i++)
{
connectResponseRecord.address.push_back(connectResponseRecord.rawData[5 + i]);
}
portOffset = 5 + count;
}
if (connectResponseRecord.addressType == AddressType::AT_IPV6)
{
std::stringstream stream;
stream << std::hex << connectResponseRecord.rawData[4];
stream << std::hex << connectResponseRecord.rawData[5];
stream << ":";
stream << std::hex << connectResponseRecord.rawData[6];
stream << std::hex << connectResponseRecord.rawData[7];
stream << ":";
stream << std::hex << connectResponseRecord.rawData[8];
stream << std::hex << connectResponseRecord.rawData[9];
stream << ":";
stream << std::hex << connectResponseRecord.rawData[10];
stream << std::hex << connectResponseRecord.rawData[11];
stream << ":";
stream << std::hex << connectResponseRecord.rawData[12];
stream << std::hex << connectResponseRecord.rawData[13];
stream << ":";
stream << std::hex << connectResponseRecord.rawData[14];
stream << std::hex << connectResponseRecord.rawData[15];
stream << ":";
stream << std::hex << connectResponseRecord.rawData[16];
stream << std::hex << connectResponseRecord.rawData[17];
stream << ":";
stream << std::hex << connectResponseRecord.rawData[18];
stream << std::hex << connectResponseRecord.rawData[19];
connectResponseRecord.address = stream.str();
portOffset = 20;
}
connectResponseRecord.port = connectResponseRecord.rawData[portOffset] * 256 + connectResponseRecord.rawData[portOffset + 1];
doWriteSomething();
}
else
{
lowerSocket().close();
}
});
}
unsigned char item;
std::string result;
void doReadSomething()
{
boost::asio::async_read(socket,
boost::asio::buffer(&item, 1),
[this](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
result += boost::lexical_cast<std::string>(static_cast<unsigned int>(item)) + " ";
std::cout << boost::lexical_cast<std::string>(static_cast<unsigned int>(item)) + " ";
doReadSomething();
}
else
{
lowerSocket().close();
}
});
}
void doReadSomethingText()
{
boost::asio::async_read(socket,
boost::asio::buffer(&item, 1),
[this](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
result += (item);
std::cout << item;
doReadSomethingText();
}
else
{
lowerSocket().close();
}
});
}
private:
boost::asio::io_service& ioService;
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket;
};
int main()
{
std::cout << "Hello" << std::endl;
boost::asio::io_service ioService;
//boost::asio::io_service::work work(ioService);
boost::asio::ip::tcp::resolver resolver(ioService);
//auto endpointIterator = resolver.resolve({ "telegram-proxy.fishrungames.com", "8043" });
auto endpointIterator = resolver.resolve({ "127.0.0.1", "8043" });
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
ctx.load_verify_file("rootca.crt");
proxyClient c(ioService, ctx, endpointIterator);
std::thread t([&ioService]() { ioService.run(); });
t.join();
return 0;
}