16
16
#include < compat/compat.h>
17
17
#include < consensus/consensus.h>
18
18
#include < crypto/sha256.h>
19
- #include < node/eviction.h>
20
19
#include < fs.h>
21
20
#include < i2p.h>
22
21
#include < net_permissions.h>
23
22
#include < netaddress.h>
24
23
#include < netbase.h>
24
+ #include < node/eviction.h>
25
25
#include < node/interface_ui.h>
26
26
#include < protocol.h>
27
27
#include < random.h>
28
28
#include < scheduler.h>
29
29
#include < util/sock.h>
30
30
#include < util/strencodings.h>
31
+ #include < util/string.h>
31
32
#include < util/syscall_sandbox.h>
32
33
#include < util/system.h>
33
34
#include < util/thread.h>
@@ -64,6 +65,8 @@ static_assert (MAX_BLOCK_RELAY_ONLY_ANCHORS <= static_cast<size_t>(MAX_BLOCK_REL
64
65
/* * Anchor IP address database file name */
65
66
const char * const ANCHORS_DATABASE_FILENAME = " anchors.dat" ;
66
67
68
+ static constexpr uint64_t V2_MAX_CONTENTS_LENGTH = 0x01000000 - 1 ; // 2^24 - 1
69
+
67
70
// How often to dump addresses to peers.dat
68
71
static constexpr std::chrono::minutes DUMP_PEERS_INTERVAL{15 };
69
72
@@ -109,6 +112,8 @@ const std::string NET_MESSAGE_TYPE_OTHER = "*other*";
109
112
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL ; // SHA256("netgroup")[0:8]
110
113
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL ; // SHA256("localhostnonce")[0:8]
111
114
static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL ; // SHA256("addrcache")[0:8]
115
+
116
+ static constexpr uint8_t V2_MAX_MSG_TYPE_LEN = 12 ; // maximum length for V2 (BIP324) string message types
112
117
//
113
118
// Global state variables
114
119
//
@@ -668,7 +673,14 @@ bool CNode::ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete)
668
673
if (m_deserializer->Complete ()) {
669
674
// decompose a transport agnostic CNetMessage from the deserializer
670
675
bool reject_message{false };
671
- CNetMessage msg = m_deserializer->GetMessage (time , reject_message);
676
+ bool disconnect{false };
677
+ CNetMessage msg = m_deserializer->GetMessage (time , reject_message, disconnect);
678
+
679
+ if (disconnect) {
680
+ // v2 p2p incorrect MAC tag. Disconnect from peer.
681
+ return false ;
682
+ }
683
+
672
684
if (reject_message) {
673
685
// Message deserialization failed. Drop the message but don't disconnect the peer.
674
686
// store the size of the corrupt message
@@ -760,10 +772,12 @@ const uint256& V1TransportDeserializer::GetMessageHash() const
760
772
return data_hash;
761
773
}
762
774
763
- CNetMessage V1TransportDeserializer::GetMessage (const std::chrono::microseconds time, bool & reject_message)
775
+ CNetMessage V1TransportDeserializer::GetMessage (const std::chrono::microseconds time, bool & reject_message, bool & disconnect )
764
776
{
765
777
// Initialize out parameter
766
778
reject_message = false ;
779
+ disconnect = false ;
780
+
767
781
// decompose a single CNetMessage from the TransportDeserializer
768
782
CNetMessage msg (std::move (vRecv));
769
783
@@ -785,6 +799,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds
785
799
HexStr (Span{hash}.first (CMessageHeader::CHECKSUM_SIZE)),
786
800
HexStr (hdr.pchChecksum ),
787
801
m_node_id);
802
+ // TODO: Should we disconnect the v1 peer in this case?
788
803
reject_message = true ;
789
804
} else if (!hdr.IsCommandValid ()) {
790
805
LogPrint (BCLog::NET, " Header error: Invalid message type (%s, %u bytes), peer=%d\n " ,
@@ -797,7 +812,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds
797
812
return msg;
798
813
}
799
814
800
- void V1TransportSerializer::prepareForTransport (CSerializedNetMsg& msg, std::vector<unsigned char >& header) const
815
+ bool V1TransportSerializer::prepareForTransport (CSerializedNetMsg& msg, std::vector<unsigned char >& header) const
801
816
{
802
817
// create dbl-sha256 checksum
803
818
uint256 hash = Hash (msg.data );
@@ -809,6 +824,174 @@ void V1TransportSerializer::prepareForTransport(CSerializedNetMsg& msg, std::vec
809
824
// serialize header
810
825
header.reserve (CMessageHeader::HEADER_SIZE);
811
826
CVectorWriter{SER_NETWORK, INIT_PROTO_VERSION, header, 0 , hdr};
827
+ return true ;
828
+ }
829
+
830
+ int V2TransportDeserializer::readHeader (Span<const uint8_t > pkt_bytes)
831
+ {
832
+ // copy data to temporary parsing buffer
833
+ const size_t remaining = BIP324_LENGTH_FIELD_LEN - m_hdr_pos;
834
+ const size_t copy_bytes = std::min<unsigned int >(remaining, pkt_bytes.size ());
835
+
836
+ memcpy (&vRecv[m_hdr_pos], pkt_bytes.data (), copy_bytes);
837
+ m_hdr_pos += copy_bytes;
838
+
839
+ // if we don't have the encrypted length yet, exit
840
+ if (m_hdr_pos < BIP324_LENGTH_FIELD_LEN) {
841
+ return copy_bytes;
842
+ }
843
+
844
+ // we have the 3 bytes encrypted packet length at this point
845
+ std::array<std::byte, BIP324_LENGTH_FIELD_LEN> encrypted_pkt_len;
846
+ memcpy (encrypted_pkt_len.data (), vRecv.data (), BIP324_LENGTH_FIELD_LEN);
847
+
848
+ // the encrypted packet data = bip324 header + contents (message type + message payload)
849
+ m_contents_size = m_cipher_suite->DecryptLength (encrypted_pkt_len);
850
+
851
+ // m_contents_size is the size of the p2p message
852
+ if (m_contents_size > V2_MAX_CONTENTS_LENGTH) {
853
+ return -1 ;
854
+ }
855
+
856
+ // switch state to reading message data
857
+ m_in_data = true ;
858
+
859
+ return copy_bytes;
860
+ }
861
+
862
+ int V2TransportDeserializer::readData (Span<const uint8_t > pkt_bytes)
863
+ {
864
+ // Read the BIP324 encrypted packet data.
865
+ const size_t remaining = BIP324_HEADER_LEN + m_contents_size + RFC8439_EXPANSION - m_data_pos;
866
+ const size_t copy_bytes = std::min<unsigned int >(remaining, pkt_bytes.size ());
867
+
868
+ // extend buffer, respect previous copied encrypted length
869
+ if (vRecv.size () < BIP324_LENGTH_FIELD_LEN + m_data_pos + copy_bytes) {
870
+ // Allocate up to 256 KiB ahead, but never more than the total message size.
871
+ vRecv.resize (BIP324_LENGTH_FIELD_LEN + std::min (BIP324_HEADER_LEN + m_contents_size, m_data_pos + copy_bytes + 256 * 1024 ) + RFC8439_EXPANSION, std::byte{0x00 });
872
+ }
873
+
874
+ memcpy (&vRecv[BIP324_LENGTH_FIELD_LEN + m_data_pos], pkt_bytes.data (), copy_bytes);
875
+ m_data_pos += copy_bytes;
876
+
877
+ return copy_bytes;
878
+ }
879
+
880
+ CNetMessage V2TransportDeserializer::GetMessage (const std::chrono::microseconds time, bool & reject_message, bool & disconnect)
881
+ {
882
+ const size_t min_contents_size = 1 ; // BIP324 1-byte message type id is the minimum contents
883
+
884
+ // Initialize out parameters
885
+ reject_message = (vRecv.size () < V2_MIN_PACKET_LENGTH + min_contents_size);
886
+ disconnect = false ;
887
+
888
+ // In v2, vRecv contains:
889
+ // 3 bytes of encrypted packet length
890
+ // 1-byte encrypted bip324 header
891
+ // variable length encrypted contents(message type and message payload) and
892
+ // mac tag
893
+ assert (Complete ());
894
+
895
+ std::string msg_type;
896
+
897
+ BIP324HeaderFlags flags;
898
+ size_t msg_type_size = 1 ; // at least one byte needed for message type
899
+ if (m_cipher_suite->Crypt ({},
900
+ Span{reinterpret_cast <const std::byte*>(vRecv.data () + BIP324_LENGTH_FIELD_LEN), BIP324_HEADER_LEN + m_contents_size + RFC8439_EXPANSION},
901
+ Span{reinterpret_cast <std::byte*>(vRecv.data ()), m_contents_size}, flags, false )) {
902
+ // MAC check was successful
903
+ vRecv.resize (m_contents_size);
904
+ reject_message = reject_message || (BIP324HeaderFlags (BIP324_IGNORE & flags) != BIP324_NONE);
905
+
906
+ if (!reject_message) {
907
+ uint8_t size_or_shortid = 0 ;
908
+ try {
909
+ vRecv >> size_or_shortid;
910
+ } catch (const std::ios_base::failure&) {
911
+ LogPrint (BCLog::NET, " Invalid message type, peer=%d\n " , m_node_id);
912
+ reject_message = true ;
913
+ }
914
+
915
+ if (size_or_shortid > 0 && size_or_shortid <= V2_MAX_MSG_TYPE_LEN && vRecv.size () >= size_or_shortid) {
916
+ // first byte is a number between 1 and 12. Must be a string command.
917
+ // use direct read since we already read the varlen size
918
+ msg_type.resize (size_or_shortid);
919
+ vRecv.read (MakeWritableByteSpan (msg_type));
920
+ msg_type_size += size_or_shortid;
921
+ } else {
922
+ auto mtype = GetMessageTypeFromShortID (size_or_shortid);
923
+ if (mtype.has_value ()) {
924
+ msg_type = mtype.value ();
925
+ } else {
926
+ // unknown-short-id results in a valid but unknown message (will be skipped)
927
+ msg_type = " unknown-" + ToString (size_or_shortid);
928
+ }
929
+ }
930
+ }
931
+ } else {
932
+ // Invalid mac tag
933
+ LogPrint (BCLog::NET, " Invalid v2 mac tag, peer=%d\n " , m_node_id);
934
+ disconnect = true ;
935
+ reject_message = true ;
936
+ }
937
+
938
+ // we'll always return a CNetMessage (even if decryption fails)
939
+ // decompose a single CNetMessage from the TransportDeserializer
940
+ CNetMessage msg (std::move (vRecv));
941
+ msg.m_type = msg_type;
942
+ msg.m_time = time ;
943
+
944
+ if (!reject_message) {
945
+ msg.m_message_size = m_contents_size - msg_type_size;
946
+ msg.m_raw_message_size = V2_MIN_PACKET_LENGTH + m_contents_size; // raw wire size
947
+ }
948
+
949
+ Reset ();
950
+ return msg;
951
+ }
952
+
953
+ bool V2TransportSerializer::prepareForTransport (CSerializedNetMsg& msg, std::vector<unsigned char >& header) const
954
+ {
955
+ size_t serialized_msg_type_size = 1 ; // short-IDs are 1 byte
956
+ std::optional<uint8_t > short_msg_type = GetShortIDFromMessageType (msg.m_type );
957
+ if (!short_msg_type) {
958
+ // message type without an assigned short-ID
959
+ assert (msg.m_type .size () <= V2_MAX_MSG_TYPE_LEN);
960
+ // encode as varstr, max 12 chars
961
+ serialized_msg_type_size = ::GetSerializeSize (msg.m_type , PROTOCOL_VERSION);
962
+ }
963
+
964
+ std::vector<unsigned char > msg_type_bytes (serialized_msg_type_size);
965
+ // append the short-ID or the varstr of the msg type
966
+ CVectorWriter vector_writer (SER_NETWORK, INIT_PROTO_VERSION, msg_type_bytes, 0 );
967
+ if (short_msg_type) {
968
+ // append the single byte short ID
969
+ vector_writer << short_msg_type.value ();
970
+ } else {
971
+ // or the ASCII command string
972
+ vector_writer << msg.m_type ;
973
+ }
974
+
975
+ // insert message type directly into the CSerializedNetMsg data buffer (insert at begin)
976
+ // TODO: if we refactor the BIP324CipherSuite::Crypt() function to allow separate buffers for
977
+ // the message type and payload we could avoid a insert and thus a potential reallocation
978
+ msg.data .insert (msg.data .begin (), msg_type_bytes.begin (), msg_type_bytes.end ());
979
+
980
+ auto contents_size = msg.data .size ();
981
+ auto encrypted_pkt_size = V2_MIN_PACKET_LENGTH + contents_size;
982
+ // resize the message buffer to make space for the MAC tag
983
+ msg.data .resize (encrypted_pkt_size, 0 );
984
+
985
+ BIP324HeaderFlags flags{BIP324_NONE};
986
+ // encrypt the payload, this should always succeed (controlled buffers, don't check the MAC during encrypting)
987
+ auto success = m_cipher_suite->Crypt ({},
988
+ Span{reinterpret_cast <const std::byte*>(msg.data .data ()), contents_size},
989
+ Span{reinterpret_cast <std::byte*>(msg.data .data ()), encrypted_pkt_size},
990
+ flags, true );
991
+ if (!success) {
992
+ LogPrint (BCLog::NET, " error in v2 p2p encryption for message type: %s\n " , msg.m_type );
993
+ }
994
+ return success;
812
995
}
813
996
814
997
size_t CConnman::SocketSendData (CNode& node) const
@@ -2790,7 +2973,10 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
2790
2973
2791
2974
// make sure we use the appropriate network transport format
2792
2975
std::vector<unsigned char > serializedHeader;
2793
- pnode->m_serializer ->prepareForTransport (msg, serializedHeader);
2976
+ if (!pnode->m_serializer ->prepareForTransport (msg, serializedHeader)) {
2977
+ return ;
2978
+ }
2979
+
2794
2980
size_t nTotalSize = nMessageSize + serializedHeader.size ();
2795
2981
2796
2982
size_t nBytesSent = 0 ;
0 commit comments