Configure prevention pairing over non-private network

This commit is contained in:
loki 2019-12-27 16:04:18 +01:00
commit b3ae81cb3a
8 changed files with 195 additions and 11 deletions

View file

@ -79,6 +79,8 @@ set(SUNSHINE_TARGET_FILES
sunshine/platform/common.h
sunshine/process.cpp
sunshine/process.h
sunshine/network.cpp
sunshine/network.h
sunshine/move_by_copy.h
sunshine/task_pool.h
sunshine/thread_pool.h

@ -1 +1 @@
Subproject commit e70509e078ade2eb9679862ab6a48b4ee2fefb66
Subproject commit f4b7101ad369f56423291d6ac39ebf61a6518298

View file

@ -10,6 +10,15 @@
# The name displayed by Moonlight
# sunshine_name = sunshine
# The origin of the remote endpoint address that is not denied for HTTP method /pin
# Could be any of the following values:
# pc|lan|wan
# pc: Only localhost may access /pin
# lan: Only those in LAN may access /pin
# wan: Anyone may access /pin
#
# origin_pin_allowed = lan
# Pretty self-explanatory
unique_id = 03904e64-51da-4fb3-9afd-a9f7ff70fea4
@ -25,7 +34,7 @@ ping_timeout = 2000
# How much error correcting packets must be send for every video max_b_frames
# This is just some random number, don't know the optimal value
# The higher fec_percentage, the lower space for the actual data to send per frame there is
fec_percentage = 1
fec_percentage = 10
# The back/select button on the controller
@ -39,7 +48,7 @@ fec_percentage = 1
# FFmpeg software encoding parameters
# Honestly, I have no idea what the optimal values would be.
# Play around with this :)
max_b_frames = 16
max_b_frames = 4
gop_size = 24
# Constant Rate Factor. Between 1 and 52. It allows QP to go up during motion and down with still image, resulting in constant perceived quality

View file

@ -36,12 +36,13 @@ stream_t stream {
};
nvhttp_t nvhttp {
"lan", // origin_pin
PRIVATE_KEY_FILE,
CERTIFICATE_FILE,
"sunshine", // sunshine_name
"03904e64-51da-4fb3-9afd-a9f7ff70fea4", // unique_id
"devices.json" // file_devices
"sunshine"s, // sunshine_name,
"03904e64-51da-4fb3-9afd-a9f7ff70fea4"s, // unique_id
"devices.json"s // file_devices
};
input_t input {
@ -102,6 +103,32 @@ void string_f(std::unordered_map<std::string, std::string> &vars, const std::str
input = std::move(it->second);
}
void string_restricted_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::string &input, const std::vector<std::string_view> &allowed_vals) {
std::string temp;
string_f(vars, name, temp);
for(auto &allowed_val : allowed_vals) {
if(temp == allowed_val) {
input = std::move(temp);
return;
}
}
}
void int_restricted_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, int &input, const std::vector<std::string_view> &allowed_vals) {
std::string temp;
string_f(vars, name, temp);
for(int x = 0; x < allowed_vals.size(); ++x) {
auto &allowed_val = allowed_vals[x];
if(temp == allowed_val) {
input = x;
return;
}
}
}
void int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, int &input) {
auto it = vars.find(name);
@ -142,6 +169,10 @@ void parse_file(const char *file) {
string_f(vars, "file_devices", nvhttp.file_devices);
string_f(vars, "external_ip", nvhttp.external_ip);
string_restricted_f(vars, "origin_pin_allowed", nvhttp.origin_pin_allowed, {
"pc"sv, "lan"sv, "wan"sv
});
int to = -1;
int_f(vars, "ping_timeout", to);
if(to > 0) {

View file

@ -28,6 +28,10 @@ struct stream_t {
};
struct nvhttp_t {
// Could be any of the following values:
// pc|lan|wan
std::string origin_pin_allowed;
std::string pkey; // must be 2048 bits
std::string cert; // must be signed with a key of 2048 bits

96
sunshine/network.cpp Normal file
View file

@ -0,0 +1,96 @@
//
// Created by loki on 12/27/19.
//
#include <algorithm>
#include "network.h"
#include "utility.h"
namespace net {
using namespace std::literals;
// In the format "xxx.xxx.xxx.xxx/x"
std::pair<std::uint32_t, std::uint32_t> ip_block(const std::string_view &ip);
std::vector<std::pair<std::uint32_t, std::uint32_t>> pc_ips {
ip_block("127.0.0.1/32"sv)
};
std::vector<std::tuple<std::uint32_t, std::uint32_t>> lan_ips {
ip_block("192.168.0.0/16"sv),
ip_block("172.16.0.0/12"),
ip_block("10.0.0.0/8"sv)
};
std::uint32_t ip(const std::string_view &ip_str) {
auto begin = std::begin(ip_str);
auto end = std::end(ip_str);
auto temp_end = std::find(begin, end, '.');
std::uint32_t ip = 0;
auto shift = 24;
while(temp_end != end) {
ip += (util::from_chars(begin, temp_end) << shift);
shift -= 8;
begin = temp_end + 1;
temp_end = std::find(begin, end, '.');
}
ip += util::from_chars(begin, end);
return ip;
}
// In the format "xxx.xxx.xxx.xxx/x"
std::pair<std::uint32_t, std::uint32_t> ip_block(const std::string_view &ip_str) {
auto begin = std::begin(ip_str);
auto end = std::find(begin, std::end(ip_str), '/');
auto addr = ip({ begin, (std::size_t)(end - begin) });
auto bits = 32 - util::from_chars(end + 1, std::end(ip_str));
return { addr, addr + ((1 << bits) - 1) };
}
net_e from_enum_string(const std::string_view &view) {
if(view == "wan") {
return WAN;
}
if(view == "lan") {
return LAN;
}
return PC;
}
net_e from_address(const std::string_view &view) {
auto addr = ip(view);
for(auto [ip_low, ip_high] : pc_ips) {
if(addr >= ip_low && addr <= ip_high) {
return PC;
}
}
for(auto [ip_low, ip_high] : lan_ips) {
if(addr >= ip_low && addr <= ip_high) {
return LAN;
}
}
return WAN;
}
std::string_view to_enum_string(net_e net) {
switch(net) {
case PC:
return "pc"sv;
case LAN:
return "lan"sv;
case WAN:
return "wan"sv;
}
// avoid warning
return "wan"sv;
}
}

22
sunshine/network.h Normal file
View file

@ -0,0 +1,22 @@
//
// Created by loki on 12/27/19.
//
#ifndef SUNSHINE_NETWORK_H
#define SUNSHINE_NETWORK_H
#include <tuple>
namespace net {
enum net_e : int {
PC,
LAN,
WAN
};
net_e from_enum_string(const std::string_view &view);
std::string_view to_enum_string(net_e net);
net_e from_address(const std::string_view &view);
}
#endif //SUNSHINE_NETWORK_H

View file

@ -22,6 +22,7 @@
#include "nvhttp.h"
#include "platform/common.h"
#include "process.h"
#include "network.h"
namespace nvhttp {
@ -37,7 +38,6 @@ namespace pt = boost::property_tree;
std::string read_file(const char *path);
std::string local_ip;
using https_server_t = SimpleWeb::Server<SimpleWeb::HTTPS>;
using http_server_t = SimpleWeb::Server<SimpleWeb::HTTP>;
@ -88,6 +88,8 @@ enum class op_e {
};
std::int64_t current_appid { -1 };
std::string local_ip;
net::net_e origin_pin_allowed;
void save_devices() {
pt::ptree root;
@ -105,7 +107,7 @@ void save_devices() {
cert_nodes.push_back(std::make_pair(""s, cert_node));
}
node.add_child("certs"s, cert_nodes);
nodes.push_back(std::make_pair(""s, node));
}
@ -374,6 +376,16 @@ template<class T>
void pin(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
print_req<T>(request);
auto address = request->remote_endpoint_address();
auto ip_type = net::from_address(address);
if(ip_type > origin_pin_allowed) {
std::cout << '[' << address << "] -- denied"sv << std::endl;
response->write(SimpleWeb::StatusCode::client_error_forbidden);
return;
}
pt::ptree tree;
auto &sess = std::begin(map_id_sess)->second;
@ -384,16 +396,22 @@ void pin(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response,
pt::write_xml(data, tree);
auto &async_response = sess.async_insert_pin.response;
if(async_response.left()) {
if(async_response.has_left() && async_response.left()) {
async_response.left()->write(data.str());
}
else {
else if(async_response.has_right() && async_response.right()){
async_response.right()->write(data.str());
}
else {
response->write(SimpleWeb::StatusCode::client_error_im_a_teapot);
return;
}
// reset async_response
async_response = std::decay_t<decltype(async_response.left())>();
// response to the current request
response->write(""s);
response->write(SimpleWeb::StatusCode::success_ok);
}
template<class T>
@ -631,6 +649,8 @@ void appasset(resp_https_t response, req_https_t request) {
void start() {
local_ip = platf::get_local_ip();
origin_pin_allowed = net::from_enum_string(config::nvhttp.origin_pin_allowed);
if(local_ip.empty()) {
std::cout << "Error: Could not determine the local ip-address"sv << std::endl;