aboutsummaryrefslogtreecommitdiff
path: root/src/net.h
diff options
context:
space:
mode:
authorPieter Wuille <pieter@wuille.net>2023-08-29 22:37:18 -0400
committerPieter Wuille <pieter@wuille.net>2023-09-07 09:01:01 -0400
commit8da8642062fa2c7aa2f49995b832c3d0897e37ed (patch)
tree60052bc38273e2403a88d251192b1dde0f8214d0 /src/net.h
parent13a7f01557272db652b3f333af3f06af6897253f (diff)
net: make V2Transport auto-detect incoming V1 and fall back to it
Diffstat (limited to 'src/net.h')
-rw-r--r--src/net.h67
1 files changed, 54 insertions, 13 deletions
diff --git a/src/net.h b/src/net.h
index 27d141bc6e..9194a677b1 100644
--- a/src/net.h
+++ b/src/net.h
@@ -444,25 +444,40 @@ private:
* an empty version packet contents is interpreted as no extensions supported. */
static constexpr std::array<std::byte, 0> VERSION_CONTENTS = {};
+ /** The length of the V1 prefix to match bytes initially received by responders with to
+ * determine if their peer is speaking V1 or V2. */
+ static constexpr size_t V1_PREFIX_LEN = 12;
+
// The sender side and receiver side of V2Transport are state machines that are transitioned
// through, based on what has been received. The receive state corresponds to the contents of,
// and bytes received to, the receive buffer. The send state controls what can be appended to
- // the send buffer.
+ // the send buffer and what can be sent from it.
/** State type that defines the current contents of the receive buffer and/or how the next
* received bytes added to it will be interpreted.
*
* Diagram:
*
- * start /---------\
- * | | |
- * v v |
- * KEY -> GARB_GARBTERM -> GARBAUTH -> VERSION -> APP -> APP_READY
+ * start(responder)
+ * |
+ * | start(initiator) /---------\
+ * | | | |
+ * v v v |
+ * KEY_MAYBE_V1 -> KEY -> GARB_GARBTERM -> GARBAUTH -> VERSION -> APP -> APP_READY
+ * |
+ * \-------> V1
*/
enum class RecvState : uint8_t {
+ /** (Responder only) either v2 public key or v1 header.
+ *
+ * This is the initial state for responders, before data has been received to distinguish
+ * v1 from v2 connections. When that happens, the state becomes either KEY (for v2) or V1
+ * (for v1). */
+ KEY_MAYBE_V1,
+
/** Public key.
*
- * This is the initial state, during which the other side's public key is
+ * This is the initial state for initiators, during which the other side's public key is
* received. When that information arrives, the ciphers get initialized and the state
* becomes GARB_GARBTERM. */
KEY,
@@ -502,23 +517,40 @@ private:
* Nothing can be received in this state. When the message is retrieved by GetMessage,
* the state becomes APP again. */
APP_READY,
+
+ /** Nothing (this transport is using v1 fallback).
+ *
+ * All receive operations are redirected to m_v1_fallback. */
+ V1,
};
/** State type that controls the sender side.
*
* Diagram:
*
- * start
- * |
- * v
- * AWAITING_KEY -> READY
+ * start(responder)
+ * |
+ * | start(initiator)
+ * | |
+ * v v
+ * MAYBE_V1 -> AWAITING_KEY -> READY
+ * |
+ * \-----> V1
*/
enum class SendState : uint8_t {
+ /** (Responder only) Not sending until v1 or v2 is detected.
+ *
+ * This is the initial state for responders. The send buffer contains the public key to
+ * send, but nothing is sent in this state yet. When the receiver determines whether this
+ * is a V1 or V2 connection, the sender state becomes AWAITING_KEY (for v2) or V1 (for v1).
+ */
+ MAYBE_V1,
+
/** Waiting for the other side's public key.
*
- * This is the initial state. The public key is sent out. When the receiver receives the
- * other side's public key and transitions to GARB_GARBTERM, the sender state becomes
- * READY. */
+ * This is the initial state for initiators. The public key is sent out. When the receiver
+ * receives the other side's public key and transitions to GARB_GARBTERM, the sender state
+ * becomes READY. */
AWAITING_KEY,
/** Normal sending state.
@@ -528,6 +560,11 @@ private:
* appended to the send buffer (in addition to the key which may still be there). In this
* state a message can be provided if the send buffer is empty. */
READY,
+
+ /** This transport is using v1 fallback.
+ *
+ * All send operations are redirected to m_v1_fallback. */
+ V1,
};
/** Cipher state. */
@@ -536,6 +573,8 @@ private:
const bool m_initiating;
/** NodeId (for debug logging). */
const NodeId m_nodeid;
+ /** Encapsulate a V1Transport to fall back to. */
+ V1Transport m_v1_fallback;
/** Lock for receiver-side fields. */
mutable Mutex m_recv_mutex ACQUIRED_BEFORE(m_send_mutex);
@@ -575,6 +614,8 @@ private:
static std::optional<std::string> GetMessageType(Span<const uint8_t>& contents) noexcept;
/** Determine how many received bytes can be processed in one go (not allowed in V1 state). */
size_t GetMaxBytesToProcess() noexcept EXCLUSIVE_LOCKS_REQUIRED(m_recv_mutex);
+ /** Process bytes in m_recv_buffer, while in KEY_MAYBE_V1 state. */
+ void ProcessReceivedMaybeV1Bytes() noexcept EXCLUSIVE_LOCKS_REQUIRED(m_recv_mutex, !m_send_mutex);
/** Process bytes in m_recv_buffer, while in KEY state. */
void ProcessReceivedKeyBytes() noexcept EXCLUSIVE_LOCKS_REQUIRED(m_recv_mutex, !m_send_mutex);
/** Process bytes in m_recv_buffer, while in GARB_GARBTERM state. */