Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(nvhttp): wrap TLS socket to ensure graceful closure #3077

Merged
merged 1 commit into from
Aug 25, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 39 additions & 20 deletions src/nvhttp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,38 @@

crypto::cert_chain_t cert_chain;

class SunshineHttpsServer: public SimpleWeb::Server<SimpleWeb::HTTPS> {
class SunshineHTTPS: public SimpleWeb::HTTPS {
public:
SunshineHttpsServer(const std::string &certification_file, const std::string &private_key_file):
SimpleWeb::Server<SimpleWeb::HTTPS>::Server(certification_file, private_key_file) {}
SunshineHTTPS(boost::asio::io_service &io_service, boost::asio::ssl::context &ctx):
SimpleWeb::HTTPS(io_service, ctx) {}

Check warning on line 50 in src/nvhttp.cpp

View check run for this annotation

Codecov / codecov/patch

src/nvhttp.cpp#L49-L50

Added lines #L49 - L50 were not covered by tests

virtual ~SunshineHTTPS() {

Check warning on line 52 in src/nvhttp.cpp

View check run for this annotation

Codecov / codecov/patch

src/nvhttp.cpp#L52

Added line #L52 was not covered by tests
// Gracefully shutdown the TLS connection
SimpleWeb::error_code ec;

Check warning on line 54 in src/nvhttp.cpp

View check run for this annotation

Codecov / codecov/patch

src/nvhttp.cpp#L54

Added line #L54 was not covered by tests
shutdown(ec);
}
};

class SunshineHTTPSServer: public SimpleWeb::ServerBase<SunshineHTTPS> {
public:
SunshineHTTPSServer(const std::string &certification_file, const std::string &private_key_file):
ServerBase<SunshineHTTPS>::ServerBase(443),

Check warning on line 62 in src/nvhttp.cpp

View check run for this annotation

Codecov / codecov/patch

src/nvhttp.cpp#L61-L62

Added lines #L61 - L62 were not covered by tests
ReenigneArcher marked this conversation as resolved.
Show resolved Hide resolved
context(boost::asio::ssl::context::tls_server) {
// Disabling TLS 1.0 and 1.1 (see RFC 8996)
context.set_options(boost::asio::ssl::context::no_tlsv1);
context.set_options(boost::asio::ssl::context::no_tlsv1_1);
context.use_certificate_chain_file(certification_file);
context.use_private_key_file(private_key_file, boost::asio::ssl::context::pem);
}

std::function<int(SSL *)> verify;
std::function<void(std::shared_ptr<Response>, std::shared_ptr<Request>)> on_verify_failed;

protected:
boost::asio::ssl::context context;

void
after_bind() override {
SimpleWeb::Server<SimpleWeb::HTTPS>::after_bind();

if (verify) {
context.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert | boost::asio::ssl::verify_client_once);
context.set_verify_callback([](int verified, boost::asio::ssl::verify_context &ctx) {
Expand Down Expand Up @@ -108,7 +127,7 @@
}
};

using https_server_t = SunshineHttpsServer;
using https_server_t = SunshineHTTPSServer;
using http_server_t = SimpleWeb::Server<SimpleWeb::HTTP>;

struct conf_intern_t {
Expand Down Expand Up @@ -142,7 +161,7 @@
struct {
util::Either<
std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTP>::Response>,
std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTPS>::Response>>
std::shared_ptr<typename SimpleWeb::ServerBase<SunshineHTTPS>::Response>>
response;
std::string salt;
} async_insert_pin;
Expand All @@ -154,8 +173,8 @@
std::atomic<uint32_t> session_id_counter;

using args_t = SimpleWeb::CaseInsensitiveMultimap;
using resp_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTPS>::Response>;
using req_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTPS>::Request>;
using resp_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SunshineHTTPS>::Response>;
using req_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SunshineHTTPS>::Request>;
using resp_http_t = std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTP>::Response>;
using req_http_t = std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTP>::Request>;

Expand Down Expand Up @@ -483,7 +502,7 @@
struct tunnel;

template <>
struct tunnel<SimpleWeb::HTTPS> {
struct tunnel<SunshineHTTPS> {
static auto constexpr to_string = "HTTPS"sv;
};

Expand Down Expand Up @@ -671,7 +690,7 @@
print_req<T>(request);

int pair_status = 0;
if constexpr (std::is_same_v<SimpleWeb::HTTPS, T>) {
if constexpr (std::is_same_v<SunshineHTTPS, T>) {
auto args = request->parse_query_string();
auto clientID = args.find("uniqueid"s);

Expand All @@ -696,7 +715,7 @@

// Only include the MAC address for requests sent from paired clients over HTTPS.
// For HTTP requests, use a placeholder MAC address that Moonlight knows to ignore.
if constexpr (std::is_same_v<SimpleWeb::HTTPS, T>) {
if constexpr (std::is_same_v<SunshineHTTPS, T>) {
tree.put("root.mac", platf::get_mac_address(net::addr_to_normalized_string(local_endpoint.address())));
}
else {
Expand Down Expand Up @@ -777,7 +796,7 @@

void
applist(resp_https_t response, req_https_t request) {
print_req<SimpleWeb::HTTPS>(request);
print_req<SunshineHTTPS>(request);

pt::ptree tree;

Expand Down Expand Up @@ -806,7 +825,7 @@

void
launch(bool &host_audio, resp_https_t response, req_https_t request) {
print_req<SimpleWeb::HTTPS>(request);
print_req<SunshineHTTPS>(request);

pt::ptree tree;
auto g = util::fail_guard([&]() {
Expand Down Expand Up @@ -899,7 +918,7 @@

void
resume(bool &host_audio, resp_https_t response, req_https_t request) {
print_req<SimpleWeb::HTTPS>(request);
print_req<SunshineHTTPS>(request);

pt::ptree tree;
auto g = util::fail_guard([&]() {
Expand Down Expand Up @@ -985,7 +1004,7 @@

void
cancel(resp_https_t response, req_https_t request) {
print_req<SimpleWeb::HTTPS>(request);
print_req<SunshineHTTPS>(request);

pt::ptree tree;
auto g = util::fail_guard([&]() {
Expand Down Expand Up @@ -1016,7 +1035,7 @@

void
appasset(resp_https_t response, req_https_t request) {
print_req<SimpleWeb::HTTPS>(request);
print_req<SunshineHTTPS>(request);

auto args = request->parse_query_string();
auto app_image = proc::proc.get_app_image(util::from_view(get_arg(args, "appid")));
Expand Down Expand Up @@ -1109,9 +1128,9 @@
tree.put("root.<xmlattr>.status_message"s, "The client is not authorized. Certificate verification failed."s);
};

https_server.default_resource["GET"] = not_found<SimpleWeb::HTTPS>;
https_server.resource["^/serverinfo$"]["GET"] = serverinfo<SimpleWeb::HTTPS>;
https_server.resource["^/pair$"]["GET"] = [&add_cert](auto resp, auto req) { pair<SimpleWeb::HTTPS>(add_cert, resp, req); };
https_server.default_resource["GET"] = not_found<SunshineHTTPS>;
https_server.resource["^/serverinfo$"]["GET"] = serverinfo<SunshineHTTPS>;
https_server.resource["^/pair$"]["GET"] = [&add_cert](auto resp, auto req) { pair<SunshineHTTPS>(add_cert, resp, req); };
https_server.resource["^/applist$"]["GET"] = applist;
https_server.resource["^/appasset$"]["GET"] = appasset;
https_server.resource["^/launch$"]["GET"] = [&host_audio](auto resp, auto req) { launch(host_audio, resp, req); };
Expand Down
Loading