Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #659 - add P2P security options #887

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
383edb6
Added command line parameters
jmjatlanta May 4, 2018
b98a9ce
Intermediate commit
jmjatlanta Jun 22, 2018
6a518e2
Algorithm set by command line parameter
jmjatlanta Jun 22, 2018
155df38
Remove duplicate code
jmjatlanta Jun 22, 2018
5f8c1dc
Allow a list of nodes to be advertised
jmjatlanta Mar 4, 2019
97282a5
Code cleanup
jmjatlanta Apr 11, 2019
0caff3e
Make address list optional
jmjatlanta Apr 11, 2019
cbc0624
Removed unnecessary 'protected'
jmjatlanta Apr 11, 2019
12b0840
const ref in set_advertise_algorithm
jmjatlanta Apr 15, 2019
a41059c
removed random, add exclude advert. list
jmjatlanta Apr 15, 2019
317e348
correct/improve p2p unit testing
jmjatlanta May 6, 2019
c3a1f61
Switch to flat_set and find algorithms
jmjatlanta May 6, 2019
20570f6
switch to binary search
jmjatlanta May 7, 2019
5568ba0
Make ifc to add seed nodes consistent
jmjatlanta May 7, 2019
8482159
add test for exclude_list
jmjatlanta May 10, 2019
703a46b
Move reflection to .hxx
jmjatlanta May 10, 2019
236c8d1
fix poorly resolved conflicts
jmjatlanta May 13, 2019
6510da4
remove mistakenly added command line param
jmjatlanta May 13, 2019
65dd814
modified test to compile on clang
jmjatlanta May 14, 2019
1b53bff
2nd attempt to satisfy travis build/clang
jmjatlanta May 14, 2019
a4d68eb
3rd attempt at travis compile error
jmjatlanta May 14, 2019
9773501
4th attempt at travis compile error
jmjatlanta May 14, 2019
9e31106
5th fix for travis
jmjatlanta May 15, 2019
ed66336
6th try - sledgehammer
jmjatlanta May 16, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 22 additions & 74 deletions libraries/app/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
#include <fc/io/fstream.hpp>
#include <fc/rpc/api_connection.hpp>
#include <fc/rpc/websocket_api.hpp>
#include <fc/network/resolve.hpp>
#include <fc/crypto/base64.hpp>

#include <boost/filesystem/path.hpp>
Expand Down Expand Up @@ -122,44 +121,19 @@ void application_impl::reset_p2p_node(const fc::path& data_dir)
_p2p_network->load_configuration(data_dir / "p2p");
_p2p_network->set_node_delegate(this);

// passed as one URL per parameter
if( _options->count("seed-node") )
{
auto seeds = _options->at("seed-node").as<vector<string>>();
for( const string& endpoint_string : seeds )
{
try {
std::vector<fc::ip::endpoint> endpoints = resolve_string_to_ip_endpoints(endpoint_string);
for (const fc::ip::endpoint& endpoint : endpoints)
{
ilog("Adding seed node ${endpoint}", ("endpoint", endpoint));
_p2p_network->add_node(endpoint);
_p2p_network->connect_to_endpoint(endpoint);
}
} catch( const fc::exception& e ) {
wlog( "caught exception ${e} while adding seed node ${endpoint}",
("e", e.to_detail_string())("endpoint", endpoint_string) );
}
}
_p2p_network->add_seed_nodes(seeds);
}

// passed as a collection of URLs in a string
if( _options->count("seed-nodes") )
{
auto seeds_str = _options->at("seed-nodes").as<string>();
auto seeds = fc::json::from_string(seeds_str).as<vector<string>>(2);
for( const string& endpoint_string : seeds )
{
try {
std::vector<fc::ip::endpoint> endpoints = resolve_string_to_ip_endpoints(endpoint_string);
for (const fc::ip::endpoint& endpoint : endpoints)
{
ilog("Adding seed node ${endpoint}", ("endpoint", endpoint));
_p2p_network->add_node(endpoint);
}
} catch( const fc::exception& e ) {
wlog( "caught exception ${e} while adding seed node ${endpoint}",
("e", e.to_detail_string())("endpoint", endpoint_string) );
}
}
_p2p_network->add_seed_nodes(seeds);
}
else
{
Expand All @@ -185,20 +159,7 @@ void application_impl::reset_p2p_node(const fc::path& data_dir)
"seed.bts.bangzi.info:55501", // Bangzi (Germany)
"seeds.bitshares.eu:1776" // pc (http://seeds.quisquis.de/bitshares.html)
};
for( const string& endpoint_string : seeds )
{
try {
std::vector<fc::ip::endpoint> endpoints = resolve_string_to_ip_endpoints(endpoint_string);
for (const fc::ip::endpoint& endpoint : endpoints)
{
ilog("Adding seed node ${endpoint}", ("endpoint", endpoint));
_p2p_network->add_node(endpoint);
}
} catch( const fc::exception& e ) {
wlog( "caught exception ${e} while adding seed node ${endpoint}",
("e", e.to_detail_string())("endpoint", endpoint_string) );
}
}
_p2p_network->add_seed_nodes(seeds);
}

if( _options->count("p2p-endpoint") )
Expand All @@ -208,42 +169,25 @@ void application_impl::reset_p2p_node(const fc::path& data_dir)
_p2p_network->listen_to_p2p_network();
ilog("Configured p2p node to listen on ${ip}", ("ip", _p2p_network->get_actual_listening_endpoint()));

if (_options->count("advertise-peer-algorithm") )
{
if ( _options->count("advertise-peer-list") )
_p2p_network->set_advertise_algorithm(
_options->at("advertise-peer-algorithm").as<string>(),
_options->at("advertise-peer-list").as<std::vector<std::string>>() );
else
_p2p_network->set_advertise_algorithm( _options->at("advertise-peer-algorithm").as<string>() );
}

if (_options->count("accept-incoming-connections") )
_p2p_network->accept_incoming_connections( _options->at("accept-incoming-connections").as<bool>() );

_p2p_network->connect_to_p2p_network();
_p2p_network->sync_from(net::item_id(net::core_message_type_enum::block_message_type,
_chain_db->head_block_id()),
std::vector<uint32_t>());
} FC_CAPTURE_AND_RETHROW() }

std::vector<fc::ip::endpoint> application_impl::resolve_string_to_ip_endpoints(const std::string& endpoint_string)
{
try
{
string::size_type colon_pos = endpoint_string.find(':');
if (colon_pos == std::string::npos)
FC_THROW("Missing required port number in endpoint string \"${endpoint_string}\"",
("endpoint_string", endpoint_string));
std::string port_string = endpoint_string.substr(colon_pos + 1);
try
{
uint16_t port = boost::lexical_cast<uint16_t>(port_string);

std::string hostname = endpoint_string.substr(0, colon_pos);
std::vector<fc::ip::endpoint> endpoints = fc::resolve(hostname, port);
if (endpoints.empty())
FC_THROW_EXCEPTION( fc::unknown_host_exception,
"The host name can not be resolved: ${hostname}",
("hostname", hostname) );
return endpoints;
}
catch (const boost::bad_lexical_cast&)
{
FC_THROW("Bad port: ${port}", ("port", port_string));
}
}
FC_CAPTURE_AND_RETHROW((endpoint_string))
}


void application_impl::new_connection( const fc::http::websocket_connection_ptr& c )
{
auto wsc = std::make_shared<fc::rpc::websocket_api_connection>(*c, GRAPHENE_NET_MAX_NESTED_OBJECTS);
Expand Down Expand Up @@ -1020,6 +964,10 @@ void application::set_program_options(boost::program_options::options_descriptio
"For asset_api::get_asset_holders to set its default limit value as 100")
("api-limit-get-key-references",boost::program_options::value<uint64_t>()->default_value(100),
"For database_api_impl::get_key_references to set its default limit value as 100")
("accept-incoming-connections", bpo::value<bool>()->implicit_value(true), "Accept incoming connections")
("advertise-peer-algorithm", bpo::value<string>()->implicit_value("all"), "Determines which peers are advertised")
("advertise-peer-list", bpo::value<vector<string>>()->composing(),
"P2P nodes to advertise (may specify multiple times")
;
command_line_options.add(configuration_file_options);
command_line_options.add_options()
Expand Down
2 changes: 0 additions & 2 deletions libraries/app/application_impl.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ class application_impl : public net::node_delegate

void reset_p2p_node(const fc::path& data_dir);

std::vector<fc::ip::endpoint> resolve_string_to_ip_endpoints(const std::string& endpoint_string);

void new_connection( const fc::http::websocket_connection_ptr& c );

void reset_websocket_server();
Expand Down
124 changes: 103 additions & 21 deletions libraries/net/include/graphene/net/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/
#pragma once

#include <fc/thread/thread.hpp>
#include <graphene/net/core_messages.hpp>
#include <graphene/net/message.hpp>
#include <graphene/net/peer_database.hpp>
Expand All @@ -43,7 +44,7 @@ namespace graphene { namespace net {
{
void operator()(node_impl*);
};
}
} // namespace detail

// during network development, we need to track message propagation across the network
// using a structure like this:
Expand Down Expand Up @@ -195,13 +196,57 @@ namespace graphene { namespace net {
node(const std::string& user_agent);
virtual ~node();

/*****
* Close the peer database, shut down threads
*/
void close();

/*****
* Let this object know the delegate
* NOTE: The thread upon which this method is called is the
* thread that those delegate methods will be called.
*/
void set_node_delegate( node_delegate* del );

/******
* Control what information gets shared when a remote asks
* for p2p peers
*/
void set_advertise_algorithm( std::string algo,
const fc::optional<std::vector<std::string>>& advertise_list = fc::optional<std::vector<std::string>>() );

/*****
* Load (or create) and parse a configuration file
* @param configuration_directory a directory where the p2p configuration exists
*/
void load_configuration( const fc::path& configuration_directory );

/**
* Specifies the network interface and port upon which incoming
* connections should be accepted.
* NOTE: a simple setter, does not open ports
*/
void listen_on_endpoint( const fc::ip::endpoint& ep, bool wait_if_not_available );

/**
* Specifies the port upon which incoming connections should be accepted.
* NOTE: a simple setter, does not open ports
* @param port the port to listen on
* @param wait_if_not_available if true and the port is not available, enter a
* sleep and retry loop to wait for it to become
* available. If false and the port is not available,
* just choose a random available port
*/
void listen_on_port(uint16_t port, bool wait_if_not_available);

/****
* Listen for connections
*/
virtual void listen_to_p2p_network();

/*****
* start message loops for different aspects of P2P network
*/
virtual void connect_to_p2p_network();

/**
Expand All @@ -211,32 +256,42 @@ namespace graphene { namespace net {
*/
void add_node( const fc::ip::endpoint& ep );

/****
* @brief Add an endpoint as a seed to the p2p network
*
* @param seed_string the url
* @param connect_immediately will start the connection process immediately
*/
void add_seed_node(const std::string& seed_string);

/*****
* @brief add a list of nodes to seed the p2p network
* @param seeds a vector of url strings
* @param connect_immediately attempt a connection immediately
*/
void add_seed_nodes(std::vector<std::string> seeds);

/**
* Attempt to connect to the specified endpoint immediately.
*/
virtual void connect_to_endpoint( const fc::ip::endpoint& ep );

/**
* Specifies the network interface and port upon which incoming
* connections should be accepted.
/***
* @brief Helper to convert a string to a collection of endpoints
*
* This converts a string (i.e. "bitshares.eu:665535" to a collection of endpoints.
* NOTE: Throws an exception if not in correct format or was unable to resolve URL.
*
* @param in the incoming string
* @returns a vector of endpoints
*/
void listen_on_endpoint( const fc::ip::endpoint& ep, bool wait_if_not_available );
static std::vector<fc::ip::endpoint> resolve_string_to_ip_endpoints(const std::string& in);

/**
* Call with true to enable listening for incoming connections
*/
void accept_incoming_connections(bool accept);

/**
* Specifies the port upon which incoming connections should be accepted.
* @param port the port to listen on
* @param wait_if_not_available if true and the port is not available, enter a
* sleep and retry loop to wait for it to become
* available. If false and the port is not available,
* just choose a random available port
*/
void listen_on_port(uint16_t port, bool wait_if_not_available);

/**
* Returns the endpoint the node is listening on. This is usually the same
* as the value previously passed in to listen_on_endpoint, unless we
Expand All @@ -249,7 +304,9 @@ namespace graphene { namespace net {
*/
std::vector<peer_status> get_connected_peers() const;

/** return the number of peers we're actively connected to */
/**
* @returns the number of peers we're actively connected to
*/
virtual uint32_t get_connection_count() const;

/**
Expand All @@ -263,18 +320,43 @@ namespace graphene { namespace net {
}

/**
* Node starts the process of fetching all items after item_id of the
* given item_type. During this process messages are not broadcast.
* Node starts the process of fetching all items after item_id of the
* given item_type. During this process messages are not broadcast.
* @param current_head_block fetch items after this point
* @param hard_fork_block_numbers
*/
virtual void sync_from(const item_id& current_head_block, const std::vector<uint32_t>& hard_fork_block_numbers);
virtual void sync_from(const item_id& current_head_block, const std::vector<uint32_t>& hard_fork_block_numbers);

bool is_connected() const;
/***
* @returns true if it is actively connected to any node
*/
bool is_connected() const;

/*****
* @param params the parameters to set
*/
void set_advanced_node_parameters(const fc::variant_object& params);

/*********
* @returns advanced node parameters
*/
fc::variant_object get_advanced_node_parameters();

/****
* @param transaction_id the transaction id
* @returns propagation data for that transaction
*/
message_propagation_data get_transaction_propagation_data(const graphene::protocol::transaction_id_type& transaction_id);
message_propagation_data get_block_propagation_data(const graphene::protocol::block_id_type& block_id);

/******
* @returns the node id (public key) for this node
*/
node_id_t get_node_id() const;

/*****
* @param allowed_peers peers that we can connect to
*/
void set_allowed_peers(const std::vector<node_id_t>& allowed_peers);

/**
Expand All @@ -292,7 +374,7 @@ namespace graphene { namespace net {

void disable_peer_advertising();
fc::variant_object get_call_statistics() const;
private:
protected:
std::unique_ptr<detail::node_impl, detail::node_impl_deleter> my;
};

Expand Down
5 changes: 3 additions & 2 deletions libraries/net/include/graphene/net/peer_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,9 @@ namespace graphene { namespace net
unsigned _send_message_queue_tasks_running; // temporary debugging
#endif
bool _currently_handling_message; // true while we're in the middle of handling a message from the remote system
private:
protected:
peer_connection(peer_connection_delegate* delegate);
private:
void destroy();
public:
static peer_connection_ptr make_shared(peer_connection_delegate* delegate); // use this instead of the constructor
Expand All @@ -287,7 +288,7 @@ namespace graphene { namespace net
void on_connection_closed(message_oriented_connection* originating_connection) override;

void send_queueable_message(std::unique_ptr<queued_message>&& message_to_send);
void send_message(const message& message_to_send, size_t message_send_time_field_offset = (size_t)-1);
virtual void send_message(const message& message_to_send, size_t message_send_time_field_offset = (size_t)-1);
void send_item(const item_id& item_to_send);
void close_connection();
void destroy_connection();
Expand Down
Loading