Skip to content

Commit cab8d85

Browse files
committed
P2P: always send/expect network magic bytes
1 parent 886122e commit cab8d85

File tree

5 files changed

+105
-31
lines changed

5 files changed

+105
-31
lines changed

lib/net/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ const fn seed_node_addrs(network: Network) -> &'static [SocketAddr] {
186186
pub struct Net {
187187
pub server: Endpoint,
188188
archive: Archive,
189+
network: Network,
189190
state: State,
190191
active_peers: Arc<RwLock<HashMap<SocketAddr, PeerConnectionHandle>>>,
191192
// None indicates that the stream has ended
@@ -280,6 +281,7 @@ impl Net {
280281
let connection_ctxt = PeerConnectionCtxt {
281282
env,
282283
archive: self.archive.clone(),
284+
network: self.network,
283285
state: self.state.clone(),
284286
};
285287

@@ -358,6 +360,7 @@ impl Net {
358360
let net = Net {
359361
server,
360362
archive,
363+
network,
361364
state,
362365
active_peers,
363366
peer_info_tx,
@@ -430,7 +433,7 @@ impl Net {
430433
remote_address,
431434
}
432435
})?;
433-
Connection::from(raw_conn)
436+
Connection::new(raw_conn, self.network)
434437
}
435438
None => {
436439
tracing::debug!("server endpoint closed");
@@ -462,6 +465,7 @@ impl Net {
462465
let connection_ctxt = PeerConnectionCtxt {
463466
env,
464467
archive: self.archive.clone(),
468+
network: self.network,
465469
state: self.state.clone(),
466470
};
467471
let (connection_handle, info_rx) =

lib/net/peer/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,14 @@ pub(in crate::net::peer) mod connection {
7171

7272
#[derive(Debug, Error)]
7373
pub enum Receive {
74+
#[error("received incorrect magic: {}", hex::encode(.0))]
75+
BadMagic(crate::net::peer::message::MagicBytes),
7476
#[error("bincode error")]
7577
Bincode(#[from] bincode::Error),
7678
#[error("connection error")]
7779
Connection(#[from] quinn::ConnectionError),
80+
#[error("failed to read magic bytes")]
81+
ReadMagic(#[source] quinn::ReadExactError),
7882
#[error("read to end error")]
7983
ReadToEnd(#[from] quinn::ReadToEndError),
8084
}

lib/net/peer/message.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,29 @@ use serde::{Deserialize, Serialize};
77

88
use crate::{
99
net::peer::{PeerState, PeerStateId},
10-
types::{AuthorizedTransaction, BlockHash, Body, Header, Tip, Txid},
10+
types::{
11+
AuthorizedTransaction, BlockHash, Body, Header, Network, Tip, Txid,
12+
},
1113
};
1214

15+
pub const MAGIC_BYTES_LEN: usize = 4;
16+
17+
pub type MagicBytes = [u8; MAGIC_BYTES_LEN];
18+
19+
pub const fn magic_bytes(network: Network) -> MagicBytes {
20+
// First 4 bytes are the US-TTY (LSB Right) Baudot–Murray code for "THNDR".
21+
// Rightmost bits of the 4th byte is the network identifier.
22+
let b0 = 0b1000_0101;
23+
let b1 = 0b0001_1000;
24+
let b2 = 0b1001_0101;
25+
let mut b3 = 0b0000_0000;
26+
match network {
27+
Network::Regtest => (),
28+
Network::Signet => b3 |= 0b0000_0001,
29+
}
30+
[b0, b1, b2, b3]
31+
}
32+
1333
#[derive(BorshSerialize, Clone, Debug, Deserialize, Serialize)]
1434
pub struct Heartbeat(pub PeerState);
1535

lib/net/peer/mod.rs

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use tokio::{spawn, task::JoinHandle, time::Duration};
1818
use crate::{
1919
archive::Archive,
2020
state::State,
21-
types::{AuthorizedTransaction, Hash, Tip, Version, hash, schema},
21+
types::{AuthorizedTransaction, Hash, Network, Tip, Version, hash, schema},
2222
};
2323

2424
mod channel_pool;
@@ -140,6 +140,7 @@ where
140140
#[derive(Clone)]
141141
pub struct Connection {
142142
pub(in crate::net) inner: quinn::Connection,
143+
pub network: Network,
143144
}
144145

145146
impl Connection {
@@ -154,14 +155,25 @@ impl Connection {
154155
self.inner.remote_address()
155156
}
156157

157-
pub async fn new(
158+
pub fn new(connection: quinn::Connection, network: Network) -> Self {
159+
Self {
160+
inner: connection,
161+
network,
162+
}
163+
}
164+
165+
pub async fn from_connecting(
158166
connecting: quinn::Connecting,
167+
network: Network,
159168
) -> Result<Self, quinn::ConnectionError> {
160169
let addr = connecting.remote_address();
161170
tracing::trace!(%addr, "connecting to peer");
162171
let connection = connecting.await?;
163172
tracing::info!(%addr, "connected successfully to peer");
164-
Ok(Self { inner: connection })
173+
Ok(Self {
174+
inner: connection,
175+
network,
176+
})
165177
}
166178

167179
async fn receive_request(
@@ -170,6 +182,15 @@ impl Connection {
170182
{
171183
let (tx, mut rx) = self.inner.accept_bi().await?;
172184
tracing::trace!(recv_id = %rx.id(), "Receiving request");
185+
let mut magic_bytes = [0u8; message::MAGIC_BYTES_LEN];
186+
rx.read_exact(&mut magic_bytes)
187+
.await
188+
.map_err(error::connection::Receive::ReadMagic)?;
189+
if magic_bytes != message::magic_bytes(self.network) {
190+
return Err(
191+
error::connection::Receive::BadMagic(magic_bytes).into()
192+
);
193+
}
173194
let msg_bytes = rx.read_to_end(Connection::READ_REQUEST_LIMIT).await?;
174195
let msg: RequestMessage = bincode::deserialize(&msg_bytes)?;
175196
tracing::trace!(
@@ -191,8 +212,9 @@ impl Connection {
191212
"Sending heartbeat"
192213
);
193214
let message = RequestMessageRef::from(heartbeat);
194-
let message = bincode::serialize(&message)?;
195-
send.write_all(&message).await.map_err(|err| {
215+
let mut message_buf = message::magic_bytes(self.network).to_vec();
216+
bincode::serialize_into::<&mut Vec<_>, _>(&mut message_buf, &message)?;
217+
send.write_all(&message_buf).await.map_err(|err| {
196218
error::connection::Send::Write {
197219
stream_id: send.id(),
198220
source: err,
@@ -203,10 +225,20 @@ impl Connection {
203225
}
204226

205227
async fn receive_response(
228+
network: Network,
206229
mut recv: RecvStream,
207230
read_response_limit: NonZeroUsize,
208231
) -> ResponseResult {
209232
tracing::trace!(recv_id = %recv.id(), "Receiving response");
233+
let mut magic_bytes = [0u8; message::MAGIC_BYTES_LEN];
234+
recv.read_exact(&mut magic_bytes)
235+
.await
236+
.map_err(error::connection::Receive::ReadMagic)?;
237+
if magic_bytes != message::magic_bytes(network) {
238+
return Err(
239+
error::connection::Receive::BadMagic(magic_bytes).into()
240+
);
241+
}
210242
let response_bytes =
211243
recv.read_to_end(read_response_limit.get()).await?;
212244
let response: ResponseMessage = bincode::deserialize(&response_bytes)?;
@@ -230,40 +262,52 @@ impl Connection {
230262
"Sending request"
231263
);
232264
let message = RequestMessageRef::from(request);
233-
let message = bincode::serialize(&message)?;
234-
send.write_all(&message).await.map_err(|err| {
265+
let mut message_buf = message::magic_bytes(self.network).to_vec();
266+
bincode::serialize_into::<&mut Vec<_>, _>(&mut message_buf, &message)?;
267+
send.write_all(&message_buf).await.map_err(|err| {
235268
error::connection::Send::Write {
236269
stream_id: send.id(),
237270
source: err,
238271
}
239272
})?;
240273
send.finish()?;
241-
Ok(Self::receive_response(recv, read_response_limit).await)
274+
Ok(
275+
Self::receive_response(self.network, recv, read_response_limit)
276+
.await,
277+
)
242278
}
243279

280+
// Send a pre-serialized response, where the response does not include
281+
// magic bytes
244282
async fn send_serialized_response(
283+
network: Network,
245284
mut response_tx: SendStream,
246285
serialized_response: &[u8],
247286
) -> Result<(), error::connection::SendResponse> {
248287
tracing::trace!(
249288
send_id = %response_tx.id(),
250289
"Sending response"
251290
);
252-
response_tx
253-
.write_all(serialized_response)
254-
.await
255-
.map_err(|err| {
256-
{
257-
error::connection::Send::Write {
258-
stream_id: response_tx.id(),
259-
source: err,
260-
}
291+
async {
292+
response_tx
293+
.write_all(&message::magic_bytes(network))
294+
.await?;
295+
response_tx.write_all(serialized_response).await
296+
}
297+
.await
298+
.map_err(|err| {
299+
{
300+
error::connection::Send::Write {
301+
stream_id: response_tx.id(),
302+
source: err,
261303
}
262-
.into()
263-
})
304+
}
305+
.into()
306+
})
264307
}
265308

266309
async fn send_response(
310+
network: Network,
267311
mut response_tx: SendStream,
268312
response: ResponseMessage,
269313
) -> Result<(), error::connection::SendResponse> {
@@ -272,8 +316,9 @@ impl Connection {
272316
send_id = %response_tx.id(),
273317
"Sending response"
274318
);
275-
let response_bytes = bincode::serialize(&response)?;
276-
response_tx.write_all(&response_bytes).await.map_err(|err| {
319+
let mut message_buf = message::magic_bytes(network).to_vec();
320+
bincode::serialize_into::<&mut Vec<_>, _>(&mut message_buf, &response)?;
321+
response_tx.write_all(&message_buf).await.map_err(|err| {
277322
{
278323
error::connection::Send::Write {
279324
stream_id: response_tx.id(),
@@ -285,15 +330,10 @@ impl Connection {
285330
}
286331
}
287332

288-
impl From<quinn::Connection> for Connection {
289-
fn from(inner: quinn::Connection) -> Self {
290-
Self { inner }
291-
}
292-
}
293-
294333
pub struct ConnectionContext {
295334
pub env: sneed::Env,
296335
pub archive: Archive,
336+
pub network: Network,
297337
pub state: State,
298338
}
299339

@@ -427,7 +467,8 @@ pub fn connect(
427467
let status_repr = status_repr.clone();
428468
let info_tx = info_tx.clone();
429469
move || async move {
430-
let connection = Connection::new(connecting).await?;
470+
let connection =
471+
Connection::from_connecting(connecting, ctxt.network).await?;
431472
status_repr.store(
432473
PeerConnectionStatus::Connected.as_repr(),
433474
atomic::Ordering::SeqCst,

lib/net/peer/task.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,8 @@ impl ConnectionTask {
609609
}
610610
(_, _) => ResponseMessage::NoBlock { block_hash },
611611
};
612-
let () = Connection::send_response(response_tx, resp).await?;
612+
let () =
613+
Connection::send_response(ctxt.network, response_tx, resp).await?;
613614
Ok(())
614615
}
615616

@@ -661,6 +662,7 @@ impl ConnectionTask {
661662
match validate_tx_result {
662663
Err(err) => {
663664
Connection::send_response(
665+
ctxt.network,
664666
response_tx,
665667
ResponseMessage::TransactionRejected(txid),
666668
)
@@ -669,6 +671,7 @@ impl ConnectionTask {
669671
}
670672
Ok(_) => {
671673
Connection::send_response(
674+
ctxt.network,
672675
response_tx,
673676
ResponseMessage::TransactionAccepted(txid),
674677
)
@@ -844,8 +847,10 @@ impl ConnectionTask {
844847
serialized_response,
845848
response_tx,
846849
}) => {
850+
let network = ctxt.network;
847851
self.mailbox_tx.send_response_spawner.spawn(async move {
848852
Connection::send_serialized_response(
853+
network,
849854
response_tx,
850855
&serialized_response,
851856
)

0 commit comments

Comments
 (0)