diff --git a/performance.md b/performance.md index 736ff47..c4bd9c0 100644 --- a/performance.md +++ b/performance.md @@ -69,15 +69,12 @@ For all the test, the best average RTT out of 3 runs is selected. The latency is assumed to be half of the RTT. -| Payload size | 100 bytes | 500 bytes | 1000 bytes | -| ----------------------------- | --------- | --------- | ---------- | -| Without VpnCloud | 158 µs | 164 µs | 171 µs | -| Unencrypted VpnCloud | 208 µs | 225 µs | 236 µs | -| Difference | +50 µs | +61 µs | +65 µs | -| Encrypted VpnCloud (ChaCha20) | 229 µs | 242 µs | 259 µs | -| Difference | +21 µs | +17 µs | +23 µs | -| Encrypted VpnCloud (AES256) | 223 µs | 232 µs | 249 µs | -| Difference | +15 µs | +7 µs | +13 µs | +| Payload size | 100 bytes | 500 bytes | 1000 bytes | +| ----------------------------- | --------------- | --------------- | --------------- | +| Without VpnCloud | 158 µs | 164 µs | 171 µs | +| Unencrypted VpnCloud | 208 µs (+50 µs) | 225 µs (+61 µs) | 236 µs (+65 µs) | +| Encrypted VpnCloud (ChaCha20) | 229 µs (+21 µs) | 242 µs (+17 µs) | 259 µs (+23 µs) | +| Encrypted VpnCloud (AES256) | 223 µs (+15 µs) | 232 µs ( +7 µs) | 249 µs (+13 µs) | ### Conclusion diff --git a/src/cloud.rs b/src/cloud.rs index 3eff503..b3f921c 100644 --- a/src/cloud.rs +++ b/src/cloud.rs @@ -11,13 +11,13 @@ use epoll; use nix::sys::signal::{SIGTERM, SIGQUIT, SIGINT}; use signal::trap::Trap; use time::SteadyTime; -use rand::random; +use rand::{random, sample, thread_rng}; use super::types::{Table, Protocol, Range, Error, NetworkId, NodeId}; use super::device::Device; use super::udpmessage::{encode, decode, Options, Message}; use super::crypto::Crypto; -use super::util::{now, Time, Duration, time_rand}; +use super::util::{now, Time, Duration}; struct PeerList { timeout: Duration, @@ -67,15 +67,8 @@ impl PeerList { } #[inline] - fn subset(&self, size: usize, seed: u32) -> Vec { - let mut peers = self.as_vec(); - let mut psrng = seed; - let len = peers.len(); - for i in size..len { - peers.swap_remove(psrng as usize % (len - i)); - psrng = ((1664525 as u64) * (psrng as u64) + (1013904223 as u64)) as u32; - } - peers + fn subset(&self, size: usize) -> Vec { + sample(&mut thread_rng(), self.as_vec(), size) } #[inline] @@ -165,8 +158,11 @@ impl GenericCloud

{ } debug!("Connecting to {}", addr); if reconnect { - let addr = addr.to_socket_addrs().unwrap().next().unwrap(); - self.reconnect_peers.push(addr); + if let Ok(mut addrs) = addr.to_socket_addrs() { + while let Some(addr) = addrs.next() { + self.reconnect_peers.push(addr); + } + } } let addrs = self.addresses.clone(); let node_id = self.node_id.clone(); @@ -185,7 +181,7 @@ impl GenericCloud

{ peer_num = 10; } } - let peers = self.peers.subset(peer_num, time_rand() as u32); + let peers = self.peers.subset(peer_num); let msg = Message::Peers(peers); for addr in &self.peers.as_vec() { try!(self.send_msg(addr, &msg)); diff --git a/src/crypto.rs b/src/crypto.rs index df511f2..0949eb8 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -143,7 +143,9 @@ fn inc_nonce_12(nonce: &mut [u8; 12]) { impl Crypto { pub fn init() { - unsafe { sodium_init() }; + if unsafe { sodium_init() } != 0 { + fail!("Failed to initialize crypto library"); + } } pub fn sodium_version() -> String { @@ -196,7 +198,7 @@ impl Crypto { crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE ) }; if res != 0 { - panic!("Key derivation failed"); + fail!("Key derivation failed"); } match method { CryptoMethod::ChaCha20 => { diff --git a/src/util.rs b/src/util.rs index 6d923d3..010449b 100644 --- a/src/util.rs +++ b/src/util.rs @@ -11,13 +11,6 @@ pub fn now() -> Time { tv.tv_sec } -#[inline] -pub fn time_rand() -> i64 { - let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 }; - unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut tv); } - tv.tv_sec ^ tv.tv_nsec -} - #[inline(always)] pub fn memcopy(src: &[u8], dst: &mut[u8]) { assert!(dst.len() >= src.len()); diff --git a/vpncloud.md b/vpncloud.md index a0260d5..32ce977 100644 --- a/vpncloud.md +++ b/vpncloud.md @@ -182,8 +182,8 @@ vpncloud -t tun -c REMOTE_HOST:PORT --subnet 10.0.0.X/32 --ifup 'ifconfig $IFNAM ### Important notes - It is important to configure the interface in a way that all addresses on the - VPN can be reached directly. E.g. if addresses 10.0.0.1 and 10.0.0.2 are used, - the interface needs to be configured as /24. + VPN can be reached directly. E.g. if addresses 10.0.0.1, 10.0.0.2 and so on + are used, the interface needs to be configured as /24. For TUN devices, this means that the prefix length of the subnets must be different than the prefix length that the interface is configured with. @@ -201,12 +201,12 @@ vpncloud -t tun -c REMOTE_HOST:PORT --subnet 10.0.0.X/32 --ifup 'ifconfig $IFNAM primitives are expected to be very secure, their application has not been reviewed. The shared key is hashed using *ScryptSalsa208Sha256* to derive a key, - which is used to encrypt the payload of messages using *ChaCha20Poly1305*. - The encryption includes an authentication that also protects the header and - all additional headers. + which is used to encrypt the payload of messages using *ChaCha20Poly1305* or + *AES256-GCM*. The encryption includes an authentication that also protects the + header and all additional headers. This method does only protect against attacks on single messages but not - on attacks that manipulate the message series itself (i.e. suppress messages, - reorder them, and duplicate them). + against attacks that manipulate the message series itself (i.e. suppress + messages, reorder them, or duplicate them). ## NETWORK PROTOCOL @@ -300,8 +300,11 @@ field will follow: and the later 2 bytes are port number (both in network byte order). * **Initial message** (message type 2): - This packet contains all the local subnets claimed by the nodes. - Its first byte marks the stage of the initial handshake process. After that, + This packet contains the following information: + - A random node id to distinguish different nodes + - All the local subnets claimed by the nodes + Its first byte marks the stage of the initial handshake process. + The next 16 bytes contain the unique node id. After that, the list of local subnets follows. The subnet list is encoded in the following way: Its first byte of data contains the number of encoded subnets that follow. After that, the given @@ -328,8 +331,7 @@ of their peers to spread this information and to avoid peer timeouts. To avoid the cubic growth of management traffic, nodes should at a certain network size start sending partial peer lists instead of the full list. A reasonable number would be the square root of the number of peers. -The subsets can be selected using round robin (making sure all peers eventually -receive all information) or randomly. +The subsets should be selected randomly. Nodes should remove peers from their peer list after a certain period of inactivity or when receiving a **closing message**. Before shutting down, nodes