2017-02-21 19:38:18 +02:00
// Copyright (c) 2014-2017, The Monero Project
2015-12-24 18:05:19 +02:00
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
# include "gtest/gtest.h"
# include "cryptonote_core/cryptonote_core.h"
# include "p2p/net_node.h"
# include "cryptonote_protocol/cryptonote_protocol_handler.h"
2017-08-25 18:14:46 +03:00
# define MAKE_IPV4_ADDRESS(a,b,c,d) epee::net_utils::ipv4_network_address{MAKE_IP(a,b,c,d),0}
2017-06-19 13:26:02 +03:00
2015-12-24 18:05:19 +02:00
namespace cryptonote {
class blockchain_storage ;
}
class test_core
{
public :
void on_synchronized ( ) { }
2017-08-22 16:54:18 +03:00
void safesyncmode ( const bool ) { }
2015-12-24 18:05:19 +02:00
uint64_t get_current_blockchain_height ( ) const { return 1 ; }
void set_target_blockchain_height ( uint64_t ) { }
bool init ( const boost : : program_options : : variables_map & vm ) { return true ; }
bool deinit ( ) { return true ; }
bool get_short_chain_history ( std : : list < crypto : : hash > & ids ) const { return true ; }
bool get_stat_info ( cryptonote : : core_stat_info & st_inf ) const { return true ; }
bool have_block ( const crypto : : hash & id ) const { return true ; }
2017-09-10 19:35:59 +03:00
void get_blockchain_top ( uint64_t & height , crypto : : hash & top_id ) const { height = 0 ; top_id = crypto : : null_hash ; }
2017-01-14 15:01:21 +02:00
bool handle_incoming_tx ( const cryptonote : : blobdata & tx_blob , cryptonote : : tx_verification_context & tvc , bool keeped_by_block , bool relayed , bool do_not_relay ) { return true ; }
2017-07-10 17:38:56 +03:00
bool handle_incoming_txs ( const std : : list < cryptonote : : blobdata > & tx_blob , std : : vector < cryptonote : : tx_verification_context > & tvc , bool keeped_by_block , bool relayed , bool do_not_relay ) { return true ; }
2015-12-24 18:05:19 +02:00
bool handle_incoming_block ( const cryptonote : : blobdata & block_blob , cryptonote : : block_verification_context & bvc , bool update_miner_blocktemplate = true ) { return true ; }
void pause_mine ( ) { }
void resume_mine ( ) { }
bool on_idle ( ) { return true ; }
bool find_blockchain_supplement ( const std : : list < crypto : : hash > & qblock_ids , cryptonote : : NOTIFY_RESPONSE_CHAIN_ENTRY : : request & resp ) { return true ; }
bool handle_get_objects ( cryptonote : : NOTIFY_REQUEST_GET_OBJECTS : : request & arg , cryptonote : : NOTIFY_RESPONSE_GET_OBJECTS : : request & rsp , cryptonote : : cryptonote_connection_context & context ) { return true ; }
2016-03-21 12:12:12 +02:00
cryptonote : : blockchain_storage & get_blockchain_storage ( ) { throw std : : runtime_error ( " Called invalid member function: please never call get_blockchain_storage on the TESTING class test_core. " ) ; }
2015-12-24 18:05:19 +02:00
bool get_test_drop_download ( ) const { return true ; }
bool get_test_drop_download_height ( ) const { return true ; }
bool prepare_handle_incoming_blocks ( const std : : list < cryptonote : : block_complete_entry > & blocks ) { return true ; }
bool cleanup_handle_incoming_blocks ( bool force_sync = false ) { return true ; }
uint64_t get_target_blockchain_height ( ) const { return 1 ; }
2017-08-16 23:19:53 +03:00
size_t get_block_sync_size ( uint64_t height ) const { return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT ; }
2016-10-22 22:46:51 +03:00
virtual void on_transaction_relayed ( const cryptonote : : blobdata & tx ) { }
2016-11-11 20:16:13 +02:00
bool get_testnet ( ) const { return false ; }
2017-05-14 16:06:55 +03:00
bool get_pool_transaction ( const crypto : : hash & id , cryptonote : : blobdata & tx_blob ) const { return false ; }
bool pool_has_tx ( const crypto : : hash & txid ) const { return false ; }
2017-01-15 18:05:55 +02:00
bool get_blocks ( uint64_t start_offset , size_t count , std : : list < std : : pair < cryptonote : : blobdata , cryptonote : : block > > & blocks , std : : list < cryptonote : : blobdata > & txs ) const { return false ; }
2017-02-11 21:38:18 +02:00
bool get_transactions ( const std : : vector < crypto : : hash > & txs_ids , std : : list < cryptonote : : transaction > & txs , std : : list < crypto : : hash > & missed_txs ) const { return false ; }
bool get_block_by_hash ( const crypto : : hash & h , cryptonote : : block & blk , bool * orphan = NULL ) const { return false ; }
2017-08-10 12:10:04 +03:00
uint8_t get_ideal_hard_fork_version ( uint64_t height ) const { return 0 ; }
uint8_t get_hard_fork_version ( uint64_t height ) const { return 0 ; }
2017-08-12 17:24:39 +03:00
cryptonote : : difficulty_type get_block_cumulative_difficulty ( uint64_t height ) const { return 0 ; }
2017-09-02 19:11:20 +03:00
bool fluffy_blocks_enabled ( ) const { return false ; }
2015-12-24 18:05:19 +02:00
} ;
typedef nodetool : : node_server < cryptonote : : t_cryptonote_protocol_handler < test_core > > Server ;
2017-06-19 13:26:02 +03:00
static bool is_blocked ( Server & server , const epee : : net_utils : : network_address & address , time_t * t = NULL )
2015-12-24 18:05:19 +02:00
{
2017-06-19 13:26:02 +03:00
const std : : string host = address . host_str ( ) ;
std : : map < std : : string , time_t > hosts = server . get_blocked_hosts ( ) ;
for ( auto rec : hosts )
2015-12-24 18:05:19 +02:00
{
2017-06-19 13:26:02 +03:00
if ( rec . first = = host )
2015-12-24 18:05:19 +02:00
{
if ( t )
* t = rec . second ;
return true ;
}
}
return false ;
}
TEST ( ban , add )
{
test_core pr_core ;
cryptonote : : t_cryptonote_protocol_handler < test_core > cprotocol ( pr_core , NULL ) ;
Server server ( cprotocol ) ;
cprotocol . set_p2p_endpoint ( & server ) ;
// starts empty
2017-06-19 13:26:02 +03:00
ASSERT_TRUE ( server . get_blocked_hosts ( ) . empty ( ) ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
2015-12-24 18:05:19 +02:00
// add an IP
2017-06-19 13:26:02 +03:00
ASSERT_TRUE ( server . block_host ( MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_TRUE ( server . get_blocked_hosts ( ) . size ( ) = = 1 ) ;
ASSERT_TRUE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
2015-12-24 18:05:19 +02:00
// add the same, should not change
2017-06-19 13:26:02 +03:00
ASSERT_TRUE ( server . block_host ( MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_TRUE ( server . get_blocked_hosts ( ) . size ( ) = = 1 ) ;
ASSERT_TRUE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
2015-12-24 18:05:19 +02:00
// remove an unblocked IP, should not change
2017-06-19 13:26:02 +03:00
ASSERT_FALSE ( server . unblock_host ( MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
ASSERT_TRUE ( server . get_blocked_hosts ( ) . size ( ) = = 1 ) ;
ASSERT_TRUE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
2015-12-24 18:05:19 +02:00
// remove the IP, ends up empty
2017-06-19 13:26:02 +03:00
ASSERT_TRUE ( server . unblock_host ( MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_TRUE ( server . get_blocked_hosts ( ) . size ( ) = = 0 ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
2015-12-24 18:05:19 +02:00
// remove the IP from an empty list, still empty
2017-06-19 13:26:02 +03:00
ASSERT_FALSE ( server . unblock_host ( MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_TRUE ( server . get_blocked_hosts ( ) . size ( ) = = 0 ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
2015-12-24 18:05:19 +02:00
// add two for known amounts of time, they're both blocked
2017-06-19 13:26:02 +03:00
ASSERT_TRUE ( server . block_host ( MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) , 1 ) ) ;
ASSERT_TRUE ( server . block_host ( MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) , 3 ) ) ;
ASSERT_TRUE ( server . get_blocked_hosts ( ) . size ( ) = = 2 ) ;
ASSERT_TRUE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_TRUE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
ASSERT_TRUE ( server . unblock_host ( MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_TRUE ( server . unblock_host ( MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
2015-12-24 18:05:19 +02:00
// these tests would need to call is_remote_ip_allowed, which is private
#if 0
// after two seconds, the first IP is unblocked, but not the second yet
sleep ( 2 ) ;
2017-06-19 13:26:02 +03:00
ASSERT_TRUE ( server . get_blocked_hosts ( ) . size ( ) = = 1 ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_TRUE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
2015-12-24 18:05:19 +02:00
// after two more seconds, the second IP is also unblocked
sleep ( 2 ) ;
2017-06-19 13:26:02 +03:00
ASSERT_TRUE ( server . get_blocked_hosts ( ) . size ( ) = = 0 ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) ) ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
2015-12-24 18:05:19 +02:00
# endif
// add an IP again, then re-ban for longer, then shorter
time_t t ;
2017-06-19 13:26:02 +03:00
ASSERT_TRUE ( server . block_host ( MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) , 2 ) ) ;
ASSERT_TRUE ( server . get_blocked_hosts ( ) . size ( ) = = 1 ) ;
ASSERT_TRUE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) , & t ) ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
2015-12-24 18:05:19 +02:00
ASSERT_TRUE ( t > = 1 ) ;
2017-06-19 13:26:02 +03:00
ASSERT_TRUE ( server . block_host ( MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) , 9 ) ) ;
ASSERT_TRUE ( server . get_blocked_hosts ( ) . size ( ) = = 1 ) ;
ASSERT_TRUE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) , & t ) ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
2015-12-24 18:05:19 +02:00
ASSERT_TRUE ( t > = 8 ) ;
2017-06-19 13:26:02 +03:00
ASSERT_TRUE ( server . block_host ( MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) , 5 ) ) ;
ASSERT_TRUE ( server . get_blocked_hosts ( ) . size ( ) = = 1 ) ;
ASSERT_TRUE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 4 ) , & t ) ) ;
ASSERT_FALSE ( is_blocked ( server , MAKE_IPV4_ADDRESS ( 1 , 2 , 3 , 5 ) ) ) ;
2015-12-24 18:05:19 +02:00
ASSERT_TRUE ( t > = 4 ) ;
}