diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index a07bb25d..487d8607 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -392,5 +392,34 @@ bool t_command_parser_executor::hard_fork_info(const std::vector& a return m_executor.hard_fork_info(version); } +bool t_command_parser_executor::show_bans(const std::vector& args) +{ + if (!args.empty()) return false; + return m_executor.print_bans(); +} + +bool t_command_parser_executor::ban(const std::vector& args) +{ + if (args.size() != 1 && args.size() != 2) return false; + std::string ip = args[0]; + time_t seconds = P2P_IP_BLOCKTIME; + if (args.size() > 1) + { + seconds = std::stoi(args[0]); + if (seconds == 0) + { + return false; + } + } + return m_executor.ban(ip, seconds); +} + +bool t_command_parser_executor::unban(const std::vector& args) +{ + if (args.size() != 1) return false; + std::string ip = args[0]; + return m_executor.unban(ip); +} + } // namespace daemonize diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h index f00fbd77..0c042cd5 100644 --- a/src/daemon/command_parser_executor.h +++ b/src/daemon/command_parser_executor.h @@ -106,6 +106,12 @@ public: bool stop_save_graph(const std::vector& args); bool hard_fork_info(const std::vector& args); + + bool show_bans(const std::vector& args); + + bool ban(const std::vector& args); + + bool unban(const std::vector& args); }; } // namespace daemonize diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 8714b256..0999ed30 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -194,6 +194,21 @@ t_command_server::t_command_server( , std::bind(&t_command_parser_executor::hard_fork_info, &m_parser, p::_1) , "Print hard fork voting information" ); + m_command_lookup.set_handler( + "bans" + , std::bind(&t_command_parser_executor::show_bans, &m_parser, p::_1) + , "Show the currently banned IPs" + ); + m_command_lookup.set_handler( + "ban" + , std::bind(&t_command_parser_executor::ban, &m_parser, p::_1) + , "Ban a given IP for a time" + ); + m_command_lookup.set_handler( + "unban" + , std::bind(&t_command_parser_executor::unban, &m_parser, p::_1) + , "Unban a given IP" + ); } bool t_command_server::process_command_str(const std::string& cmd) diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 176df81f..547db167 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -1036,4 +1036,110 @@ bool t_rpc_command_executor::hard_fork_info(uint8_t version) return true; } +bool t_rpc_command_executor::print_bans() +{ + cryptonote::COMMAND_RPC_GETBANS::request req; + cryptonote::COMMAND_RPC_GETBANS::response res; + std::string fail_message = "Unsuccessful"; + epee::json_rpc::error error_resp; + + if (m_is_rpc) + { + if (!m_rpc_client->json_rpc_request(req, res, "get_bans", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_bans(req, res, error_resp)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + time_t now = time(nullptr); + for (auto i = res.bans.begin(); i != res.bans.end(); ++i) + { + time_t seconds = i->seconds - now; + tools::msg_writer() << epee::string_tools::get_ip_string_from_int32(i->ip) << " banned for " << seconds << " seconds"; + } + + return true; +} + + +bool t_rpc_command_executor::ban(const std::string &ip, time_t seconds) +{ + cryptonote::COMMAND_RPC_SETBANS::request req; + cryptonote::COMMAND_RPC_SETBANS::response res; + std::string fail_message = "Unsuccessful"; + epee::json_rpc::error error_resp; + + cryptonote::COMMAND_RPC_SETBANS::ban ban; + if (!epee::string_tools::get_ip_int32_from_string(ban.ip, ip)) + { + tools::fail_msg_writer() << "Invalid IP"; + return true; + } + ban.ban = true; + ban.seconds = seconds; + req.bans.push_back(ban); + + if (m_is_rpc) + { + if (!m_rpc_client->json_rpc_request(req, res, "set_bans", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_set_bans(req, res, error_resp)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + return true; +} + +bool t_rpc_command_executor::unban(const std::string &ip) +{ + cryptonote::COMMAND_RPC_SETBANS::request req; + cryptonote::COMMAND_RPC_SETBANS::response res; + std::string fail_message = "Unsuccessful"; + epee::json_rpc::error error_resp; + + cryptonote::COMMAND_RPC_SETBANS::ban ban; + if (!epee::string_tools::get_ip_int32_from_string(ban.ip, ip)) + { + tools::fail_msg_writer() << "Invalid IP"; + return true; + } + ban.ban = false; + ban.seconds = 0; + req.bans.push_back(ban); + + if (m_is_rpc) + { + if (!m_rpc_client->json_rpc_request(req, res, "set_bans", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_set_bans(req, res, error_resp)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + return true; +} + }// namespace daemonize diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index 778b73ac..95c5624f 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -124,6 +124,12 @@ public: bool stop_save_graph(); bool hard_fork_info(uint8_t version); + + bool print_bans(); + + bool ban(const std::string &ip, time_t seconds); + + bool unban(const std::string &ip); }; } // namespace daemonize diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 74599f18..39cbe01f 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -117,6 +117,9 @@ namespace nodetool size_t get_outgoing_connections_count(); peerlist_manager& get_peerlist_manager(){return m_peerlist;} void delete_connections(size_t count); + virtual bool block_ip(uint32_t adress, time_t seconds = P2P_IP_BLOCKTIME); + virtual bool unblock_ip(uint32_t address); + virtual std::map get_blocked_ips() const { return m_blocked_ips; } private: const std::vector m_seed_nodes_list = { "seeds.moneroseeds.se" @@ -171,7 +174,6 @@ namespace nodetool virtual bool drop_connection(const epee::net_utils::connection_context_base& context); virtual void request_callback(const epee::net_utils::connection_context_base& context); virtual void for_each_connection(std::function f); - virtual bool block_ip(uint32_t adress, uint32_t seconds = P2P_IP_BLOCKTIME); virtual bool add_ip_fail(uint32_t address); //----------------- i_connection_filter -------------------------------------------------------- virtual bool is_remote_ip_allowed(uint32_t adress); diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index f15e6020..067f6378 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -186,7 +186,7 @@ namespace nodetool } //----------------------------------------------------------------------------------- template - bool node_server::block_ip(uint32_t addr, uint32_t seconds) + bool node_server::block_ip(uint32_t addr, time_t seconds) { CRITICAL_REGION_LOCAL(m_blocked_ips_lock); m_blocked_ips[addr] = time(nullptr) + seconds; @@ -195,6 +195,18 @@ namespace nodetool } //----------------------------------------------------------------------------------- template + bool node_server::unblock_ip(uint32_t addr) + { + CRITICAL_REGION_LOCAL(m_blocked_ips_lock); + auto i = m_blocked_ips.find(addr); + if (i == m_blocked_ips.end()) + return false; + m_blocked_ips.erase(i); + LOG_PRINT_CYAN("IP " << epee::string_tools::get_ip_string_from_int32(addr) << " unblocked.", LOG_LEVEL_0); + return true; + } + //----------------------------------------------------------------------------------- + template bool node_server::add_ip_fail(uint32_t address) { CRITICAL_REGION_LOCAL(m_ip_fails_score_lock); diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h index 93b29deb..2505006a 100644 --- a/src/p2p/net_node_common.h +++ b/src/p2p/net_node_common.h @@ -50,7 +50,9 @@ namespace nodetool virtual void request_callback(const epee::net_utils::connection_context_base& context)=0; virtual uint64_t get_connections_count()=0; virtual void for_each_connection(std::function f)=0; - virtual bool block_ip(uint32_t adress)=0; + virtual bool block_ip(uint32_t adress, time_t seconds = 0)=0; + virtual bool unblock_ip(uint32_t adress)=0; + virtual std::map get_blocked_ips()const=0; virtual bool add_ip_fail(uint32_t adress)=0; }; @@ -86,10 +88,18 @@ namespace nodetool { return false; } - virtual bool block_ip(uint32_t adress) + virtual bool block_ip(uint32_t adress, time_t seconds) { return true; } + virtual bool unblock_ip(uint32_t adress) + { + return true; + } + virtual std::map get_blocked_ips() const + { + return std::map(); + } virtual bool add_ip_fail(uint32_t adress) { return true; diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index f5e70003..e2b30b6e 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -899,6 +899,49 @@ namespace cryptonote #endif } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_bans(const COMMAND_RPC_GETBANS::request& req, COMMAND_RPC_GETBANS::response& res, epee::json_rpc::error& error_resp) + { + if(!check_core_busy()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy."; + return false; + } + + std::map blocked_ips = m_p2p.get_blocked_ips(); + for (std::map::const_iterator i = blocked_ips.begin(); i != blocked_ips.end(); ++i) + { + COMMAND_RPC_GETBANS::ban b; + b.ip = i->first; + b.seconds = i->second; + res.bans.push_back(b); + } + + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_set_bans(const COMMAND_RPC_SETBANS::request& req, COMMAND_RPC_SETBANS::response& res, epee::json_rpc::error& error_resp) + { + if(!check_core_busy()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy."; + return false; + } + + for (auto i = req.bans.begin(); i != req.bans.end(); ++i) + { + if (i->ban) + m_p2p.block_ip(i->ip, i->seconds); + else + m_p2p.unblock_ip(i->ip); + } + + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_fast_exit(const COMMAND_RPC_FAST_EXIT::request& req, COMMAND_RPC_FAST_EXIT::response& res) { cryptonote::core::set_fast_exit(); diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 1fbd0981..3c230fd8 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -105,6 +105,8 @@ namespace cryptonote MAP_JON_RPC_WE("get_connections", on_get_connections, COMMAND_RPC_GET_CONNECTIONS) MAP_JON_RPC_WE("get_info", on_get_info_json, COMMAND_RPC_GET_INFO) MAP_JON_RPC_WE("hard_fork_info", on_hard_fork_info, COMMAND_RPC_HARD_FORK_INFO) + MAP_JON_RPC_WE("setbans", on_set_bans, COMMAND_RPC_SETBANS) + MAP_JON_RPC_WE("getbans", on_get_bans, COMMAND_RPC_GETBANS) END_JSON_RPC_MAP() END_URI_MAP2() @@ -142,6 +144,8 @@ namespace cryptonote bool on_get_connections(const COMMAND_RPC_GET_CONNECTIONS::request& req, COMMAND_RPC_GET_CONNECTIONS::response& res, epee::json_rpc::error& error_resp); bool on_get_info_json(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, epee::json_rpc::error& error_resp); bool on_hard_fork_info(const COMMAND_RPC_HARD_FORK_INFO::request& req, COMMAND_RPC_HARD_FORK_INFO::response& res, epee::json_rpc::error& error_resp); + bool on_set_bans(const COMMAND_RPC_SETBANS::request& req, COMMAND_RPC_SETBANS::response& res, epee::json_rpc::error& error_resp); + bool on_get_bans(const COMMAND_RPC_GETBANS::request& req, COMMAND_RPC_GETBANS::response& res, epee::json_rpc::error& error_resp); //----------------------- private: diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index aa88ffcb..7fb5c46f 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -888,5 +888,70 @@ namespace cryptonote END_KV_SERIALIZE_MAP() }; }; + + struct COMMAND_RPC_GETBANS + { + struct ban + { + uint32_t ip; + uint32_t seconds; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(ip) + KV_SERIALIZE(seconds) + END_KV_SERIALIZE_MAP() + }; + + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::vector bans; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(bans) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_SETBANS + { + struct ban + { + uint32_t ip; + bool ban; + uint32_t seconds; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(ip) + KV_SERIALIZE(ban) + KV_SERIALIZE(seconds) + END_KV_SERIALIZE_MAP() + }; + + struct request + { + std::vector bans; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(bans) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; }