diff --git a/nano/core_test/message_deserializer.cpp b/nano/core_test/message_deserializer.cpp index 9363b405..359bfdd1 100644 --- a/nano/core_test/message_deserializer.cpp +++ b/nano/core_test/message_deserializer.cpp @@ -178,7 +178,7 @@ TEST (message_deserializer, exact_bulk_push) TEST (message_deserializer, exact_node_id_handshake) { - nano::node_id_handshake message{ nano::dev::network_params.network, boost::none, boost::none }; + nano::node_id_handshake message{ nano::dev::network_params.network, std::nullopt, std::nullopt }; message_deserializer_success_checker (message); } diff --git a/nano/core_test/network.cpp b/nano/core_test/network.cpp index 6f4b8e2d..e1c77708 100644 --- a/nano/core_test/network.cpp +++ b/nano/core_test/network.cpp @@ -706,7 +706,9 @@ TEST (tcp_listener, tcp_node_id_handshake) auto socket (std::make_shared (*system.nodes[0])); auto bootstrap_endpoint (system.nodes[0]->tcp_listener.endpoint ()); auto cookie (system.nodes[0]->network.syn_cookies.assign (nano::transport::map_tcp_to_endpoint (bootstrap_endpoint))); - nano::node_id_handshake node_id_handshake{ nano::dev::network_params.network, cookie, boost::none }; + ASSERT_TRUE (cookie); + nano::node_id_handshake::query_payload query{ *cookie }; + nano::node_id_handshake node_id_handshake{ nano::dev::network_params.network, query }; auto input (node_id_handshake.to_shared_const_buffer ()); std::atomic write_done (false); socket->async_connect (bootstrap_endpoint, [&input, socket, &write_done] (boost::system::error_code const & ec) { @@ -720,8 +722,8 @@ TEST (tcp_listener, tcp_node_id_handshake) ASSERT_TIMELY (5s, write_done); - boost::optional> response_zero (std::make_pair (nano::account{}, nano::signature (0))); - nano::node_id_handshake node_id_handshake_response{ nano::dev::network_params.network, boost::none, response_zero }; + nano::node_id_handshake::response_payload response_zero{ 0 }; + nano::node_id_handshake node_id_handshake_response{ nano::dev::network_params.network, std::nullopt, response_zero }; auto output (node_id_handshake_response.to_bytes ()); std::atomic done (false); socket->async_read (output, output->size (), [&output, &done] (boost::system::error_code const & ec, size_t size_a) { @@ -764,7 +766,9 @@ TEST (tcp_listener, tcp_listener_timeout_node_id_handshake) auto node0 (system.nodes[0]); auto socket (std::make_shared (*node0)); auto cookie (node0->network.syn_cookies.assign (nano::transport::map_tcp_to_endpoint (node0->tcp_listener.endpoint ()))); - nano::node_id_handshake node_id_handshake{ nano::dev::network_params.network, cookie, boost::none }; + ASSERT_TRUE (cookie); + nano::node_id_handshake::query_payload query{ *cookie }; + nano::node_id_handshake node_id_handshake{ nano::dev::network_params.network, query }; auto channel = std::make_shared (*node0, socket); socket->async_connect (node0->tcp_listener.endpoint (), [&node_id_handshake, channel] (boost::system::error_code const & ec) { ASSERT_FALSE (ec); diff --git a/nano/node/messages.cpp b/nano/node/messages.cpp index 08a2796d..4da57572 100644 --- a/nano/node/messages.cpp +++ b/nano/node/messages.cpp @@ -238,32 +238,6 @@ bool nano::message_header::frontier_req_is_only_confirmed_present () const return result; } -bool nano::message_header::node_id_handshake_is_query () const -{ - auto result (false); - if (type == nano::message_type::node_id_handshake) - { - if (extensions.test (node_id_handshake_query_flag)) - { - result = true; - } - } - return result; -} - -bool nano::message_header::node_id_handshake_is_response () const -{ - auto result (false); - if (type == nano::message_type::node_id_handshake) - { - if (extensions.test (node_id_handshake_response_flag)) - { - result = true; - } - } - return result; -} - std::size_t nano::message_header::payload_length_bytes () const { switch (type) @@ -1612,75 +1586,77 @@ bool nano::telemetry_data::validate_signature () const */ nano::node_id_handshake::node_id_handshake (bool & error_a, nano::stream & stream_a, nano::message_header const & header_a) : - message (header_a), - query (boost::none), - response (boost::none) + message (header_a) { error_a = deserialize (stream_a); } -nano::node_id_handshake::node_id_handshake (nano::network_constants const & constants, boost::optional query, boost::optional> response) : +nano::node_id_handshake::node_id_handshake (nano::network_constants const & constants, std::optional query_a, std::optional response_a) : message (constants, nano::message_type::node_id_handshake), - query (query), - response (response) + query{ query_a }, + response{ response_a } { if (query) { - header.flag_set (nano::message_header::node_id_handshake_query_flag); + header.flag_set (query_flag); } if (response) { - header.flag_set (nano::message_header::node_id_handshake_response_flag); + header.flag_set (response_flag); } } -void nano::node_id_handshake::serialize (nano::stream & stream_a) const +void nano::node_id_handshake::serialize (nano::stream & stream) const { - header.serialize (stream_a); + header.serialize (stream); if (query) { - write (stream_a, *query); + query->serialize (stream); } if (response) { - write (stream_a, response->first); - write (stream_a, response->second); + response->serialize (stream); } } -bool nano::node_id_handshake::deserialize (nano::stream & stream_a) +bool nano::node_id_handshake::deserialize (nano::stream & stream) { debug_assert (header.type == nano::message_type::node_id_handshake); - auto error (false); + bool error = false; try { - if (header.node_id_handshake_is_query ()) + if (is_query (header)) { - nano::uint256_union query_hash; - read (stream_a, query_hash); - query = query_hash; + query_payload pld{}; + pld.deserialize (stream); + query = pld; } - if (header.node_id_handshake_is_response ()) + if (is_response (header)) { - nano::account response_account; - read (stream_a, response_account); - nano::signature response_signature; - read (stream_a, response_signature); - response = std::make_pair (response_account, response_signature); + response_payload pld{}; + pld.deserialize (stream); + response = pld; } } catch (std::runtime_error const &) { error = true; } - return error; } -bool nano::node_id_handshake::operator== (nano::node_id_handshake const & other_a) const +bool nano::node_id_handshake::is_query (nano::message_header const & header) { - auto result (*query == *other_a.query && *response == *other_a.response); + debug_assert (header.type == nano::message_type::node_id_handshake); + bool result = header.extensions.test (query_flag); + return result; +} + +bool nano::node_id_handshake::is_response (nano::message_header const & header) +{ + debug_assert (header.type == nano::message_type::node_id_handshake); + bool result = header.extensions.test (response_flag); return result; } @@ -1694,16 +1670,16 @@ std::size_t nano::node_id_handshake::size () const return size (header); } -std::size_t nano::node_id_handshake::size (nano::message_header const & header_a) +std::size_t nano::node_id_handshake::size (nano::message_header const & header) { - std::size_t result (0); - if (header_a.node_id_handshake_is_query ()) + std::size_t result = 0; + if (is_query (header)) { - result = sizeof (nano::uint256_union); + result += query_payload::size; } - if (header_a.node_id_handshake_is_response ()) + if (is_response (header)) { - result += sizeof (nano::account) + sizeof (nano::signature); + result += response_payload::size; } return result; } @@ -1711,21 +1687,48 @@ std::size_t nano::node_id_handshake::size (nano::message_header const & header_a std::string nano::node_id_handshake::to_string () const { std::string s = header.to_string (); - - if (query.has_value ()) + if (query) { - s += "\ncookie=" + query->to_string (); + s += "\ncookie=" + query->cookie.to_string (); } - - if (response.has_value ()) + if (response) { - s += "\nresp_node_id=" + response->first.to_string (); - s += "\nresp_sig=" + response->second.to_string (); + s += "\nresp_node_id=" + response->node_id.to_string (); + s += "\nresp_sig=" + response->signature.to_string (); } - return s; } +/* + * node_id_handshake::query_payload + */ + +void nano::node_id_handshake::query_payload::serialize (nano::stream & stream) const +{ + nano::write (stream, cookie); +} + +void nano::node_id_handshake::query_payload::deserialize (nano::stream & stream) +{ + nano::read (stream, cookie); +} + +/* + * node_id_handshake::response_payload + */ + +void nano::node_id_handshake::response_payload::serialize (nano::stream & stream) const +{ + nano::write (stream, node_id); + nano::write (stream, signature); +} + +void nano::node_id_handshake::response_payload::deserialize (nano::stream & stream) +{ + nano::read (stream, node_id); + nano::read (stream, signature); +} + /* * asc_pull_req */ diff --git a/nano/node/messages.hpp b/nano/node/messages.hpp index 55222546..0d52baa0 100644 --- a/nano/node/messages.hpp +++ b/nano/node/messages.hpp @@ -81,10 +81,6 @@ public: bool bulk_pull_ascending () const; static uint8_t constexpr frontier_req_only_confirmed = 1; bool frontier_req_is_only_confirmed_present () const; - static uint8_t constexpr node_id_handshake_query_flag = 0; - static uint8_t constexpr node_id_handshake_response_flag = 1; - bool node_id_handshake_is_query () const; - bool node_id_handshake_is_response () const; /** Size of the payload in bytes. For some messages, the payload size is based on header flags. */ std::size_t payload_length_bytes () const; @@ -351,18 +347,54 @@ public: class node_id_handshake final : public message { +public: // Payload definitions + class query_payload + { + public: + void serialize (nano::stream &) const; + void deserialize (nano::stream &); + + static std::size_t constexpr size = sizeof (nano::uint256_union); + + public: + nano::uint256_union cookie; + }; + + class response_payload + { + public: + void serialize (nano::stream &) const; + void deserialize (nano::stream &); + + static std::size_t constexpr size = sizeof (nano::account) + sizeof (nano::signature); + + public: + nano::account node_id; + nano::signature signature; + }; + public: + explicit node_id_handshake (nano::network_constants const &, std::optional query = std::nullopt, std::optional response = std::nullopt); node_id_handshake (bool &, nano::stream &, nano::message_header const &); - node_id_handshake (nano::network_constants const & constants, boost::optional, boost::optional>); + void serialize (nano::stream &) const override; bool deserialize (nano::stream &); + void visit (nano::message_visitor &) const override; - bool operator== (nano::node_id_handshake const &) const; - boost::optional query; - boost::optional> response; std::size_t size () const; static std::size_t size (nano::message_header const &); std::string to_string () const; + +public: // Header + static uint8_t constexpr query_flag = 0; + static uint8_t constexpr response_flag = 1; + + static bool is_query (nano::message_header const &); + static bool is_response (nano::message_header const &); + +public: // Payload + std::optional query; + std::optional response; }; /** diff --git a/nano/node/network.cpp b/nano/node/network.cpp index bd1d73f3..f67ed7f5 100644 --- a/nano/node/network.cpp +++ b/nano/node/network.cpp @@ -113,19 +113,30 @@ void nano::network::send_keepalive_self (std::shared_ptrsend (message); } -void nano::network::send_node_id_handshake (std::shared_ptr const & channel_a, boost::optional const & query, boost::optional const & respond_to) +void nano::network::send_node_id_handshake (std::shared_ptr const & channel_a, std::optional const & cookie, std::optional const & respond_to) { - boost::optional> response (boost::none); + std::optional response; if (respond_to) { - response = std::make_pair (node.node_id.pub, nano::sign_message (node.node_id.prv, node.node_id.pub, *respond_to)); - debug_assert (!nano::validate_message (response->first, *respond_to, response->second)); + nano::node_id_handshake::response_payload pld{ node.node_id.pub, nano::sign_message (node.node_id.prv, node.node_id.pub, *respond_to) }; + debug_assert (!nano::validate_message (pld.node_id, *respond_to, pld.signature)); + response = pld; } + + std::optional query; + if (cookie) + { + nano::node_id_handshake::query_payload pld{ *cookie }; + query = pld; + } + nano::node_id_handshake message{ node.network_params.network, query, response }; + if (node.config.logging.network_node_id_handshake_logging ()) { - node.logger.try_log (boost::str (boost::format ("Node ID handshake sent with node ID %1% to %2%: query %3%, respond_to %4% (signature %5%)") % node.node_id.pub.to_node_id () % channel_a->get_endpoint () % (query ? query->to_string () : std::string ("[none]")) % (respond_to ? respond_to->to_string () : std::string ("[none]")) % (response ? response->second.to_string () : std::string ("[none]")))); + node.logger.try_log (boost::str (boost::format ("Node ID handshake sent with node ID %1% to %2%: query %3%, respond_to %4% (signature %5%)") % node.node_id.pub.to_node_id () % channel_a->get_endpoint () % (query ? query->cookie.to_string () : std::string ("[none]")) % (respond_to ? respond_to->to_string () : std::string ("[none]")) % (response ? response->signature.to_string () : std::string ("[none]")))); } + channel_a->send (message); } diff --git a/nano/node/network.hpp b/nano/node/network.hpp index 1e3ae65b..cb103593 100644 --- a/nano/node/network.hpp +++ b/nano/node/network.hpp @@ -35,8 +35,8 @@ private: friend class network_tcp_message_manager_Test; }; /** - * Node ID cookies for node ID handshakes -*/ + * Node ID cookies for node ID handshakes + */ class syn_cookies final { public: @@ -87,7 +87,7 @@ public: void merge_peer (nano::endpoint const &); void send_keepalive (std::shared_ptr const &); void send_keepalive_self (std::shared_ptr const &); - void send_node_id_handshake (std::shared_ptr const &, boost::optional const & query, boost::optional const & respond_to); + void send_node_id_handshake (std::shared_ptr const &, std::optional const & cookie, std::optional const & respond_to); void send_confirm_req (std::shared_ptr const & channel_a, std::pair const & hash_root_a); void broadcast_confirm_req (std::shared_ptr const &); void broadcast_confirm_req_base (std::shared_ptr const &, std::shared_ptr>> const &, unsigned, bool = false); diff --git a/nano/node/transport/tcp.cpp b/nano/node/transport/tcp.cpp index 4deb770e..2adc5fa7 100644 --- a/nano/node/transport/tcp.cpp +++ b/nano/node/transport/tcp.cpp @@ -544,12 +544,21 @@ void nano::transport::tcp_channels::start_tcp (nano::endpoint const & endpoint_a if (!ec && channel) { // TCP node ID handshake - auto cookie (node_l->network.syn_cookies.assign (endpoint_a)); - nano::node_id_handshake message (node_l->network_params.network, cookie, boost::none); + + std::optional query; + if (auto cookie = node_l->network.syn_cookies.assign (endpoint_a); cookie) + { + nano::node_id_handshake::query_payload pld{ *cookie }; + query = pld; + } + + nano::node_id_handshake message{ node_l->network_params.network, query }; + if (node_l->config.logging.network_node_id_handshake_logging ()) { - node_l->logger.try_log (boost::str (boost::format ("Node ID handshake request sent with node ID %1% to %2%: query %3%") % node_l->node_id.pub.to_node_id () % endpoint_a % (cookie.has_value () ? cookie->to_string () : "not set"))); + node_l->logger.try_log (boost::str (boost::format ("Node ID handshake request sent with node ID %1% to %2%: query %3%") % node_l->node_id.pub.to_node_id () % endpoint_a % (query ? query->cookie.to_string () : "not set"))); } + channel->set_endpoint (); std::shared_ptr> receive_buffer (std::make_shared> ()); receive_buffer->resize (256); @@ -670,12 +679,17 @@ void nano::transport::tcp_channels::start_tcp_receive_node_id (std::shared_ptrset_network_version (header.version_using); - auto node_id (message.response->first); - bool process (!node_l->network.syn_cookies.validate (endpoint_a, node_id, message.response->second) && node_id != node_l->node_id.pub); + + debug_assert (message.query); + debug_assert (message.response); + + auto node_id = message.response->node_id; + bool process = (!node_l->network.syn_cookies.validate (endpoint_a, node_id, message.response->signature) && node_id != node_l->node_id.pub); if (!process) { return; } + /* If node ID is known, don't establish new connection Exception: temporary channels from tcp_server */ auto existing_channel (node_l->network.tcp_channels.find_node_id (node_id)); @@ -683,15 +697,19 @@ void nano::transport::tcp_channels::start_tcp_receive_node_id (std::shared_ptrset_node_id (node_id); channel_a->set_last_packet_received (std::chrono::steady_clock::now ()); - boost::optional> response (std::make_pair (node_l->node_id.pub, nano::sign_message (node_l->node_id.prv, node_l->node_id.pub, *message.query))); - nano::node_id_handshake response_message (node_l->network_params.network, boost::none, response); + + nano::node_id_handshake::response_payload response{ node_l->node_id.pub, nano::sign_message (node_l->node_id.prv, node_l->node_id.pub, message.query->cookie) }; + nano::node_id_handshake handshake_response (node_l->network_params.network, std::nullopt, response); + if (node_l->config.logging.network_node_id_handshake_logging ()) { - node_l->logger.try_log (boost::str (boost::format ("Node ID handshake response sent with node ID %1% to %2%: query %3%") % node_l->node_id.pub.to_node_id () % endpoint_a % (*message.query).to_string ())); + node_l->logger.try_log (boost::str (boost::format ("Node ID handshake response sent with node ID %1% to %2%: query %3%") % node_l->node_id.pub.to_node_id () % endpoint_a % message.query->cookie.to_string ())); } - channel_a->send (response_message, [node_w, channel_a, endpoint_a, cleanup_node_id_handshake_socket] (boost::system::error_code const & ec, std::size_t size_a) { + + channel_a->send (handshake_response, [node_w, channel_a, endpoint_a, cleanup_node_id_handshake_socket] (boost::system::error_code const & ec, std::size_t size_a) { auto node_l = node_w.lock (); if (!node_l) { diff --git a/nano/node/transport/tcp_server.cpp b/nano/node/transport/tcp_server.cpp index 974f39c7..89fe25a3 100644 --- a/nano/node/transport/tcp_server.cpp +++ b/nano/node/transport/tcp_server.cpp @@ -340,10 +340,10 @@ void nano::transport::tcp_server::handshake_message_visitor::node_id_handshake ( { server->send_handshake_response (*message.query); } - else if (message.response) + if (message.response) { - nano::account const & node_id (message.response->first); - if (!server->node->network.syn_cookies.validate (nano::transport::map_tcp_to_endpoint (server->remote_endpoint), node_id, message.response->second) && node_id != server->node->node_id.pub) + nano::account const & node_id = message.response->node_id; + if (!server->node->network.syn_cookies.validate (nano::transport::map_tcp_to_endpoint (server->remote_endpoint), node_id, message.response->signature) && node_id != server->node->node_id.pub) { server->to_realtime_connection (node_id); } @@ -357,15 +357,22 @@ void nano::transport::tcp_server::handshake_message_visitor::node_id_handshake ( process = true; } -void nano::transport::tcp_server::send_handshake_response (nano::uint256_union query) +void nano::transport::tcp_server::send_handshake_response (nano::node_id_handshake::query_payload const & query) { - boost::optional> response (std::make_pair (node->node_id.pub, nano::sign_message (node->node_id.prv, node->node_id.pub, query))); - debug_assert (!nano::validate_message (response->first, query, response->second)); + nano::node_id_handshake::response_payload response{ node->node_id.pub, nano::sign_message (node->node_id.prv, node->node_id.pub, query.cookie) }; + debug_assert (!nano::validate_message (response.node_id, query.cookie, response.signature)); - auto cookie (node->network.syn_cookies.assign (nano::transport::map_tcp_to_endpoint (remote_endpoint))); - nano::node_id_handshake response_message (node->network_params.network, cookie, response); + std::optional own_query; + if (auto own_cookie = node->network.syn_cookies.assign (nano::transport::map_tcp_to_endpoint (remote_endpoint)); own_cookie) + { + nano::node_id_handshake::query_payload pld{ *own_cookie }; + own_query = pld; + } - auto shared_const_buffer = response_message.to_shared_const_buffer (); + nano::node_id_handshake handshake_response{ node->network_params.network, own_query, response }; + + // TODO: Use channel + auto shared_const_buffer = handshake_response.to_shared_const_buffer (); socket->async_write (shared_const_buffer, [this_l = shared_from_this ()] (boost::system::error_code const & ec, std::size_t size_a) { if (ec) { diff --git a/nano/node/transport/tcp_server.hpp b/nano/node/transport/tcp_server.hpp index 10f8ccec..f7cebd7e 100644 --- a/nano/node/transport/tcp_server.hpp +++ b/nano/node/transport/tcp_server.hpp @@ -52,8 +52,6 @@ public: void timeout (); - void send_handshake_response (nano::uint256_union query); - std::shared_ptr const socket; std::shared_ptr const node; nano::mutex mutex; @@ -65,6 +63,8 @@ public: std::chrono::steady_clock::time_point last_telemetry_req{}; private: + void send_handshake_response (nano::node_id_handshake::query_payload const & query); + void receive_message (); void received_message (std::unique_ptr message); bool process_message (std::unique_ptr message);