521 lines
12 KiB
C++
Executable File
521 lines
12 KiB
C++
Executable File
#include <iostream>
|
|
#include <boost/asio.hpp>
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <thread>
|
|
#include <array>
|
|
#include <iomanip>
|
|
|
|
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::ip::tcp::resolver::iterator endpointIn)
|
|
: ioService(ioServiceIn)
|
|
, socket(ioServiceIn)
|
|
{
|
|
do_connect(endpointIn);
|
|
}
|
|
/*
|
|
void write(const chat_message& msg)
|
|
{
|
|
io_service_.post(
|
|
[this, msg]()
|
|
{
|
|
bool write_in_progress = !write_msgs_.empty();
|
|
write_msgs_.push_back(msg);
|
|
if (!write_in_progress)
|
|
{
|
|
do_write();
|
|
}
|
|
});
|
|
}
|
|
*/
|
|
void close()
|
|
{
|
|
ioService.post([this]() { socket.close(); });
|
|
}
|
|
|
|
private:
|
|
void do_connect(boost::asio::ip::tcp::resolver::iterator endpointIterator)
|
|
{
|
|
boost::asio::async_connect(socket, endpointIterator,
|
|
[this](boost::system::error_code ec, boost::asio::ip::tcp::resolver::iterator)
|
|
{
|
|
if (!ec)
|
|
{
|
|
sendVersion();
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
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
|
|
{
|
|
socket.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
|
|
socket.close();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
socket.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
|
|
{
|
|
socket.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
|
|
{
|
|
socket.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
|
|
{
|
|
socket.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
|
|
socket.close();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
socket.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
|
|
{
|
|
socket.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[2]);
|
|
|
|
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
|
|
{
|
|
socket.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
|
|
{
|
|
socket.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
|
|
{
|
|
socket.close();
|
|
}
|
|
});
|
|
}
|
|
|
|
/*
|
|
void do_read_header()
|
|
{
|
|
boost::asio::async_read(socket_,
|
|
boost::asio::buffer(read_msg_.data(), chat_message::header_length),
|
|
[this](boost::system::error_code ec, std::size_t length)
|
|
{
|
|
if (!ec && read_msg_.decode_header())
|
|
{
|
|
do_read_body();
|
|
}
|
|
else
|
|
{
|
|
socket_.close();
|
|
}
|
|
});
|
|
}
|
|
|
|
void do_read_body()
|
|
{
|
|
boost::asio::async_read(socket_,
|
|
boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
|
|
[this](boost::system::error_code ec, std::size_t length)
|
|
{
|
|
if (!ec)
|
|
{
|
|
std::cout.write(read_msg_.body(), read_msg_.body_length());
|
|
std::cout << "\n";
|
|
do_read_header();
|
|
}
|
|
else
|
|
{
|
|
socket_.close();
|
|
}
|
|
});
|
|
}
|
|
|
|
void do_write()
|
|
{
|
|
boost::asio::async_write(socket_,
|
|
boost::asio::buffer(write_msgs_.front().data(),
|
|
write_msgs_.front().length()),
|
|
[this](boost::system::error_code ec, std::size_t length)
|
|
{
|
|
if (!ec)
|
|
{
|
|
write_msgs_.pop_front();
|
|
if (!write_msgs_.empty())
|
|
{
|
|
do_write();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
socket_.close();
|
|
}
|
|
});
|
|
}
|
|
*/
|
|
private:
|
|
boost::asio::io_service& ioService;
|
|
boost::asio::ip::tcp::socket socket;
|
|
};
|
|
|
|
|
|
int main()
|
|
{
|
|
std::cout << "Hello" << std::endl;
|
|
|
|
boost::asio::io_service ioService;
|
|
|
|
boost::asio::ip::tcp::resolver resolver(ioService);
|
|
auto endpointIterator = resolver.resolve({ "telegram-proxy.fishrungames.com", "8043" });
|
|
|
|
|
|
proxyClient c(ioService, endpointIterator);
|
|
|
|
std::thread t([&ioService]() { ioService.run(); });
|
|
|
|
|
|
t.join();
|
|
|
|
return 0;
|
|
} |