diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 21f2bf81e..97706f745 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -197,6 +197,8 @@ #define RPC_CREDITS_PER_HASH_SCALE ((float)(1<<24)) +#define DNS_BLOCKLIST_LIFETIME (86400 * 8) + // New constants are intended to go here namespace config { diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp index aee1fa593..8dd551d1e 100644 --- a/src/p2p/net_node.cpp +++ b/src/p2p/net_node.cpp @@ -149,6 +149,7 @@ namespace nodetool const command_line::arg_descriptor arg_ban_list = {"ban-list", "Specify ban list file, one IP address per line"}; const command_line::arg_descriptor arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true}; const command_line::arg_descriptor arg_no_sync = {"no-sync", "Don't synchronize the blockchain with other peers", false}; + const command_line::arg_descriptor arg_enable_dns_blocklist = {"enable-dns-blocklist", "Apply realtime blocklist from DNS", false}; const command_line::arg_descriptor arg_no_igd = {"no-igd", "Disable UPnP port mapping"}; const command_line::arg_descriptor arg_igd = {"igd", "UPnP port mapping (disabled, enabled, delayed)", "delayed"}; diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index f13b36a82..9fba5d636 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -287,7 +287,7 @@ namespace nodetool uint32_t get_max_out_public_peers() const; void change_max_in_public_peers(size_t count); uint32_t get_max_in_public_peers() const; - virtual bool block_host(epee::net_utils::network_address address, time_t seconds = P2P_IP_BLOCKTIME); + virtual bool block_host(epee::net_utils::network_address address, time_t seconds = P2P_IP_BLOCKTIME, bool add_only = false); virtual bool unblock_host(const epee::net_utils::network_address &address); virtual bool block_subnet(const epee::net_utils::ipv4_network_subnet &subnet, time_t seconds = P2P_IP_BLOCKTIME); virtual bool unblock_subnet(const epee::net_utils::ipv4_network_subnet &subnet); @@ -369,6 +369,7 @@ namespace nodetool bool peer_sync_idle_maker(); bool do_handshake_with_peer(peerid_type& pi, p2p_connection_context& context, bool just_take_peerlist = false); bool do_peer_timed_sync(const epee::net_utils::connection_context_base& context, peerid_type peer_id); + bool update_dns_blocklist(); bool make_new_connection_from_anchor_peerlist(const std::vector& anchor_peerlist); bool make_new_connection_from_peerlist(network_zone& zone, bool use_white_list); @@ -474,6 +475,7 @@ namespace nodetool epee::math_helper::once_a_time_seconds<60*30, false> m_peerlist_store_interval; epee::math_helper::once_a_time_seconds<60> m_gray_peerlist_housekeeping_interval; epee::math_helper::once_a_time_seconds<3600, false> m_incoming_connections_interval; + epee::math_helper::once_a_time_seconds<7000> m_dns_blocklist_interval; std::list m_priority_peers; std::vector m_exclusive_peers; @@ -512,6 +514,8 @@ namespace nodetool cryptonote::network_type m_nettype; epee::net_utils::ssl_support_t m_ssl_support; + + bool m_enable_dns_blocklist; }; const int64_t default_limit_up = P2P_DEFAULT_LIMIT_RATE_UP; // kB/s @@ -533,6 +537,7 @@ namespace nodetool extern const command_line::arg_descriptor arg_ban_list; extern const command_line::arg_descriptor arg_p2p_hide_my_port; extern const command_line::arg_descriptor arg_no_sync; + extern const command_line::arg_descriptor arg_enable_dns_blocklist; extern const command_line::arg_descriptor arg_no_igd; extern const command_line::arg_descriptor arg_igd; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 128d17155..054ea7952 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,7 @@ namespace nodetool command_line::add_arg(desc, arg_ban_list); command_line::add_arg(desc, arg_p2p_hide_my_port); command_line::add_arg(desc, arg_no_sync); + command_line::add_arg(desc, arg_enable_dns_blocklist); command_line::add_arg(desc, arg_no_igd); command_line::add_arg(desc, arg_igd); command_line::add_arg(desc, arg_out_peers); @@ -226,7 +228,7 @@ namespace nodetool } //----------------------------------------------------------------------------------- template - bool node_server::block_host(epee::net_utils::network_address addr, time_t seconds) + bool node_server::block_host(epee::net_utils::network_address addr, time_t seconds, bool add_only) { if(!addr.is_blockable()) return false; @@ -240,7 +242,11 @@ namespace nodetool else limit = now + seconds; const std::string host_str = addr.host_str(); - m_blocked_hosts[host_str] = limit; + auto it = m_blocked_hosts.find(host_str); + if (it == m_blocked_hosts.end()) + m_blocked_hosts[host_str] = limit; + else if (it->second < limit || !add_only) + it->second = limit; // drop any connection to that address. This should only have to look into // the zone related to the connection, but really make sure everything is @@ -497,6 +503,8 @@ namespace nodetool if (command_line::has_arg(vm, arg_no_sync)) m_payload_handler.set_no_sync(true); + m_enable_dns_blocklist = command_line::get_arg(vm, arg_enable_dns_blocklist); + if ( !set_max_out_peers(public_zone, command_line::get_arg(vm, arg_out_peers) ) ) return false; else @@ -1971,6 +1979,52 @@ namespace nodetool m_gray_peerlist_housekeeping_interval.do_call(boost::bind(&node_server::gray_peerlist_housekeeping, this)); m_peerlist_store_interval.do_call(boost::bind(&node_server::store_config, this)); m_incoming_connections_interval.do_call(boost::bind(&node_server::check_incoming_connections, this)); + m_dns_blocklist_interval.do_call(boost::bind(&node_server::update_dns_blocklist, this)); + return true; + } + //----------------------------------------------------------------------------------- + template + bool node_server::update_dns_blocklist() + { + if (!m_enable_dns_blocklist) + return true; + if (m_nettype != cryptonote::MAINNET) + return true; + + static const std::vector dns_urls = { + "blocklist.moneropulse.se" + , "blocklist.moneropulse.org" + , "blocklist.moneropulse.net" + , "blocklist.moneropulse.no" + , "blocklist.moneropulse.fr" + , "blocklist.moneropulse.de" + , "blocklist.moneropulse.ch" + }; + + std::vector records; + if (!tools::dns_utils::load_txt_records_from_dns(records, dns_urls)) + return true; + + unsigned good = 0, bad = 0; + for (const auto& record : records) + { + std::vector ips; + boost::split(ips, record, boost::is_any_of(";")); + for (const auto &ip: ips) + { + const expect parsed_addr = net::get_network_address(ip, 0); + if (!parsed_addr) + { + MWARNING("Invalid IP address from DNS blocklist: " << ip << " - " << parsed_addr.error()); + ++bad; + continue; + } + block_host(*parsed_addr, DNS_BLOCKLIST_LIFETIME, true); + ++good; + } + } + if (good > 0) + MINFO(good << " addresses added to the blocklist"); return true; } //----------------------------------------------------------------------------------- diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h index f1490a0db..0da758ad4 100644 --- a/src/p2p/net_node_common.h +++ b/src/p2p/net_node_common.h @@ -58,7 +58,7 @@ namespace nodetool virtual uint64_t get_public_connections_count()=0; virtual void for_each_connection(std::function f)=0; virtual bool for_connection(const boost::uuids::uuid&, std::function f)=0; - virtual bool block_host(epee::net_utils::network_address address, time_t seconds = 0)=0; + virtual bool block_host(epee::net_utils::network_address address, time_t seconds = 0, bool add_only = false)=0; virtual bool unblock_host(const epee::net_utils::network_address &address)=0; virtual std::map get_blocked_hosts()=0; virtual std::map get_blocked_subnets()=0; @@ -108,7 +108,7 @@ namespace nodetool { return false; } - virtual bool block_host(epee::net_utils::network_address address, time_t seconds) + virtual bool block_host(epee::net_utils::network_address address, time_t seconds, bool add_only) { return true; }