#include #include #include #include #include #include enum AddressType { AT_IPV4 = 0, AT_HOST = 3, AT_IPV6 = 4 }; class ConnectResponseRecord { public: std::vector 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(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 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 serverVersionMethod; std::array serverAuthStatus; std::vector 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(login.size()); data += login; data += static_cast(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 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> firstPartPtr = std::make_shared>(); 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> 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> secondPartPtr = std::make_shared>(); 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.rawData[1]); connectResponseRecord.addressType = static_cast(connectResponseRecord.rawData[2]); size_t portOffset = 8; if (connectResponseRecord.addressType == AddressType::AT_IPV4) { connectResponseRecord.address = boost::lexical_cast(static_cast(connectResponseRecord.rawData[4])) + "." + boost::lexical_cast(static_cast(connectResponseRecord.rawData[5])) + "." + boost::lexical_cast(static_cast(connectResponseRecord.rawData[6])) + "." + boost::lexical_cast(static_cast(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(static_cast(item)) + " "; std::cout << boost::lexical_cast(static_cast(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; }