Updated dependencies, rustfmt

This commit is contained in:
Dennis Schwerdel 2019-12-04 09:32:35 +01:00
parent b279c43718
commit 509ab1504e
26 changed files with 1328 additions and 959 deletions

View File

@ -2,6 +2,11 @@
This project follows [semantic versioning](http://semver.org).
### Unreleased
- [changed] Rust version 1.41.0
- [changed] Updated dependencies
### v1.0.0 (2019-03-21)
- [added] Added ability to publish small beacons for rendezvous

733
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -18,16 +18,16 @@ serde = "1.0"
serde_derive = "1.0"
serde_yaml = "0.8"
log = { version = "0.4", features = ["std"] }
signal = "0.6"
signal = "0.7"
libc = "0.2"
rand = "0.6"
rand = "0.7"
fnv = "1"
net2 = "0.2"
yaml-rust = "0.4"
igd = "^0.8.2"
igd = "0.9"
siphasher = "0.3"
daemonize = "0.3"
ring = "0.14"
daemonize = "0.4"
ring = "0.16"
base-62 = "0.1"
[build-dependencies]

17
rustfmt.toml Normal file
View File

@ -0,0 +1,17 @@
use_small_heuristics = "Max"
comment_width = 120
fn_args_layout = "Compressed"
where_single_line = true
merge_imports = true
max_width = 120
force_multiline_blocks = true
normalize_comments = true
trailing_comma = "Never"
trailing_semicolon = false
use_field_init_shorthand = true
use_try_shorthand = true
wrap_comments = true
overflow_delimited_expr = true
blank_lines_upper_bound = 2
normalize_doc_attributes = true
inline_attribute_width = 50

View File

@ -5,20 +5,24 @@
use base_62;
use ring::digest;
use std::num::Wrapping;
use std::path::Path;
use std::io::{self, Write, Read};
use std::fs::{self, Permissions, File};
use std::os::unix::fs::PermissionsExt;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::marker::PhantomData;
use std::mem;
use std::thread;
use std::process::{Command, Stdio};
use std::{
fs::{self, File, Permissions},
io::{self, Read, Write},
marker::PhantomData,
mem,
num::Wrapping,
os::unix::fs::PermissionsExt,
path::Path,
process::{Command, Stdio},
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex
},
thread
};
use super::util::{Encoder, TimeSource};
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr, SocketAddrV6, Ipv6Addr};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
const TYPE_BEGIN: u8 = 0;
@ -52,10 +56,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
Self {
magic: magic.to_owned(),
shared_key: shared_key.to_owned(),
future_peers: Arc::new(FutureResult {
has_result: AtomicBool::new(false),
result: Mutex::new(Vec::new())
}),
future_peers: Arc::new(FutureResult { has_result: AtomicBool::new(false), result: Mutex::new(Vec::new()) }),
_dummy_ts: PhantomData
}
}
@ -95,10 +96,9 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
fn end(&self) -> String {
base_62::encode(&self.get_keystream(TYPE_END, 0, 0))[0..5].to_string()
}
fn encrypt_data(&self, data: &mut Vec<u8>) {
// Note: the 1 byte seed is only meant to protect from random changes,
// not malicious ones. For full protection, at least 8 bytes (~12
// not malicious ones. For full protection, at least 8 bytes (~12
// characters) would be needed.
let seed = sha512(data as &[u8])[0];
self.mask_with_keystream(data as &mut [u8], TYPE_DATA, seed);
@ -163,9 +163,9 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
return peers
}
if !self.decrypt_data(&mut data) {
return peers
return peers
}
let then = Wrapping(Encoder::read_u16(&data[pos..=pos+1]));
let then = Wrapping(Encoder::read_u16(&data[pos..=pos + 1]));
if let Some(ttl) = ttl_hours {
let now = Wrapping(Self::now_hour_16());
if now - then > Wrapping(ttl) && then - now > Wrapping(ttl) {
@ -180,24 +180,28 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
}
for _ in 0..v4count {
assert!(data.len() >= pos + 6);
let dat = &data[pos..pos+6];
let dat = &data[pos..pos + 6];
pos += 6;
let port = Encoder::read_u16(&dat[4..]);
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(dat[0], dat[1], dat[2], dat[3]), port));
peers.push(addr);
}
let v6count = (data.len() - pos)/18;
let v6count = (data.len() - pos) / 18;
for _ in 0..v6count {
assert!(data.len() >= pos + 18);
let dat = &data[pos..pos+18];
let dat = &data[pos..pos + 18];
pos += 18;
let mut ip = [0u16; 8];
for i in 0..8 {
ip[i] = Encoder::read_u16(&dat[i*2..i*2+2]);
ip[i] = Encoder::read_u16(&dat[i * 2..i * 2 + 2]);
}
let port = Encoder::read_u16(&dat[16..]);
let addr = SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(ip[0], ip[1], ip[2],
ip[3], ip[4], ip[5], ip[6], ip[7]), port, 0, 0));
let addr = SocketAddr::V6(SocketAddrV6::new(
Ipv6Addr::new(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]),
port,
0,
0
));
peers.push(addr);
}
peers
@ -222,9 +226,15 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
let end = self.end();
let beacon = format!("{}{}{}", begin, data, end);
debug!("Calling beacon command: {}", cmd);
let process = Command::new("sh").args(&["-c", cmd])
.env("begin", begin).env("data", data).env("end", end).env("beacon", beacon)
.stdout(Stdio::piped()).stderr(Stdio::piped()).spawn()?;
let process = Command::new("sh")
.args(&["-c", cmd])
.env("begin", begin)
.env("data", data)
.env("end", end)
.env("beacon", beacon)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
thread::spawn(move || {
let output = process.wait_with_output().expect("Failed to wait on child");
if !output.status.success() {
@ -256,7 +266,9 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
peers
}
pub fn read_from_file<P: AsRef<Path>>(&self, path: P, ttl_hours: Option<u16>) -> Result<Vec<SocketAddr>, io::Error> {
pub fn read_from_file<P: AsRef<Path>>(
&self, path: P, ttl_hours: Option<u16>
) -> Result<Vec<SocketAddr>, io::Error> {
let mut f = File::open(&path)?;
let mut contents = String::new();
f.read_to_string(&mut contents)?;
@ -267,9 +279,13 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
let begin = self.begin();
let end = self.end();
debug!("Calling beacon command: {}", cmd);
let process = Command::new("sh").args(&["-c", cmd])
.env("begin", begin).env("end", end)
.stdout(Stdio::piped()).stderr(Stdio::piped()).spawn()?;
let process = Command::new("sh")
.args(&["-c", cmd])
.env("begin", begin)
.env("end", end)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
let this = self.clone();
thread::spawn(move || {
let output = process.wait_with_output().expect("Failed to wait on child");
@ -299,14 +315,14 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
}
#[cfg(test)] use crate::util::MockTimeSource;
#[cfg(test)] use std::str::FromStr;
#[cfg(test)] use std::time::Duration;
#[cfg(test)] use tempfile;
#[cfg(test)] use crate::util::MockTimeSource;
#[test]
fn encode() {
MockTimeSource::set_time(2000*3600);
MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
@ -322,77 +338,92 @@ fn encode() {
#[test]
fn decode() {
MockTimeSource::set_time(2000*3600);
MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
peers.push(SocketAddr::from_str("6.6.6.6:53").unwrap());
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None)));
peers.push(SocketAddr::from_str("[::1]:5678").unwrap());
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("juWwKjF5qZG7PE5imnpi5XARaXnP3UsMsGBLxM4FNFDzvjlKt1SO55LN", None)));
assert_eq!(
format!("{:?}", peers),
format!("{:?}", ser.decode("juWwKjF5qZG7PE5imnpi5XARaXnP3UsMsGBLxM4FNFDzvjlKt1SO55LN", None))
);
}
#[test]
fn decode_split() {
MockTimeSource::set_time(2000*3600);
MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
peers.push(SocketAddr::from_str("6.6.6.6:53").unwrap());
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("juWwK-hj.VT:Yj bw\tJj\ntY(AZ)lM[fE]j7üIDäO55LN", None)));
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("j -, \nuW--wKhjVTYjbwJjtYAZlMfEj7IDO(5}5ÖÄÜ\nLN", None)));
assert_eq!(
format!("{:?}", peers),
format!("{:?}", ser.decode("juWwK-hj.VT:Yj bw\tJj\ntY(AZ)lM[fE]j7üIDäO55LN", None))
);
assert_eq!(
format!("{:?}", peers),
format!("{:?}", ser.decode("j -, \nuW--wKhjVTYjbwJjtYAZlMfEj7IDO(5}5ÖÄÜ\nLN", None))
);
}
#[test]
fn decode_offset() {
MockTimeSource::set_time(2000*3600);
MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
peers.push(SocketAddr::from_str("6.6.6.6:53").unwrap());
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("Hello World: juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN! End of the World", None)));
assert_eq!(
format!("{:?}", peers),
format!("{:?}", ser.decode("Hello World: juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN! End of the World", None))
);
}
#[test]
fn decode_multiple() {
MockTimeSource::set_time(2000*3600);
MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
peers.push(SocketAddr::from_str("6.6.6.6:53").unwrap());
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("juWwKkBEVBp9SsDiN3BO55LN juWwKtGGPQz1gXIBd68O55LN", None)));
assert_eq!(
format!("{:?}", peers),
format!("{:?}", ser.decode("juWwKkBEVBp9SsDiN3BO55LN juWwKtGGPQz1gXIBd68O55LN", None))
);
}
#[test]
fn decode_ttl() {
MockTimeSource::set_time(2000*3600);
MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
peers.push(SocketAddr::from_str("6.6.6.6:53").unwrap());
MockTimeSource::set_time(2000*3600);
MockTimeSource::set_time(2000 * 3600);
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None).len());
MockTimeSource::set_time(2100*3600);
MockTimeSource::set_time(2100 * 3600);
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None).len());
MockTimeSource::set_time(2005*3600);
MockTimeSource::set_time(2005 * 3600);
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None).len());
MockTimeSource::set_time(1995*3600);
MockTimeSource::set_time(1995 * 3600);
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None).len());
MockTimeSource::set_time(2000*3600);
MockTimeSource::set_time(2000 * 3600);
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24)).len());
MockTimeSource::set_time(1995*3600);
MockTimeSource::set_time(1995 * 3600);
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24)).len());
MockTimeSource::set_time(2005*3600);
MockTimeSource::set_time(2005 * 3600);
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24)).len());
MockTimeSource::set_time(2100*3600);
MockTimeSource::set_time(2100 * 3600);
assert_eq!(0, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24)).len());
MockTimeSource::set_time(1900*3600);
MockTimeSource::set_time(1900 * 3600);
assert_eq!(0, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24)).len());
}
#[test]
fn decode_invalid() {
MockTimeSource::set_time(2000*3600);
MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
assert_eq!(0, ser.decode("", None).len());
assert_eq!(0, ser.decode("juWwKO55LN", None).len());
@ -406,7 +437,7 @@ fn decode_invalid() {
#[test]
fn encode_decode() {
MockTimeSource::set_time(2000*3600);
MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
@ -418,7 +449,7 @@ fn encode_decode() {
#[test]
fn encode_decode_file() {
MockTimeSource::set_time(2000*3600);
MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
@ -432,7 +463,7 @@ fn encode_decode_file() {
#[test]
fn encode_decode_cmd() {
MockTimeSource::set_time(2000*3600);
MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());

View File

@ -4,22 +4,25 @@
use test::Bencher;
use std::str::FromStr;
use std::net::{UdpSocket, ToSocketAddrs, Ipv4Addr, SocketAddr, SocketAddrV4};
use std::{
net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs, UdpSocket},
str::FromStr
};
use super::MAGIC;
use super::config::Config;
use super::cloud::GenericCloud;
use super::device::Type;
use super::udpmessage::{Message, encode, decode};
use super::crypto::{Crypto, CryptoMethod};
use super::ethernet::{self, SwitchTable};
use super::types::{Address, Table, Protocol};
use super::ip::Packet;
use super::util::{TimeSource, SystemTimeSource, MockTimeSource};
use super::poll::WaitImpl;
use super::device::TunTapDevice;
use super::net::MockSocket;
use super::{
cloud::GenericCloud,
config::Config,
crypto::{Crypto, CryptoMethod},
device::{TunTapDevice, Type},
ethernet::{self, SwitchTable},
ip::Packet,
net::MockSocket,
poll::WaitImpl,
types::{Address, Protocol, Table},
udpmessage::{decode, encode, Message},
util::{MockTimeSource, SystemTimeSource, TimeSource},
MAGIC
};
#[bench]
fn crypto_chacha20(b: &mut Bencher) {
@ -99,37 +102,29 @@ fn switch_lookup(b: &mut Bencher) {
fn ethernet_parse(b: &mut Bencher) {
let mut data = [0; 1500];
data[5] = 45;
b.iter(|| {
ethernet::Frame::parse(&data).unwrap()
});
b.iter(|| ethernet::Frame::parse(&data).unwrap());
b.bytes = 1400;
}
#[bench]
fn ipv4_parse(b: &mut Bencher) {
let mut data = [0; 1500];
data[0] = 4*16;
b.iter(|| {
Packet::parse(&data).unwrap()
});
data[0] = 4 * 16;
b.iter(|| Packet::parse(&data).unwrap());
b.bytes = 1400;
}
#[bench]
fn ipv6_parse(b: &mut Bencher) {
let mut data = [0; 1500];
data[0] = 6*16;
b.iter(|| {
Packet::parse(&data).unwrap()
});
data[0] = 6 * 16;
b.iter(|| Packet::parse(&data).unwrap());
b.bytes = 1400;
}
#[bench]
fn now(b: &mut Bencher) {
b.iter(|| {
SystemTimeSource::now()
});
b.iter(|| SystemTimeSource::now());
b.bytes = 1400;
}
@ -139,9 +134,7 @@ fn epoll_wait(b: &mut Bencher) {
let socketv6 = UdpSocket::bind("[::]:0").unwrap();
let device = TunTapDevice::dummy("dummy", "/dev/zero", Type::Dummy).unwrap();
let mut waiter = WaitImpl::testing(&socketv4, &socketv6, &device, 1000).unwrap();
b.iter(|| {
assert!(waiter.next().is_some())
});
b.iter(|| assert!(waiter.next().is_some()));
b.bytes = 1400;
}
@ -152,7 +145,11 @@ fn create_test_node() -> TestNode {
&Config::default(),
TunTapDevice::dummy("dummy", "/dev/null", Type::Tap).unwrap(),
SwitchTable::new(1800, 10),
true, true, vec![], Crypto::None, None
true,
true,
vec![],
Crypto::None,
None
)
}
@ -161,9 +158,7 @@ fn handle_interface_data(b: &mut Bencher) {
let mut node = create_test_node();
let mut data = [0; 1500];
data[105] = 45;
b.iter(|| {
node.handle_interface_data(&mut data, 100, 1400).unwrap()
});
b.iter(|| node.handle_interface_data(&mut data, 100, 1400).unwrap());
b.bytes = 1400;
}
@ -173,9 +168,7 @@ fn handle_net_message(b: &mut Bencher) {
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1));
let mut data = [0; 1500];
data[105] = 45;
b.iter(|| {
node.handle_net_message(addr.clone(), Message::Data(&mut data, 0, 1400)).unwrap()
});
b.iter(|| node.handle_net_message(addr.clone(), Message::Data(&mut data, 0, 1400)).unwrap());
b.bytes = 1400;
}
@ -184,8 +177,6 @@ fn udp_send(b: &mut Bencher) {
let sock = UdpSocket::bind("127.0.0.1:0").unwrap();
let data = [0; 1400];
let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1);
b.iter(|| {
sock.send_to(&data, &addr).unwrap()
});
b.iter(|| sock.send_to(&data, &addr).unwrap());
b.bytes = 1400;
}

View File

@ -2,30 +2,34 @@
// Copyright (C) 2015-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::net::{SocketAddr, ToSocketAddrs};
use std::collections::HashMap;
use std::io::{self, Write};
use std::fmt;
use std::marker::PhantomData;
use std::hash::BuildHasherDefault;
use std::cmp::min;
use std::fs::{self, File, Permissions};
use std::os::unix::fs::PermissionsExt;
use std::{
cmp::min,
collections::HashMap,
fmt,
fs::{self, File, Permissions},
hash::BuildHasherDefault,
io::{self, Write},
marker::PhantomData,
net::{SocketAddr, ToSocketAddrs},
os::unix::fs::PermissionsExt
};
use fnv::FnvHasher;
use rand::{prelude::*, random, thread_rng};
use super::config::Config;
use super::types::{Table, Protocol, Range, Error, HeaderMagic, NodeId};
use super::device::Device;
use super::udpmessage::{encode, decode, Message};
use super::crypto::Crypto;
use super::port_forwarding::PortForwarding;
use super::util::{TimeSource, Time, Duration, resolve, CtrlC};
use super::poll::{WaitImpl, WaitResult};
use super::traffic::TrafficStats;
use super::beacon::BeaconSerializer;
use super::net::Socket;
use super::{
beacon::BeaconSerializer,
config::Config,
crypto::Crypto,
device::Device,
net::Socket,
poll::{WaitImpl, WaitResult},
port_forwarding::PortForwarding,
traffic::TrafficStats,
types::{Error, HeaderMagic, NodeId, Protocol, Range, Table},
udpmessage::{decode, encode, Message},
util::{resolve, CtrlC, Duration, Time, TimeSource}
};
pub type Hash = BuildHasherDefault<FnvHasher>;
@ -37,7 +41,7 @@ pub const STATS_INTERVAL: Time = 60;
struct PeerData {
timeout: Time,
node_id: NodeId,
alt_addrs: Vec<SocketAddr>,
alt_addrs: Vec<SocketAddr>
}
pub struct PeerList<TS: TimeSource> {
@ -50,7 +54,7 @@ pub struct PeerList<TS: TimeSource> {
impl<TS: TimeSource> PeerList<TS> {
fn new(timeout: Duration) -> PeerList<TS> {
PeerList{
PeerList {
peers: HashMap::default(),
timeout,
nodes: HashMap::default(),
@ -86,10 +90,10 @@ impl<TS: TimeSource> PeerList<TS> {
}
#[inline]
pub fn is_connected<Addr: ToSocketAddrs+fmt::Debug>(&self, addr: Addr) -> Result<bool, Error> {
pub fn is_connected<Addr: ToSocketAddrs + fmt::Debug>(&self, addr: Addr) -> Result<bool, Error> {
for addr in resolve(&addr)? {
if self.contains_addr(&addr) {
return Ok(true);
return Ok(true)
}
}
Ok(false)
@ -117,7 +121,7 @@ impl<TS: TimeSource> PeerList<TS> {
#[inline]
fn refresh(&mut self, addr: &SocketAddr) {
if let Some(ref mut data) = self.peers.get_mut(addr) {
data.timeout = TS::now()+Time::from(self.timeout);
data.timeout = TS::now() + Time::from(self.timeout);
}
}
@ -184,7 +188,7 @@ impl<TS: TimeSource> PeerList<TS> {
writeln!(out, "Peers:")?;
let now = TS::now();
for (addr, data) in &self.peers {
writeln!(out, " - {} (ttl: {} s)", addr, data.timeout-now)?;
writeln!(out, " - {} (ttl: {} s)", addr, data.timeout - now)?;
}
Ok(())
}
@ -218,7 +222,7 @@ pub struct GenericCloud<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSou
crypto: Crypto,
next_peerlist: Time,
update_freq: Duration,
buffer_out: [u8; 64*1024],
buffer_out: [u8; 64 * 1024],
next_housekeep: Time,
next_stats_out: Time,
next_beacon: Time,
@ -231,10 +235,11 @@ pub struct GenericCloud<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSou
impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D, P, T, S, TS> {
#[allow(clippy::too_many_arguments)]
pub fn new(config: &Config, device: D, table: T,
learning: bool, broadcast: bool, addresses: Vec<Range>,
crypto: Crypto, port_forwarding: Option<PortForwarding>
) -> Self {
pub fn new(
config: &Config, device: D, table: T, learning: bool, broadcast: bool, addresses: Vec<Range>, crypto: Crypto,
port_forwarding: Option<PortForwarding>
) -> Self
{
let socket4 = match S::listen_v4("0.0.0.0", config.port) {
Ok(socket) => socket,
Err(err) => fail!("Failed to open ipv4 address 0.0.0.0:{}: {}", config.port, err)
@ -244,7 +249,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
Err(err) => fail!("Failed to open ipv6 address ::{}: {}", config.port, err)
};
let now = TS::now();
let mut res = GenericCloud{
let mut res = GenericCloud {
magic: config.get_magic(),
node_id: random(),
peers: PeerList::new(config.peer_timeout),
@ -259,7 +264,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
device,
next_peerlist: now,
update_freq: config.get_keepalive(),
buffer_out: [0; 64*1024],
buffer_out: [0; 64 * 1024],
next_housekeep: now,
next_stats_out: now + STATS_INTERVAL,
next_beacon: now,
@ -299,7 +304,9 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
};
match socket.send(msg_data, *addr) {
Ok(written) if written == msg_data.len() => Ok(()),
Ok(_) => Err(Error::Socket("Sent out truncated packet", io::Error::new(io::ErrorKind::Other, "truncated"))),
Ok(_) => {
Err(Error::Socket("Sent out truncated packet", io::Error::new(io::ErrorKind::Other, "truncated")))
}
Err(e) => Err(Error::Socket("IOError when sending", e))
}?
}
@ -352,7 +359,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
/// connect to the peer if it is not already connected.
pub fn add_reconnect_peer(&mut self, add: String) {
let now = TS::now();
let resolved = match resolve(&add as &str) {
let resolved = match resolve(&add as &str) {
Ok(addrs) => addrs,
Err(err) => {
warn!("Failed to resolve {}: {:?}", add, err);
@ -363,7 +370,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
address: add,
tries: 0,
timeout: 1,
resolved: resolved,
resolved,
next_resolve: now,
next: now
})
@ -374,10 +381,10 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
/// # Errors
/// Returns an `Error::SocketError` if the given address is a name that failed to resolve to
/// actual addresses.
fn is_own_address<Addr: ToSocketAddrs+fmt::Debug>(&self, addr: Addr) -> Result<bool, Error> {
fn is_own_address<Addr: ToSocketAddrs + fmt::Debug>(&self, addr: Addr) -> Result<bool, Error> {
for addr in resolve(&addr)? {
if self.own_addresses.contains(&addr) {
return Ok(true);
return Ok(true)
}
}
Ok(false)
@ -391,7 +398,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
///
/// # Errors
/// This method returns `Error::NameError` if the address is a name that fails to resolve.
pub fn connect<Addr: ToSocketAddrs+fmt::Debug+Clone>(&mut self, addr: Addr) -> Result<(), Error> {
pub fn connect<Addr: ToSocketAddrs + fmt::Debug + Clone>(&mut self, addr: Addr) -> Result<(), Error> {
if self.peers.is_connected(addr.clone())? || self.is_own_address(addr.clone())? {
return Ok(())
}
@ -523,11 +530,15 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
/// Stores the beacon
fn store_beacon(&mut self) -> Result<(), Error> {
if let Some(ref path) = self.config.beacon_store {
let peers: Vec<_> = self.own_addresses.choose_multiple(&mut thread_rng(),3).cloned().collect();
let peers: Vec<_> = self.own_addresses.choose_multiple(&mut thread_rng(), 3).cloned().collect();
if path.starts_with('|') {
self.beacon_serializer.write_to_cmd(&peers, &path[1..]).map_err(|e| Error::Beacon("Failed to call beacon command", e))?;
self.beacon_serializer
.write_to_cmd(&peers, &path[1..])
.map_err(|e| Error::Beacon("Failed to call beacon command", e))?;
} else {
self.beacon_serializer.write_to_file(&peers, &path).map_err(|e| Error::Beacon("Failed to write beacon to file", e))?;
self.beacon_serializer
.write_to_file(&peers, &path)
.map_err(|e| Error::Beacon("Failed to write beacon to file", e))?;
}
}
Ok(())
@ -538,10 +549,15 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
let peers;
if let Some(ref path) = self.config.beacon_load {
if path.starts_with('|') {
self.beacon_serializer.read_from_cmd(&path[1..], Some(50)).map_err(|e| Error::Beacon("Failed to call beacon command", e))?;
self.beacon_serializer
.read_from_cmd(&path[1..], Some(50))
.map_err(|e| Error::Beacon("Failed to call beacon command", e))?;
return Ok(())
} else {
peers = self.beacon_serializer.read_from_file(&path, Some(50)).map_err(|e| Error::Beacon("Failed to read beacon from file", e))?;
peers = self
.beacon_serializer
.read_from_file(&path, Some(50))
.map_err(|e| Error::Beacon("Failed to read beacon from file", e))?;
}
} else {
return Ok(())
@ -555,7 +571,9 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
/// Calculates, resets and writes out the statistics to a file
fn write_out_stats(&mut self) -> Result<(), io::Error> {
if self.config.stats_file.is_none() { return Ok(()) }
if self.config.stats_file.is_none() {
return Ok(())
}
debug!("Writing out stats");
let mut f = File::create(self.config.stats_file.as_ref().unwrap())?;
self.peers.write_out(&mut f)?;
@ -586,10 +604,11 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
/// - with `Error::SocketError` if sending a message fails
pub fn handle_interface_data(&mut self, payload: &mut [u8], start: usize, end: usize) -> Result<(), Error> {
let (src, dst) = P::parse(&payload[start..end])?;
debug!("Read data from interface: src: {}, dst: {}, {} bytes", src, dst, end-start);
self.traffic.count_out_payload(dst, src, end-start);
debug!("Read data from interface: src: {}, dst: {}, {} bytes", src, dst, end - start);
self.traffic.count_out_payload(dst, src, end - start);
match self.table.lookup(&dst) {
Some(addr) => { // Peer found for destination
Some(addr) => {
// Peer found for destination
debug!("Found destination for {} => {}", dst, addr);
self.send_msg(addr, &mut Message::Data(payload, start, end))?;
if !self.peers.contains_addr(&addr) {
@ -599,7 +618,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
self.table.remove(&dst);
self.connect_sock(addr)?;
}
},
}
None => {
if self.broadcast {
debug!("No destination for {} found, broadcasting", dst);
@ -651,18 +670,18 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
match msg {
Message::Data(payload, start, end) => {
let (src, dst) = P::parse(&payload[start..end])?;
debug!("Writing data to device: {} bytes", end-start);
self.traffic.count_in_payload(src, dst, end-start);
debug!("Writing data to device: {} bytes", end - start);
self.traffic.count_in_payload(src, dst, end - start);
if let Err(e) = self.device.write(&mut payload[..end], start) {
error!("Failed to send via device: {}", e);
return Err(e);
return Err(e)
}
if self.learning {
// Learn single address
self.table.learn(src, None, peer);
}
// Not adding peer in this case to increase performance
},
}
Message::Peers(peers) => {
// Connect to sender if not connected
if !self.peers.contains_addr(&peer) {
@ -677,7 +696,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
}
// Refresh peer
self.peers.refresh(&peer);
},
}
Message::Init(stage, node_id, ranges) => {
// Avoid connecting to self
if node_id == self.node_id {
@ -697,12 +716,12 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
if stage == 0 {
let own_addrs = self.addresses.clone();
let own_node_id = self.node_id;
self.send_msg(peer, &mut Message::Init(stage+1, own_node_id, own_addrs))?;
self.send_msg(peer, &mut Message::Init(stage + 1, own_node_id, own_addrs))?;
}
// Send peers in any case
let peers = self.peers.as_vec();
self.send_msg(peer, &mut Message::Peers(peers))?;
},
}
Message::Close => {
self.peers.remove(&peer);
self.table.remove_all(&peer);
@ -745,7 +764,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
let mut start = 64;
let (offset, size) = try_fail!(self.device.read(&mut buffer[start..]), "Failed to read from tap device: {}");
start += offset;
if let Err(e) = self.handle_interface_data(buffer, start, start+size) {
if let Err(e) = self.handle_interface_data(buffer, start, start + size) {
error!("Error: {}", e);
}
}
@ -759,8 +778,9 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
/// Also, this method will call `housekeep` every second.
pub fn run(&mut self) {
let ctrlc = CtrlC::new();
let waiter = try_fail!(WaitImpl::new(&self.socket4, &self.socket6, &self.device, 1000), "Failed to setup poll: {}");
let mut buffer = [0; 64*1024];
let waiter =
try_fail!(WaitImpl::new(&self.socket4, &self.socket6, &self.device, 1000), "Failed to setup poll: {}");
let mut buffer = [0; 64 * 1024];
let mut poll_error = false;
for evt in waiter {
match evt {
@ -770,8 +790,8 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
}
error!("Poll wait failed: {}, retrying...", err);
poll_error = true;
},
WaitResult::Timeout => {},
}
WaitResult::Timeout => {}
WaitResult::SocketV4 => self.handle_socket_v4_event(&mut buffer),
WaitResult::SocketV6 => self.handle_socket_v6_event(&mut buffer),
WaitResult::Device => self.handle_device_event(&mut buffer)
@ -793,9 +813,9 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
}
#[cfg(test)] use super::device::MockDevice;
#[cfg(test)] use super::net::MockSocket;
#[cfg(test)] use super::util::MockTimeSource;
#[cfg(test)] use super::device::MockDevice;
#[cfg(test)]
impl<P: Protocol, T: Table> GenericCloud<MockDevice, P, T, MockSocket, MockTimeSource> {
@ -812,17 +832,17 @@ impl<P: Protocol, T: Table> GenericCloud<MockDevice, P, T, MockSocket, MockTimeS
}
pub fn trigger_socket_v4_event(&mut self) {
let mut buffer = [0; 64*1024];
let mut buffer = [0; 64 * 1024];
self.handle_socket_v4_event(&mut buffer);
}
pub fn trigger_socket_v6_event(&mut self) {
let mut buffer = [0; 64*1024];
let mut buffer = [0; 64 * 1024];
self.handle_socket_v6_event(&mut buffer);
}
pub fn trigger_device_event(&mut self) {
let mut buffer = [0; 64*1024];
let mut buffer = [0; 64 * 1024];
self.handle_device_event(&mut buffer);
}

View File

@ -2,15 +2,17 @@
// Copyright (C) 2015-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md)
use super::{MAGIC, Args};
use super::{Args, MAGIC};
use super::device::Type;
use super::types::{Mode, HeaderMagic};
use super::crypto::CryptoMethod;
use super::util::{Encoder, Duration};
use super::{
crypto::CryptoMethod,
device::Type,
types::{HeaderMagic, Mode},
util::{Duration, Encoder}
};
use std::hash::{Hash, Hasher};
use siphasher::sip::SipHasher24;
use std::hash::{Hash, Hasher};
const HASH_PREFIX: &str = "hash:";
@ -47,13 +49,23 @@ pub struct Config {
impl Default for Config {
fn default() -> Self {
Config {
device_type: Type::Tap, device_name: "vpncloud%d".to_string(), device_path: None,
ifup: None, ifdown: None,
crypto: CryptoMethod::ChaCha20, shared_key: None,
device_type: Type::Tap,
device_name: "vpncloud%d".to_string(),
device_path: None,
ifup: None,
ifdown: None,
crypto: CryptoMethod::ChaCha20,
shared_key: None,
magic: None,
port: 3210, peers: vec![], peer_timeout: 1800, keepalive: None,
beacon_store: None, beacon_load: None, beacon_interval: 3600,
mode: Mode::Normal, dst_timeout: 300,
port: 3210,
peers: vec![],
peer_timeout: 1800,
keepalive: None,
beacon_store: None,
beacon_load: None,
beacon_interval: 3600,
mode: Mode::Normal,
dst_timeout: 300,
subnets: vec![],
port_forwarding: true,
daemonize: false,
@ -235,7 +247,7 @@ impl Config {
pub fn get_keepalive(&self) -> Duration {
match self.keepalive {
Some(dur) => dur,
None => self.peer_timeout/2-60
None => self.peer_timeout / 2 - 60
}
}
}
@ -265,7 +277,7 @@ pub struct ConfigFile {
pub pid_file: Option<String>,
pub stats_file: Option<String>,
pub user: Option<String>,
pub group: Option<String>,
pub group: Option<String>
}
@ -299,7 +311,7 @@ group: nogroup
pid_file: /run/vpncloud.run
stats_file: /var/log/vpncloud.stats
";
assert_eq!(serde_yaml::from_str::<ConfigFile>(config_file).unwrap(), ConfigFile{
assert_eq!(serde_yaml::from_str::<ConfigFile>(config_file).unwrap(), ConfigFile {
device_type: Some(Type::Tun),
device_name: Some("vpncloud%d".to_string()),
device_path: Some("/dev/net/tun".to_string()),
@ -329,7 +341,7 @@ stats_file: /var/log/vpncloud.stats
#[test]
fn config_merge() {
let mut config = Config::default();
config.merge_file(ConfigFile{
config.merge_file(ConfigFile {
device_type: Some(Type::Tun),
device_name: Some("vpncloud%d".to_string()),
device_path: None,
@ -354,7 +366,7 @@ fn config_merge() {
pid_file: Some("/run/vpncloud.run".to_string()),
stats_file: Some("/var/log/vpncloud.stats".to_string())
});
assert_eq!(config, Config{
assert_eq!(config, Config {
device_type: Type::Tun,
device_name: "vpncloud%d".to_string(),
device_path: None,
@ -380,7 +392,7 @@ fn config_merge() {
stats_file: Some("/var/log/vpncloud.stats".to_string()),
..Default::default()
});
config.merge_args(Args{
config.merge_args(Args {
flag_type: Some(Type::Tap),
flag_device: Some("vpncloud0".to_string()),
flag_device_path: Some("/dev/null".to_string()),
@ -407,7 +419,7 @@ fn config_merge() {
flag_group: Some("root".to_string()),
..Default::default()
});
assert_eq!(config, Config{
assert_eq!(config, Config {
device_type: Type::Tap,
device_name: "vpncloud0".to_string(),
device_path: Some("/dev/null".to_string()),
@ -417,7 +429,11 @@ fn config_merge() {
crypto: CryptoMethod::ChaCha20,
shared_key: Some("anothersecret".to_string()),
port: 3211,
peers: vec!["remote.machine.foo:3210".to_string(), "remote.machine.bar:3210".to_string(), "another:3210".to_string()],
peers: vec![
"remote.machine.foo:3210".to_string(),
"remote.machine.bar:3210".to_string(),
"another:3210".to_string()
],
peer_timeout: 1801,
keepalive: Some(850),
dst_timeout: 301,

View File

@ -4,14 +4,10 @@
use std::num::NonZeroU32;
use ring::aead::*;
use ring::pbkdf2;
use ring::rand::*;
use ring::digest::*;
use ring::{aead::*, pbkdf2, rand::*};
use super::types::Error;
const SALT: &[u8; 32] = b"vpncloudVPNCLOUDvpncl0udVpnCloud";
const HEX_PREFIX: &str = "hex:";
const HASH_PREFIX: &str = "hash:";
@ -25,8 +21,7 @@ pub enum CryptoMethod {
}
pub struct CryptoData {
sealing_key: SealingKey,
opening_key: OpeningKey,
crypto_key: LessSafeKey,
nonce: Vec<u8>,
key: Vec<u8>
}
@ -51,14 +46,13 @@ fn inc_nonce(nonce: &mut [u8]) {
warn!("Nonce overflowed");
}
impl Crypto {
#[inline]
pub fn method(&self) -> u8 {
match *self {
Crypto::None => 0,
Crypto::ChaCha20Poly1305{..} => 1,
Crypto::AES256GCM{..} => 2
Crypto::ChaCha20Poly1305 { .. } => 1,
Crypto::AES256GCM { .. } => 2
}
}
@ -66,7 +60,7 @@ impl Crypto {
pub fn nonce_bytes(&self) -> usize {
match *self {
Crypto::None => 0,
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) => data.sealing_key.algorithm().nonce_len()
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) => data.crypto_key.algorithm().nonce_len()
}
}
@ -79,11 +73,11 @@ impl Crypto {
}
#[inline]
#[allow(unknown_lints,clippy::match_same_arms)]
#[allow(unknown_lints, clippy::match_same_arms)]
pub fn additional_bytes(&self) -> usize {
match *self {
Crypto::None => 0,
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) => data.sealing_key.algorithm().tag_len()
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) => data.crypto_key.algorithm().tag_len()
}
}
@ -102,18 +96,22 @@ impl Crypto {
fail!("Raw secret key must be exactly {} bytes long", algo.key_len());
}
for i in 0..algo.key_len() {
key[i] = try_fail!(u8::from_str_radix(&password[2*i..=2*i+1], 16), "Failed to parse raw secret key: {}");
key[i] = try_fail!(
u8::from_str_radix(&password[2 * i..=2 * i + 1], 16),
"Failed to parse raw secret key: {}"
);
}
} else {
let password = if password.starts_with(HASH_PREFIX) {
&password[HASH_PREFIX.len()..]
} else {
password
};
pbkdf2::derive(&SHA256, NonZeroU32::new(4096).unwrap(), SALT, password.as_bytes(), &mut key);
let password = if password.starts_with(HASH_PREFIX) { &password[HASH_PREFIX.len()..] } else { password };
pbkdf2::derive(
pbkdf2::PBKDF2_HMAC_SHA256,
NonZeroU32::new(4096).unwrap(),
SALT,
password.as_bytes(),
&mut key
);
}
let sealing_key = SealingKey::new(algo, &key[..algo.key_len()]).expect("Failed to create key");
let opening_key = OpeningKey::new(algo, &key[..algo.key_len()]).expect("Failed to create key");
let crypto_key = LessSafeKey::new(UnboundKey::new(algo, &key[..algo.key_len()]).expect("Failed to create key"));
let mut nonce: Vec<u8> = Vec::with_capacity(algo.nonce_len());
for _ in 0..algo.nonce_len() {
nonce.push(0);
@ -122,7 +120,7 @@ impl Crypto {
if SystemRandom::new().fill(&mut nonce[1..]).is_err() {
fail!("Randomizing nonce failed");
}
let data = CryptoData { sealing_key, opening_key, nonce, key };
let data = CryptoData { crypto_key, nonce, key };
match method {
CryptoMethod::ChaCha20 => Crypto::ChaCha20Poly1305(data),
CryptoMethod::AES256 => Crypto::AES256GCM(data)
@ -134,9 +132,9 @@ impl Crypto {
Crypto::None => Ok(buf.len()),
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) => {
let nonce = Nonce::try_assume_unique_for_key(nonce).unwrap();
match open_in_place(&data.opening_key, nonce, Aad::from(header), 0, buf) {
Ok(plaintext) => Ok(plaintext.len()),
Err(_) => Err(Error::Crypto("Failed to decrypt"))
match data.crypto_key.open_in_place(nonce, Aad::from(header), buf) {
Ok(plaintext) => Ok(plaintext.len()),
Err(_) => Err(Error::Crypto("Failed to decrypt"))
}
}
}