mirror of https://github.com/dswd/vpncloud.git
Compare commits
2 Commits
800e284408
...
16da58b8df
Author | SHA1 | Date |
---|---|---|
Dennis Schwerdel | 16da58b8df | |
Dennis Schwerdel | 47f872d5f4 |
|
@ -1,165 +0,0 @@
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"region": "eu-central-1",
|
|
||||||
"instance_type": "m5.large",
|
|
||||||
"ami": "ami-00a205cb8e06c3c4e",
|
|
||||||
"version": "2.0-pre",
|
|
||||||
"duration": 621.4215319156647
|
|
||||||
},
|
|
||||||
"native": {
|
|
||||||
"iperf": {
|
|
||||||
"throughput": 9680424000.0,
|
|
||||||
"cpu_sender": 12.878548,
|
|
||||||
"cpu_receiver": 66.330665
|
|
||||||
},
|
|
||||||
"ping_100": {
|
|
||||||
"rtt_min": 0.045,
|
|
||||||
"rtt_max": 0.204,
|
|
||||||
"rtt_avg": 0.052,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_500": {
|
|
||||||
"rtt_min": 0.047,
|
|
||||||
"rtt_max": 0.213,
|
|
||||||
"rtt_avg": 0.054,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_1000": {
|
|
||||||
"rtt_min": 0.048,
|
|
||||||
"rtt_max": 0.629,
|
|
||||||
"rtt_avg": 0.055,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"plain": {
|
|
||||||
"iperf": {
|
|
||||||
"throughput": 5733394000.0,
|
|
||||||
"cpu_sender": 11.835632,
|
|
||||||
"cpu_receiver": 67.865656
|
|
||||||
},
|
|
||||||
"ping_100": {
|
|
||||||
"rtt_min": 0.074,
|
|
||||||
"rtt_max": 3.375,
|
|
||||||
"rtt_avg": 0.093,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_500": {
|
|
||||||
"rtt_min": 0.076,
|
|
||||||
"rtt_max": 1.886,
|
|
||||||
"rtt_avg": 0.095,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_1000": {
|
|
||||||
"rtt_min": 0.076,
|
|
||||||
"rtt_max": 1.873,
|
|
||||||
"rtt_avg": 0.094,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"aes256": {
|
|
||||||
"iperf": {
|
|
||||||
"throughput": 3917323000.0,
|
|
||||||
"cpu_sender": 7.746875,
|
|
||||||
"cpu_receiver": 65.508621
|
|
||||||
},
|
|
||||||
"ping_100": {
|
|
||||||
"rtt_min": 0.076,
|
|
||||||
"rtt_max": 1.527,
|
|
||||||
"rtt_avg": 0.093,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_500": {
|
|
||||||
"rtt_min": 0.075,
|
|
||||||
"rtt_max": 1.969,
|
|
||||||
"rtt_avg": 0.094,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_1000": {
|
|
||||||
"rtt_min": 0.079,
|
|
||||||
"rtt_max": 1.973,
|
|
||||||
"rtt_avg": 0.096,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"aes128": {
|
|
||||||
"iperf": {
|
|
||||||
"throughput": 3899771000.0,
|
|
||||||
"cpu_sender": 6.73498,
|
|
||||||
"cpu_receiver": 64.197019
|
|
||||||
},
|
|
||||||
"ping_100": {
|
|
||||||
"rtt_min": 0.073,
|
|
||||||
"rtt_max": 1.522,
|
|
||||||
"rtt_avg": 0.094,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_500": {
|
|
||||||
"rtt_min": 0.08,
|
|
||||||
"rtt_max": 1.979,
|
|
||||||
"rtt_avg": 0.098,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_1000": {
|
|
||||||
"rtt_min": 0.082,
|
|
||||||
"rtt_max": 2.162,
|
|
||||||
"rtt_avg": 0.099,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chacha20": {
|
|
||||||
"iperf": {
|
|
||||||
"throughput": 2888735000.0,
|
|
||||||
"cpu_sender": 6.548527,
|
|
||||||
"cpu_receiver": 63.424257
|
|
||||||
},
|
|
||||||
"ping_100": {
|
|
||||||
"rtt_min": 0.078,
|
|
||||||
"rtt_max": 0.276,
|
|
||||||
"rtt_avg": 0.095,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_500": {
|
|
||||||
"rtt_min": 0.084,
|
|
||||||
"rtt_max": 0.241,
|
|
||||||
"rtt_avg": 0.1,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_1000": {
|
|
||||||
"rtt_min": 0.087,
|
|
||||||
"rtt_max": 0.424,
|
|
||||||
"rtt_avg": 0.106,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"results": {
|
|
||||||
"throughput_mbits": {
|
|
||||||
"native": 9680.424,
|
|
||||||
"plain": 5733.394,
|
|
||||||
"aes256": 3917.323,
|
|
||||||
"aes128": 3899.771,
|
|
||||||
"chacha20": 2888.735
|
|
||||||
},
|
|
||||||
"latency_us": {
|
|
||||||
"plain": {
|
|
||||||
"100": 20.5,
|
|
||||||
"500": 20.5,
|
|
||||||
"1000": 19.5
|
|
||||||
},
|
|
||||||
"aes256": {
|
|
||||||
"100": 20.5,
|
|
||||||
"500": 20.0,
|
|
||||||
"1000": 20.5
|
|
||||||
},
|
|
||||||
"aes128": {
|
|
||||||
"100": 21.0,
|
|
||||||
"500": 22.000000000000004,
|
|
||||||
"1000": 22.000000000000004
|
|
||||||
},
|
|
||||||
"chacha20": {
|
|
||||||
"100": 21.5,
|
|
||||||
"500": 23.000000000000004,
|
|
||||||
"1000": 25.5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"region": "eu-central-1",
|
||||||
|
"instance_type": "m5.large",
|
||||||
|
"ami": "ami-00a205cb8e06c3c4e",
|
||||||
|
"version": "2.0.0-alpha1",
|
||||||
|
"duration": 621.3780446052551
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"iperf": {
|
||||||
|
"throughput": 9681224000.0,
|
||||||
|
"cpu_sender": 13.679709,
|
||||||
|
"cpu_receiver": 71.69651
|
||||||
|
},
|
||||||
|
"ping_100": {
|
||||||
|
"rtt_min": 0.045,
|
||||||
|
"rtt_max": 0.18,
|
||||||
|
"rtt_avg": 0.051,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
},
|
||||||
|
"ping_500": {
|
||||||
|
"rtt_min": 0.047,
|
||||||
|
"rtt_max": 0.184,
|
||||||
|
"rtt_avg": 0.054,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
},
|
||||||
|
"ping_1000": {
|
||||||
|
"rtt_min": 0.049,
|
||||||
|
"rtt_max": 0.175,
|
||||||
|
"rtt_avg": 0.056,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plain": {
|
||||||
|
"iperf": {
|
||||||
|
"throughput": 5472962000.0,
|
||||||
|
"cpu_sender": 15.087884,
|
||||||
|
"cpu_receiver": 67.570992
|
||||||
|
},
|
||||||
|
"ping_100": {
|
||||||
|
"rtt_min": 0.078,
|
||||||
|
"rtt_max": 0.257,
|
||||||
|
"rtt_avg": 0.093,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
},
|
||||||
|
"ping_500": {
|
||||||
|
"rtt_min": 0.08,
|
||||||
|
"rtt_max": 0.243,
|
||||||
|
"rtt_avg": 0.097,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
},
|
||||||
|
"ping_1000": {
|
||||||
|
"rtt_min": 0.08,
|
||||||
|
"rtt_max": 0.591,
|
||||||
|
"rtt_avg": 0.096,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"aes256": {
|
||||||
|
"iperf": {
|
||||||
|
"throughput": 3947676000.0,
|
||||||
|
"cpu_sender": 6.859741,
|
||||||
|
"cpu_receiver": 62.826154
|
||||||
|
},
|
||||||
|
"ping_100": {
|
||||||
|
"rtt_min": 0.081,
|
||||||
|
"rtt_max": 1.653,
|
||||||
|
"rtt_avg": 0.096,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
},
|
||||||
|
"ping_500": {
|
||||||
|
"rtt_min": 0.081,
|
||||||
|
"rtt_max": 1.259,
|
||||||
|
"rtt_avg": 0.098,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
},
|
||||||
|
"ping_1000": {
|
||||||
|
"rtt_min": 0.082,
|
||||||
|
"rtt_max": 0.257,
|
||||||
|
"rtt_avg": 0.099,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"aes128": {
|
||||||
|
"iperf": {
|
||||||
|
"throughput": 4200596000.0,
|
||||||
|
"cpu_sender": 10.291266,
|
||||||
|
"cpu_receiver": 64.395908
|
||||||
|
},
|
||||||
|
"ping_100": {
|
||||||
|
"rtt_min": 0.081,
|
||||||
|
"rtt_max": 0.294,
|
||||||
|
"rtt_avg": 0.097,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
},
|
||||||
|
"ping_500": {
|
||||||
|
"rtt_min": 0.084,
|
||||||
|
"rtt_max": 0.238,
|
||||||
|
"rtt_avg": 0.099,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
},
|
||||||
|
"ping_1000": {
|
||||||
|
"rtt_min": 0.086,
|
||||||
|
"rtt_max": 0.291,
|
||||||
|
"rtt_avg": 0.101,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chacha20": {
|
||||||
|
"iperf": {
|
||||||
|
"throughput": 2854407000.0,
|
||||||
|
"cpu_sender": 5.648368,
|
||||||
|
"cpu_receiver": 58.473016
|
||||||
|
},
|
||||||
|
"ping_100": {
|
||||||
|
"rtt_min": 0.082,
|
||||||
|
"rtt_max": 0.515,
|
||||||
|
"rtt_avg": 0.098,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
},
|
||||||
|
"ping_500": {
|
||||||
|
"rtt_min": 0.089,
|
||||||
|
"rtt_max": 3.457,
|
||||||
|
"rtt_avg": 0.105,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
},
|
||||||
|
"ping_1000": {
|
||||||
|
"rtt_min": 0.092,
|
||||||
|
"rtt_max": 0.366,
|
||||||
|
"rtt_avg": 0.108,
|
||||||
|
"pkt_loss": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"results": {
|
||||||
|
"throughput_mbits": {
|
||||||
|
"native": 9681.224,
|
||||||
|
"plain": 5472.962,
|
||||||
|
"aes256": 3947.676,
|
||||||
|
"aes128": 4200.596,
|
||||||
|
"chacha20": 2854.407
|
||||||
|
},
|
||||||
|
"latency_us": {
|
||||||
|
"plain": {
|
||||||
|
"100": 21.0,
|
||||||
|
"500": 21.5,
|
||||||
|
"1000": 20.0
|
||||||
|
},
|
||||||
|
"aes256": {
|
||||||
|
"100": 22.500000000000004,
|
||||||
|
"500": 22.000000000000004,
|
||||||
|
"1000": 21.5
|
||||||
|
},
|
||||||
|
"aes128": {
|
||||||
|
"100": 23.000000000000004,
|
||||||
|
"500": 22.500000000000004,
|
||||||
|
"1000": 22.500000000000004
|
||||||
|
},
|
||||||
|
"chacha20": {
|
||||||
|
"100": 23.500000000000004,
|
||||||
|
"500": 25.5,
|
||||||
|
"1000": 26.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ from datetime import date
|
||||||
# Note: this script will run for ~8 minutes and incur costs of about $ 0.02
|
# Note: this script will run for ~8 minutes and incur costs of about $ 0.02
|
||||||
|
|
||||||
FILE = "../target/release/vpncloud"
|
FILE = "../target/release/vpncloud"
|
||||||
VERSION = "2.0-pre"
|
VERSION = "2.0.0-alpha1"
|
||||||
REGION = "eu-central-1"
|
REGION = "eu-central-1"
|
||||||
|
|
||||||
env = EC2Environment(
|
env = EC2Environment(
|
||||||
|
|
34
src/cloud.rs
34
src/cloud.rs
|
@ -492,7 +492,13 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
||||||
writeln!(f, "peers:")?;
|
writeln!(f, "peers:")?;
|
||||||
let now = TS::now();
|
let now = TS::now();
|
||||||
for (addr, data) in &self.peers {
|
for (addr, data) in &self.peers {
|
||||||
writeln!(f, " - \"{}\": {{ ttl_secs: {} }}", addr_nice(*addr), data.timeout - now)?;
|
writeln!(
|
||||||
|
f,
|
||||||
|
" - \"{}\": {{ ttl_secs: {}, crypto: {} }}",
|
||||||
|
addr_nice(*addr),
|
||||||
|
data.timeout - now,
|
||||||
|
data.crypto.algorithm_name()
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
self.table.write_out(f)?;
|
self.table.write_out(f)?;
|
||||||
|
@ -717,11 +723,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
||||||
self.pending_inits.insert(src, init);
|
self.pending_inits.insert(src, init);
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => return Err(err)
|
||||||
debug!("Init error from {}: {}", src, err);
|
|
||||||
info!("Ignoring invalid init message from peer {}", addr_nice(src));
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if let Some(peer) = self.peers.get_mut(&src) {
|
} else if let Some(peer) = self.peers.get_mut(&src) {
|
||||||
peer.crypto.handle_message(data)
|
peer.crypto.handle_message(data)
|
||||||
|
@ -748,21 +750,27 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
||||||
fn handle_socket_event(&mut self, buffer: &mut MsgBuffer) {
|
fn handle_socket_event(&mut self, buffer: &mut MsgBuffer) {
|
||||||
let src = try_fail!(self.socket.receive(buffer), "Failed to read from network socket: {}");
|
let src = try_fail!(self.socket.receive(buffer), "Failed to read from network socket: {}");
|
||||||
self.traffic.count_in_traffic(src, buffer.len());
|
self.traffic.count_in_traffic(src, buffer.len());
|
||||||
if let Err(e) = self.handle_net_message(src, buffer) {
|
match self.handle_net_message(src, buffer) {
|
||||||
if let Error::CryptoInit(_) = e {
|
Err(e @ Error::CryptoInitFatal(_)) => {
|
||||||
debug!("Crypto init error: {}", e);
|
debug!("Fatal crypto init error from {}: {}", src, e);
|
||||||
info!("Closing pending connection to {} due to error in crypto init", addr_nice(src));
|
info!("Closing pending connection to {} due to error in crypto init", addr_nice(src));
|
||||||
self.pending_inits.remove(&src);
|
self.pending_inits.remove(&src);
|
||||||
} else {
|
|
||||||
error!("Error: {}", e);
|
|
||||||
}
|
}
|
||||||
|
Err(e @ Error::CryptoInit(_)) => {
|
||||||
|
debug!("Recoverable init error from {}: {}", src, e);
|
||||||
|
info!("Ignoring invalid init message from peer {}", addr_nice(src));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("{}", e);
|
||||||
|
}
|
||||||
|
Ok(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_device_event(&mut self, buffer: &mut MsgBuffer) {
|
fn handle_device_event(&mut self, buffer: &mut MsgBuffer) {
|
||||||
try_fail!(self.device.read(buffer), "Failed to read from device: {}");
|
try_fail!(self.device.read(buffer), "Failed to read from device: {}");
|
||||||
if let Err(e) = self.handle_interface_data(buffer) {
|
if let Err(e) = self.handle_interface_data(buffer) {
|
||||||
error!("Error: {}", e);
|
error!("{}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -797,7 +805,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if let Err(e) = self.housekeep() {
|
if let Err(e) = self.housekeep() {
|
||||||
error!("Error: {}", e)
|
error!("{}", e)
|
||||||
}
|
}
|
||||||
self.next_housekeep = TS::now() + 1
|
self.next_housekeep = TS::now() + 1
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,6 +210,7 @@ impl CryptoCore {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rotate_key(&mut self, key: LessSafeKey, id: u64, use_for_sending: bool) {
|
pub fn rotate_key(&mut self, key: LessSafeKey, id: u64, use_for_sending: bool) {
|
||||||
|
debug!("Rotated key {} (use for sending: {})", id, use_for_sending);
|
||||||
let id = (id % 4) as usize;
|
let id = (id % 4) as usize;
|
||||||
self.keys[id] = CryptoKey::new(&self.rand, key, self.nonce_half);
|
self.keys[id] = CryptoKey::new(&self.rand, key, self.nonce_half);
|
||||||
if use_for_sending {
|
if use_for_sending {
|
||||||
|
|
|
@ -453,7 +453,7 @@ impl<P: Payload> InitState<P> {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
self.next_stage = CLOSING;
|
self.next_stage = CLOSING;
|
||||||
Err(Error::CryptoInit("Initialization timeout"))
|
Err(Error::CryptoInitFatal("Initialization timeout"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,7 +565,7 @@ impl<P: Payload> InitState<P> {
|
||||||
debug!("Init: best algorithm is {:?} with speed {}", algo.0, algo.1);
|
debug!("Init: best algorithm is {:?} with speed {}", algo.0, algo.1);
|
||||||
Ok(Some(algo))
|
Ok(Some(algo))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::CryptoInit("No common algorithms"))
|
Err(Error::CryptoInitFatal("No common algorithms"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,7 +578,7 @@ impl<P: Payload> InitState<P> {
|
||||||
if self.salted_node_id_hash == salted_node_id_hash
|
if self.salted_node_id_hash == salted_node_id_hash
|
||||||
|| self.check_salted_node_id_hash(&salted_node_id_hash, self.node_id)
|
|| self.check_salted_node_id_hash(&salted_node_id_hash, self.node_id)
|
||||||
{
|
{
|
||||||
return Err(Error::CryptoInit("Connected to self"))
|
return Err(Error::CryptoInitFatal("Connected to self"))
|
||||||
}
|
}
|
||||||
if stage != self.next_stage {
|
if stage != self.next_stage {
|
||||||
if self.next_stage == STAGE_PONG && stage == STAGE_PING {
|
if self.next_stage == STAGE_PONG && stage == STAGE_PING {
|
||||||
|
@ -598,7 +598,7 @@ impl<P: Payload> InitState<P> {
|
||||||
self.repeat_last_message(out);
|
self.repeat_last_message(out);
|
||||||
return Ok(InitResult::Continue)
|
return Ok(InitResult::Continue)
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::CryptoInit("Received invalid stage as first message"))
|
return Err(Error::CryptoInitFatal("Received invalid stage as first message"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.failed_retries = 0;
|
self.failed_retries = 0;
|
||||||
|
@ -633,7 +633,7 @@ impl<P: Payload> InitState<P> {
|
||||||
|
|
||||||
// decrypt the payload
|
// decrypt the payload
|
||||||
let peer_payload =
|
let peer_payload =
|
||||||
self.decrypt(&mut encrypted_payload).map_err(|_| Error::CryptoInit("Failed to decrypt payload"))?;
|
self.decrypt(&mut encrypted_payload).map_err(|_| Error::CryptoInitFatal("Failed to decrypt payload"))?;
|
||||||
|
|
||||||
// create and send stage 3 reply
|
// create and send stage 3 reply
|
||||||
self.send_message(STAGE_PENG, None, out);
|
self.send_message(STAGE_PENG, None, out);
|
||||||
|
@ -645,7 +645,7 @@ impl<P: Payload> InitState<P> {
|
||||||
InitMsg::Peng { mut encrypted_payload, .. } => {
|
InitMsg::Peng { mut encrypted_payload, .. } => {
|
||||||
// decrypt the payload
|
// decrypt the payload
|
||||||
let peer_payload =
|
let peer_payload =
|
||||||
self.decrypt(&mut encrypted_payload).map_err(|_| Error::CryptoInit("Failed to decrypt payload"))?;
|
self.decrypt(&mut encrypted_payload).map_err(|_| Error::CryptoInitFatal("Failed to decrypt payload"))?;
|
||||||
|
|
||||||
self.next_stage = CLOSING; // force resend when receiving any message
|
self.next_stage = CLOSING; // force resend when receiving any message
|
||||||
Ok(InitResult::Success { peer_payload, is_initiator: false })
|
Ok(InitResult::Success { peer_payload, is_initiator: false })
|
||||||
|
|
|
@ -124,7 +124,12 @@ impl Crypto {
|
||||||
speeds.into_iter().map(|(a, s)| format!("{}: {:.1} MiB/s", a, s)).collect::<Vec<_>>().join(", ")
|
speeds.into_iter().map(|(a, s)| format!("{}: {:.1} MiB/s", a, s)).collect::<Vec<_>>().join(", ")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(Self { node_id, key_pair: Arc::new(key_pair), trusted_keys: trusted_keys.into_boxed_slice().into(), algorithms: algos })
|
Ok(Self {
|
||||||
|
node_id,
|
||||||
|
key_pair: Arc::new(key_pair),
|
||||||
|
trusted_keys: trusted_keys.into_boxed_slice().into(),
|
||||||
|
algorithms: algos
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_keypair(password: Option<&str>) -> (String, String) {
|
pub fn generate_keypair(password: Option<&str>) -> (String, String) {
|
||||||
|
@ -268,6 +273,23 @@ impl<P: Payload> PeerCrypto<P> {
|
||||||
self.core.is_some()
|
self.core.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn algorithm_name(&self) -> &'static str {
|
||||||
|
if let Some(ref core) = self.core {
|
||||||
|
let algo = core.algorithm();
|
||||||
|
if algo == &aead::CHACHA20_POLY1305 {
|
||||||
|
"chacha20"
|
||||||
|
} else if algo == &aead::AES_128_GCM {
|
||||||
|
"aes128"
|
||||||
|
} else if algo == &aead::AES_256_GCM {
|
||||||
|
"aes256"
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"plain"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_init_message(&mut self, buffer: &mut MsgBuffer) -> Result<MessageResult<P>, Error> {
|
fn handle_init_message(&mut self, buffer: &mut MsgBuffer) -> Result<MessageResult<P>, Error> {
|
||||||
let result = self.get_init()?.handle_init(buffer)?;
|
let result = self.get_init()?.handle_init(buffer)?;
|
||||||
if !buffer.is_empty() {
|
if !buffer.is_empty() {
|
||||||
|
@ -284,7 +306,7 @@ impl<P: Payload> PeerCrypto<P> {
|
||||||
self.init = None
|
self.init = None
|
||||||
}
|
}
|
||||||
if self.core.is_some() {
|
if self.core.is_some() {
|
||||||
self.rotation = Some(RotationState::new(!is_initiator, buffer)?);
|
self.rotation = Some(RotationState::new(!is_initiator, buffer));
|
||||||
}
|
}
|
||||||
if !is_initiator {
|
if !is_initiator {
|
||||||
if self.unencrypted {
|
if self.unencrypted {
|
||||||
|
@ -375,7 +397,7 @@ impl<P: Payload> PeerCrypto<P> {
|
||||||
self.rotate_counter += 1;
|
self.rotate_counter += 1;
|
||||||
if self.rotate_counter >= ROTATE_INTERVAL {
|
if self.rotate_counter >= ROTATE_INTERVAL {
|
||||||
self.rotate_counter = 0;
|
self.rotate_counter = 0;
|
||||||
if let Some(rot) = rotate.cycle(out)? {
|
if let Some(rot) = rotate.cycle(out) {
|
||||||
let core = self.get_core()?;
|
let core = self.get_core()?;
|
||||||
let algo = core.algorithm();
|
let algo = core.algorithm();
|
||||||
let key = LessSafeKey::new(UnboundKey::new(algo, &rot.key[..algo.key_len()]).unwrap());
|
let key = LessSafeKey::new(UnboundKey::new(algo, &rot.key[..algo.key_len()]).unwrap());
|
||||||
|
|
|
@ -97,18 +97,19 @@ pub struct RotatedKey {
|
||||||
|
|
||||||
impl RotationState {
|
impl RotationState {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn new(initiator: bool, out: &mut MsgBuffer) -> Result<Self, Error> {
|
pub fn new(initiator: bool, out: &mut MsgBuffer) -> Self {
|
||||||
if initiator {
|
if initiator {
|
||||||
let (private_key, public_key) = Self::create_key();
|
let (private_key, public_key) = Self::create_key();
|
||||||
Self::send(&RotationMessage { message_id: 1, confirm: None, propose: public_key }, out)?;
|
Self::send(&RotationMessage { message_id: 1, confirm: None, propose: public_key }, out);
|
||||||
Ok(Self { confirmed: None, pending: None, proposed: Some(private_key), message_id: 1, timeout: false })
|
Self { confirmed: None, pending: None, proposed: Some(private_key), message_id: 1, timeout: false }
|
||||||
} else {
|
} else {
|
||||||
Ok(Self { confirmed: None, pending: None, proposed: None, message_id: 0, timeout: false })
|
Self { confirmed: None, pending: None, proposed: None, message_id: 0, timeout: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send(msg: &RotationMessage, out: &mut MsgBuffer) -> Result<(), Error> {
|
fn send(msg: &RotationMessage, out: &mut MsgBuffer) {
|
||||||
assert!(out.is_empty());
|
assert!(out.is_empty());
|
||||||
|
debug!("Rotation sending message with id {}", msg.message_id);
|
||||||
let len;
|
let len;
|
||||||
{
|
{
|
||||||
let mut cursor = Cursor::new(out.buffer());
|
let mut cursor = Cursor::new(out.buffer());
|
||||||
|
@ -116,7 +117,6 @@ impl RotationState {
|
||||||
len = cursor.position() as usize;
|
len = cursor.position() as usize;
|
||||||
}
|
}
|
||||||
out.set_length(len);
|
out.set_length(len);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_key() -> (EcdhPrivateKey, EcdhPublicKey) {
|
fn create_key() -> (EcdhPrivateKey, EcdhPublicKey) {
|
||||||
|
@ -152,6 +152,7 @@ impl RotationState {
|
||||||
if msg.message_id <= self.message_id {
|
if msg.message_id <= self.message_id {
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
|
debug!("Received rotation message with id {}", msg.message_id);
|
||||||
self.timeout = false;
|
self.timeout = false;
|
||||||
// Create key from proposal and store reply as pending
|
// Create key from proposal and store reply as pending
|
||||||
let (private_key, public_key) = Self::create_key();
|
let (private_key, public_key) = Self::create_key();
|
||||||
|
@ -168,7 +169,7 @@ impl RotationState {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn cycle(&mut self, out: &mut MsgBuffer) -> Result<Option<RotatedKey>, Error> {
|
pub fn cycle(&mut self, out: &mut MsgBuffer) -> Option<RotatedKey> {
|
||||||
if let Some(ref private_key) = self.proposed {
|
if let Some(ref private_key) = self.proposed {
|
||||||
// Still a proposed key that has not been confirmed, proposal must have been lost
|
// Still a proposed key that has not been confirmed, proposal must have been lost
|
||||||
if self.timeout {
|
if self.timeout {
|
||||||
|
@ -178,10 +179,10 @@ impl RotationState {
|
||||||
Self::send(
|
Self::send(
|
||||||
&RotationMessage { confirm: Some(confirmed_key.clone()), propose: proposed_key, message_id },
|
&RotationMessage { confirm: Some(confirmed_key.clone()), propose: proposed_key, message_id },
|
||||||
out
|
out
|
||||||
)?;
|
);
|
||||||
} else {
|
} else {
|
||||||
// First message has been lost
|
// First message has been lost
|
||||||
Self::send(&RotationMessage { confirm: None, propose: proposed_key, message_id: 1 }, out)?;
|
Self::send(&RotationMessage { confirm: None, propose: proposed_key, message_id: 1 }, out);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.timeout = true;
|
self.timeout = true;
|
||||||
|
@ -195,14 +196,14 @@ impl RotationState {
|
||||||
let (private_key, propose_key) = Self::create_key();
|
let (private_key, propose_key) = Self::create_key();
|
||||||
self.proposed = Some(private_key);
|
self.proposed = Some(private_key);
|
||||||
self.confirmed = Some((confirm_key.clone(), message_id));
|
self.confirmed = Some((confirm_key.clone(), message_id));
|
||||||
Self::send(&RotationMessage { confirm: Some(confirm_key), propose: propose_key, message_id }, out)?;
|
Self::send(&RotationMessage { confirm: Some(confirm_key), propose: propose_key, message_id }, out);
|
||||||
return Ok(Some(RotatedKey { key, id: message_id, use_for_sending: false }))
|
return Some(RotatedKey { key, id: message_id, use_for_sending: false })
|
||||||
} else {
|
} else {
|
||||||
// Nothing pending nor proposed, still waiting to receive message 1
|
// Nothing pending nor proposed, still waiting to receive message 1
|
||||||
// Do nothing, peer will retry
|
// Do nothing, peer will retry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(None)
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,8 +251,8 @@ mod tests {
|
||||||
let mut out2 = MsgBuffer::new(8);
|
let mut out2 = MsgBuffer::new(8);
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
let mut node1 = RotationState::new(true, &mut out1).unwrap();
|
let mut node1 = RotationState::new(true, &mut out1);
|
||||||
let mut node2 = RotationState::new(false, &mut out2).unwrap();
|
let mut node2 = RotationState::new(false, &mut out2);
|
||||||
assert!(!out1.is_empty());
|
assert!(!out1.is_empty());
|
||||||
let msg1 = out1.msg().unwrap();
|
let msg1 = out1.msg().unwrap();
|
||||||
assert_eq!(msg1.message_id, 1);
|
assert_eq!(msg1.message_id, 1);
|
||||||
|
@ -260,8 +261,8 @@ mod tests {
|
||||||
let key = node2.process_message(msg1);
|
let key = node2.process_message(msg1);
|
||||||
assert!(key.is_none());
|
assert!(key.is_none());
|
||||||
// Cycle 1
|
// Cycle 1
|
||||||
let key1 = node1.cycle(&mut out1).unwrap();
|
let key1 = node1.cycle(&mut out1);
|
||||||
let key2 = node2.cycle(&mut out2).unwrap();
|
let key2 = node2.cycle(&mut out2);
|
||||||
assert!(key1.is_none());
|
assert!(key1.is_none());
|
||||||
assert!(out1.is_empty());
|
assert!(out1.is_empty());
|
||||||
assert!(key2.is_some());
|
assert!(key2.is_some());
|
||||||
|
@ -279,8 +280,8 @@ mod tests {
|
||||||
assert_eq!(key.id, 2);
|
assert_eq!(key.id, 2);
|
||||||
assert_eq!(key.use_for_sending, true);
|
assert_eq!(key.use_for_sending, true);
|
||||||
// Cycle 2
|
// Cycle 2
|
||||||
let key1 = node1.cycle(&mut out1).unwrap();
|
let key1 = node1.cycle(&mut out1);
|
||||||
let key2 = node2.cycle(&mut out2).unwrap();
|
let key2 = node2.cycle(&mut out2);
|
||||||
assert!(key1.is_some());
|
assert!(key1.is_some());
|
||||||
let key1 = key1.unwrap();
|
let key1 = key1.unwrap();
|
||||||
assert_eq!(key1.id, 3);
|
assert_eq!(key1.id, 3);
|
||||||
|
@ -298,8 +299,8 @@ mod tests {
|
||||||
assert_eq!(key.id, 3);
|
assert_eq!(key.id, 3);
|
||||||
assert_eq!(key.use_for_sending, true);
|
assert_eq!(key.use_for_sending, true);
|
||||||
// Cycle 3
|
// Cycle 3
|
||||||
let key1 = node1.cycle(&mut out1).unwrap();
|
let key1 = node1.cycle(&mut out1);
|
||||||
let key2 = node2.cycle(&mut out2).unwrap();
|
let key2 = node2.cycle(&mut out2);
|
||||||
assert!(key1.is_none());
|
assert!(key1.is_none());
|
||||||
assert!(out1.is_empty());
|
assert!(out1.is_empty());
|
||||||
assert!(key2.is_some());
|
assert!(key2.is_some());
|
||||||
|
@ -323,30 +324,30 @@ mod tests {
|
||||||
let mut out1 = MsgBuffer::new(8);
|
let mut out1 = MsgBuffer::new(8);
|
||||||
let mut out2 = MsgBuffer::new(8);
|
let mut out2 = MsgBuffer::new(8);
|
||||||
|
|
||||||
let mut node1 = RotationState::new(true, &mut out1).unwrap();
|
let mut node1 = RotationState::new(true, &mut out1);
|
||||||
let mut node2 = RotationState::new(false, &mut out2).unwrap();
|
let mut node2 = RotationState::new(false, &mut out2);
|
||||||
let msg1 = out1.clone().msg().unwrap();
|
let msg1 = out1.clone().msg().unwrap();
|
||||||
let msg1_copy = out1.msg().unwrap();
|
let msg1_copy = out1.msg().unwrap();
|
||||||
node2.process_message(msg1);
|
node2.process_message(msg1);
|
||||||
assert!(node2.process_message(msg1_copy).is_none());
|
assert!(node2.process_message(msg1_copy).is_none());
|
||||||
node1.cycle(&mut out1).unwrap();
|
node1.cycle(&mut out1);
|
||||||
node2.cycle(&mut out2).unwrap();
|
node2.cycle(&mut out2);
|
||||||
let msg2 = out2.clone().msg().unwrap();
|
let msg2 = out2.clone().msg().unwrap();
|
||||||
let msg2_copy = out2.msg().unwrap();
|
let msg2_copy = out2.msg().unwrap();
|
||||||
// Message 2
|
// Message 2
|
||||||
assert!(node1.process_message(msg2).is_some());
|
assert!(node1.process_message(msg2).is_some());
|
||||||
assert!(node1.process_message(msg2_copy).is_none());
|
assert!(node1.process_message(msg2_copy).is_none());
|
||||||
// Cycle 2
|
// Cycle 2
|
||||||
node1.cycle(&mut out1).unwrap();
|
node1.cycle(&mut out1);
|
||||||
node2.cycle(&mut out2).unwrap();
|
node2.cycle(&mut out2);
|
||||||
let msg1 = out1.clone().msg().unwrap();
|
let msg1 = out1.clone().msg().unwrap();
|
||||||
let msg1_copy = out1.msg().unwrap();
|
let msg1_copy = out1.msg().unwrap();
|
||||||
// Message 3
|
// Message 3
|
||||||
assert!(node2.process_message(msg1).is_some());
|
assert!(node2.process_message(msg1).is_some());
|
||||||
assert!(node2.process_message(msg1_copy).is_none());
|
assert!(node2.process_message(msg1_copy).is_none());
|
||||||
// Cycle 3
|
// Cycle 3
|
||||||
node1.cycle(&mut out1).unwrap();
|
node1.cycle(&mut out1);
|
||||||
node2.cycle(&mut out2).unwrap();
|
node2.cycle(&mut out2);
|
||||||
let msg2 = out2.clone().msg().unwrap();
|
let msg2 = out2.clone().msg().unwrap();
|
||||||
let msg2_copy = out2.msg().unwrap();
|
let msg2_copy = out2.msg().unwrap();
|
||||||
// Message 4
|
// Message 4
|
||||||
|
@ -359,22 +360,22 @@ mod tests {
|
||||||
let mut out1 = MsgBuffer::new(8);
|
let mut out1 = MsgBuffer::new(8);
|
||||||
let mut out2 = MsgBuffer::new(8);
|
let mut out2 = MsgBuffer::new(8);
|
||||||
|
|
||||||
let mut node1 = RotationState::new(true, &mut out1).unwrap();
|
let mut node1 = RotationState::new(true, &mut out1);
|
||||||
let mut node2 = RotationState::new(false, &mut out2).unwrap();
|
let mut node2 = RotationState::new(false, &mut out2);
|
||||||
let _msg1 = out1.msg().unwrap();
|
let _msg1 = out1.msg().unwrap();
|
||||||
// drop msg1
|
// drop msg1
|
||||||
node1.cycle(&mut out1).unwrap();
|
node1.cycle(&mut out1);
|
||||||
node2.cycle(&mut out2).unwrap();
|
node2.cycle(&mut out2);
|
||||||
assert!(out2.msg().is_none());
|
assert!(out2.msg().is_none());
|
||||||
// Cycle 2
|
// Cycle 2
|
||||||
node1.cycle(&mut out1).unwrap();
|
node1.cycle(&mut out1);
|
||||||
node2.cycle(&mut out2).unwrap();
|
node2.cycle(&mut out2);
|
||||||
let msg1 = out1.msg().unwrap();
|
let msg1 = out1.msg().unwrap();
|
||||||
// Message 3
|
// Message 3
|
||||||
assert!(node2.process_message(msg1).is_none());
|
assert!(node2.process_message(msg1).is_none());
|
||||||
// Cycle 3
|
// Cycle 3
|
||||||
node1.cycle(&mut out1).unwrap();
|
node1.cycle(&mut out1);
|
||||||
node2.cycle(&mut out2).unwrap();
|
node2.cycle(&mut out2);
|
||||||
let msg2 = out2.msg().unwrap();
|
let msg2 = out2.msg().unwrap();
|
||||||
// Message 4
|
// Message 4
|
||||||
assert!(node1.process_message(msg2).is_some());
|
assert!(node1.process_message(msg2).is_some());
|
||||||
|
@ -385,22 +386,22 @@ mod tests {
|
||||||
let mut out1 = MsgBuffer::new(8);
|
let mut out1 = MsgBuffer::new(8);
|
||||||
let mut out2 = MsgBuffer::new(8);
|
let mut out2 = MsgBuffer::new(8);
|
||||||
|
|
||||||
let mut node1 = RotationState::new(true, &mut out1).unwrap();
|
let mut node1 = RotationState::new(true, &mut out1);
|
||||||
let mut node2 = RotationState::new(false, &mut out2).unwrap();
|
let mut node2 = RotationState::new(false, &mut out2);
|
||||||
let msg1 = out1.msg().unwrap();
|
let msg1 = out1.msg().unwrap();
|
||||||
assert!(node1.process_message(msg1).is_none());
|
assert!(node1.process_message(msg1).is_none());
|
||||||
node1.cycle(&mut out1).unwrap();
|
node1.cycle(&mut out1);
|
||||||
node2.cycle(&mut out2).unwrap();
|
node2.cycle(&mut out2);
|
||||||
assert!(out2.msg().is_none());
|
assert!(out2.msg().is_none());
|
||||||
// Cycle 2
|
// Cycle 2
|
||||||
node1.cycle(&mut out1).unwrap();
|
node1.cycle(&mut out1);
|
||||||
node2.cycle(&mut out2).unwrap();
|
node2.cycle(&mut out2);
|
||||||
let msg1 = out1.msg().unwrap();
|
let msg1 = out1.msg().unwrap();
|
||||||
// Message 3
|
// Message 3
|
||||||
assert!(node2.process_message(msg1).is_none());
|
assert!(node2.process_message(msg1).is_none());
|
||||||
// Cycle 3
|
// Cycle 3
|
||||||
node1.cycle(&mut out1).unwrap();
|
node1.cycle(&mut out1);
|
||||||
node2.cycle(&mut out2).unwrap();
|
node2.cycle(&mut out2);
|
||||||
let msg2 = out2.msg().unwrap();
|
let msg2 = out2.msg().unwrap();
|
||||||
// Message 4
|
// Message 4
|
||||||
assert!(node1.process_message(msg2).is_some());
|
assert!(node1.process_message(msg2).is_some());
|
||||||
|
|
|
@ -5,10 +5,14 @@ use std::io;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Crypto init error, this is fatal and the init needs to be aborted
|
/// Crypto init error, this is recoverable
|
||||||
#[error("Crypto initialization error: {0}")]
|
#[error("Crypto initialization error: {0}")]
|
||||||
CryptoInit(&'static str),
|
CryptoInit(&'static str),
|
||||||
|
|
||||||
|
/// Crypto init error, this is fatal and the init needs to be aborted
|
||||||
|
#[error("Fatal crypto initialization error: {0}")]
|
||||||
|
CryptoInitFatal(&'static str),
|
||||||
|
|
||||||
/// Crypto error with this one message, no permanent error
|
/// Crypto error with this one message, no permanent error
|
||||||
#[error("Crypto error: {0}")]
|
#[error("Crypto error: {0}")]
|
||||||
Crypto(&'static str),
|
Crypto(&'static str),
|
||||||
|
|
11
src/table.rs
11
src/table.rs
|
@ -62,6 +62,11 @@ impl<TS: TimeSource> ClaimTable<TS> {
|
||||||
for claim in claims {
|
for claim in claims {
|
||||||
self.claims.push(ClaimEntry { peer, claim, timeout: TS::now() + self.claim_timeout as Time })
|
self.claims.push(ClaimEntry { peer, claim, timeout: TS::now() + self.claim_timeout as Time })
|
||||||
}
|
}
|
||||||
|
for entry in self.cache.values_mut() {
|
||||||
|
if entry.peer == peer {
|
||||||
|
entry.timeout = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
self.housekeep()
|
self.housekeep()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +76,11 @@ impl<TS: TimeSource> ClaimTable<TS> {
|
||||||
entry.timeout = 0
|
entry.timeout = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for entry in self.cache.values_mut() {
|
||||||
|
if entry.peer == peer {
|
||||||
|
entry.timeout = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
self.housekeep()
|
self.housekeep()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +102,6 @@ impl<TS: TimeSource> ClaimTable<TS> {
|
||||||
|
|
||||||
pub fn housekeep(&mut self) {
|
pub fn housekeep(&mut self) {
|
||||||
let now = TS::now();
|
let now = TS::now();
|
||||||
// TODO: also remove cache when removing claims
|
|
||||||
self.cache.retain(|_, v| v.timeout >= now);
|
self.cache.retain(|_, v| v.timeout >= now);
|
||||||
self.claims.retain(|e| e.timeout >= now);
|
self.claims.retain(|e| e.timeout >= now);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue