Compare commits

..

3 Commits

Author SHA1 Message Date
Dennis Schwerdel 04d934491c Merge branch 'master' of github.com:dswd/vpncloud 2019-12-04 09:34:15 +01:00
Dennis Schwerdel 509ab1504e Updated dependencies, rustfmt 2019-12-04 09:32:35 +01:00
Dennis Schwerdel b279c43718 gitignore 2019-03-22 14:00:52 +01:00
27 changed files with 1330 additions and 959 deletions

2
.gitignore vendored
View File

@ -7,3 +7,5 @@ deb/vpncloud/vpncloud.1*
Stats.ods Stats.ods
dist dist
builder/cache builder/cache
.idea
release.sh

View File

@ -2,6 +2,11 @@
This project follows [semantic versioning](http://semver.org). This project follows [semantic versioning](http://semver.org).
### Unreleased
- [changed] Rust version 1.41.0
- [changed] Updated dependencies
### v1.0.0 (2019-03-21) ### v1.0.0 (2019-03-21)
- [added] Added ability to publish small beacons for rendezvous - [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_derive = "1.0"
serde_yaml = "0.8" serde_yaml = "0.8"
log = { version = "0.4", features = ["std"] } log = { version = "0.4", features = ["std"] }
signal = "0.6" signal = "0.7"
libc = "0.2" libc = "0.2"
rand = "0.6" rand = "0.7"
fnv = "1" fnv = "1"
net2 = "0.2" net2 = "0.2"
yaml-rust = "0.4" yaml-rust = "0.4"
igd = "^0.8.2" igd = "0.9"
siphasher = "0.3" siphasher = "0.3"
daemonize = "0.3" daemonize = "0.4"
ring = "0.14" ring = "0.16"
base-62 = "0.1" base-62 = "0.1"
[build-dependencies] [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 base_62;
use ring::digest; use ring::digest;
use std::num::Wrapping; use std::{
use std::path::Path; fs::{self, File, Permissions},
use std::io::{self, Write, Read}; io::{self, Read, Write},
use std::fs::{self, Permissions, File}; marker::PhantomData,
use std::os::unix::fs::PermissionsExt; mem,
use std::sync::atomic::{AtomicBool, Ordering}; num::Wrapping,
use std::sync::{Arc, Mutex}; os::unix::fs::PermissionsExt,
use std::marker::PhantomData; path::Path,
use std::mem; process::{Command, Stdio},
use std::thread; sync::{
use std::process::{Command, Stdio}; atomic::{AtomicBool, Ordering},
Arc, Mutex
},
thread
};
use super::util::{Encoder, TimeSource}; 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; const TYPE_BEGIN: u8 = 0;
@ -52,10 +56,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
Self { Self {
magic: magic.to_owned(), magic: magic.to_owned(),
shared_key: shared_key.to_owned(), shared_key: shared_key.to_owned(),
future_peers: Arc::new(FutureResult { future_peers: Arc::new(FutureResult { has_result: AtomicBool::new(false), result: Mutex::new(Vec::new()) }),
has_result: AtomicBool::new(false),
result: Mutex::new(Vec::new())
}),
_dummy_ts: PhantomData _dummy_ts: PhantomData
} }
} }
@ -95,7 +96,6 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
fn end(&self) -> String { fn end(&self) -> String {
base_62::encode(&self.get_keystream(TYPE_END, 0, 0))[0..5].to_string() base_62::encode(&self.get_keystream(TYPE_END, 0, 0))[0..5].to_string()
} }
fn encrypt_data(&self, data: &mut Vec<u8>) { fn encrypt_data(&self, data: &mut Vec<u8>) {
// Note: the 1 byte seed is only meant to protect from random changes, // 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
@ -165,7 +165,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
if !self.decrypt_data(&mut data) { 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 { if let Some(ttl) = ttl_hours {
let now = Wrapping(Self::now_hour_16()); let now = Wrapping(Self::now_hour_16());
if now - then > Wrapping(ttl) && then - now > Wrapping(ttl) { if now - then > Wrapping(ttl) && then - now > Wrapping(ttl) {
@ -180,24 +180,28 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
} }
for _ in 0..v4count { for _ in 0..v4count {
assert!(data.len() >= pos + 6); assert!(data.len() >= pos + 6);
let dat = &data[pos..pos+6]; let dat = &data[pos..pos + 6];
pos += 6; pos += 6;
let port = Encoder::read_u16(&dat[4..]); let port = Encoder::read_u16(&dat[4..]);
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(dat[0], dat[1], dat[2], dat[3]), port)); let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(dat[0], dat[1], dat[2], dat[3]), port));
peers.push(addr); peers.push(addr);
} }
let v6count = (data.len() - pos)/18; let v6count = (data.len() - pos) / 18;
for _ in 0..v6count { for _ in 0..v6count {
assert!(data.len() >= pos + 18); assert!(data.len() >= pos + 18);
let dat = &data[pos..pos+18]; let dat = &data[pos..pos + 18];
pos += 18; pos += 18;
let mut ip = [0u16; 8]; let mut ip = [0u16; 8];
for i in 0..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 port = Encoder::read_u16(&dat[16..]);
let addr = SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(ip[0], ip[1], ip[2], let addr = SocketAddr::V6(SocketAddrV6::new(
ip[3], ip[4], ip[5], ip[6], ip[7]), port, 0, 0)); 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.push(addr);
} }
peers peers
@ -222,9 +226,15 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
let end = self.end(); let end = self.end();
let beacon = format!("{}{}{}", begin, data, end); let beacon = format!("{}{}{}", begin, data, end);
debug!("Calling beacon command: {}", cmd); debug!("Calling beacon command: {}", cmd);
let process = Command::new("sh").args(&["-c", cmd]) let process = Command::new("sh")
.env("begin", begin).env("data", data).env("end", end).env("beacon", beacon) .args(&["-c", cmd])
.stdout(Stdio::piped()).stderr(Stdio::piped()).spawn()?; .env("begin", begin)
.env("data", data)
.env("end", end)
.env("beacon", beacon)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
thread::spawn(move || { thread::spawn(move || {
let output = process.wait_with_output().expect("Failed to wait on child"); let output = process.wait_with_output().expect("Failed to wait on child");
if !output.status.success() { if !output.status.success() {
@ -256,7 +266,9 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
peers 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 f = File::open(&path)?;
let mut contents = String::new(); let mut contents = String::new();
f.read_to_string(&mut contents)?; f.read_to_string(&mut contents)?;
@ -267,9 +279,13 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
let begin = self.begin(); let begin = self.begin();
let end = self.end(); let end = self.end();
debug!("Calling beacon command: {}", cmd); debug!("Calling beacon command: {}", cmd);
let process = Command::new("sh").args(&["-c", cmd]) let process = Command::new("sh")
.env("begin", begin).env("end", end) .args(&["-c", cmd])
.stdout(Stdio::piped()).stderr(Stdio::piped()).spawn()?; .env("begin", begin)
.env("end", end)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
let this = self.clone(); let this = self.clone();
thread::spawn(move || { thread::spawn(move || {
let output = process.wait_with_output().expect("Failed to wait on child"); 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::str::FromStr;
#[cfg(test)] use std::time::Duration; #[cfg(test)] use std::time::Duration;
#[cfg(test)] use tempfile; #[cfg(test)] use tempfile;
#[cfg(test)] use crate::util::MockTimeSource;
#[test] #[test]
fn encode() { fn encode() {
MockTimeSource::set_time(2000*3600); MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey"); let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new(); let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap()); peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
@ -322,77 +338,92 @@ fn encode() {
#[test] #[test]
fn decode() { fn decode() {
MockTimeSource::set_time(2000*3600); MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey"); let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new(); let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap()); peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
peers.push(SocketAddr::from_str("6.6.6.6:53").unwrap()); peers.push(SocketAddr::from_str("6.6.6.6:53").unwrap());
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None))); assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None)));
peers.push(SocketAddr::from_str("[::1]:5678").unwrap()); 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] #[test]
fn decode_split() { fn decode_split() {
MockTimeSource::set_time(2000*3600); MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey"); let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new(); let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap()); peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
peers.push(SocketAddr::from_str("6.6.6.6:53").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!(
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("j -, \nuW--wKhjVTYjbwJjtYAZlMfEj7IDO(5}5ÖÄÜ\nLN", None))); 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] #[test]
fn decode_offset() { fn decode_offset() {
MockTimeSource::set_time(2000*3600); MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey"); let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new(); let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap()); peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
peers.push(SocketAddr::from_str("6.6.6.6:53").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] #[test]
fn decode_multiple() { fn decode_multiple() {
MockTimeSource::set_time(2000*3600); MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey"); let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new(); let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap()); peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
peers.push(SocketAddr::from_str("6.6.6.6:53").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] #[test]
fn decode_ttl() { fn decode_ttl() {
MockTimeSource::set_time(2000*3600); MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey"); let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new(); let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap()); peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
peers.push(SocketAddr::from_str("6.6.6.6:53").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()); 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()); 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()); 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()); 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()); 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()); 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()); 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()); 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()); assert_eq!(0, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24)).len());
} }
#[test] #[test]
fn decode_invalid() { fn decode_invalid() {
MockTimeSource::set_time(2000*3600); MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey"); let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
assert_eq!(0, ser.decode("", None).len()); assert_eq!(0, ser.decode("", None).len());
assert_eq!(0, ser.decode("juWwKO55LN", None).len()); assert_eq!(0, ser.decode("juWwKO55LN", None).len());
@ -406,7 +437,7 @@ fn decode_invalid() {
#[test] #[test]
fn encode_decode() { fn encode_decode() {
MockTimeSource::set_time(2000*3600); MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey"); let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new(); let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap()); peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
@ -418,7 +449,7 @@ fn encode_decode() {
#[test] #[test]
fn encode_decode_file() { fn encode_decode_file() {
MockTimeSource::set_time(2000*3600); MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey"); let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new(); let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap()); peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());
@ -432,7 +463,7 @@ fn encode_decode_file() {
#[test] #[test]
fn encode_decode_cmd() { fn encode_decode_cmd() {
MockTimeSource::set_time(2000*3600); MockTimeSource::set_time(2000 * 3600);
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey"); let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
let mut peers = Vec::new(); let mut peers = Vec::new();
peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap()); peers.push(SocketAddr::from_str("1.2.3.4:5678").unwrap());

View File

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

View File

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

View File

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

View File

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

View File

@ -2,15 +2,16 @@
// Copyright (C) 2015-2019 Dennis Schwerdel // Copyright (C) 2015-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md) // This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::os::unix::io::{AsRawFd, RawFd}; use std::{
use std::io::{self, Error as IoError, ErrorKind, Read, Write}; collections::VecDeque,
use std::fs; fmt, fs,
use std::fmt; io::{self, Error as IoError, ErrorKind, Read, Write},
use std::collections::VecDeque; os::unix::io::{AsRawFd, RawFd}
};
use super::types::Error; use super::types::Error;
extern { extern "C" {
fn setup_tap_device(fd: i32, ifname: *mut u8) -> i32; fn setup_tap_device(fd: i32, ifname: *mut u8) -> i32;
fn setup_tun_device(fd: i32, ifname: *mut u8) -> i32; fn setup_tun_device(fd: i32, ifname: *mut u8) -> i32;
} }
@ -78,7 +79,7 @@ pub trait Device: AsRawFd {
pub struct TunTapDevice { pub struct TunTapDevice {
fd: fs::File, fd: fs::File,
ifname: String, ifname: String,
type_: Type, type_: Type
} }
@ -94,18 +95,16 @@ impl TunTapDevice {
/// ///
/// # Errors /// # Errors
/// This method will return an error when the underlying system call fails. Common cases are: /// This method will return an error when the underlying system call fails. Common cases are:
/// - The special device file `/dev/net/tun` does not exist or is not accessible by the current /// - The special device file `/dev/net/tun` does not exist or is not accessible by the current user.
/// user.
/// - The interface name is invalid or already in use. /// - The interface name is invalid or already in use.
/// - The current user does not have enough permissions to create tun/tap devices (this /// - The current user does not have enough permissions to create tun/tap devices (this requires root permissions).
/// requires root permissions).
/// ///
/// # Panics /// # Panics
/// This method panics if the interface name is longer than 31 bytes. /// This method panics if the interface name is longer than 31 bytes.
pub fn new(ifname: &str, type_: Type, path: Option<&str>) -> io::Result<Self> { pub fn new(ifname: &str, type_: Type, path: Option<&str>) -> io::Result<Self> {
let path = path.unwrap_or_else(|| Self::default_path(type_)); let path = path.unwrap_or_else(|| Self::default_path(type_));
if type_ == Type::Dummy { if type_ == Type::Dummy {
return Self::dummy(ifname, path, type_); return Self::dummy(ifname, path, type_)
} }
let fd = fs::OpenOptions::new().read(true).write(true).open(path)?; let fd = fs::OpenOptions::new().read(true).write(true).open(path)?;
// Add trailing \0 to interface name // Add trailing \0 to interface name
@ -125,8 +124,8 @@ impl TunTapDevice {
while ifname_c.last() == Some(&0) { while ifname_c.last() == Some(&0) {
ifname_c.pop(); ifname_c.pop();
} }
Ok(Self{fd, ifname: String::from_utf8(ifname_c).unwrap(), type_}) Ok(Self { fd, ifname: String::from_utf8(ifname_c).unwrap(), type_ })
}, }
_ => Err(IoError::last_os_error()) _ => Err(IoError::last_os_error())
} }
} }
@ -155,7 +154,7 @@ impl TunTapDevice {
/// This method will return an error if the file can not be opened for reading and writing. /// This method will return an error if the file can not be opened for reading and writing.
#[allow(dead_code)] #[allow(dead_code)]
pub fn dummy(ifname: &str, path: &str, type_: Type) -> io::Result<Self> { pub fn dummy(ifname: &str, path: &str, type_: Type) -> io::Result<Self> {
Ok(TunTapDevice{ Ok(TunTapDevice {
fd: fs::OpenOptions::new().create(true).read(true).write(true).open(path)?, fd: fs::OpenOptions::new().create(true).read(true).write(true).open(path)?,
ifname: ifname.to_string(), ifname: ifname.to_string(),
type_ type_
@ -168,15 +167,21 @@ impl TunTapDevice {
(start, read) (start, read)
} }
#[cfg(any(target_os = "bitrig", target_os = "dragonfly", #[cfg(any(
target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "bitrig",
target_os = "netbsd", target_os = "openbsd"))] target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
))]
#[inline] #[inline]
fn correct_data_after_read(&mut self, buffer: &mut [u8], start: usize, read: usize) -> (usize, usize) { fn correct_data_after_read(&mut self, buffer: &mut [u8], start: usize, read: usize) -> (usize, usize) {
if self.type_ == Type::Tun { if self.type_ == Type::Tun {
// BSD-based systems add a 4-byte header containing the Ethertype for TUN // BSD-based systems add a 4-byte header containing the Ethertype for TUN
assert!(read>=4); assert!(read >= 4);
(start+4, read-4) (start + 4, read - 4)
} else { } else {
(start, read) (start, read)
} }
@ -188,20 +193,27 @@ impl TunTapDevice {
start start
} }
#[cfg(any(target_os = "bitrig", target_os = "dragonfly", #[cfg(any(
target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "bitrig",
target_os = "netbsd", target_os = "openbsd"))] target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
))]
#[inline] #[inline]
fn correct_data_before_write(&mut self, buffer: &mut [u8], start: usize) -> usize { fn correct_data_before_write(&mut self, buffer: &mut [u8], start: usize) -> usize {
if self.type_ == Type::Tun { if self.type_ == Type::Tun {
// BSD-based systems add a 4-byte header containing the Ethertype for TUN // BSD-based systems add a 4-byte header containing the Ethertype for TUN
assert!(start>=4); assert!(start >= 4);
match buffer[start] >> 4 { // IP version match buffer[start] >> 4 {
4 => buffer[start-4..start].copy_from_slice(&[0x00, 0x00, 0x08, 0x00]), // IP version
6 => buffer[start-4..start].copy_from_slice(&[0x00, 0x00, 0x86, 0xdd]), 4 => buffer[start - 4..start].copy_from_slice(&[0x00, 0x00, 0x08, 0x00]),
6 => buffer[start - 4..start].copy_from_slice(&[0x00, 0x00, 0x86, 0xdd]),
_ => unreachable!() _ => unreachable!()
} }
start-4 start - 4
} else { } else {
start start
} }
@ -230,7 +242,6 @@ impl Device for TunTapDevice {
Err(e) => Err(Error::TunTapDev("Write error", e)) Err(e) => Err(Error::TunTapDev("Write error", e))
} }
} }
} }
impl AsRawFd for TunTapDevice { impl AsRawFd for TunTapDevice {

View File

@ -2,17 +2,20 @@
// Copyright (C) 2015-2019 Dennis Schwerdel // Copyright (C) 2015-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md) // This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::net::SocketAddr; use std::{
use std::collections::HashMap; collections::{hash_map::Entry, HashMap},
use std::collections::hash_map::Entry; hash::BuildHasherDefault,
use std::hash::BuildHasherDefault; io::{self, Write},
use std::io::{self, Write}; marker::PhantomData,
use std::marker::PhantomData; net::SocketAddr
};
use fnv::FnvHasher; use fnv::FnvHasher;
use super::types::{Error, Table, Protocol, Address}; use super::{
use super::util::{TimeSource, Time, Duration}; types::{Address, Error, Protocol, Table},
util::{Duration, Time, TimeSource}
};
/// An ethernet frame dissector /// An ethernet frame dissector
/// ///
@ -29,25 +32,27 @@ impl Protocol for Frame {
/// This method will fail when the given data is not a valid ethernet frame. /// This method will fail when the given data is not a valid ethernet frame.
fn parse(data: &[u8]) -> Result<(Address, Address), Error> { fn parse(data: &[u8]) -> Result<(Address, Address), Error> {
if data.len() < 14 { if data.len() < 14 {
return Err(Error::Parse("Frame is too short")); return Err(Error::Parse("Frame is too short"))
} }
let mut pos = 0; let mut pos = 0;
let dst_data = &data[pos..pos+6]; let dst_data = &data[pos..pos + 6];
pos += 6; pos += 6;
let src_data = &data[pos..pos+6]; let src_data = &data[pos..pos + 6];
pos += 6; pos += 6;
if data[pos] == 0x81 && data[pos+1] == 0x00 { if data[pos] == 0x81 && data[pos + 1] == 0x00 {
pos += 2; pos += 2;
if data.len() < pos + 2 { if data.len() < pos + 2 {
return Err(Error::Parse("Vlan frame is too short")); return Err(Error::Parse("Vlan frame is too short"))
} }
let mut src = [0; 16]; let mut src = [0; 16];
let mut dst = [0; 16]; let mut dst = [0; 16];
src[0] = data[pos]; src[1] = data[pos+1]; src[0] = data[pos];
dst[0] = data[pos]; dst[1] = data[pos+1]; src[1] = data[pos + 1];
dst[0] = data[pos];
dst[1] = data[pos + 1];
src[2..8].copy_from_slice(src_data); src[2..8].copy_from_slice(src_data);
dst[2..8].copy_from_slice(dst_data); dst[2..8].copy_from_slice(dst_data);
Ok((Address{data: src, len: 8}, Address{data: dst, len: 8})) Ok((Address { data: src, len: 8 }, Address { data: dst, len: 8 }))
} else { } else {
let src = Address::read_from_fixed(src_data, 6)?; let src = Address::read_from_fixed(src_data, 6)?;
let dst = Address::read_from_fixed(dst_data, 6)?; let dst = Address::read_from_fixed(dst_data, 6)?;
@ -82,7 +87,7 @@ pub struct SwitchTable<TS> {
impl<TS: TimeSource> SwitchTable<TS> { impl<TS: TimeSource> SwitchTable<TS> {
/// Creates a new switch table /// Creates a new switch table
pub fn new(timeout: Duration, protection_period: Duration) -> Self { pub fn new(timeout: Duration, protection_period: Duration) -> Self {
Self{table: HashMap::default(), timeout, protection_period, _dummy_ts: PhantomData} Self { table: HashMap::default(), timeout, protection_period, _dummy_ts: PhantomData }
} }
} }
@ -118,9 +123,9 @@ impl<TS: TimeSource> Table for SwitchTable<TS> {
let deadline = TS::now() + Time::from(self.timeout); let deadline = TS::now() + Time::from(self.timeout);
match self.table.entry(key) { match self.table.entry(key) {
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
entry.insert(SwitchTableValue{address: addr, timeout: deadline}); entry.insert(SwitchTableValue { address: addr, timeout: deadline });
info!("Learned address {} => {}", key, addr); info!("Learned address {} => {}", key, addr);
}, }
Entry::Occupied(mut entry) => { Entry::Occupied(mut entry) => {
let mut entry = entry.get_mut(); let mut entry = entry.get_mut();
if entry.timeout + Time::from(self.protection_period) > deadline { if entry.timeout + Time::from(self.protection_period) > deadline {
@ -163,33 +168,33 @@ impl<TS: TimeSource> Table for SwitchTable<TS> {
} }
#[cfg(test)] use std::str::FromStr;
#[cfg(test)] use std::net::ToSocketAddrs;
#[cfg(test)] use super::util::MockTimeSource; #[cfg(test)] use super::util::MockTimeSource;
#[cfg(test)] use std::net::ToSocketAddrs;
#[cfg(test)] use std::str::FromStr;
#[test] #[test]
fn decode_frame_without_vlan() { fn decode_frame_without_vlan() {
let data = [6,5,4,3,2,1,1,2,3,4,5,6,1,2,3,4,5,6,7,8]; let data = [6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8];
let (src, dst) = Frame::parse(&data).unwrap(); let (src, dst) = Frame::parse(&data).unwrap();
assert_eq!(src, Address{data: [1,2,3,4,5,6,0,0,0,0,0,0,0,0,0,0], len: 6}); assert_eq!(src, Address { data: [1, 2, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], len: 6 });
assert_eq!(dst, Address{data: [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], len: 6}); assert_eq!(dst, Address { data: [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], len: 6 });
} }
#[test] #[test]
fn decode_frame_with_vlan() { fn decode_frame_with_vlan() {
let data = [6,5,4,3,2,1,1,2,3,4,5,6,0x81,0,4,210,1,2,3,4,5,6,7,8]; let data = [6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 0x81, 0, 4, 210, 1, 2, 3, 4, 5, 6, 7, 8];
let (src, dst) = Frame::parse(&data).unwrap(); let (src, dst) = Frame::parse(&data).unwrap();
assert_eq!(src, Address{data: [4,210,1,2,3,4,5,6,0,0,0,0,0,0,0,0], len: 8}); assert_eq!(src, Address { data: [4, 210, 1, 2, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0], len: 8 });
assert_eq!(dst, Address{data: [4,210,6,5,4,3,2,1,0,0,0,0,0,0,0,0], len: 8}); assert_eq!(dst, Address { data: [4, 210, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0], len: 8 });
} }
#[test] #[test]
fn decode_invalid_frame() { fn decode_invalid_frame() {
assert!(Frame::parse(&[6,5,4,3,2,1,1,2,3,4,5,6,1,2,3,4,5,6,7,8]).is_ok()); assert!(Frame::parse(&[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8]).is_ok());
// truncated frame // truncated frame
assert!(Frame::parse(&[]).is_err()); assert!(Frame::parse(&[]).is_err());
// truncated vlan frame // truncated vlan frame
assert!(Frame::parse(&[6,5,4,3,2,1,1,2,3,4,5,6,0x81,0x00]).is_err()); assert!(Frame::parse(&[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 0x81, 0x00]).is_err());
} }
#[test] #[test]

View File

@ -2,14 +2,16 @@
// Copyright (C) 2015-2019 Dennis Schwerdel // Copyright (C) 2015-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md) // This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::net::SocketAddr; use std::{
use std::collections::{hash_map, HashMap}; collections::{hash_map, HashMap},
use std::hash::BuildHasherDefault; hash::BuildHasherDefault,
use std::io::{self, Write}; io::{self, Write},
net::SocketAddr
};
use fnv::FnvHasher; use fnv::FnvHasher;
use super::types::{Protocol, Error, Table, Address}; use super::types::{Address, Error, Protocol, Table};
/// An IP packet dissector /// An IP packet dissector
@ -26,26 +28,26 @@ impl Protocol for Packet {
/// This method will fail when the given data is not a valid ipv4 and ipv6 packet. /// This method will fail when the given data is not a valid ipv4 and ipv6 packet.
fn parse(data: &[u8]) -> Result<(Address, Address), Error> { fn parse(data: &[u8]) -> Result<(Address, Address), Error> {
if data.is_empty() { if data.is_empty() {
return Err(Error::Parse("Empty header")); return Err(Error::Parse("Empty header"))
} }
let version = data[0] >> 4; let version = data[0] >> 4;
match version { match version {
4 => { 4 => {
if data.len() < 20 { if data.len() < 20 {
return Err(Error::Parse("Truncated IPv4 header")); return Err(Error::Parse("Truncated IPv4 header"))
} }
let src = Address::read_from_fixed(&data[12..], 4)?; let src = Address::read_from_fixed(&data[12..], 4)?;
let dst = Address::read_from_fixed(&data[16..], 4)?; let dst = Address::read_from_fixed(&data[16..], 4)?;
Ok((src, dst)) Ok((src, dst))
}, }
6 => { 6 => {
if data.len() < 40 { if data.len() < 40 {
return Err(Error::Parse("Truncated IPv6 header")); return Err(Error::Parse("Truncated IPv6 header"))
} }
let src = Address::read_from_fixed(&data[8..], 16)?; let src = Address::read_from_fixed(&data[8..], 16)?;
let dst = Address::read_from_fixed(&data[24..], 16)?; let dst = Address::read_from_fixed(&data[24..], 16)?;
Ok((src, dst)) Ok((src, dst))
}, }
_ => Err(Error::Parse("Invalid version")) _ => Err(Error::Parse("Invalid version"))
} }
} }
@ -91,11 +93,13 @@ impl Table for RoutingTable {
let mut group_bytes = [0; 16]; let mut group_bytes = [0; 16];
group_bytes[..group_len].copy_from_slice(&addr.data[..group_len]); group_bytes[..group_len].copy_from_slice(&addr.data[..group_len]);
// Create an entry // Create an entry
let routing_entry = RoutingEntry{address, bytes: addr, prefix_len}; let routing_entry = RoutingEntry { address, bytes: addr, prefix_len };
// Add the entry to the routing table, creating a new list of the prefix group is empty. // Add the entry to the routing table, creating a new list of the prefix group is empty.
match self.0.entry(group_bytes) { match self.0.entry(group_bytes) {
hash_map::Entry::Occupied(mut entry) => entry.get_mut().push(routing_entry), hash_map::Entry::Occupied(mut entry) => entry.get_mut().push(routing_entry),
hash_map::Entry::Vacant(entry) => { entry.insert(vec![routing_entry]); } hash_map::Entry::Vacant(entry) => {
entry.insert(vec![routing_entry]);
}
} }
} }
@ -126,7 +130,7 @@ impl Table for RoutingTable {
match_len += 8; match_len += 8;
} else { } else {
match_len += b.leading_zeros(); match_len += b.leading_zeros();
break; break
} }
} }
// If the full prefix matches and the match is longer than the longest prefix // If the full prefix matches and the match is longer than the longest prefix
@ -144,7 +148,7 @@ impl Table for RoutingTable {
/// This method does not do anything. /// This method does not do anything.
fn housekeep(&mut self) { fn housekeep(&mut self) {
//nothing to do // nothing to do
} }
/// Write out the table /// Write out the table
@ -174,38 +178,49 @@ impl Table for RoutingTable {
} }
#[cfg(test)] use std::str::FromStr;
#[cfg(test)] use std::net::ToSocketAddrs; #[cfg(test)] use std::net::ToSocketAddrs;
#[cfg(test)] use std::str::FromStr;
#[test] #[test]
fn decode_ipv4_packet() { fn decode_ipv4_packet() {
let data = [0x40,0,0,0,0,0,0,0,0,0,0,0,192,168,1,1,192,168,1,2]; let data = [0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 1, 1, 192, 168, 1, 2];
let (src, dst) = Packet::parse(&data).unwrap(); let (src, dst) = Packet::parse(&data).unwrap();
assert_eq!(src, Address{data: [192,168,1,1,0,0,0,0,0,0,0,0,0,0,0,0], len: 4}); assert_eq!(src, Address { data: [192, 168, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], len: 4 });
assert_eq!(dst, Address{data: [192,168,1,2,0,0,0,0,0,0,0,0,0,0,0,0], len: 4}); assert_eq!(dst, Address { data: [192, 168, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], len: 4 });
} }
#[test] #[test]
fn decode_ipv6_packet() { fn decode_ipv6_packet() {
let data = [0x60,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,0,9,8,7,6,5,4,3,2,1,6,5,4,3,2,1]; let data = [
0x60, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 6, 5,
4, 3, 2, 1
];
let (src, dst) = Packet::parse(&data).unwrap(); let (src, dst) = Packet::parse(&data).unwrap();
assert_eq!(src, Address{data: [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6], len: 16}); assert_eq!(src, Address { data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6], len: 16 });
assert_eq!(dst, Address{data: [0,9,8,7,6,5,4,3,2,1,6,5,4,3,2,1], len: 16}); assert_eq!(dst, Address { data: [0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1], len: 16 });
} }
#[test] #[test]
fn decode_invalid_packet() { fn decode_invalid_packet() {
assert!(Packet::parse(&[0x40,0,0,0,0,0,0,0,0,0,0,0,192,168,1,1,192,168,1,2]).is_ok()); assert!(Packet::parse(&[0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 1, 1, 192, 168, 1, 2]).is_ok());
assert!(Packet::parse(&[0x60,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,0,9,8,7,6,5,4,3,2,1,6,5,4,3,2,1]).is_ok()); assert!(Packet::parse(&[
0x60, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 6, 5,
4, 3, 2, 1
])
.is_ok());
// no data // no data
assert!(Packet::parse(&[]).is_err()); assert!(Packet::parse(&[]).is_err());
// wrong version // wrong version
assert!(Packet::parse(&[0x20]).is_err()); assert!(Packet::parse(&[0x20]).is_err());
// truncated ipv4 // truncated ipv4
assert!(Packet::parse(&[0x40,0,0,0,0,0,0,0,0,0,0,0,192,168,1,1,192,168,1]).is_err()); assert!(Packet::parse(&[0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 1, 1, 192, 168, 1]).is_err());
// truncated ipv6 // truncated ipv6
assert!(Packet::parse(&[0x60,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,0,9,8,7,6,5,4,3,2,1,6,5,4,3,2]).is_err()); assert!(Packet::parse(&[
0x60, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 6, 5,
4, 3, 2
])
.is_err());
} }

View File

@ -10,42 +10,49 @@
#[cfg(test)] extern crate tempfile; #[cfg(test)] extern crate tempfile;
#[cfg(feature = "bench")] extern crate test; #[cfg(feature = "bench")] extern crate test;
#[macro_use] pub mod util; #[macro_use]
#[cfg(test)] #[macro_use] mod tests; pub mod util;
pub mod types; #[cfg(test)]
#[macro_use]
mod tests;
pub mod beacon;
#[cfg(feature = "bench")] mod benches;
pub mod cloud;
pub mod config;
pub mod crypto; pub mod crypto;
pub mod udpmessage; pub mod device;
pub mod ethernet; pub mod ethernet;
pub mod ip; pub mod ip;
pub mod cloud; pub mod net;
pub mod device;
pub mod poll; pub mod poll;
pub mod config;
pub mod port_forwarding; pub mod port_forwarding;
pub mod traffic; pub mod traffic;
pub mod beacon; pub mod types;
pub mod net; pub mod udpmessage;
#[cfg(feature = "bench")] mod benches;
use docopt::Docopt; use docopt::Docopt;
use std::sync::Mutex; use std::{
use std::str::FromStr; fs::File,
use std::process::Command; io::{self, Write},
use std::fs::File; net::UdpSocket,
use std::path::Path; path::Path,
use std::io::{self, Write}; process::Command,
use std::net::UdpSocket; str::FromStr,
sync::Mutex
};
use crate::device::{TunTapDevice, Device, Type}; use crate::{
use crate::ethernet::SwitchTable; cloud::GenericCloud,
use crate::ip::RoutingTable; config::Config,
use crate::types::{Mode, Range, Protocol, HeaderMagic, Error}; crypto::{Crypto, CryptoMethod},
use crate::cloud::GenericCloud; device::{Device, TunTapDevice, Type},
use crate::crypto::{Crypto, CryptoMethod}; ethernet::SwitchTable,
use crate::port_forwarding::PortForwarding; ip::RoutingTable,
use crate::util::{Duration, SystemTimeSource}; port_forwarding::PortForwarding,
use crate::config::Config; types::{Error, HeaderMagic, Mode, Protocol, Range},
util::{Duration, SystemTimeSource}
};
const VERSION: u8 = 1; const VERSION: u8 = 1;
@ -96,9 +103,9 @@ impl DualLogger {
pub fn new<P: AsRef<Path>>(path: Option<P>) -> Result<Self, io::Error> { pub fn new<P: AsRef<Path>>(path: Option<P>) -> Result<Self, io::Error> {
if let Some(path) = path { if let Some(path) = path {
let file = File::create(path)?; let file = File::create(path)?;
Ok(DualLogger{file: Mutex::new(Some(file))}) Ok(DualLogger { file: Mutex::new(Some(file)) })
} else { } else {
Ok(DualLogger{file: Mutex::new(None)}) Ok(DualLogger { file: Mutex::new(None) })
} }
} }
} }
@ -116,7 +123,8 @@ impl log::Log for DualLogger {
let mut file = self.file.lock().expect("Lock poisoned"); let mut file = self.file.lock().expect("Lock poisoned");
if let Some(ref mut file) = *file { if let Some(ref mut file) = *file {
let time = time::strftime("%F %T", &time::now()).expect("Failed to format timestamp"); let time = time::strftime("%F %T", &time::now()).expect("Failed to format timestamp");
writeln!(file, "{} - {} - {}", time, record.level(), record.args()).expect("Failed to write to logfile"); writeln!(file, "{} - {} - {}", time, record.level(), record.args())
.expect("Failed to write to logfile");
} }
} }
} }
@ -135,9 +143,11 @@ fn run_script(script: &str, ifname: &str) {
cmd.arg("-c").arg(&script).env("IFNAME", ifname); cmd.arg("-c").arg(&script).env("IFNAME", ifname);
debug!("Running script: {:?}", cmd); debug!("Running script: {:?}", cmd);
match cmd.status() { match cmd.status() {
Ok(status) => if !status.success() { Ok(status) => {
if !status.success() {
error!("Script returned with error: {:?}", status.code()) error!("Script returned with error: {:?}", status.code())
}, }
}
Err(e) => error!("Failed to execute script {:?}: {}", script, e) Err(e) => error!("Failed to execute script {:?}: {}", script, e)
} }
} }
@ -154,17 +164,36 @@ enum AnyCloud<P: Protocol> {
impl<P: Protocol> AnyCloud<P> { impl<P: Protocol> AnyCloud<P> {
#[allow(unknown_lints, clippy::too_many_arguments)] #[allow(unknown_lints, clippy::too_many_arguments)]
fn new(config: &Config, device: TunTapDevice, table: AnyTable, fn new(
learning: bool, broadcast: bool, addresses: Vec<Range>, config: &Config, device: TunTapDevice, table: AnyTable, learning: bool, broadcast: bool, addresses: Vec<Range>,
crypto: Crypto, port_forwarding: Option<PortForwarding>) -> Self { crypto: Crypto, port_forwarding: Option<PortForwarding>
) -> Self
{
match table { match table {
AnyTable::Switch(t) => AnyCloud::Switch(GenericCloud::<TunTapDevice, P, SwitchTable<SystemTimeSource>, UdpSocket, SystemTimeSource>::new( AnyTable::Switch(t) => {
config, device,t, learning, broadcast, addresses, crypto, port_forwarding AnyCloud::Switch(GenericCloud::<
)), TunTapDevice,
AnyTable::Routing(t) => AnyCloud::Routing(GenericCloud::<TunTapDevice, P, RoutingTable, UdpSocket, SystemTimeSource>::new( P,
config, device,t, learning, broadcast, addresses, crypto, port_forwarding SwitchTable<SystemTimeSource>,
UdpSocket,
SystemTimeSource
>::new(
config, device, t, learning, broadcast, addresses, crypto, port_forwarding
)) ))
} }
AnyTable::Routing(t) => {
AnyCloud::Routing(GenericCloud::<TunTapDevice, P, RoutingTable, UdpSocket, SystemTimeSource>::new(
config,
device,
t,
learning,
broadcast,
addresses,
crypto,
port_forwarding
))
}
}
} }
fn ifname(&self) -> &str { fn ifname(&self) -> &str {
@ -197,9 +226,13 @@ impl<P: Protocol> AnyCloud<P> {
} }
fn run<P: Protocol> (config: Config) { fn run<P: Protocol>(config: Config) {
let device = try_fail!(TunTapDevice::new(&config.device_name, config.device_type, config.device_path.as_ref().map(|s| s as &str)), let device = try_fail!(
"Failed to open virtual {} interface {}: {}", config.device_type, config.device_name); TunTapDevice::new(&config.device_name, config.device_type, config.device_path.as_ref().map(|s| s as &str)),
"Failed to open virtual {} interface {}: {}",
config.device_type,
config.device_name
);
info!("Opened device {}", device.ifname()); info!("Opened device {}", device.ifname());
let mut ranges = Vec::with_capacity(config.subnets.len()); let mut ranges = Vec::with_capacity(config.subnets.len());
for s in &config.subnets { for s in &config.subnets {
@ -207,11 +240,13 @@ fn run<P: Protocol> (config: Config) {
} }
let dst_timeout = config.dst_timeout; let dst_timeout = config.dst_timeout;
let (learning, broadcasting, table) = match config.mode { let (learning, broadcasting, table) = match config.mode {
Mode::Normal => match config.device_type { Mode::Normal => {
match config.device_type {
Type::Tap => (true, true, AnyTable::Switch(SwitchTable::new(dst_timeout, 10))), Type::Tap => (true, true, AnyTable::Switch(SwitchTable::new(dst_timeout, 10))),
Type::Tun => (false, false, AnyTable::Routing(RoutingTable::new())), Type::Tun => (false, false, AnyTable::Routing(RoutingTable::new())),
Type::Dummy => (false, false, AnyTable::Switch(SwitchTable::new(dst_timeout, 10))) Type::Dummy => (false, false, AnyTable::Switch(SwitchTable::new(dst_timeout, 10)))
}, }
}
Mode::Router => (false, false, AnyTable::Routing(RoutingTable::new())), Mode::Router => (false, false, AnyTable::Routing(RoutingTable::new())),
Mode::Switch => (true, true, AnyTable::Switch(SwitchTable::new(dst_timeout, 10))), Mode::Switch => (true, true, AnyTable::Switch(SwitchTable::new(dst_timeout, 10))),
Mode::Hub => (false, true, AnyTable::Switch(SwitchTable::new(dst_timeout, 10))) Mode::Hub => (false, true, AnyTable::Switch(SwitchTable::new(dst_timeout, 10)))
@ -220,12 +255,8 @@ fn run<P: Protocol> (config: Config) {
Some(ref key) => Crypto::from_shared_key(config.crypto, key), Some(ref key) => Crypto::from_shared_key(config.crypto, key),
None => Crypto::None None => Crypto::None
}; };
let port_forwarding = if config.port_forwarding { let port_forwarding = if config.port_forwarding { PortForwarding::new(config.port) } else { None };
PortForwarding::new(config.port) let mut cloud = AnyCloud::<P>::new(&config, device, table, learning, broadcasting, ranges, crypto, port_forwarding);
} else {
None
};
let mut cloud = AnyCloud::<P>::new(&config, device, table, learning,broadcasting,ranges, crypto, port_forwarding);
if let Some(script) = config.ifup { if let Some(script) = config.ifup {
run_script(&script, cloud.ifname()); run_script(&script, cloud.ifname());
} }
@ -256,24 +287,19 @@ fn run<P: Protocol> (config: Config) {
fn main() { fn main() {
let args: Args = Docopt::new(USAGE).and_then(|d| d.deserialize()).unwrap_or_else(|e| e.exit()); let args: Args = Docopt::new(USAGE).and_then(|d| d.deserialize()).unwrap_or_else(|e| e.exit());
if args.flag_version { if args.flag_version {
println!("VpnCloud v{}, protocol version {}", println!("VpnCloud v{}, protocol version {}", env!("CARGO_PKG_VERSION"), VERSION);
env!("CARGO_PKG_VERSION"), return
VERSION
);
return;
} }
let logger = try_fail!(DualLogger::new(args.flag_log_file.as_ref()), "Failed to open logfile: {}"); let logger = try_fail!(DualLogger::new(args.flag_log_file.as_ref()), "Failed to open logfile: {}");
log::set_boxed_logger(Box::new(logger)).unwrap(); log::set_boxed_logger(Box::new(logger)).unwrap();
assert!(!args.flag_verbose || !args.flag_quiet); assert!(!args.flag_verbose || !args.flag_quiet);
log::set_max_level( log::set_max_level(if args.flag_verbose {
if args.flag_verbose {
log::LevelFilter::Debug log::LevelFilter::Debug
} else if args.flag_quiet { } else if args.flag_quiet {
log::LevelFilter::Error log::LevelFilter::Error
} else { } else {
log::LevelFilter::Info log::LevelFilter::Info
} });
);
let mut config = Config::default(); let mut config = Config::default();
if let Some(ref file) = args.flag_config { if let Some(ref file) = args.flag_config {
info!("Reading config file '{}'", file); info!("Reading config file '{}'", file);

View File

@ -1,7 +1,9 @@
use std::os::unix::io::{RawFd, AsRawFd}; use std::{
use std::net::{UdpSocket, SocketAddr, SocketAddrV4, SocketAddrV6}; collections::VecDeque,
use std::io::{self, ErrorKind}; io::{self, ErrorKind},
use std::collections::VecDeque; net::{SocketAddr, SocketAddrV4, SocketAddrV6, UdpSocket},
os::unix::io::{AsRawFd, RawFd}
};
use net2::UdpBuilder; use net2::UdpBuilder;
@ -16,13 +18,20 @@ pub trait Socket: AsRawFd + Sized {
impl Socket for UdpSocket { impl Socket for UdpSocket {
fn listen_v4(host: &str, port: u16) -> Result<Self, io::Error> { fn listen_v4(host: &str, port: u16) -> Result<Self, io::Error> {
UdpBuilder::new_v4().expect("Failed to obtain ipv4 socket builder") UdpBuilder::new_v4()
.reuse_address(true).expect("Failed to set so_reuseaddr").bind((host, port)) .expect("Failed to obtain ipv4 socket builder")
.reuse_address(true)
.expect("Failed to set so_reuseaddr")
.bind((host, port))
} }
fn listen_v6(host: &str, port: u16) -> Result<Self, io::Error> { fn listen_v6(host: &str, port: u16) -> Result<Self, io::Error> {
UdpBuilder::new_v6().expect("Failed to obtain ipv4 socket builder") UdpBuilder::new_v6()
.only_v6(true).expect("Failed to set only_v6") .expect("Failed to obtain ipv4 socket builder")
.reuse_address(true).expect("Failed to set so_reuseaddr").bind((host, port)) .only_v6(true)
.expect("Failed to set only_v6")
.reuse_address(true)
.expect("Failed to set so_reuseaddr")
.bind((host, port))
} }
fn receive(&mut self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), io::Error> { fn receive(&mut self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), io::Error> {
self.recv_from(buffer) self.recv_from(buffer)

View File

@ -4,13 +4,11 @@
use libc; use libc;
use std::os::unix::io::RawFd;
use std::io;
use crate::device::Device; use crate::device::Device;
use std::{io, os::unix::io::RawFd};
use super::WaitResult; use super::WaitResult;
use crate::device::Type; use crate::{device::Type, net::Socket};
use crate::net::Socket;
pub struct EpollWait { pub struct EpollWait {
poll_fd: RawFd, poll_fd: RawFd,
@ -18,23 +16,25 @@ pub struct EpollWait {
socketv4: RawFd, socketv4: RawFd,
socketv6: RawFd, socketv6: RawFd,
device: RawFd, device: RawFd,
timeout: u32, timeout: u32
} }
impl EpollWait { impl EpollWait {
pub fn new<S: Socket>(socketv4: &S, socketv6: &S, device: &Device, timeout: u32) -> io::Result<Self> { pub fn new<S: Socket>(socketv4: &S, socketv6: &S, device: &dyn Device, timeout: u32) -> io::Result<Self> {
Self::create(socketv4, socketv6, device, timeout, libc::EPOLLIN as u32) Self::create(socketv4, socketv6, device, timeout, libc::EPOLLIN as u32)
} }
pub fn testing<S: Socket>(socketv4: &S, socketv6: &S, device: &Device, timeout: u32) -> io::Result<Self> { pub fn testing<S: Socket>(socketv4: &S, socketv6: &S, device: &dyn Device, timeout: u32) -> io::Result<Self> {
Self::create(socketv4, socketv6, device, timeout, ( libc::EPOLLIN | libc::EPOLLOUT ) as u32) Self::create(socketv4, socketv6, device, timeout, (libc::EPOLLIN | libc::EPOLLOUT) as u32)
} }
fn create<S: Socket>(socketv4: &S, socketv6: &S, device: &Device, timeout: u32, flags: u32) -> io::Result<Self> { fn create<S: Socket>(
let mut event = libc::epoll_event{u64: 0, events: 0}; socketv4: &S, socketv6: &S, device: &dyn Device, timeout: u32, flags: u32
) -> io::Result<Self> {
let mut event = libc::epoll_event { u64: 0, events: 0 };
let poll_fd = unsafe { libc::epoll_create(3) }; let poll_fd = unsafe { libc::epoll_create(3) };
if poll_fd == -1 { if poll_fd == -1 {
return Err(io::Error::last_os_error()); return Err(io::Error::last_os_error())
} }
let raw_fds = if device.get_type() != Type::Dummy { let raw_fds = if device.get_type() != Type::Dummy {
vec![socketv4.as_raw_fd(), socketv6.as_raw_fd(), device.as_raw_fd()] vec![socketv4.as_raw_fd(), socketv6.as_raw_fd(), device.as_raw_fd()]
@ -46,7 +46,7 @@ impl EpollWait {
event.events = flags; event.events = flags;
let res = unsafe { libc::epoll_ctl(poll_fd, libc::EPOLL_CTL_ADD, fd, &mut event) }; let res = unsafe { libc::epoll_ctl(poll_fd, libc::EPOLL_CTL_ADD, fd, &mut event) };
if res == -1 { if res == -1 {
return Err(io::Error::last_os_error()); return Err(io::Error::last_os_error())
} }
} }
Ok(Self { Ok(Self {
@ -73,7 +73,8 @@ impl Iterator for EpollWait {
Some(match unsafe { libc::epoll_wait(self.poll_fd, &mut self.event, 1, self.timeout as i32) } { Some(match unsafe { libc::epoll_wait(self.poll_fd, &mut self.event, 1, self.timeout as i32) } {
-1 => WaitResult::Error(io::Error::last_os_error()), -1 => WaitResult::Error(io::Error::last_os_error()),
0 => WaitResult::Timeout, 0 => WaitResult::Timeout,
1 => if self.event.u64 == self.socketv4 as u64 { 1 => {
if self.event.u64 == self.socketv4 as u64 {
WaitResult::SocketV4 WaitResult::SocketV4
} else if self.event.u64 == self.socketv6 as u64 { } else if self.event.u64 == self.socketv6 as u64 {
WaitResult::SocketV6 WaitResult::SocketV6
@ -81,9 +82,9 @@ impl Iterator for EpollWait {
WaitResult::Device WaitResult::Device
} else { } else {
unreachable!() unreachable!()
}, }
}
_ => unreachable!() _ => unreachable!()
}) })
} }
} }

View File

@ -2,8 +2,10 @@
// Copyright (C) 2015-2019 Dennis Schwerdel // Copyright (C) 2015-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md) // This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::net::{SocketAddrV4, UdpSocket, SocketAddr}; use std::{
use std::io; io,
net::{SocketAddr, SocketAddrV4, UdpSocket}
};
use igd::*; use igd::*;
@ -17,17 +19,18 @@ pub struct PortForwarding {
pub internal_addr: SocketAddrV4, pub internal_addr: SocketAddrV4,
pub external_addr: SocketAddrV4, pub external_addr: SocketAddrV4,
pub gateway: Gateway, pub gateway: Gateway,
pub next_extension: Option<Time>, pub next_extension: Option<Time>
} }
impl PortForwarding { impl PortForwarding {
pub fn new(port: u16) -> Option<Self> { pub fn new(port: u16) -> Option<Self> {
// Get the gateway // Get the gateway
let gateway = match search_gateway() { let gateway = match search_gateway(Default::default()) {
Ok(gateway) => gateway, Ok(gateway) => gateway,
Err(err) => { Err(err) => {
if let SearchError::IoError(ref err) = err { if let SearchError::IoError(ref err) = err {
if err.kind() == io::ErrorKind::WouldBlock { // Why this code? if err.kind() == io::ErrorKind::WouldBlock {
// Why this code?
warn!("Port-forwarding: no router found"); warn!("Port-forwarding: no router found");
return None return None
} }
@ -60,46 +63,49 @@ impl PortForwarding {
// - If the port is used, request any port // - If the port is used, request any port
// - If timeout is denied, try permanent forwarding // - If timeout is denied, try permanent forwarding
info!("Port-forwarding: external IP is {}", external_ip); info!("Port-forwarding: external IP is {}", external_ip);
let (external_addr, timeout) = match gateway.add_port(PortMappingProtocol::UDP, internal_addr.port(), internal_addr, LEASE_TIME, DESCRIPTION) { let (external_addr, timeout) = match gateway.add_port(
PortMappingProtocol::UDP,
internal_addr.port(),
internal_addr,
LEASE_TIME,
DESCRIPTION
) {
Ok(()) => (SocketAddrV4::new(external_ip, internal_addr.port()), LEASE_TIME), Ok(()) => (SocketAddrV4::new(external_ip, internal_addr.port()), LEASE_TIME),
Err(AddPortError::PortInUse) => match gateway.add_any_port(PortMappingProtocol::UDP, internal_addr, LEASE_TIME, DESCRIPTION) { Err(AddPortError::PortInUse) => {
match gateway.add_any_port(PortMappingProtocol::UDP, internal_addr, LEASE_TIME, DESCRIPTION) {
Ok(port) => (SocketAddrV4::new(external_ip, port), LEASE_TIME), Ok(port) => (SocketAddrV4::new(external_ip, port), LEASE_TIME),
Err(AddAnyPortError::OnlyPermanentLeasesSupported) => match gateway.add_any_port(PortMappingProtocol::UDP, internal_addr, 0, DESCRIPTION) { Err(AddAnyPortError::OnlyPermanentLeasesSupported) => {
match gateway.add_any_port(PortMappingProtocol::UDP, internal_addr, 0, DESCRIPTION) {
Ok(port) => (SocketAddrV4::new(external_ip, port), 0), Ok(port) => (SocketAddrV4::new(external_ip, port), 0),
Err(err) => { Err(err) => {
error!("Port-forwarding: failed to activate port forwarding: {}", err); error!("Port-forwarding: failed to activate port forwarding: {}", err);
return None return None
} }
}, }
}
Err(err) => { Err(err) => {
error!("Port-forwarding: failed to activate port forwarding: {}", err); error!("Port-forwarding: failed to activate port forwarding: {}", err);
return None return None
} }
}, }
Err(AddPortError::OnlyPermanentLeasesSupported) => match gateway.add_port(PortMappingProtocol::UDP, internal_addr.port(), internal_addr, 0, DESCRIPTION) { }
Err(AddPortError::OnlyPermanentLeasesSupported) => {
match gateway.add_port(PortMappingProtocol::UDP, internal_addr.port(), internal_addr, 0, DESCRIPTION) {
Ok(()) => (SocketAddrV4::new(external_ip, internal_addr.port()), 0), Ok(()) => (SocketAddrV4::new(external_ip, internal_addr.port()), 0),
Err(err) => { Err(err) => {
error!("Port-forwarding: failed to activate port forwarding: {}", err); error!("Port-forwarding: failed to activate port forwarding: {}", err);
return None return None
} }
}, }
}
Err(err) => { Err(err) => {
error!("Port-forwarding: failed to activate port forwarding: {}", err); error!("Port-forwarding: failed to activate port forwarding: {}", err);
return None return None
} }
}; };
info!("Port-forwarding: sucessfully activated port forward on {}, timeout: {}", external_addr, timeout); info!("Port-forwarding: sucessfully activated port forward on {}, timeout: {}", external_addr, timeout);
let next_extension = if timeout > 0 { let next_extension = if timeout > 0 { Some(SystemTimeSource::now() + Time::from(timeout) - 60) } else { None };
Some(SystemTimeSource::now() + Time::from(timeout) - 60) Some(PortForwarding { internal_addr, external_addr, gateway, next_extension })
} else {
None
};
Some(PortForwarding {
internal_addr,
external_addr,
gateway,
next_extension
})
} }
pub fn check_extend(&mut self) { pub fn check_extend(&mut self) {
@ -110,7 +116,13 @@ impl PortForwarding {
} else { } else {
return return
} }
match self.gateway.add_port(PortMappingProtocol::UDP, self.external_addr.port(), self.internal_addr, LEASE_TIME, DESCRIPTION) { match self.gateway.add_port(
PortMappingProtocol::UDP,
self.external_addr.port(),
self.internal_addr,
LEASE_TIME,
DESCRIPTION
) {
Ok(()) => debug!("Port-forwarding: extended port forwarding"), Ok(()) => debug!("Port-forwarding: extended port forwarding"),
Err(err) => error!("Port-forwarding: failed to extend port forwarding: {}", err) Err(err) => error!("Port-forwarding: failed to extend port forwarding: {}", err)
}; };

View File

@ -2,23 +2,26 @@
// Copyright (C) 2015-2019 Dennis Schwerdel // Copyright (C) 2015-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md) // This software is licensed under GPL-3 or newer (see LICENSE.md)
#[macro_use] mod helper; #[macro_use]
mod peers; mod helper;
mod payload; mod payload;
mod peers;
pub use std::net::SocketAddr; pub use std::net::SocketAddr;
use std::sync::atomic::{Ordering, AtomicUsize}; use std::sync::atomic::{AtomicUsize, Ordering};
pub use super::ethernet::{self, SwitchTable}; pub use super::{
pub use super::util::MockTimeSource; cloud::GenericCloud,
pub use super::net::MockSocket; config::Config,
pub use super::device::MockDevice; crypto::Crypto,
pub use super::udpmessage::Message; device::MockDevice,
pub use super::config::Config; ethernet::{self, SwitchTable},
pub use super::crypto::Crypto; ip::{self, RoutingTable},
pub use super::cloud::GenericCloud; net::MockSocket,
pub use super::types::{Protocol, Table, Range}; types::{Protocol, Range, Table},
pub use super::ip::{self, RoutingTable}; udpmessage::Message,
util::MockTimeSource
};
type TestNode<P, T> = GenericCloud<MockDevice, P, T, MockSocket, MockTimeSource>; type TestNode<P, T> = GenericCloud<MockDevice, P, T, MockSocket, MockTimeSource>;
@ -38,12 +41,7 @@ fn create_tap_node() -> TapTestNode {
fn create_tap_node_with_config(mut config: Config) -> TapTestNode { fn create_tap_node_with_config(mut config: Config) -> TapTestNode {
config.port = NEXT_PORT.with(|p| p.fetch_add(1, Ordering::Relaxed)) as u16; config.port = NEXT_PORT.with(|p| p.fetch_add(1, Ordering::Relaxed)) as u16;
TestNode::new( TestNode::new(&config, MockDevice::new(), SwitchTable::new(1800, 10), true, true, vec![], Crypto::None, None)
&config,
MockDevice::new(),
SwitchTable::new(1800, 10),
true, true, vec![], Crypto::None, None
)
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -52,7 +50,11 @@ fn create_tun_node(addresses: Vec<Range>) -> TunTestNode {
&Config { port: NEXT_PORT.with(|p| p.fetch_add(1, Ordering::Relaxed)) as u16, ..Config::default() }, &Config { port: NEXT_PORT.with(|p| p.fetch_add(1, Ordering::Relaxed)) as u16, ..Config::default() },
MockDevice::new(), MockDevice::new(),
RoutingTable::new(), RoutingTable::new(),
false, false, addresses, Crypto::None, None false,
false,
addresses,
Crypto::None,
None
) )
} }

View File

@ -67,20 +67,20 @@ fn switch_learns() {
#[test] #[test]
fn switch_honours_vlans() { fn switch_honours_vlans() {
//TODO // TODO
} }
#[test] #[test]
fn switch_forgets() { fn switch_forgets() {
//TODO // TODO
} }
#[test] #[test]
fn router_delivers() { fn router_delivers() {
//TODO // TODO
} }
#[test] #[test]
fn router_drops_unknown_dest() { fn router_drops_unknown_dest() {
//TODO // TODO
} }

View File

@ -97,9 +97,11 @@ fn cross_connect() {
fn connect_via_beacons() { fn connect_via_beacons() {
MockTimeSource::set_time(0); MockTimeSource::set_time(0);
let beacon_path = "target/.vpncloud_test"; let beacon_path = "target/.vpncloud_test";
let mut node1 = create_tap_node_with_config(Config { beacon_store: Some(beacon_path.to_string()), ..Config::default()}); let mut node1 =
create_tap_node_with_config(Config { beacon_store: Some(beacon_path.to_string()), ..Config::default() });
let node1_addr = node1.address().unwrap().0; let node1_addr = node1.address().unwrap().0;
let mut node2 = create_tap_node_with_config(Config { beacon_load: Some(beacon_path.to_string()), ..Config::default()}); let mut node2 =
create_tap_node_with_config(Config { beacon_load: Some(beacon_path.to_string()), ..Config::default() });
let node2_addr = addr!("2.2.2.2:2222"); let node2_addr = addr!("2.2.2.2:2222");
assert!(!node1.peers().contains_node(&node2.node_id())); assert!(!node1.peers().contains_node(&node2.node_id()));
@ -164,14 +166,14 @@ fn lost_init1() {
simulate!(node1 => node1_addr, node2 => node2_addr); simulate!(node1 => node1_addr, node2 => node2_addr);
assert_connected!(node1, node2); assert_connected!(node1, node2);
} }
#[test] #[test]
fn wrong_magic() { fn wrong_magic() {
let mut node1 = create_tap_node(); let mut node1 = create_tap_node();
let node1_addr = addr!("1.2.3.4:5678"); let node1_addr = addr!("1.2.3.4:5678");
let mut node2 = create_tap_node_with_config(Config { magic: Some("hash:different".to_string()), ..Config::default()}); let mut node2 =
create_tap_node_with_config(Config { magic: Some("hash:different".to_string()), ..Config::default() });
let node2_addr = addr!("2.3.4.5:6789"); let node2_addr = addr!("2.3.4.5:6789");
node1.connect("2.3.4.5:6789").unwrap(); node1.connect("2.3.4.5:6789").unwrap();
@ -185,21 +187,20 @@ fn wrong_magic() {
#[test] #[test]
fn peer_exchange() { fn peer_exchange() {
//TODO // TODO
} }
#[test] #[test]
fn lost_peer_exchange() { fn lost_peer_exchange() {
//TODO // TODO
} }
#[test] #[test]
fn remove_dead_peers() { fn remove_dead_peers() {
//TODO // TODO
} }
#[test] #[test]
fn update_primary_address() { fn update_primary_address() {
//TODO // TODO
} }

View File

@ -2,13 +2,13 @@
// Copyright (C) 2018-2019 Dennis Schwerdel // Copyright (C) 2018-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md) // This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::net::SocketAddr; use std::{
use std::collections::HashMap; collections::HashMap,
use std::io::{self, Write}; io::{self, Write},
net::SocketAddr
};
use super::types::Address; use super::{cloud::Hash, types::Address, util::Bytes};
use super::cloud::Hash;
use super::util::Bytes;
#[derive(Default)] #[derive(Default)]
@ -95,11 +95,11 @@ impl TrafficStats {
} }
} }
pub fn get_peer_traffic(&self) -> impl Iterator<Item=(&SocketAddr, &TrafficEntry)> { pub fn get_peer_traffic(&self) -> impl Iterator<Item = (&SocketAddr, &TrafficEntry)> {
self.peers.iter() self.peers.iter()
} }
pub fn get_payload_traffic(&self) -> impl Iterator<Item=(&(Address, Address), &TrafficEntry)> { pub fn get_payload_traffic(&self) -> impl Iterator<Item = (&(Address, Address), &TrafficEntry)> {
self.payload.iter() self.payload.iter()
} }
@ -109,14 +109,21 @@ impl TrafficStats {
let mut peers: Vec<_> = self.get_peer_traffic().collect(); let mut peers: Vec<_> = self.get_peer_traffic().collect();
peers.sort_unstable_by_key(|(_, data)| (data.out_bytes + data.in_bytes)); peers.sort_unstable_by_key(|(_, data)| (data.out_bytes + data.in_bytes));
for (addr, data) in peers.iter().rev() { for (addr, data) in peers.iter().rev() {
writeln!(out, " - {}: in={}/s, out={}/s", addr, Bytes(data.in_bytes/60), Bytes(data.out_bytes/60))?; writeln!(out, " - {}: in={}/s, out={}/s", addr, Bytes(data.in_bytes / 60), Bytes(data.out_bytes / 60))?;
} }
writeln!(out)?; writeln!(out)?;
writeln!(out, "Payload traffic:")?; writeln!(out, "Payload traffic:")?;
let mut payload: Vec<_> = self.get_payload_traffic().collect(); let mut payload: Vec<_> = self.get_payload_traffic().collect();
payload.sort_unstable_by_key(|(_, data)| (data.out_bytes + data.in_bytes)); payload.sort_unstable_by_key(|(_, data)| (data.out_bytes + data.in_bytes));
for ((remote, local), data) in payload.iter().rev() { for ((remote, local), data) in payload.iter().rev() {
writeln!(out, " - {} <-> {}: in={}/s, out={}/s", remote, local, Bytes(data.in_bytes/60), Bytes(data.out_bytes/60))?; writeln!(
out,
" - {} <-> {}: in={}/s, out={}/s",
remote,
local,
Bytes(data.in_bytes / 60),
Bytes(data.out_bytes / 60)
)?;
} }
Ok(()) Ok(())
} }

View File

@ -2,11 +2,13 @@
// Copyright (C) 2015-2019 Dennis Schwerdel // Copyright (C) 2015-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md) // This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr}; use std::{
use std::fmt; fmt,
use std::str::FromStr; hash::{Hash, Hasher},
use std::hash::{Hash, Hasher}; io::{self, Write},
use std::io::{self, Write}; net::{Ipv4Addr, Ipv6Addr, SocketAddr},
str::FromStr
};
use super::util::{bytes_to_hex, Encoder}; use super::util::{bytes_to_hex, Encoder};
@ -26,7 +28,7 @@ impl Address {
#[inline] #[inline]
pub fn read_from(data: &[u8]) -> Result<(Address, usize), Error> { pub fn read_from(data: &[u8]) -> Result<(Address, usize), Error> {
if data.is_empty() { if data.is_empty() {
return Err(Error::Parse("Address too short")); return Err(Error::Parse("Address too short"))
} }
let len = data[0] as usize; let len = data[0] as usize;
let addr = Address::read_from_fixed(&data[1..], len)?; let addr = Address::read_from_fixed(&data[1..], len)?;
@ -36,18 +38,18 @@ impl Address {
#[inline] #[inline]
pub fn read_from_fixed(data: &[u8], len: usize) -> Result<Address, Error> { pub fn read_from_fixed(data: &[u8], len: usize) -> Result<Address, Error> {
if len > 16 { if len > 16 {
return Err(Error::Parse("Invalid address, too long")); return Err(Error::Parse("Invalid address, too long"))
} }
if data.len() < len { if data.len() < len {
return Err(Error::Parse("Address too short")); return Err(Error::Parse("Address too short"))
} }
let mut bytes = [0; 16]; let mut bytes = [0; 16];
bytes[0..len].copy_from_slice(&data[0..len]); bytes[0..len].copy_from_slice(&data[0..len]);
Ok(Address{data: bytes, len: len as u8}) Ok(Address { data: bytes, len: len as u8 })
} }
#[inline] #[inline]
pub fn write_to(&self, data: &mut[u8]) -> usize { pub fn write_to(&self, data: &mut [u8]) -> usize {
assert!(data.len() > self.len as usize); assert!(data.len() > self.len as usize);
data[0] = self.len; data[0] = self.len;
let len = self.len as usize; let len = self.len as usize;
@ -99,23 +101,23 @@ impl fmt::Debug for Address {
} }
impl FromStr for Address { impl FromStr for Address {
type Err=Error; type Err = Error;
#[allow(unknown_lints,clippy::needless_range_loop)] #[allow(unknown_lints, clippy::needless_range_loop)]
fn from_str(text: &str) -> Result<Self, Self::Err> { fn from_str(text: &str) -> Result<Self, Self::Err> {
if let Ok(addr) = Ipv4Addr::from_str(text) { if let Ok(addr) = Ipv4Addr::from_str(text) {
let ip = addr.octets(); let ip = addr.octets();
let mut res = [0; 16]; let mut res = [0; 16];
res[0..4].copy_from_slice(&ip); res[0..4].copy_from_slice(&ip);
return Ok(Address{data: res, len: 4}); return Ok(Address { data: res, len: 4 })
} }
if let Ok(addr) = Ipv6Addr::from_str(text) { if let Ok(addr) = Ipv6Addr::from_str(text) {
let segments = addr.segments(); let segments = addr.segments();
let mut res = [0; 16]; let mut res = [0; 16];
for i in 0..8 { for i in 0..8 {
Encoder::write_u16(segments[i], &mut res[2*i..]); Encoder::write_u16(segments[i], &mut res[2 * i..]);
} }
return Ok(Address{data: res, len: 16}); return Ok(Address { data: res, len: 16 })
} }
let parts: Vec<&str> = text.split(':').collect(); let parts: Vec<&str> = text.split(':').collect();
if parts.len() == 6 { if parts.len() == 6 {
@ -123,7 +125,7 @@ impl FromStr for Address {
for i in 0..6 { for i in 0..6 {
bytes[i] = u8::from_str_radix(parts[i], 16).map_err(|_| Error::Parse("Failed to parse mac"))?; bytes[i] = u8::from_str_radix(parts[i], 16).map_err(|_| Error::Parse("Failed to parse mac"))?;
} }
return Ok(Address{data: bytes, len: 6}); return Ok(Address { data: bytes, len: 6 })
} }
Err(Error::Parse("Failed to parse address")) Err(Error::Parse("Failed to parse address"))
} }
@ -141,14 +143,14 @@ impl Range {
pub fn read_from(data: &[u8]) -> Result<(Range, usize), Error> { pub fn read_from(data: &[u8]) -> Result<(Range, usize), Error> {
let (address, read) = Address::read_from(data)?; let (address, read) = Address::read_from(data)?;
if data.len() < read + 1 { if data.len() < read + 1 {
return Err(Error::Parse("Range too short")); return Err(Error::Parse("Range too short"))
} }
let prefix_len = data[read]; let prefix_len = data[read];
Ok((Range{base: address, prefix_len}, read + 1)) Ok((Range { base: address, prefix_len }, read + 1))
} }
#[inline] #[inline]
pub fn write_to(&self, data: &mut[u8]) -> usize { pub fn write_to(&self, data: &mut [u8]) -> usize {
let pos = self.base.write_to(data); let pos = self.base.write_to(data);
assert!(data.len() > pos); assert!(data.len() > pos);
data[pos] = self.prefix_len; data[pos] = self.prefix_len;
@ -157,17 +159,16 @@ impl Range {
} }
impl FromStr for Range { impl FromStr for Range {
type Err=Error; type Err = Error;
fn from_str(text: &str) -> Result<Self, Self::Err> { fn from_str(text: &str) -> Result<Self, Self::Err> {
let pos = match text.find('/') { let pos = match text.find('/') {
Some(pos) => pos, Some(pos) => pos,
None => return Err(Error::Parse("Invalid range format")) None => return Err(Error::Parse("Invalid range format"))
}; };
let prefix_len = u8::from_str(&text[pos+1..]) let prefix_len = u8::from_str(&text[pos + 1..]).map_err(|_| Error::Parse("Failed to parse prefix length"))?;
.map_err(|_| Error::Parse("Failed to parse prefix length"))?;
let base = Address::from_str(&text[..pos])?; let base = Address::from_str(&text[..pos])?;
Ok(Range{base, prefix_len}) Ok(Range { base, prefix_len })
} }
} }
@ -201,7 +202,7 @@ impl fmt::Display for Mode {
Mode::Normal => write!(formatter, "normal"), Mode::Normal => write!(formatter, "normal"),
Mode::Hub => write!(formatter, "hub"), Mode::Hub => write!(formatter, "hub"),
Mode::Switch => write!(formatter, "switch"), Mode::Switch => write!(formatter, "switch"),
Mode::Router => write!(formatter, "router"), Mode::Router => write!(formatter, "router")
} }
} }
} }
@ -250,9 +251,15 @@ impl fmt::Display for Error {
fn address_parse_fmt() { fn address_parse_fmt() {
assert_eq!(format!("{}", Address::from_str("120.45.22.5").unwrap()), "120.45.22.5"); assert_eq!(format!("{}", Address::from_str("120.45.22.5").unwrap()), "120.45.22.5");
assert_eq!(format!("{}", Address::from_str("78:2d:16:05:01:02").unwrap()), "78:2d:16:05:01:02"); assert_eq!(format!("{}", Address::from_str("78:2d:16:05:01:02").unwrap()), "78:2d:16:05:01:02");
assert_eq!(format!("{}", Address{data: [3,56,120,45,22,5,1,2,0,0,0,0,0,0,0,0], len: 8}), "vlan824/78:2d:16:05:01:02"); assert_eq!(
assert_eq!(format!("{}", Address::from_str("0001:0203:0405:0607:0809:0a0b:0c0d:0e0f").unwrap()), "0001:0203:0405:0607:0809:0a0b:0c0d:0e0f"); format!("{}", Address { data: [3, 56, 120, 45, 22, 5, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0], len: 8 }),
assert_eq!(format!("{:?}", Address{data: [1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0], len: 2}), "0102"); "vlan824/78:2d:16:05:01:02"
);
assert_eq!(
format!("{}", Address::from_str("0001:0203:0405:0607:0809:0a0b:0c0d:0e0f").unwrap()),
"0001:0203:0405:0607:0809:0a0b:0c0d:0e0f"
);
assert_eq!(format!("{:?}", Address { data: [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], len: 2 }), "0102");
assert!(Address::from_str("").is_err()); // Failed to parse address assert!(Address::from_str("").is_err()); // Failed to parse address
} }
@ -278,16 +285,29 @@ fn address_decode_encode() {
#[test] #[test]
fn address_eq() { fn address_eq() {
assert_eq!(Address::read_from_fixed(&[1,2,3,4], 4).unwrap(), Address::read_from_fixed(&[1,2,3,4], 4).unwrap()); assert_eq!(
assert_ne!(Address::read_from_fixed(&[1,2,3,4], 4).unwrap(), Address::read_from_fixed(&[1,2,3,5], 4).unwrap()); Address::read_from_fixed(&[1, 2, 3, 4], 4).unwrap(),
assert_eq!(Address::read_from_fixed(&[1,2,3,4], 3).unwrap(), Address::read_from_fixed(&[1,2,3,5], 3).unwrap()); Address::read_from_fixed(&[1, 2, 3, 4], 4).unwrap()
assert_ne!(Address::read_from_fixed(&[1,2,3,4], 3).unwrap(), Address::read_from_fixed(&[1,2,3,4], 4).unwrap()); );
assert_ne!(
Address::read_from_fixed(&[1, 2, 3, 4], 4).unwrap(),
Address::read_from_fixed(&[1, 2, 3, 5], 4).unwrap()
);
assert_eq!(
Address::read_from_fixed(&[1, 2, 3, 4], 3).unwrap(),
Address::read_from_fixed(&[1, 2, 3, 5], 3).unwrap()
);
assert_ne!(
Address::read_from_fixed(&[1, 2, 3, 4], 3).unwrap(),
Address::read_from_fixed(&[1, 2, 3, 4], 4).unwrap()
);
} }
#[test] #[test]
fn address_range_decode_encode() { fn address_range_decode_encode() {
let mut buf = [0; 32]; let mut buf = [0; 32];
let range = Range{base: Address{data: [0,1,2,3,0,0,0,0,0,0,0,0,0,0,0,0], len: 4}, prefix_len: 24}; let range =
Range { base: Address { data: [0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], len: 4 }, prefix_len: 24 };
assert_eq!(range.write_to(&mut buf), 6); assert_eq!(range.write_to(&mut buf), 6);
assert_eq!(&buf[0..6], &[4, 0, 1, 2, 3, 24]); assert_eq!(&buf[0..6], &[4, 0, 1, 2, 3, 24]);
assert_eq!((range, 6), Range::read_from(&buf).unwrap()); assert_eq!((range, 6), Range::read_from(&buf).unwrap());

View File

@ -2,18 +2,22 @@
// Copyright (C) 2015-2019 Dennis Schwerdel // Copyright (C) 2015-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md) // This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::fmt; use std::{
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr, SocketAddrV6, Ipv6Addr}; fmt,
net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}
};
use super::types::{NodeId, HeaderMagic, Error, Range, NODE_ID_BYTES}; use super::{
use super::util::{bytes_to_hex, Encoder}; crypto::Crypto,
use super::crypto::Crypto; types::{Error, HeaderMagic, NodeId, Range, NODE_ID_BYTES},
util::{bytes_to_hex, Encoder}
};
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Default)]
#[repr(packed)] #[repr(packed)]
struct TopHeader { struct TopHeader {
magic: HeaderMagic, magic: HeaderMagic,
crypto_method : u8, crypto_method: u8,
_reserved1: u8, _reserved1: u8,
_reserved2: u8, _reserved2: u8,
msgtype: u8 msgtype: u8
@ -27,7 +31,7 @@ impl TopHeader {
pub fn read_from(data: &[u8]) -> Result<(TopHeader, usize), Error> { pub fn read_from(data: &[u8]) -> Result<(TopHeader, usize), Error> {
if data.len() < TopHeader::size() { if data.len() < TopHeader::size() {
return Err(Error::Parse("Empty message")); return Err(Error::Parse("Empty message"))
} }
let mut header = TopHeader::default(); let mut header = TopHeader::default();
header.magic.copy_from_slice(&data[0..4]); header.magic.copy_from_slice(&data[0..4]);
@ -36,7 +40,7 @@ impl TopHeader {
Ok((header, TopHeader::size())) Ok((header, TopHeader::size()))
} }
#[allow(unknown_lints,clippy::trivially_copy_pass_by_ref)] #[allow(unknown_lints, clippy::trivially_copy_pass_by_ref)]
pub fn write_to(&self, data: &mut [u8]) -> usize { pub fn write_to(&self, data: &mut [u8]) -> usize {
assert!(data.len() >= 8); assert!(data.len() >= 8);
data[0..4].copy_from_slice(&self.magic); data[0..4].copy_from_slice(&self.magic);
@ -49,10 +53,10 @@ impl TopHeader {
} }
pub enum Message<'a> { pub enum Message<'a> {
Data(&'a mut[u8], usize, usize), // data, start, end Data(&'a mut [u8], usize, usize), // data, start, end
Peers(Vec<SocketAddr>), // peers Peers(Vec<SocketAddr>), // peers
Init(u8, NodeId, Vec<Range>), // step, node_id, ranges Init(u8, NodeId, Vec<Range>), // step, node_id, ranges
Close, Close
} }
impl<'a> Message<'a> { impl<'a> Message<'a> {
@ -69,7 +73,7 @@ impl<'a> Message<'a> {
impl<'a> fmt::Debug for Message<'a> { impl<'a> fmt::Debug for Message<'a> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self { match *self {
Message::Data(_, start, end) => write!(formatter, "Data({} bytes)", end-start), Message::Data(_, start, end) => write!(formatter, "Data({} bytes)", end - start),
Message::Peers(ref peers) => { Message::Peers(ref peers) => {
write!(formatter, "Peers [")?; write!(formatter, "Peers [")?;
let mut first = true; let mut first = true;
@ -81,27 +85,29 @@ impl<'a> fmt::Debug for Message<'a> {
write!(formatter, "{}", p)?; write!(formatter, "{}", p)?;
} }
write!(formatter, "]") write!(formatter, "]")
}, }
Message::Init(stage, ref node_id, ref peers) => write!(formatter, "Init(stage={}, node_id={}, {:?})", stage, bytes_to_hex(node_id), peers), Message::Init(stage, ref node_id, ref peers) => {
Message::Close => write!(formatter, "Close"), write!(formatter, "Init(stage={}, node_id={}, {:?})", stage, bytes_to_hex(node_id), peers)
}
Message::Close => write!(formatter, "Close")
} }
} }
} }
#[allow(unknown_lints,clippy::needless_range_loop)] #[allow(unknown_lints, clippy::needless_range_loop)]
pub fn decode<'a>(data: &'a mut [u8], magic: HeaderMagic, crypto: &Crypto) -> Result<Message<'a>, Error> { pub fn decode<'a>(data: &'a mut [u8], magic: HeaderMagic, crypto: &Crypto) -> Result<Message<'a>, Error> {
let mut end = data.len(); let mut end = data.len();
let (header, mut pos) = TopHeader::read_from(&data[..end])?; let (header, mut pos) = TopHeader::read_from(&data[..end])?;
if header.magic != magic { if header.magic != magic {
return Err(Error::WrongHeaderMagic(header.magic)); return Err(Error::WrongHeaderMagic(header.magic))
} }
if header.crypto_method != crypto.method() { if header.crypto_method != crypto.method() {
return Err(Error::Crypto("Wrong crypto method")); return Err(Error::Crypto("Wrong crypto method"))
} }
if crypto.method() > 0 { if crypto.method() > 0 {
let len = crypto.nonce_bytes(); let len = crypto.nonce_bytes();
if end < pos + len { if end < pos + len {
return Err(Error::Parse("Truncated crypto header")); return Err(Error::Parse("Truncated crypto header"))
} }
{ {
let (before, after) = data.split_at_mut(pos); let (before, after) = data.split_at_mut(pos);
@ -109,20 +115,20 @@ pub fn decode<'a>(data: &'a mut [u8], magic: HeaderMagic, crypto: &Crypto) -> Re
pos += len; pos += len;
end = crypto.decrypt(crypto_data, nonce, &before[..TopHeader::size()])? + pos; end = crypto.decrypt(crypto_data, nonce, &before[..TopHeader::size()])? + pos;
} }
assert_eq!(end, data.len()-crypto.additional_bytes()); assert_eq!(end, data.len() - crypto.additional_bytes());
} }
let msg = match header.msgtype { let msg = match header.msgtype {
0 => Message::Data(data, pos, end), 0 => Message::Data(data, pos, end),
1 => { 1 => {
if end < pos + 1 { if end < pos + 1 {
return Err(Error::Parse("Missing IPv4 count")); return Err(Error::Parse("Missing IPv4 count"))
} }
let mut peers = Vec::new(); let mut peers = Vec::new();
let count = data[pos]; let count = data[pos];
pos += 1; pos += 1;
let len = count as usize * 6; let len = count as usize * 6;
if end < pos + len { if end < pos + len {
return Err(Error::Parse("IPv4 peer data too short")); return Err(Error::Parse("IPv4 peer data too short"))
} }
for _ in 0..count { for _ in 0..count {
let ip = &data[pos..]; let ip = &data[pos..];
@ -134,13 +140,13 @@ pub fn decode<'a>(data: &'a mut [u8], magic: HeaderMagic, crypto: &Crypto) -> Re
peers.push(addr); peers.push(addr);
} }
if end < pos + 1 { if end < pos + 1 {
return Err(Error::Parse("Missing IPv6 count")); return Err(Error::Parse("Missing IPv6 count"))
} }
let count = data[pos]; let count = data[pos];
pos += 1; pos += 1;
let len = count as usize * 18; let len = count as usize * 18;
if end < pos + len { if end < pos + len {
return Err(Error::Parse("IPv6 peer data too short")); return Err(Error::Parse("IPv6 peer data too short"))
} }
for _ in 0..count { for _ in 0..count {
let mut ip = [0u16; 8]; let mut ip = [0u16; 8];
@ -150,20 +156,24 @@ pub fn decode<'a>(data: &'a mut [u8], magic: HeaderMagic, crypto: &Crypto) -> Re
} }
let port = Encoder::read_u16(&data[pos..]); let port = Encoder::read_u16(&data[pos..]);
pos += 2; pos += 2;
let addr = SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(ip[0], ip[1], ip[2], let addr = SocketAddr::V6(SocketAddrV6::new(
ip[3], ip[4], ip[5], ip[6], ip[7]), port, 0, 0)); 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.push(addr);
} }
Message::Peers(peers) Message::Peers(peers)
}, }
2 => { 2 => {
if end < pos + 2 + NODE_ID_BYTES { if end < pos + 2 + NODE_ID_BYTES {
return Err(Error::Parse("Init data too short")); return Err(Error::Parse("Init data too short"))
} }
let stage = data[pos]; let stage = data[pos];
pos += 1; pos += 1;
let mut node_id = [0; NODE_ID_BYTES]; let mut node_id = [0; NODE_ID_BYTES];
node_id.copy_from_slice(&data[pos..pos+NODE_ID_BYTES]); node_id.copy_from_slice(&data[pos..pos + NODE_ID_BYTES]);
pos += NODE_ID_BYTES; pos += NODE_ID_BYTES;
let count = data[pos] as usize; let count = data[pos] as usize;
pos += 1; pos += 1;
@ -174,15 +184,17 @@ pub fn decode<'a>(data: &'a mut [u8], magic: HeaderMagic, crypto: &Crypto) -> Re
addrs.push(range); addrs.push(range);
} }
Message::Init(stage, node_id, addrs) Message::Init(stage, node_id, addrs)
}, }
3 => Message::Close, 3 => Message::Close,
_ => return Err(Error::Parse("Unknown message type")) _ => return Err(Error::Parse("Unknown message type"))
}; };
Ok(msg) Ok(msg)
} }
#[allow(unknown_lints,clippy::needless_range_loop)] #[allow(unknown_lints, clippy::needless_range_loop)]
pub fn encode<'a>(msg: &'a mut Message, mut buf: &'a mut [u8], magic: HeaderMagic, crypto: &mut Crypto) -> &'a mut [u8] { pub fn encode<'a>(
msg: &'a mut Message, mut buf: &'a mut [u8], magic: HeaderMagic, crypto: &mut Crypto
) -> &'a mut [u8] {
let header_type = match msg { let header_type = match msg {
Message::Data(_, _, _) => 0, Message::Data(_, _, _) => 0,
Message::Peers(_) => 1, Message::Peers(_) => 1,
@ -196,7 +208,7 @@ pub fn encode<'a>(msg: &'a mut Message, mut buf: &'a mut [u8], magic: HeaderMagi
buf = data; buf = data;
start = data_start; start = data_start;
end = data_end; end = data_end;
}, }
Message::Peers(ref peers) => { Message::Peers(ref peers) => {
let mut v4addrs = Vec::new(); let mut v4addrs = Vec::new();
let mut v6addrs = Vec::new(); let mut v6addrs = Vec::new();
@ -214,11 +226,11 @@ pub fn encode<'a>(msg: &'a mut Message, mut buf: &'a mut [u8], magic: HeaderMagi
pos += 1; pos += 1;
for addr in v4addrs { for addr in v4addrs {
let ip = addr.ip().octets(); let ip = addr.ip().octets();
buf[pos..pos+4].copy_from_slice(&ip); buf[pos..pos + 4].copy_from_slice(&ip);
pos += 4; pos += 4;
Encoder::write_u16(addr.port(), &mut buf[pos..]); Encoder::write_u16(addr.port(), &mut buf[pos..]);
pos += 2; pos += 2;
}; }
buf[pos] = v6addrs.len() as u8; buf[pos] = v6addrs.len() as u8;
pos += 1; pos += 1;
for addr in v6addrs { for addr in v6addrs {
@ -229,15 +241,15 @@ pub fn encode<'a>(msg: &'a mut Message, mut buf: &'a mut [u8], magic: HeaderMagi
} }
Encoder::write_u16(addr.port(), &mut buf[pos..]); Encoder::write_u16(addr.port(), &mut buf[pos..]);
pos += 2; pos += 2;
}; }
end = pos; end = pos;
}, }
Message::Init(stage, ref node_id, ref ranges) => { Message::Init(stage, ref node_id, ref ranges) => {
let mut pos = start; let mut pos = start;
assert!(buf.len() >= pos + 2 + NODE_ID_BYTES); assert!(buf.len() >= pos + 2 + NODE_ID_BYTES);
buf[pos] = stage; buf[pos] = stage;
pos += 1; pos += 1;
buf[pos..pos+NODE_ID_BYTES].copy_from_slice(node_id); buf[pos..pos + NODE_ID_BYTES].copy_from_slice(node_id);
pos += NODE_ID_BYTES; pos += NODE_ID_BYTES;
assert!(ranges.len() <= 255); assert!(ranges.len() <= 255);
buf[pos] = ranges.len() as u8; buf[pos] = ranges.len() as u8;
@ -246,9 +258,8 @@ pub fn encode<'a>(msg: &'a mut Message, mut buf: &'a mut [u8], magic: HeaderMagi
pos += range.write_to(&mut buf[pos..]); pos += range.write_to(&mut buf[pos..]);
} }
end = pos; end = pos;
},
Message::Close => {
} }
Message::Close => {}
} }
assert!(start >= 64); assert!(start >= 64);
assert!(buf.len() >= end + 64); assert!(buf.len() >= end + 64);
@ -266,53 +277,68 @@ pub fn encode<'a>(msg: &'a mut Message, mut buf: &'a mut [u8], magic: HeaderMagi
let (nonce, rest) = rest.split_at_mut(crypto.nonce_bytes()); let (nonce, rest) = rest.split_at_mut(crypto.nonce_bytes());
debug_assert_eq!(junk_before.len() + header.len() + crypto.nonce_bytes(), crypto_start); debug_assert_eq!(junk_before.len() + header.len() + crypto.nonce_bytes(), crypto_start);
assert!(rest.len() >= end - crypto_start + crypto.additional_bytes()); assert!(rest.len() >= end - crypto_start + crypto.additional_bytes());
end = crypto.encrypt(rest, end-crypto_start, nonce, header) + crypto_start; end = crypto.encrypt(rest, end - crypto_start, nonce, header) + crypto_start;
} }
&mut buf[start..end] &mut buf[start..end]
} }
impl<'a> PartialEq for Message<'a> { impl<'a> PartialEq for Message<'a> {
fn eq(&self, other: &Message) -> bool { fn eq(&self, other: &Message) -> bool {
match *self { match *self {
Message::Data(ref data1, start1, end1) => if let Message::Data(ref data2, start2, end2) = *other { Message::Data(ref data1, start1, end1) => {
if let Message::Data(ref data2, start2, end2) = *other {
data1[start1..end1] == data2[start2..end2] data1[start1..end1] == data2[start2..end2]
} else { false }, } else {
Message::Peers(ref peers1) => if let Message::Peers(ref peers2) = *other { false
}
}
Message::Peers(ref peers1) => {
if let Message::Peers(ref peers2) = *other {
peers1 == peers2 peers1 == peers2
} else { false }, } else {
Message::Init(step1, node_id1, ref ranges1) => if let Message::Init(step2, node_id2, ref ranges2) = *other { false
}
}
Message::Init(step1, node_id1, ref ranges1) => {
if let Message::Init(step2, node_id2, ref ranges2) = *other {
step1 == step2 && node_id1 == node_id2 && ranges1 == ranges2 step1 == step2 && node_id1 == node_id2 && ranges1 == ranges2
} else { false }, } else {
Message::Close => if let Message::Close = *other { false
}
}
Message::Close => {
if let Message::Close = *other {
true true
} else { false } } else {
false
}
}
} }
} }
} }
#[cfg(test)] use std::str::FromStr;
#[cfg(test)] use super::MAGIC;
#[cfg(test)] use super::types::Address;
#[cfg(test)] use super::crypto::CryptoMethod; #[cfg(test)] use super::crypto::CryptoMethod;
#[cfg(test)] use super::types::Address;
#[cfg(test)] use super::MAGIC;
#[cfg(test)] use std::str::FromStr;
#[test] #[test]
#[allow(unused_assignments)] #[allow(unused_assignments)]
fn udpmessage_packet() { fn udpmessage_packet() {
let mut crypto = Crypto::None; let mut crypto = Crypto::None;
let mut payload = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, let mut payload = [
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1,2,3,4,5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
];
let mut msg = Message::Data(&mut payload, 64, 69); let mut msg = Message::Data(&mut payload, 64, 69);
let mut buf = [0; 1024]; let mut buf = [0; 1024];
let mut len = 0; let mut len = 0;
{ {
let res = encode(&mut msg, &mut [], MAGIC, &mut crypto); let res = encode(&mut msg, &mut [], MAGIC, &mut crypto);
assert_eq!(res.len(), 13); assert_eq!(res.len(), 13);
assert_eq!(&res[..8], &[118,112,110,1,0,0,0,0]); assert_eq!(&res[..8], &[118, 112, 110, 1, 0, 0, 0, 0]);
for i in 0..res.len() { for i in 0..res.len() {
buf[i] = res[i]; buf[i] = res[i];
} }
@ -326,11 +352,12 @@ fn udpmessage_packet() {
#[allow(unused_assignments)] #[allow(unused_assignments)]
fn udpmessage_encrypted() { fn udpmessage_encrypted() {
let mut crypto = Crypto::from_shared_key(CryptoMethod::ChaCha20, "test"); let mut crypto = Crypto::from_shared_key(CryptoMethod::ChaCha20, "test");
let mut payload = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, let mut payload = [
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1,2,3,4,5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
];
let mut orig_payload = [0; 133]; let mut orig_payload = [0; 133];
for i in 0..payload.len() { for i in 0..payload.len() {
orig_payload[i] = payload[i]; orig_payload[i] = payload[i];
@ -342,7 +369,7 @@ fn udpmessage_encrypted() {
{ {
let res = encode(&mut msg, &mut [], MAGIC, &mut crypto); let res = encode(&mut msg, &mut [], MAGIC, &mut crypto);
assert_eq!(res.len(), 41); assert_eq!(res.len(), 41);
assert_eq!(&res[..8], &[118,112,110,1,1,0,0,0]); assert_eq!(&res[..8], &[118, 112, 110, 1, 1, 0, 0, 0]);
for i in 0..res.len() { for i in 0..res.len() {
buf[i] = res[i]; buf[i] = res[i];
} }
@ -356,9 +383,15 @@ fn udpmessage_encrypted() {
fn udpmessage_peers() { fn udpmessage_peers() {
use std::str::FromStr; use std::str::FromStr;
let mut crypto = Crypto::None; let mut crypto = Crypto::None;
let mut msg = Message::Peers(vec![SocketAddr::from_str("1.2.3.4:123").unwrap(), SocketAddr::from_str("5.6.7.8:12345").unwrap(), SocketAddr::from_str("[0001:0203:0405:0607:0809:0a0b:0c0d:0e0f]:6789").unwrap()]); let mut msg = Message::Peers(vec![
let mut should = [118,112,110,1,0,0,0,1,2,1,2,3,4,0,123,5,6,7,8,48,57,1,0,1,2,3,4,5,6,7, SocketAddr::from_str("1.2.3.4:123").unwrap(),
8,9,10,11,12,13,14,15,26,133]; SocketAddr::from_str("5.6.7.8:12345").unwrap(),
SocketAddr::from_str("[0001:0203:0405:0607:0809:0a0b:0c0d:0e0f]:6789").unwrap(),
]);
let mut should = [
118, 112, 110, 1, 0, 0, 0, 1, 2, 1, 2, 3, 4, 0, 123, 5, 6, 7, 8, 48, 57, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 26, 133
];
{ {
let mut buf = [0; 1024]; let mut buf = [0; 1024];
let res = encode(&mut msg, &mut buf[..], MAGIC, &mut crypto); let res = encode(&mut msg, &mut buf[..], MAGIC, &mut crypto);
@ -370,24 +403,29 @@ fn udpmessage_peers() {
let msg2 = decode(&mut should, MAGIC, &mut crypto).unwrap(); let msg2 = decode(&mut should, MAGIC, &mut crypto).unwrap();
assert_eq!(msg, msg2); assert_eq!(msg, msg2);
// Missing IPv4 count // Missing IPv4 count
assert!(decode(&mut[118,112,110,1,0,0,0,1], MAGIC, &mut crypto).is_err()); assert!(decode(&mut [118, 112, 110, 1, 0, 0, 0, 1], MAGIC, &mut crypto).is_err());
// Truncated IPv4 // Truncated IPv4
assert!(decode(&mut[118,112,110,1,0,0,0,1,1], MAGIC, &mut crypto).is_err()); assert!(decode(&mut [118, 112, 110, 1, 0, 0, 0, 1, 1], MAGIC, &mut crypto).is_err());
// Missing IPv6 count // Missing IPv6 count
assert!(decode(&mut[118,112,110,1,0,0,0,1,1,1,2,3,4,0,0], MAGIC, &mut crypto).is_err()); assert!(decode(&mut [118, 112, 110, 1, 0, 0, 0, 1, 1, 1, 2, 3, 4, 0, 0], MAGIC, &mut crypto).is_err());
// Truncated IPv6 // Truncated IPv6
assert!(decode(&mut[118,112,110,1,0,0,0,1,1,1,2,3,4,0,0,1], MAGIC, &mut crypto).is_err()); assert!(decode(&mut [118, 112, 110, 1, 0, 0, 0, 1, 1, 1, 2, 3, 4, 0, 0, 1], MAGIC, &mut crypto).is_err());
} }
#[test] #[test]
fn udpmessage_init() { fn udpmessage_init() {
use super::types::Address; use super::types::Address;
let mut crypto = Crypto::None; let mut crypto = Crypto::None;
let addrs = vec![Range{base: Address{data: [0,1,2,3,0,0,0,0,0,0,0,0,0,0,0,0], len: 4}, prefix_len: 24}, let addrs = vec![
Range{base: Address{data: [0,1,2,3,4,5,0,0,0,0,0,0,0,0,0,0], len: 6}, prefix_len: 16}]; Range { base: Address { data: [0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], len: 4 }, prefix_len: 24 },
let node_id = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; Range { base: Address { data: [0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], len: 6 }, prefix_len: 16 },
];
let node_id = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let mut msg = Message::Init(0, node_id, addrs); let mut msg = Message::Init(0, node_id, addrs);
let mut should = [118,112,110,1,0,0,0,2,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,2,4,0,1,2,3,24,6,0,1,2,3,4,5,16]; let mut should = [
118, 112, 110, 1, 0, 0, 0, 2, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 2, 4, 0, 1, 2, 3, 24, 6,
0, 1, 2, 3, 4, 5, 16
];
{ {
let mut buf = [0; 1024]; let mut buf = [0; 1024];
let res = encode(&mut msg, &mut buf[..], MAGIC, &mut crypto); let res = encode(&mut msg, &mut buf[..], MAGIC, &mut crypto);
@ -404,7 +442,7 @@ fn udpmessage_init() {
fn udpmessage_close() { fn udpmessage_close() {
let mut crypto = Crypto::None; let mut crypto = Crypto::None;
let mut msg = Message::Close; let mut msg = Message::Close;
let mut should = [118,112,110,1,0,0,0,3]; let mut should = [118, 112, 110, 1, 0, 0, 0, 3];
{ {
let mut buf = [0; 1024]; let mut buf = [0; 1024];
let res = encode(&mut msg, &mut buf[..], MAGIC, &mut crypto); let res = encode(&mut msg, &mut buf[..], MAGIC, &mut crypto);
@ -418,37 +456,55 @@ fn udpmessage_close() {
#[test] #[test]
fn udpmessage_invalid() { fn udpmessage_invalid() {
let mut crypto = Crypto::None; let mut crypto = Crypto::None;
assert!(decode(&mut [0x76,0x70,0x6e,1,0,0,0,0], MAGIC, &mut crypto).is_ok()); assert!(decode(&mut [0x76, 0x70, 0x6e, 1, 0, 0, 0, 0], MAGIC, &mut crypto).is_ok());
// too short // too short
assert!(decode(&mut [], MAGIC, &mut crypto).is_err()); assert!(decode(&mut [], MAGIC, &mut crypto).is_err());
// invalid protocol // invalid protocol
assert!(decode(&mut [0,1,2,0,0,0,0,0], MAGIC, &mut crypto).is_err()); assert!(decode(&mut [0, 1, 2, 0, 0, 0, 0, 0], MAGIC, &mut crypto).is_err());
// invalid version // invalid version
assert!(decode(&mut [0x76,0x70,0x6e,0xaa,0,0,0,0], MAGIC, &mut crypto).is_err()); assert!(decode(&mut [0x76, 0x70, 0x6e, 0xaa, 0, 0, 0, 0], MAGIC, &mut crypto).is_err());
// invalid crypto // invalid crypto
assert!(decode(&mut [0x76,0x70,0x6e,1,0xaa,0,0,0], MAGIC, &mut crypto).is_err()); assert!(decode(&mut [0x76, 0x70, 0x6e, 1, 0xaa, 0, 0, 0], MAGIC, &mut crypto).is_err());
// invalid msg type // invalid msg type
assert!(decode(&mut [0x76,0x70,0x6e,1,0,0,0,0xaa], MAGIC, &mut crypto).is_err()); assert!(decode(&mut [0x76, 0x70, 0x6e, 1, 0, 0, 0, 0xaa], MAGIC, &mut crypto).is_err());
} }
#[test] #[test]
fn udpmessage_invalid_crypto() { fn udpmessage_invalid_crypto() {
let mut crypto = Crypto::from_shared_key(CryptoMethod::ChaCha20, "test"); let mut crypto = Crypto::from_shared_key(CryptoMethod::ChaCha20, "test");
// truncated crypto // truncated crypto
assert!(decode(&mut [0x76,0x70,0x6e,1,1,0,0,0], MAGIC, &mut crypto).is_err()); assert!(decode(&mut [0x76, 0x70, 0x6e, 1, 1, 0, 0, 0], MAGIC, &mut crypto).is_err());
} }
#[test] #[test]
fn message_fmt() { fn message_fmt() {
assert_eq!(format!("{:?}", Message::Data(&mut [1,2,3,4,5], 0, 5)), "Data(5 bytes)"); assert_eq!(format!("{:?}", Message::Data(&mut [1, 2, 3, 4, 5], 0, 5)), "Data(5 bytes)");
assert_eq!(format!("{:?}", Message::Peers(vec![SocketAddr::from_str("1.2.3.4:123").unwrap(), assert_eq!(
format!(
"{:?}",
Message::Peers(vec![
SocketAddr::from_str("1.2.3.4:123").unwrap(),
SocketAddr::from_str("5.6.7.8:12345").unwrap(), SocketAddr::from_str("5.6.7.8:12345").unwrap(),
SocketAddr::from_str("[0001:0203:0405:0607:0809:0a0b:0c0d:0e0f]:6789").unwrap()])), SocketAddr::from_str("[0001:0203:0405:0607:0809:0a0b:0c0d:0e0f]:6789").unwrap()
"Peers [1.2.3.4:123, 5.6.7.8:12345, [1:203:405:607:809:a0b:c0d:e0f]:6789]"); ])
assert_eq!(format!("{:?}", Message::Init(0, [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], vec![ ),
Range{base: Address{data: [0,1,2,3,0,0,0,0,0,0,0,0,0,0,0,0], len: 4}, prefix_len: 24}, "Peers [1.2.3.4:123, 5.6.7.8:12345, [1:203:405:607:809:a0b:c0d:e0f]:6789]"
Range{base: Address{data: [0,1,2,3,4,5,0,0,0,0,0,0,0,0,0,0], len: 6}, prefix_len: 16} );
])), "Init(stage=0, node_id=000102030405060708090a0b0c0d0e0f, [0.1.2.3/24, 00:01:02:03:04:05/16])"); assert_eq!(
format!(
"{:?}",
Message::Init(0, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], vec![
Range {
base: Address { data: [0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], len: 4 },
prefix_len: 24
},
Range {
base: Address { data: [0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], len: 6 },
prefix_len: 16
}
])
),
"Init(stage=0, node_id=000102030405060708090a0b0c0d0e0f, [0.1.2.3/24, 00:01:02:03:04:05/16])"
);
assert_eq!(format!("{:?}", Message::Close), "Close"); assert_eq!(format!("{:?}", Message::Close), "Close");
} }

View File

@ -2,17 +2,17 @@
// Copyright (C) 2015-2019 Dennis Schwerdel // Copyright (C) 2015-2019 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md) // This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::net::{SocketAddr, ToSocketAddrs}; use std::{
use std::fmt; fmt,
use std::sync::atomic::{AtomicIsize, Ordering}; net::{SocketAddr, ToSocketAddrs},
sync::atomic::{AtomicIsize, Ordering}
};
use super::types::Error; use super::types::Error;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")] use libc;
use libc;
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))] use time;
use time;
use signal::{trap::Trap, Signal}; use signal::{trap::Trap, Signal};
use std::time::Instant; use std::time::Instant;
@ -30,9 +30,7 @@ pub fn bytes_to_hex(bytes: &[u8]) -> String {
v.push(HEX_CHARS[(byte >> 4) as usize]); v.push(HEX_CHARS[(byte >> 4) as usize]);
v.push(HEX_CHARS[(byte & 0xf) as usize]); v.push(HEX_CHARS[(byte & 0xf) as usize]);
} }
unsafe { unsafe { String::from_utf8_unchecked(v) }
String::from_utf8_unchecked(v)
}
} }
@ -52,8 +50,7 @@ impl Encoder {
#[inline] #[inline]
pub fn read_u32(data: &[u8]) -> u32 { pub fn read_u32(data: &[u8]) -> u32 {
(u32::from(data[0]) << 24) | (u32::from(data[1]) << 16) | (u32::from(data[0]) << 24) | (u32::from(data[1]) << 16) | (u32::from(data[2]) << 8) | u32::from(data[3])
(u32::from(data[2]) << 8) | u32::from(data[3])
} }
#[inline] #[inline]
@ -66,10 +63,14 @@ impl Encoder {
#[inline] #[inline]
pub fn read_u64(data: &[u8]) -> u64 { pub fn read_u64(data: &[u8]) -> u64 {
(u64::from(data[0]) << 56) | (u64::from(data[1]) << 48) | (u64::from(data[0]) << 56)
(u64::from(data[2]) << 40) | (u64::from(data[3]) << 32) | | (u64::from(data[1]) << 48)
(u64::from(data[4]) << 24) | (u64::from(data[5]) << 16) | | (u64::from(data[2]) << 40)
(u64::from(data[6]) << 8) | u64::from(data[7]) | (u64::from(data[3]) << 32)
| (u64::from(data[4]) << 24)
| (u64::from(data[5]) << 16)
| (u64::from(data[6]) << 8)
| u64::from(data[7])
} }
#[inline] #[inline]
@ -115,15 +116,17 @@ macro_rules! try_fail {
} }
#[allow(unknown_lints,clippy::needless_pass_by_value)] #[allow(unknown_lints, clippy::needless_pass_by_value)]
pub fn resolve<Addr: ToSocketAddrs+fmt::Debug>(addr: Addr) -> Result<Vec<SocketAddr>, Error> { pub fn resolve<Addr: ToSocketAddrs + fmt::Debug>(addr: Addr) -> Result<Vec<SocketAddr>, Error> {
let addrs = addr.to_socket_addrs().map_err(|_| Error::Name(format!("{:?}", addr)))?; let addrs = addr.to_socket_addrs().map_err(|_| Error::Name(format!("{:?}", addr)))?;
// Remove duplicates in addrs (why are there duplicates???) // Remove duplicates in addrs (why are there duplicates???)
let mut addrs = addrs.collect::<Vec<_>>(); let mut addrs = addrs.collect::<Vec<_>>();
// Try IPv4 first as it usually is faster // Try IPv4 first as it usually is faster
addrs.sort_by_key(|addr| match *addr { addrs.sort_by_key(|addr| {
match *addr {
SocketAddr::V4(_) => 4, SocketAddr::V4(_) => 4,
SocketAddr::V6(_) => 6 SocketAddr::V6(_) => 6
}
}); });
addrs.dedup(); addrs.dedup();
Ok(addrs) Ok(addrs)
@ -131,11 +134,9 @@ pub fn resolve<Addr: ToSocketAddrs+fmt::Debug>(addr: Addr) -> Result<Vec<SocketA
#[allow(unused_macros)] #[allow(unused_macros)]
macro_rules! addr { macro_rules! addr {
($addr: expr) => { ($addr: expr) => {{
{
std::net::ToSocketAddrs::to_socket_addrs($addr).unwrap().next().unwrap() std::net::ToSocketAddrs::to_socket_addrs($addr).unwrap().next().unwrap()
} }};
};
} }
@ -147,29 +148,28 @@ impl fmt::Display for Bytes {
if size >= 512.0 { if size >= 512.0 {
size /= 1024.0; size /= 1024.0;
} else { } else {
return write!(formatter, "{:.0} B", size); return write!(formatter, "{:.0} B", size)
} }
if size >= 512.0 { if size >= 512.0 {
size /= 1024.0; size /= 1024.0;
} else { } else {
return write!(formatter, "{:.1} KiB", size); return write!(formatter, "{:.1} KiB", size)
} }
if size >= 512.0 { if size >= 512.0 {
size /= 1024.0; size /= 1024.0;
} else { } else {
return write!(formatter, "{:.1} MiB", size); return write!(formatter, "{:.1} MiB", size)
} }
if size >= 512.0 { if size >= 512.0 {
size /= 1024.0; size /= 1024.0;
} else { } else {
return write!(formatter, "{:.1} GiB", size); return write!(formatter, "{:.1} GiB", size)
} }
write!(formatter, "{:.1} TiB", size) write!(formatter, "{:.1} TiB", size)
} }
} }
pub struct CtrlC { pub struct CtrlC {
dummy_time: Instant, dummy_time: Instant,
trap: Trap trap: Trap
@ -205,7 +205,9 @@ impl TimeSource for SystemTimeSource {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn now() -> Time { fn now() -> Time {
let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 }; let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 };
unsafe { libc::clock_gettime(6, &mut tv); } unsafe {
libc::clock_gettime(6, &mut tv);
}
tv.tv_sec as Time tv.tv_sec as Time
} }

8
vpncloud.code-workspace Normal file
View File

@ -0,0 +1,8 @@
{
"folders": [
{
"path": "."
}
],
"settings": {}
}