diff --git a/Dockerfile b/Dockerfile index 2656e734..9eeb0aea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,20 @@ -FROM alpine:3.11 - -COPY . trojan -RUN apk add --no-cache --virtual .build-deps \ +FROM alpine:3.15 AS builder +COPY . /trojan +RUN apk add --no-cache \ + boost-dev \ build-base \ cmake \ - boost-dev \ - openssl-dev \ mariadb-connector-c-dev \ - && (cd trojan && cmake . && make -j $(nproc) && strip -s trojan \ - && mv trojan /usr/local/bin) \ - && rm -rf trojan \ - && apk del .build-deps \ - && apk add --no-cache --virtual .trojan-rundeps \ - libstdc++ \ - boost-system \ + openssl-dev \ + && (cd /trojan && cmake . && make -j $(nproc) && strip -s trojan) + +FROM alpine:3.15 +RUN apk add --no-cache \ boost-program_options \ + boost-system \ + libstdc++ \ mariadb-connector-c +COPY --from=builder /trojan/trojan /usr/local/bin/trojan WORKDIR /config -CMD ["trojan", "config.json"] +ENTRYPOINT ["/usr/local/bin/trojan", "/config/config.json"] diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0521fb80..cdda2615 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -37,8 +37,8 @@ stages: steps: - bash: | set -euo pipefail - curl -LO https://slproweb.com/download/Win64OpenSSL-1_1_1h.exe - powershell ".\\Win64OpenSSL-1_1_1h.exe /silent /sp- /suppressmsgboxes /DIR='C:\\Program Files\\OpenSSL-Win64'" + curl -LO https://slproweb.com/download/Win64OpenSSL-1_1_1o.exe + powershell ".\\Win64OpenSSL-1_1_1o.exe /silent /sp- /suppressmsgboxes /DIR='C:\\Program Files\\OpenSSL-Win64'" cmake -DBoost_INCLUDE_DIR="${BOOST_ROOT_1_72_0}/include" -DBoost_USE_STATIC_LIBS=ON -DOPENSSL_ROOT_DIR='C:/Program Files/OpenSSL-Win64' -DOPENSSL_USE_STATIC_LIBS=ON -DENABLE_MYSQL=OFF . cmake --build . --config Release - publish: $(System.DefaultWorkingDirectory)/Release/trojan.exe diff --git a/src/core/config.cpp b/src/core/config.cpp index 425f376a..95d65277 100644 --- a/src/core/config.cpp +++ b/src/core/config.cpp @@ -165,3 +165,7 @@ string Config::SHA224(const string &message) { EVP_MD_CTX_free(ctx); return string(mdString); } + +bool Config::no_auth() const { + return !mysql.enabled && password.empty(); +} \ No newline at end of file diff --git a/src/core/config.h b/src/core/config.h index d3fb0bd6..5406cb3c 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -87,6 +87,7 @@ class Config { void populate(const std::string &JSON); bool sip003(); static std::string SHA224(const std::string &message); + bool no_auth() const; private: void populate(const boost::property_tree::ptree &tree); }; diff --git a/src/main.cpp b/src/main.cpp index 99483403..97a5411f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -146,6 +146,9 @@ int main(int argc, const char *argv[]) { } else { config.load(config_file); } + if (config.no_auth()){ + Log::log_with_date_time("no authentication method", Log::WARN); + } Service service(config, test); if (test) { Log::log("The config file looks good.", Log::OFF); diff --git a/src/session/clientsession.cpp b/src/session/clientsession.cpp index 05373484..863a5945 100644 --- a/src/session/clientsession.cpp +++ b/src/session/clientsession.cpp @@ -162,7 +162,10 @@ void ClientSession::in_recv(const string &data) { destroy(); return; } - out_write_buf = config.password.cbegin()->first + "\r\n" + data[1] + data.substr(3) + "\r\n"; + out_write_buf = string().append(config.password.cbegin()->first) + .append("\r\n").append(1, data[1]) + .append(data.substr(3)) + .append("\r\n"); TrojanRequest req; if (req.parse(out_write_buf) == -1) { Log::log_with_endpoint(in_endpoint, "unsupported command", Log::ERROR); diff --git a/src/session/serversession.cpp b/src/session/serversession.cpp index fd4bc981..ea0820dc 100644 --- a/src/session/serversession.cpp +++ b/src/session/serversession.cpp @@ -67,6 +67,14 @@ void ServerSession::in_async_read() { auto self = shared_from_this(); in_socket.async_read_some(boost::asio::buffer(in_read_buf, MAX_LENGTH), [this, self](const boost::system::error_code error, size_t length) { if (error) { + if ((boost::asio::error::eof == error) || + (boost::asio::error::connection_reset == error) || + (boost::asio::error::operation_aborted == error)) + { + Log::log_with_endpoint(in_endpoint, "remote server actively closed the connection", Log::INFO); + status = ACTIVE_DISCONNECT; + } + destroy(); return; } @@ -137,19 +145,27 @@ void ServerSession::in_recv(const string &data) { TrojanRequest req; bool valid = req.parse(data) != -1; if (valid) { - auto password_iterator = config.password.find(req.password); - if (password_iterator == config.password.end()) { - valid = false; - if (auth && auth->auth(req.password)) { - valid = true; - auth_password = req.password; - Log::log_with_endpoint(in_endpoint, "authenticated by authenticator (" + req.password.substr(0, 7) + ')', Log::INFO); + if (config.no_auth()) { + Log::log_with_endpoint(in_endpoint, "authentication is disabled", Log::INFO); + }else{ + auto password_iterator = config.password.find(req.password); + if (password_iterator == config.password.end()) { + valid = false; + if (auth && auth->auth(req.password)) { + valid = true; + auth_password = req.password; + Log::log_with_endpoint(in_endpoint, + "authenticated by authenticator (" + req.password.substr(0, 7) + ')', + Log::INFO); + } + } else { + Log::log_with_endpoint(in_endpoint, "authenticated as " + password_iterator->second, Log::INFO); + } + if (!valid) { + Log::log_with_endpoint(in_endpoint, + "valid trojan request structure but possibly incorrect password (" + + req.password + ')', Log::WARN); } - } else { - Log::log_with_endpoint(in_endpoint, "authenticated as " + password_iterator->second, Log::INFO); - } - if (!valid) { - Log::log_with_endpoint(in_endpoint, "valid trojan request structure but possibly incorrect password (" + req.password + ')', Log::WARN); } } string query_addr = valid ? req.address.address : config.remote_addr; @@ -330,6 +346,7 @@ void ServerSession::destroy() { if (status == DESTROY) { return; } + auto previous_status = status; status = DESTROY; Log::log_with_endpoint(in_endpoint, "disconnected, " + to_string(recv_len) + " bytes received, " + to_string(sent_len) + " bytes sent, lasted for " + to_string(time(nullptr) - start_time) + " seconds", Log::INFO); if (auth && !auth_password.empty()) { @@ -347,6 +364,11 @@ void ServerSession::destroy() { udp_socket.cancel(ec); udp_socket.close(ec); } + if (previous_status == ACTIVE_DISCONNECT) { + in_socket.next_layer().cancel(ec); + in_socket.next_layer().shutdown(tcp::socket::shutdown_both, ec); + in_socket.next_layer().close(ec); + } if (in_socket.next_layer().is_open()) { auto self = shared_from_this(); auto ssl_shutdown_cb = [this, self](const boost::system::error_code error) { diff --git a/src/session/serversession.h b/src/session/serversession.h index c351f28d..03bfcaca 100644 --- a/src/session/serversession.h +++ b/src/session/serversession.h @@ -30,7 +30,8 @@ class ServerSession : public Session { HANDSHAKE, FORWARD, UDP_FORWARD, - DESTROY + DESTROY, + ACTIVE_DISCONNECT } status; boost::asio::ssl::streamin_socket; boost::asio::ip::tcp::socket out_socket;