diff --git a/.github/workflows/debian-dev.yml b/.github/workflows/debian-dev.yml index 44a05a8..6064a97 100644 --- a/.github/workflows/debian-dev.yml +++ b/.github/workflows/debian-dev.yml @@ -6,6 +6,7 @@ on: - dev paths: - 'core/src/**' + - '.github/workflows/**' jobs: build: @@ -29,17 +30,17 @@ jobs: cd .. mkdir -p nipovpn/usr/bin/ cp build/core/nipovpn nipovpn/usr/bin/nipovpn - dpkg-deb --build nipovpn/ build/nipovpn-stage.deb + dpkg-deb --build nipovpn/ build/nipovpn_staging_v1-0-${{ github.run_number }}.deb - name: Upload the Debian nipovpn as an artifact uses: actions/upload-artifact@v3 with: name: nipovpn - path: build/nipovpn-stage.deb + path: build/nipovpn_staging_v1-0-${{ github.run_number }}.deb - name: Show nipovpn information run: | - dpkg -I build/nipovpn-stage.deb + dpkg -I build/nipovpn_staging_v1-0-${{ github.run_number }}.deb release: needs: build @@ -59,7 +60,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} with: tag_name: 'v1.0.${{ github.run_number }}' - release_name: Release ${{ github.run_number }} + release_name: Staging v1.0.${{ github.run_number }} draft: false prerelease: true @@ -69,6 +70,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./nipovpn-stage.deb - asset_name: nipovpn-stage.deb + asset_path: ./nipovpn_staging_v1-0-${{ github.run_number }}.deb + asset_name: nipovpn_staging_v1-0-${{ github.run_number }}.deb asset_content_type: application/octet-stream diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index 011d1b7..2e0ae90 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -29,17 +29,17 @@ jobs: cd .. mkdir -p nipovpn/usr/bin/ cp build/core/nipovpn nipovpn/usr/bin/nipovpn - dpkg-deb --build nipovpn/ build/nipovpn.deb + dpkg-deb --build nipovpn/ build/nipovpn_v1-0-${{ github.run_number }}.deb - name: Upload the Debian nipovpn as an artifact uses: actions/upload-artifact@v3 with: name: nipovpn - path: build/nipovpn.deb + path: build/nipovpn_v1-0-${{ github.run_number }}.deb - name: Show nipovpn information run: | - dpkg -I build/nipovpn.deb + dpkg -I build/nipovpn_v1-0-${{ github.run_number }}.deb release: needs: build @@ -59,7 +59,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} with: tag_name: 'v1.0.${{ github.run_number }}' - release_name: Release ${{ github.run_number }} + release_name: Version v1.0.${{ github.run_number }} draft: false prerelease: false @@ -69,6 +69,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./nipovpn.deb - asset_name: nipovpn.deb + asset_path: ./nipovpn_v1-0-${{ github.run_number }}.deb + asset_name: nipovpn_v1-0-${{ github.run_number }}.deb asset_content_type: application/octet-stream diff --git a/core/src/agenthandler.cpp b/core/src/agenthandler.cpp index 1cd8470..8c6572f 100644 --- a/core/src/agenthandler.cpp +++ b/core/src/agenthandler.cpp @@ -14,7 +14,10 @@ AgentHandler::AgentHandler(boost::asio::streambuf &readBuffer, writeBuffer_(writeBuffer), request_(HTTP::create(config, log, readBuffer, uuid)), clientConnStr_(clientConnStr), - uuid_(uuid) {} + uuid_(uuid) { + end_ = false; + connect_ = false; +} AgentHandler::~AgentHandler() {} @@ -28,14 +31,12 @@ void AgentHandler::handle() { if (encryption.ok) { log_->write("[" + to_string(uuid_) + "] [AgentHandler handle] [Encryption Done]", Log::Level::DEBUG); - std::string newReq( request_->genHttpPostReqString(encode64(encryption.message))); if (request_->detectType()) { log_->write("[" + to_string(uuid_) + "] [AgentHandler handle] [Request] : " + request_->toString(), Log::Level::DEBUG); - if (request_->parsedHttpRequest().target().length() > 0) { log_->write("[" + to_string(uuid_) + "] [CONNECT] [SRC " + clientConnStr_ + "]" + " [DST " + boost::lexical_cast( @@ -43,13 +44,11 @@ void AgentHandler::handle() { "]", Log::Level::INFO); } - if (!client_->socket().is_open() || request_->httpType() == HTTP::HttpType::http || request_->httpType() == HTTP::HttpType::connect) { + connect_ = true; boost::system::error_code ec; - ; - if (!client_->doConnect(config_->agent().serverIp, config_->agent().serverPort)) { log_->write(std::string("[" + to_string(uuid_) + "] [CONNECT] [ERROR] [To Server] [SRC ") + @@ -58,7 +57,6 @@ void AgentHandler::handle() { std::to_string(config_->agent().serverPort) + "]", Log::Level::INFO); } - if (ec) { log_->write(std::string("[" + to_string(uuid_) + "] [AgentHandler handle] Connection error: ") + ec.message(), @@ -68,43 +66,32 @@ void AgentHandler::handle() { } copyStringToStreambuf(newReq, readBuffer_); - log_->write("[" + to_string(uuid_) + "] [AgentHandler handle] [Request To Server] : \n" + newReq, Log::Level::DEBUG); - client_->doWrite(readBuffer_); client_->doRead(); - if (client_->readBuffer().size() > 0) { - if (request_->httpType() != HTTP::HttpType::connect) { - HTTP::pointer response = HTTP::create(config_, log_, client_->readBuffer(), uuid_); - - if (response->parseHttpResp()) { - log_->write( "[" + to_string(uuid_) + "] [AgentHandler handle] [Response] : " + response->restoString(), Log::Level::DEBUG); - - BoolStr decryption{false, std::string("FAILED")}; decryption = aes256Decrypt(decode64(boost::lexical_cast( response->parsedHttpResponse().body())), config_->agent().token); - - + if (boost::lexical_cast(response->parsedHttpResponse()[config_->general().chunkHeader]) == "yes") { + end_ = true; + } if (decryption.ok) { - copyStringToStreambuf(decryption.message, writeBuffer_); log_->write("[" + to_string(uuid_) + "] [AgentHandler handle] [Decryption Done]", Log::Level::DEBUG); } else { - log_->write("[" + to_string(uuid_) + "] [AgentHandler handle] [Decryption Failed] : [ " + decryption.message + "] ", Log::Level::DEBUG); @@ -114,7 +101,6 @@ void AgentHandler::handle() { client_->socket().close(); } } else { - log_->write( "[AgentHandler handle] [NOT HTTP Response] " "[Response] : " + @@ -122,21 +108,17 @@ void AgentHandler::handle() { Log::Level::DEBUG); } } else { - + connect_ = true; log_->write("[" + to_string(uuid_) + "] [AgentHandler handle] [Response to connect] : \n" + streambufToString(client_->readBuffer()), Log::Level::DEBUG); - - moveStreambuf(client_->readBuffer(), writeBuffer_); } } else { - client_->socket().close(); return; } } else { - log_->write("[" + to_string(uuid_) + "] [AgentHandler handle] [NOT HTTP Request] [Request] : " + streambufToString(readBuffer_), Log::Level::DEBUG); @@ -145,7 +127,6 @@ void AgentHandler::handle() { return; } } else { - log_->write("[" + to_string(uuid_) + "] [AgentHandler handle] [Encryption Failed] : [ " + encryption.message + "] ", Log::Level::DEBUG); @@ -154,7 +135,61 @@ void AgentHandler::handle() { client_->socket().remote_endpoint().address().to_string() + ":" + std::to_string(client_->socket().remote_endpoint().port()) + "] ", Log::Level::INFO); + client_->socket().close(); + return; + } +} +void AgentHandler::continueRead() { + std::lock_guard lock(mutex_); + std::string newReq( + request_->genHttpRestPostReqString()); + copyStringToStreambuf(newReq, readBuffer_); + client_->doWrite(readBuffer_); + client_->doRead(); + if (client_->readBuffer().size() > 0) { + if (request_->httpType() != HTTP::HttpType::connect) { + HTTP::pointer response = + HTTP::create(config_, log_, client_->readBuffer(), uuid_); + if (response->parseHttpResp()) { + log_->write( + "[" + to_string(uuid_) + "] [AgentHandler continueRead handle] [Response] : " + response->restoString(), + Log::Level::DEBUG); + BoolStr decryption{false, std::string("FAILED")}; + decryption = + aes256Decrypt(decode64(boost::lexical_cast( + response->parsedHttpResponse().body())), + config_->agent().token); + if (boost::lexical_cast(response->parsedHttpResponse()[config_->general().chunkHeader]) == "yes") { + end_ = true; + } + if (decryption.ok) { + copyStringToStreambuf(decryption.message, writeBuffer_); + log_->write("[" + to_string(uuid_) + "] [AgentHandler continueRead handle] [Decryption Done]", Log::Level::DEBUG); + } else { + log_->write("[" + to_string(uuid_) + "] [AgentHandler continueRead handle] [Decryption Failed] : [ " + + decryption.message + "] ", + Log::Level::DEBUG); + log_->write("[" + to_string(uuid_) + "] [AgentHandler continueRead handle] [Decryption Failed] : " + + request_->toString(), + Log::Level::INFO); + client_->socket().close(); + } + } else { + log_->write( + "[AgentHandler continueRead handle] [NOT HTTP Response] " + "[Response] : " + + streambufToString(client_->readBuffer()), + Log::Level::DEBUG); + } + } else { + connect_ = true; + log_->write("[" + to_string(uuid_) + "] [AgentHandler continueRead handle] [Response to connect] : \n" + + streambufToString(client_->readBuffer()), + Log::Level::DEBUG); + moveStreambuf(client_->readBuffer(), writeBuffer_); + } + } else { client_->socket().close(); return; } diff --git a/core/src/agenthandler.hpp b/core/src/agenthandler.hpp index 4812025..578cb7a 100644 --- a/core/src/agenthandler.hpp +++ b/core/src/agenthandler.hpp @@ -28,11 +28,14 @@ class AgentHandler : private Uncopyable { ~AgentHandler(); void handle(); + void continueRead(); inline const HTTP::pointer &request() & { return request_; } inline const HTTP::pointer &&request() && { return std::move(request_); } + bool end_, connect_; + private: AgentHandler(boost::asio::streambuf &readBuffer, boost::asio::streambuf &writeBuffer, diff --git a/core/src/config.cpp b/core/src/config.cpp index 34151d4..769bf17 100644 --- a/core/src/config.cpp +++ b/core/src/config.cpp @@ -11,7 +11,9 @@ Config::Config(const RunMode &mode, const std::string &filePath) configYaml_["general"]["method"].as(), configYaml_["general"]["timeWait"].as(), configYaml_["general"]["timeout"].as(), - configYaml_["general"]["repeatWait"].as()}), + configYaml_["general"]["repeatWait"].as(), + configYaml_["general"]["chunkHeader"].as(), + configYaml_["general"]["chunkSize"].as()}), log_({configYaml_["log"]["logLevel"].as(), configYaml_["log"]["logFile"].as()}), server_({configYaml_["server"]["threads"].as(), @@ -62,6 +64,8 @@ std::string Config::toString() const { << " timeWait: " << general_.timeWait << "\n" << " timeout: " << general_.timeout << "\n" << " repeatWait: " << general_.repeatWait << "\n" + << " chunkHeader: " << general_.chunkHeader << "\n" + << " chunkSize: " << general_.chunkSize << "\n" << " Log :\n" << " logLevel: " << log_.level << "\n" << " logFile: " << log_.file << "\n" diff --git a/core/src/config.hpp b/core/src/config.hpp index 7266d6a..cf6ba97 100644 --- a/core/src/config.hpp +++ b/core/src/config.hpp @@ -19,6 +19,8 @@ class Config : private Uncopyable { unsigned int timeWait; unsigned short timeout; unsigned short repeatWait; + std::string chunkHeader; + unsigned short chunkSize; }; struct Log { diff --git a/core/src/general.hpp b/core/src/general.hpp index 7affc79..ab6b820 100644 --- a/core/src/general.hpp +++ b/core/src/general.hpp @@ -309,6 +309,19 @@ inline BoolStr validateConfig(int argc, const char *argv[]) { return result; } + try { + configYaml["general"]["fakeUrl"].as(); + configYaml["general"]["method"].as(); + configYaml["general"]["timeWait"].as(); + configYaml["general"]["timeout"].as(); + configYaml["general"]["repeatWait"].as(); + configYaml["general"]["chunkHeader"].as(); + configYaml["general"]["chunkSize"].as(); + } catch (const std::exception &e) { + result.message = std::string("Error in 'general' block: ") + e.what() + "\n"; + return result; + } + try { configYaml["log"]["logFile"].as(); configYaml["log"]["logLevel"].as(); diff --git a/core/src/http.cpp b/core/src/http.cpp index f736018..e4c9d5c 100644 --- a/core/src/http.cpp +++ b/core/src/http.cpp @@ -8,7 +8,9 @@ HTTP::HTTP(const std::shared_ptr &config, parsedHttpRequest_(), httpType_(HTTP::HttpType::https), parsedTlsRequest_{"", "", TlsTypes::TLSHandshake}, - uuid_(uuid) {} + uuid_(uuid) { + chunkHeader_ = "no"; +} HTTP::HTTP(const HTTP &http) : config_(http.config_), @@ -16,7 +18,9 @@ HTTP::HTTP(const HTTP &http) buffer_(http.buffer_), parsedHttpRequest_(http.parsedHttpRequest_), parsedTlsRequest_(http.parsedTlsRequest_), - uuid_(http.uuid_) {} + uuid_(http.uuid_) { + chunkHeader_ = "no"; +} HTTP::~HTTP() {} @@ -135,15 +139,26 @@ const std::string HTTP::genHttpPostReqString(const std::string &body) const { "User-Agent: " + config_->agent().userAgent + "\r\n" + "Accept: */*\r\n" + "Connection: keep-alive\r\n" + "Content-Length: " + std::to_string(body.length()) + "\r\n" + - "Content-Type: application/x-www-form-urlencoded\r\n" + "\r\n" + body; + "Content-Type: application/x-www-form-urlencoded\r\n" + "\r\n" + body + "\r\n"; +} + +const std::string HTTP::genHttpRestPostReqString() const { + return std::string(config_->general().method + " " + + config_->general().fakeUrl + " HTTP/" + + config_->agent().httpVersion + "\r\n") + + "Host: " + config_->general().fakeUrl + "\r\n" + + "User-Agent: " + config_->agent().userAgent + "\r\n" + + "Accept: */*\r\n" + "Connection: keep-alive\r\n" + + "Rest: yes\r\n"; } const std::string HTTP::genHttpOkResString(const std::string &body) const { return std::string("HTTP/1.1 200 OK\r\n") + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: " + std::to_string(body.length()) + "\r\n" + + config_->general().chunkHeader + ": " + chunkHeader_ + "\r\n" + "Connection: keep-alive\r\n" + "Cache-Control: no-cache\r\n" + - "Pragma: no-cache\r\n" + "\r\n" + body; + "Pragma: no-cache\r\n" + "\r\n" + body + "\r\n"; } void HTTP::setIPPort() { diff --git a/core/src/http.hpp b/core/src/http.hpp index 30402a9..c165879 100644 --- a/core/src/http.hpp +++ b/core/src/http.hpp @@ -52,6 +52,8 @@ class HTTP { const std::string genHttpPostReqString(const std::string &body) const; + const std::string genHttpRestPostReqString() const; + const std::string genHttpOkResString(const std::string &body) const; inline const boost::beast::http::request & @@ -76,6 +78,7 @@ class HTTP { const std::string toString() const; const std::string restoString() const; + std::string chunkHeader_; private: explicit HTTP(const std::shared_ptr &config, diff --git a/core/src/serverhandler.cpp b/core/src/serverhandler.cpp index f70ccbf..c31474c 100644 --- a/core/src/serverhandler.cpp +++ b/core/src/serverhandler.cpp @@ -14,28 +14,25 @@ ServerHandler::ServerHandler(boost::asio::streambuf &readBuffer, writeBuffer_(writeBuffer), request_(HTTP::create(config, log, readBuffer, uuid)), clientConnStr_(clientConnStr), - uuid_(uuid) {} + uuid_(uuid) { + end_ = false; + connect_ = false; +} ServerHandler::~ServerHandler() {} void ServerHandler::handle() { std::lock_guard lock(mutex_); - - if (request_->detectType()) { - log_->write( "[" + to_string(uuid_) + "] [ServerHandler handle] [Request From Agent] : " + request_->toString(), Log::Level::DEBUG); - - BoolStr decryption{false, std::string("FAILED")}; decryption = aes256Decrypt(decode64(boost::lexical_cast( request_->parsedHttpRequest().body())), config_->agent().token); if (decryption.ok) { - log_->write( "[" + to_string(uuid_) + "] [ServerHandler handle] [Token Valid] : " + request_->toString(), Log::Level::DEBUG); @@ -43,14 +40,13 @@ void ServerHandler::handle() { std::string tempHexArrStr(tempHexArr.begin(), tempHexArr.end()); copyStringToStreambuf(tempHexArrStr, readBuffer_); - if (request_->detectType()) { log_->write( "[" + to_string(uuid_) + "] [ServerHandler handle] [Request] : " + request_->toString(), Log::Level::DEBUG); switch (request_->httpType()) { case HTTP::HttpType::connect: { - + connect_ = true; boost::asio::streambuf tempBuff; std::iostream os(&tempBuff); if (client_->doConnect(request_->dstIP(), request_->dstPort())) { @@ -77,7 +73,6 @@ void ServerHandler::handle() { } break; case HTTP::HttpType::http: case HTTP::HttpType::https: { - if (request_->httpType() == HTTP::HttpType::http) { if (client_->doConnect(request_->dstIP(), request_->dstPort())) { log_->write("[" + to_string(uuid_) + "] [CONNECT] [SRC " + clientConnStr_ + "] [DST " + @@ -97,13 +92,16 @@ void ServerHandler::handle() { } client_->doWrite(readBuffer_); client_->doRead(); + end_ = client_->end_; if (client_->readBuffer().size() > 0) { - BoolStr encryption{false, std::string("FAILED")}; encryption = aes256Encrypt(streambufToString(client_->readBuffer()), config_->agent().token); if (encryption.ok) { + if (end_) { + request_->chunkHeader_ = "yes"; + } std::string newRes( request_->genHttpOkResString(encode64(encryption.message))); copyStringToStreambuf(newRes, writeBuffer_); @@ -116,12 +114,11 @@ void ServerHandler::handle() { } } } else { - log_->write( "[" + to_string(uuid_) + "] [ServerHandler handle] [Encryption " "Failed] : [ " + - decryption.message + "] ", + encryption.message + "] ", Log::Level::DEBUG); log_->write("[" + to_string(uuid_) + "] [ServerHandler handle] [Encryption Failed] : " + request_->toString(), @@ -129,14 +126,12 @@ void ServerHandler::handle() { client_->socket().close(); } } else { - client_->socket().close(); return; } } break; } } else { - log_->write("[" + to_string(uuid_) + "] [ServerHandler handle] [NOT HTTP Request] [Request] : " + streambufToString(readBuffer_), Log::Level::DEBUG); @@ -145,7 +140,6 @@ void ServerHandler::handle() { return; } } else { - log_->write("[" + to_string(uuid_) + "] [ServerHandler handle] [Decryption Failed] : [ " + decryption.message + "] ", Log::Level::DEBUG); @@ -157,7 +151,6 @@ void ServerHandler::handle() { return; } } else { - log_->write( "[" + to_string(uuid_) + "] [ServerHandler handle] [NOT HTTP Request From Agent] [Request] : " + streambufToString(readBuffer_), @@ -167,3 +160,45 @@ void ServerHandler::handle() { return; } } + +void ServerHandler::continueRead() { + std::lock_guard lock(mutex_); + client_->doRead(); + end_ = client_->end_; + if (client_->readBuffer().size() > 0) { + BoolStr encryption{false, std::string("FAILED")}; + encryption = + aes256Encrypt(streambufToString(client_->readBuffer()), + config_->agent().token); + if (encryption.ok) { + if (end_) { + request_->chunkHeader_ = "yes"; + } + std::string newRes( + request_->genHttpOkResString(encode64(encryption.message))); + copyStringToStreambuf(newRes, writeBuffer_); + if (request_->httpType() == HTTP::HttpType::http) { + client_->socket().close(); + } else { + if (request_->parsedTlsRequest().type == + HTTP::TlsTypes::ApplicationData) { + client_->socket().close(); + } + } + } else { + log_->write( + "[" + to_string(uuid_) + + "] [ServerHandler handle] [Encryption " + "Failed] : [ " + + encryption.message + "] ", + Log::Level::DEBUG); + log_->write("[" + to_string(uuid_) + "] [ServerHandler handle] [Encryption Failed] : " + + request_->toString(), + Log::Level::INFO); + client_->socket().close(); + } + } else { + client_->socket().close(); + return; + } +} \ No newline at end of file diff --git a/core/src/serverhandler.hpp b/core/src/serverhandler.hpp index 9e94626..847bacd 100644 --- a/core/src/serverhandler.hpp +++ b/core/src/serverhandler.hpp @@ -28,10 +28,12 @@ class ServerHandler : private Uncopyable { ~ServerHandler(); void handle(); + void continueRead(); inline const HTTP::pointer &request() & { return request_; } inline const HTTP::pointer &&request() && { return std::move(request_); } + bool end_, connect_; private: explicit ServerHandler(boost::asio::streambuf &readBuffer, @@ -51,8 +53,6 @@ class ServerHandler : private Uncopyable { HTTP::pointer request_; const std::string &clientConnStr_; - boost::uuids::uuid uuid_; - std::mutex mutex_; }; diff --git a/core/src/tcpclient.cpp b/core/src/tcpclient.cpp index 06f71c3..ed4557b 100644 --- a/core/src/tcpclient.cpp +++ b/core/src/tcpclient.cpp @@ -10,7 +10,9 @@ TCPClient::TCPClient(boost::asio::io_context &io_context, io_context_(io_context), socket_(io_context), resolver_(io_context), - timeout_(io_context) {} + timeout_(io_context) { + end_ = false; +} boost::asio::ip::tcp::socket &TCPClient::socket() { std::lock_guard lock(mutex_); @@ -26,12 +28,10 @@ bool TCPClient::doConnect(const std::string &dstIP, const unsigned short &dstPort) { std::lock_guard lock(mutex_); try { - log_->write("[" + to_string(uuid_) + "] [TCPClient doConnect] [DST " + dstIP + ":" + std::to_string(dstPort) + "]", Log::Level::DEBUG); - boost::system::error_code error_code; auto endpoint = resolver_.resolve(dstIP.c_str(), std::to_string(dstPort).c_str(), error_code); if (error_code) { @@ -93,8 +93,14 @@ void TCPClient::doWrite(boost::asio::streambuf &buffer) { } void TCPClient::doRead() { + end_ = false; std::lock_guard lock(mutex_); try { + if (!socket_.is_open()) { + log_->write("[" + to_string(uuid_) + "] [TCPClient doRead] Socket is not OPEN", + Log::Level::DEBUG); + return; + } readBuffer_.consume(readBuffer_.size()); boost::system::error_code error; @@ -107,11 +113,8 @@ void TCPClient::doRead() { boost::asio::steady_timer timer(io_context_); for (auto i = 0; i <= config_->general().repeatWait; i++) { while (true) { - if (!socket_.is_open()) { - log_->write("[" + to_string(uuid_) + "] [TCPClient doRead] Socket is not OPEN", - Log::Level::DEBUG); - socketShutdown(); - return; + if (config_->runMode() == RunMode::server && readBuffer_.size() >= config_->general().chunkSize) { + break; } if (socket_.available() == 0) break; resetTimeout(); @@ -133,6 +136,13 @@ void TCPClient::doRead() { } timer.expires_after(std::chrono::milliseconds(config_->general().timeWait)); timer.wait(); + if (config_->runMode() == RunMode::server && readBuffer_.size() >= config_->general().chunkSize) { + break; + } + } + + if (config_->runMode() == RunMode::server && socket_.available() == 0) { + end_ = true; } if (readBuffer_.size() > 0) { diff --git a/core/src/tcpclient.hpp b/core/src/tcpclient.hpp index 9773bbd..bd6a1b8 100644 --- a/core/src/tcpclient.hpp +++ b/core/src/tcpclient.hpp @@ -14,50 +14,35 @@ class TCPClient : public boost::enable_shared_from_this { public: using pointer = boost::shared_ptr; - static pointer create(boost::asio::io_context &io_context, const std::shared_ptr &config, const std::shared_ptr &log) { return pointer(new TCPClient(io_context, config, log)); } - boost::asio::ip::tcp::socket &socket(); - void writeBuffer(boost::asio::streambuf &buffer); - inline boost::asio::streambuf &writeBuffer() & { return writeBuffer_; } inline boost::asio::streambuf &&writeBuffer() && { return std::move(writeBuffer_); } - inline boost::asio::streambuf &readBuffer() & { return readBuffer_; } inline boost::asio::streambuf &&readBuffer() && { return std::move(readBuffer_); } - bool doConnect(const std::string &dstIP, const unsigned short &dstPort); - void doWrite(boost::asio::streambuf &buffer); - void doRead(); - void socketShutdown(); - boost::uuids::uuid uuid_; + bool end_; private: explicit TCPClient(boost::asio::io_context &io_context, const std::shared_ptr &config, const std::shared_ptr &log); - - void resetTimeout(); - void cancelTimeout(); - void onTimeout(const boost::system::error_code &error); - - const std::shared_ptr &config_; const std::shared_ptr &log_; @@ -67,7 +52,5 @@ class TCPClient : public boost::enable_shared_from_this { boost::asio::streambuf readBuffer_; boost::asio::ip::tcp::resolver resolver_; boost::asio::deadline_timer timeout_; - - mutable std::mutex mutex_; }; diff --git a/core/src/tcpconnection.cpp b/core/src/tcpconnection.cpp index 0486460..82ae39c 100644 --- a/core/src/tcpconnection.cpp +++ b/core/src/tcpconnection.cpp @@ -12,6 +12,8 @@ TCPConnection::TCPConnection(boost::asio::io_context &io_context, timeout_(io_context), strand_(boost::asio::make_strand(io_context_)) { uuid_ = boost::uuids::random_generator()(); + end_ = false; + connect_ = false; } boost::asio::ip::tcp::socket &TCPConnection::socket() { @@ -38,7 +40,6 @@ void TCPConnection::doRead() { boost::asio::placeholders::error, boost::asio::placeholders:: bytes_transferred))); - } catch (std::exception &error) { log_->write(std::string("[" + to_string(uuid_) + "] [TCPConnection doRead] [catch] ") + error.what(), Log::Level::ERROR); @@ -48,9 +49,7 @@ void TCPConnection::doRead() { void TCPConnection::handleRead(const boost::system::error_code &error, size_t) { try { - cancelTimeout(); - if (error) { if (error == boost::asio::error::eof) { log_->write( @@ -113,6 +112,13 @@ void TCPConnection::handleRead(const boost::system::error_code &error, size_t) { std::to_string(socket_.remote_endpoint().port()), uuid_); agentHandler_->handle(); + end_ = agentHandler_->end_; + connect_ = agentHandler_->connect_; + if (writeBuffer_.size() > 0) { + doWrite(agentHandler_); + } else { + socketShutdown(); + } } else if (config_->runMode() == RunMode::server) { ServerHandler::pointer serverHandler_ = ServerHandler::create( readBuffer_, writeBuffer_, config_, log_, client_, @@ -120,12 +126,13 @@ void TCPConnection::handleRead(const boost::system::error_code &error, size_t) { std::to_string(socket_.remote_endpoint().port()), uuid_); serverHandler_->handle(); - } - - if (writeBuffer_.size() > 0) { - doWrite(); - } else { - socketShutdown(); + end_ = serverHandler_->end_; + connect_ = serverHandler_->connect_; + if (writeBuffer_.size() > 0) { + doWrite(serverHandler_); + } else { + socketShutdown(); + } } } } catch (std::exception &error) { @@ -136,35 +143,123 @@ void TCPConnection::handleRead(const boost::system::error_code &error, size_t) { } } -void TCPConnection::doWrite() { - std::lock_guard lock(mutex_); +void TCPConnection::doReadRest() { try { - log_->write("[" + to_string(uuid_) + "] [TCPConnection doWrite] [DST " + - socket_.remote_endpoint().address().to_string() + ":" + - std::to_string(socket_.remote_endpoint().port()) + - "] [Bytes " + std::to_string(writeBuffer_.size()) + "] ", - Log::Level::DEBUG); + readBuffer_.consume(readBuffer_.size()); + boost::system::error_code error; resetTimeout(); - boost::asio::async_write(socket_, writeBuffer_, - boost::asio::bind_executor(strand_, - [self = shared_from_this()](const boost::system::error_code &error, std::size_t /*bytes_transferred*/) { - self->handleWrite(error); - })); + + boost::asio::read(socket_, readBuffer_, boost::asio::transfer_at_least(1), + error); + cancelTimeout(); + + boost::asio::steady_timer timer(io_context_); + for (auto i = 0; i <= config_->general().repeatWait; i++) { + while (true) { + if (!socket_.is_open()) { + log_->write("[" + to_string(uuid_) + "] [TCPConnection doReadRest] Socket is not OPEN", + Log::Level::DEBUG); + socketShutdown(); + return; + } + if (socket_.available() == 0) break; + resetTimeout(); + boost::asio::read(socket_, readBuffer_, + boost::asio::transfer_at_least(1), error); + cancelTimeout(); + if (error == boost::asio::error::eof) { + log_->write("[" + to_string(uuid_) + "] [TCPConnection doReadRest] [EOF] Connection closed by peer.", + Log::Level::TRACE); + socketShutdown(); + return; + } else if (error) { + log_->write( + std::string("[" + to_string(uuid_) + "] [TCPConnection doReadRest] [error] ") + error.message(), + Log::Level::ERROR); + socketShutdown(); + return; + } + } + timer.expires_after(std::chrono::milliseconds(config_->general().timeWait)); + timer.wait(); + } + + if (readBuffer_.size() > 0) { + try { + + log_->write("[" + to_string(uuid_) + "] [TCPConnection doReadRest] [SRC " + + socket_.remote_endpoint().address().to_string() + ":" + + std::to_string(socket_.remote_endpoint().port()) + + "] [Bytes " + std::to_string(readBuffer_.size()) + "] ", + Log::Level::DEBUG); + log_->write("[" + to_string(uuid_) + "] [Read from] [SRC " + + socket_.remote_endpoint().address().to_string() + ":" + + std::to_string(socket_.remote_endpoint().port()) + + "] " + "[Bytes " + std::to_string(readBuffer_.size()) + + "] ", + Log::Level::TRACE); + } catch (std::exception &error) { + + log_->write( + std::string("[" + to_string(uuid_) + "] [TCPConnection doReadRest] [catch log] ") + error.what(), + Log::Level::DEBUG); + } + } else { + socketShutdown(); + return; + } } catch (std::exception &error) { - log_->write( - std::string("[" + to_string(uuid_) + "] [TCPConnection doWrite] [catch] ") + error.what(), - Log::Level::ERROR); + log_->write(std::string("[" + to_string(uuid_) + "] [TCPConnection doReadRest] [catch] ") + error.what(), + Log::Level::ERROR); socketShutdown(); } } -void TCPConnection::handleWrite(const boost::system::error_code &error) { - cancelTimeout(); - if (!error) { - doRead(); - } else { - log_->write("[" + to_string(uuid_) + "] [TCPConnection handleWrite] [error] " + error.message(), - Log::Level::ERROR); +void TCPConnection::doWrite(auto handlerPointer) { + boost::system::error_code error; + try { + if (!socket_.is_open()) { + log_->write("[" + to_string(uuid_) + "] [TCPConnection doWrite] Socket is not OPEN", + Log::Level::DEBUG); + return; + } + resetTimeout(); + if (writeBuffer_.size() > 0) { + log_->write("[" + to_string(uuid_) + "] [TCPConnection doWrite] [DST " + + socket_.remote_endpoint().address().to_string() + ":" + + std::to_string(socket_.remote_endpoint().port()) + + "] [Bytes " + std::to_string(writeBuffer_.size()) + "] ", + Log::Level::DEBUG); + log_->write("[" + to_string(uuid_) + "] [Write To] [DST " + + socket_.remote_endpoint().address().to_string() + ":" + + std::to_string(socket_.remote_endpoint().port()) + + "] [Bytes " + std::to_string(writeBuffer_.size()) + "] ", + Log::Level::TRACE); + boost::asio::write(socket_, writeBuffer_, error); + cancelTimeout(); + if (!error) { + if (end_ || connect_) { + doRead(); + } else { + if (config_->runMode() == RunMode::server) + doReadRest(); + handlerPointer->continueRead(); + end_ = handlerPointer->end_; + doWrite(handlerPointer); + } + } else { + log_->write("[" + to_string(uuid_) + "] [TCPConnection doWrite] [error] " + error.message(), + Log::Level::ERROR); + socketShutdown(); + } + } else { + socketShutdown(); + return; + } + } catch (std::exception &error) { + log_->write( + std::string("[" + to_string(uuid_) + "] [TCPConnection doWrite] [catch] ") + error.what(), + Log::Level::ERROR); socketShutdown(); } } @@ -199,7 +294,7 @@ void TCPConnection::socketShutdown() { socket_.close(); } catch (std::exception &error) { log_->write( - std::string("[" + to_string(uuid_) + "] [TCPClient socketShutdown] [catch] ") + error.what(), + std::string("[" + to_string(uuid_) + "] [TCPConnection socketShutdown] [catch] ") + error.what(), Log::Level::DEBUG); } } \ No newline at end of file diff --git a/core/src/tcpconnection.hpp b/core/src/tcpconnection.hpp index b7350cf..11c9552 100644 --- a/core/src/tcpconnection.hpp +++ b/core/src/tcpconnection.hpp @@ -12,8 +12,7 @@ class TCPConnection : public boost::enable_shared_from_this { public: using pointer = - boost::shared_ptr;// Define a type alias for a shared - // pointer to TCPConnection + boost::shared_ptr; static pointer create(boost::asio::io_context &io_context, const std::shared_ptr &config, @@ -39,9 +38,10 @@ class TCPConnection : public boost::enable_shared_from_this { void doRead(); void handleRead(const boost::system::error_code &error, size_t bytes_transferred); - void doWrite(); - void handleWrite(const boost::system::error_code &error); + void doReadRest(); + void doWrite(auto handlerPointer); void socketShutdown(); + bool end_, connect_; private: explicit TCPConnection(boost::asio::io_context &io_context, diff --git a/nipovpn/etc/nipovpn/config.yaml b/nipovpn/etc/nipovpn/config.yaml index 85dada9..38c5c0e 100644 --- a/nipovpn/etc/nipovpn/config.yaml +++ b/nipovpn/etc/nipovpn/config.yaml @@ -13,16 +13,22 @@ general: # timeout: unsigned short # Defines the timeout for I/O Operation in seconds. 0 indicates no timeout. # Useful to automatically close stalled connections. - timeout: 5 + timeout: 10 # repeatWait: unsigned short(1-65,635) # Defines the loop count which will try to repeat read from socket. # Same as timeWait - repeatWait: 10 + repeatWait: 3 + # chunkHeader: String + # Defines the chunk header that you want to inform Agent/Server if it is end or not. + chunkHeader: "END" + # chunkSize: unsigned short(512-65,535) + # Defines the chunk size that you want to read from socket. + chunkSize: 4096 # This block is to define log directives log: # logLevel: "INFO|TRACE|DEBUG" - logLevel: "INFO" + logLevel: "TRACE" # logFile: "/var/log/nipo/nipo.log" # Path of log file logFile: "/var/log/nipovpn/nipovpn.log"