-
Notifications
You must be signed in to change notification settings - Fork 107
/
vectors.rs
181 lines (151 loc) · 6.1 KB
/
vectors.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//! Fixed test vectors for isolated Zebra connections.
use std::{net::SocketAddr, task::Poll, time::Duration};
use futures::stream::StreamExt;
use tokio_util::codec::Framed;
use crate::{
constants::CURRENT_NETWORK_PROTOCOL_VERSION,
protocol::external::{AddrInVersion, Codec, Message},
types::PeerServices,
VersionMessage,
};
use super::super::*;
use Network::*;
/// Test that `connect_isolated` sends a version message with minimal distinguishing features,
/// when sent over TCP.
#[tokio::test]
async fn connect_isolated_sends_anonymised_version_message_tcp() {
let _init_guard = zebra_test::init();
if zebra_test::net::zebra_skip_network_tests() {
return;
}
connect_isolated_sends_anonymised_version_message_tcp_net(Mainnet).await;
connect_isolated_sends_anonymised_version_message_tcp_net(Testnet).await;
}
async fn connect_isolated_sends_anonymised_version_message_tcp_net(network: Network) {
// These tests might fail on machines with no configured IPv4 addresses.
// (Localhost should be enough.)
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let listen_addr = listener.local_addr().unwrap();
// Connection errors are detected using the JoinHandle.
// (They might also make the test hang.)
let mut outbound_join_handle = tokio::spawn(connect_isolated_tcp_direct(
network,
listen_addr,
"".to_string(),
));
let (inbound_conn, _) = listener.accept().await.unwrap();
let mut inbound_stream =
Framed::new(inbound_conn, Codec::builder().for_network(network).finish());
check_version_message(network, &mut inbound_stream).await;
// Let the spawned task run for a short time.
tokio::time::sleep(Duration::from_secs(1)).await;
// Make sure that the isolated connection did not:
// - panic, or
// - return a service.
//
// This test doesn't send a version message on `inbound_conn`,
// so providing a service is incorrect behaviour.
//
// A timeout error would be acceptable,
// but a TCP connection error indicates a potential test setup issue.
// So we fail on them both, because we expect this test to complete before the timeout.
let outbound_result = futures::poll!(&mut outbound_join_handle);
assert!(matches!(outbound_result, Poll::Pending));
outbound_join_handle.abort();
}
/// Test that `connect_isolated` sends a version message with minimal distinguishing features,
/// when sent in-memory.
///
/// This test also:
/// - checks `PeerTransport` support, and
/// - runs even if network tests are disabled.
#[tokio::test]
async fn connect_isolated_sends_anonymised_version_message_mem() {
let _init_guard = zebra_test::init();
connect_isolated_sends_anonymised_version_message_mem_net(Mainnet).await;
connect_isolated_sends_anonymised_version_message_mem_net(Testnet).await;
}
async fn connect_isolated_sends_anonymised_version_message_mem_net(network: Network) {
// We expect version messages to be ~100 bytes
let (inbound_stream, outbound_stream) = tokio::io::duplex(1024);
let mut outbound_join_handle =
tokio::spawn(connect_isolated(network, outbound_stream, "".to_string()));
let mut inbound_stream = Framed::new(
inbound_stream,
Codec::builder().for_network(network).finish(),
);
check_version_message(network, &mut inbound_stream).await;
// Let the spawned task run for a short time.
tokio::time::sleep(Duration::from_secs(1)).await;
// Make sure that the isolated connection did not:
// - panic, or
// - return a service.
//
// This test doesn't send a version message on `inbound_conn`,
// so providing a service is incorrect behaviour.
// (But a timeout error would be acceptable.)
let outbound_result = futures::poll!(&mut outbound_join_handle);
assert!(matches!(
outbound_result,
Poll::Pending | Poll::Ready(Ok(Err(_)))
));
outbound_join_handle.abort();
}
/// Wait to receive a version message on `inbound_stream`,
/// then check that it is correctly anonymised.
async fn check_version_message<PeerTransport>(
network: Network,
inbound_stream: &mut Framed<PeerTransport, Codec>,
) where
PeerTransport: AsyncRead + Unpin,
{
// We don't need to send any bytes to get a version message.
if let Message::Version(VersionMessage {
version,
services,
timestamp,
address_recv,
address_from,
nonce: _,
user_agent,
start_height,
relay,
}) = inbound_stream
.next()
.await
.expect("stream item")
.expect("item is Ok(msg)")
{
// Check that the version message sent by connect_isolated
// anonymises all the fields that it possibly can.
//
// The version field needs to be accurate, because it controls protocol features.
// The nonce must be randomised for security.
//
// SECURITY TODO: check if the timestamp field can be zeroed, to remove another distinguisher (#3300)
let mut fixed_isolated_addr: SocketAddr = "0.0.0.0:0".parse().unwrap();
fixed_isolated_addr.set_port(network.default_port());
// Required fields should be accurate and match most other peers.
// (We can't test nonce randomness here.)
assert_eq!(version, CURRENT_NETWORK_PROTOCOL_VERSION);
assert_eq!(timestamp.timestamp() % (5 * 60), 0);
// Other fields should be empty or zeroed.
assert_eq!(services, PeerServices::empty());
assert_eq!(
address_recv,
// Since we're connecting to the peer, we expect it to have the node flag.
//
// SECURITY TODO: should this just be zeroed anyway? (#3300)
AddrInVersion::new(fixed_isolated_addr, PeerServices::NODE_NETWORK),
);
assert_eq!(
address_from,
AddrInVersion::new(fixed_isolated_addr, PeerServices::empty()),
);
assert_eq!(user_agent, "");
assert_eq!(start_height.0, 0);
assert!(!relay);
} else {
panic!("handshake did not send version message");
}
}