From a8cd073fcc504de51b8f56766757f0295b68e066 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Wed, 28 Oct 2020 23:47:42 +0000 Subject: [PATCH] Add rpc-restricted-bind-ip option Fixes #6369 --- src/daemon/main.cpp | 3 ++- src/rpc/core_rpc_server.cpp | 18 +++++++++++++++--- src/rpc/rpc_args.cpp | 34 ++++++++++++++++++++++++++++++++++ src/rpc/rpc_args.h | 4 ++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 3db8fbcb4..d413906df 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -66,10 +66,12 @@ uint16_t parse_public_rpc_port(const po::variables_map &vm) } std::string rpc_port_str; + std::string rpc_bind_address = command_line::get_arg(vm, cryptonote::rpc_args::descriptors().rpc_bind_ip); const auto &restricted_rpc_port = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port; if (!command_line::is_arg_defaulted(vm, restricted_rpc_port)) { rpc_port_str = command_line::get_arg(vm, restricted_rpc_port); + rpc_bind_address = command_line::get_arg(vm, cryptonote::rpc_args::descriptors().rpc_restricted_bind_ip); } else if (command_line::get_arg(vm, cryptonote::core_rpc_server::arg_restricted_rpc)) { @@ -86,7 +88,6 @@ uint16_t parse_public_rpc_port(const po::variables_map &vm) throw std::runtime_error("invalid RPC port " + rpc_port_str); } - const auto rpc_bind_address = command_line::get_arg(vm, cryptonote::rpc_args::descriptors().rpc_bind_ip); const auto address = net::get_network_address(rpc_bind_address, rpc_port); if (!address) { throw std::runtime_error("failed to parse RPC bind address"); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 9b08971cd..986659a23 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -264,6 +264,18 @@ namespace cryptonote if (!rpc_config) return false; + std::string bind_ip_str = rpc_config->bind_ip; + std::string bind_ipv6_str = rpc_config->bind_ipv6_address; + if (restricted) + { + const auto restricted_rpc_port_arg = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port; + const bool has_restricted_rpc_port_arg = !command_line::is_arg_defaulted(vm, restricted_rpc_port_arg); + if (has_restricted_rpc_port_arg && port == command_line::get_arg(vm, restricted_rpc_port_arg)) + { + bind_ip_str = rpc_config->restricted_bind_ip; + bind_ipv6_str = rpc_config->restricted_bind_ipv6_address; + } + } disable_rpc_ban = rpc_config->disable_rpc_ban; std::string address = command_line::get_arg(vm, arg_rpc_payment_address); if (!address.empty() && allow_rpc_payment) @@ -300,7 +312,7 @@ namespace cryptonote if (!m_rpc_payment) { uint32_t bind_ip; - bool ok = epee::string_tools::get_ip_int32_from_string(bind_ip, rpc_config->bind_ip); + bool ok = epee::string_tools::get_ip_int32_from_string(bind_ip, bind_ip_str); if (ok & !epee::net_utils::is_ip_loopback(bind_ip)) MWARNING("The RPC server is accessible from the outside, but no RPC payment was setup. RPC access will be free for all."); } @@ -322,8 +334,8 @@ namespace cryptonote auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); }; return epee::http_server_impl_base::init( - rng, std::move(port), std::move(rpc_config->bind_ip), - std::move(rpc_config->bind_ipv6_address), std::move(rpc_config->use_ipv6), std::move(rpc_config->require_ipv4), + rng, std::move(port), std::move(bind_ip_str), + std::move(bind_ipv6_str), std::move(rpc_config->use_ipv6), std::move(rpc_config->require_ipv4), std::move(rpc_config->access_control_origins), std::move(http_login), std::move(rpc_config->ssl_options) ); } diff --git a/src/rpc/rpc_args.cpp b/src/rpc/rpc_args.cpp index 8601bd0b4..0966fb6d2 100644 --- a/src/rpc/rpc_args.cpp +++ b/src/rpc/rpc_args.cpp @@ -91,6 +91,8 @@ namespace cryptonote rpc_args::descriptors::descriptors() : rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify IP to bind RPC server"), "127.0.0.1"}) , rpc_bind_ipv6_address({"rpc-bind-ipv6-address", rpc_args::tr("Specify IPv6 address to bind RPC server"), "::1"}) + , rpc_restricted_bind_ip({"rpc-restricted-bind-ip", rpc_args::tr("Specify IP to bind restricted RPC server"), "127.0.0.1"}) + , rpc_restricted_bind_ipv6_address({"rpc-restricted-bind-ipv6-address", rpc_args::tr("Specify IPv6 address to bind restricted RPC server"), "::1"}) , rpc_use_ipv6({"rpc-use-ipv6", rpc_args::tr("Allow IPv6 for RPC"), false}) , rpc_ignore_ipv4({"rpc-ignore-ipv4", rpc_args::tr("Ignore unsuccessful IPv4 bind for RPC"), false}) , rpc_login({"rpc-login", rpc_args::tr("Specify username[:password] required for RPC server"), "", true}) @@ -113,6 +115,8 @@ namespace cryptonote const descriptors arg{}; command_line::add_arg(desc, arg.rpc_bind_ip); command_line::add_arg(desc, arg.rpc_bind_ipv6_address); + command_line::add_arg(desc, arg.rpc_restricted_bind_ip); + command_line::add_arg(desc, arg.rpc_restricted_bind_ipv6_address); command_line::add_arg(desc, arg.rpc_use_ipv6); command_line::add_arg(desc, arg.rpc_ignore_ipv4); command_line::add_arg(desc, arg.rpc_login); @@ -136,6 +140,8 @@ namespace cryptonote config.bind_ip = command_line::get_arg(vm, arg.rpc_bind_ip); config.bind_ipv6_address = command_line::get_arg(vm, arg.rpc_bind_ipv6_address); + config.restricted_bind_ip = command_line::get_arg(vm, arg.rpc_restricted_bind_ip); + config.restricted_bind_ipv6_address = command_line::get_arg(vm, arg.rpc_restricted_bind_ipv6_address); config.use_ipv6 = command_line::get_arg(vm, arg.rpc_use_ipv6); config.require_ipv4 = !command_line::get_arg(vm, arg.rpc_ignore_ipv4); config.disable_rpc_ban = command_line::get_arg(vm, arg.disable_rpc_ban); @@ -188,6 +194,34 @@ namespace cryptonote return boost::none; } } + if (!config.restricted_bind_ip.empty()) + { + // always parse IP here for error consistency + boost::system::error_code ec{}; + boost::asio::ip::address::from_string(config.restricted_bind_ip, ec); + if (ec) + { + LOG_ERROR(tr("Invalid IP address given for --") << arg.rpc_restricted_bind_ip.name); + return boost::none; + } + } + if (!config.restricted_bind_ipv6_address.empty()) + { + // allow square braces, but remove them here if present + if (config.restricted_bind_ipv6_address.find('[') != std::string::npos) + { + config.restricted_bind_ipv6_address = config.restricted_bind_ipv6_address.substr(1, config.restricted_bind_ipv6_address.size() - 2); + } + + // always parse IP here for error consistency + boost::system::error_code ec{}; + boost::asio::ip::address::from_string(config.restricted_bind_ipv6_address, ec); + if (ec) + { + LOG_ERROR(tr("Invalid IP address given for --") << arg.rpc_restricted_bind_ipv6_address.name); + return boost::none; + } + } const char *env_rpc_login = nullptr; const bool has_rpc_arg = command_line::has_arg(vm, arg.rpc_login); diff --git a/src/rpc/rpc_args.h b/src/rpc/rpc_args.h index 4cf4279b2..f06e539bd 100644 --- a/src/rpc/rpc_args.h +++ b/src/rpc/rpc_args.h @@ -53,6 +53,8 @@ namespace cryptonote const command_line::arg_descriptor rpc_bind_ip; const command_line::arg_descriptor rpc_bind_ipv6_address; + const command_line::arg_descriptor rpc_restricted_bind_ip; + const command_line::arg_descriptor rpc_restricted_bind_ipv6_address; const command_line::arg_descriptor rpc_use_ipv6; const command_line::arg_descriptor rpc_ignore_ipv4; const command_line::arg_descriptor rpc_login; @@ -81,6 +83,8 @@ namespace cryptonote std::string bind_ip; std::string bind_ipv6_address; + std::string restricted_bind_ip; + std::string restricted_bind_ipv6_address; bool use_ipv6; bool require_ipv4; std::vector access_control_origins;