fix(nvhttp): wrap TLS socket to ensure graceful closure (#3077)
This commit is contained in:
@@ -44,19 +44,38 @@ namespace nvhttp {
|
|||||||
|
|
||||||
crypto::cert_chain_t cert_chain;
|
crypto::cert_chain_t cert_chain;
|
||||||
|
|
||||||
class SunshineHttpsServer: public SimpleWeb::Server<SimpleWeb::HTTPS> {
|
class SunshineHTTPS: public SimpleWeb::HTTPS {
|
||||||
public:
|
public:
|
||||||
SunshineHttpsServer(const std::string &certification_file, const std::string &private_key_file):
|
SunshineHTTPS(boost::asio::io_service &io_service, boost::asio::ssl::context &ctx):
|
||||||
SimpleWeb::Server<SimpleWeb::HTTPS>::Server(certification_file, private_key_file) {}
|
SimpleWeb::HTTPS(io_service, ctx) {}
|
||||||
|
|
||||||
|
virtual ~SunshineHTTPS() {
|
||||||
|
// Gracefully shutdown the TLS connection
|
||||||
|
SimpleWeb::error_code ec;
|
||||||
|
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),
|
||||||
|
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<int(SSL *)> verify;
|
||||||
std::function<void(std::shared_ptr<Response>, std::shared_ptr<Request>)> on_verify_failed;
|
std::function<void(std::shared_ptr<Response>, std::shared_ptr<Request>)> on_verify_failed;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
boost::asio::ssl::context context;
|
||||||
|
|
||||||
void
|
void
|
||||||
after_bind() override {
|
after_bind() override {
|
||||||
SimpleWeb::Server<SimpleWeb::HTTPS>::after_bind();
|
|
||||||
|
|
||||||
if (verify) {
|
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_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) {
|
context.set_verify_callback([](int verified, boost::asio::ssl::verify_context &ctx) {
|
||||||
@@ -108,7 +127,7 @@ namespace nvhttp {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using https_server_t = SunshineHttpsServer;
|
using https_server_t = SunshineHTTPSServer;
|
||||||
using http_server_t = SimpleWeb::Server<SimpleWeb::HTTP>;
|
using http_server_t = SimpleWeb::Server<SimpleWeb::HTTP>;
|
||||||
|
|
||||||
struct conf_intern_t {
|
struct conf_intern_t {
|
||||||
@@ -142,7 +161,7 @@ namespace nvhttp {
|
|||||||
struct {
|
struct {
|
||||||
util::Either<
|
util::Either<
|
||||||
std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTP>::Response>,
|
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;
|
response;
|
||||||
std::string salt;
|
std::string salt;
|
||||||
} async_insert_pin;
|
} async_insert_pin;
|
||||||
@@ -154,8 +173,8 @@ namespace nvhttp {
|
|||||||
std::atomic<uint32_t> session_id_counter;
|
std::atomic<uint32_t> session_id_counter;
|
||||||
|
|
||||||
using args_t = SimpleWeb::CaseInsensitiveMultimap;
|
using args_t = SimpleWeb::CaseInsensitiveMultimap;
|
||||||
using resp_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTPS>::Response>;
|
using resp_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SunshineHTTPS>::Response>;
|
||||||
using req_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTPS>::Request>;
|
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 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>;
|
using req_http_t = std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTP>::Request>;
|
||||||
|
|
||||||
@@ -483,7 +502,7 @@ namespace nvhttp {
|
|||||||
struct tunnel;
|
struct tunnel;
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct tunnel<SimpleWeb::HTTPS> {
|
struct tunnel<SunshineHTTPS> {
|
||||||
static auto constexpr to_string = "HTTPS"sv;
|
static auto constexpr to_string = "HTTPS"sv;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -671,7 +690,7 @@ namespace nvhttp {
|
|||||||
print_req<T>(request);
|
print_req<T>(request);
|
||||||
|
|
||||||
int pair_status = 0;
|
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 args = request->parse_query_string();
|
||||||
auto clientID = args.find("uniqueid"s);
|
auto clientID = args.find("uniqueid"s);
|
||||||
|
|
||||||
@@ -696,7 +715,7 @@ namespace nvhttp {
|
|||||||
|
|
||||||
// Only include the MAC address for requests sent from paired clients over HTTPS.
|
// 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.
|
// 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())));
|
tree.put("root.mac", platf::get_mac_address(net::addr_to_normalized_string(local_endpoint.address())));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -777,7 +796,7 @@ namespace nvhttp {
|
|||||||
|
|
||||||
void
|
void
|
||||||
applist(resp_https_t response, req_https_t request) {
|
applist(resp_https_t response, req_https_t request) {
|
||||||
print_req<SimpleWeb::HTTPS>(request);
|
print_req<SunshineHTTPS>(request);
|
||||||
|
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
|
|
||||||
@@ -806,7 +825,7 @@ namespace nvhttp {
|
|||||||
|
|
||||||
void
|
void
|
||||||
launch(bool &host_audio, resp_https_t response, req_https_t request) {
|
launch(bool &host_audio, resp_https_t response, req_https_t request) {
|
||||||
print_req<SimpleWeb::HTTPS>(request);
|
print_req<SunshineHTTPS>(request);
|
||||||
|
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
auto g = util::fail_guard([&]() {
|
auto g = util::fail_guard([&]() {
|
||||||
@@ -899,7 +918,7 @@ namespace nvhttp {
|
|||||||
|
|
||||||
void
|
void
|
||||||
resume(bool &host_audio, resp_https_t response, req_https_t request) {
|
resume(bool &host_audio, resp_https_t response, req_https_t request) {
|
||||||
print_req<SimpleWeb::HTTPS>(request);
|
print_req<SunshineHTTPS>(request);
|
||||||
|
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
auto g = util::fail_guard([&]() {
|
auto g = util::fail_guard([&]() {
|
||||||
@@ -985,7 +1004,7 @@ namespace nvhttp {
|
|||||||
|
|
||||||
void
|
void
|
||||||
cancel(resp_https_t response, req_https_t request) {
|
cancel(resp_https_t response, req_https_t request) {
|
||||||
print_req<SimpleWeb::HTTPS>(request);
|
print_req<SunshineHTTPS>(request);
|
||||||
|
|
||||||
pt::ptree tree;
|
pt::ptree tree;
|
||||||
auto g = util::fail_guard([&]() {
|
auto g = util::fail_guard([&]() {
|
||||||
@@ -1016,7 +1035,7 @@ namespace nvhttp {
|
|||||||
|
|
||||||
void
|
void
|
||||||
appasset(resp_https_t response, req_https_t request) {
|
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 args = request->parse_query_string();
|
||||||
auto app_image = proc::proc.get_app_image(util::from_view(get_arg(args, "appid")));
|
auto app_image = proc::proc.get_app_image(util::from_view(get_arg(args, "appid")));
|
||||||
@@ -1109,9 +1128,9 @@ namespace nvhttp {
|
|||||||
tree.put("root.<xmlattr>.status_message"s, "The client is not authorized. Certificate verification failed."s);
|
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.default_resource["GET"] = not_found<SunshineHTTPS>;
|
||||||
https_server.resource["^/serverinfo$"]["GET"] = serverinfo<SimpleWeb::HTTPS>;
|
https_server.resource["^/serverinfo$"]["GET"] = serverinfo<SunshineHTTPS>;
|
||||||
https_server.resource["^/pair$"]["GET"] = [&add_cert](auto resp, auto req) { pair<SimpleWeb::HTTPS>(add_cert, resp, req); };
|
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["^/applist$"]["GET"] = applist;
|
||||||
https_server.resource["^/appasset$"]["GET"] = appasset;
|
https_server.resource["^/appasset$"]["GET"] = appasset;
|
||||||
https_server.resource["^/launch$"]["GET"] = [&host_audio](auto resp, auto req) { launch(host_audio, resp, req); };
|
https_server.resource["^/launch$"]["GET"] = [&host_audio](auto resp, auto req) { launch(host_audio, resp, req); };
|
||||||
|
|||||||
Reference in New Issue
Block a user