mirror of https://github.com/dswd/vpncloud.git
Compare commits
No commits in common. "c750947ab0d03864d9b5e973fd0f2956d495fd5c" and "03c295d0a904a6b20d0a92f1c20f89cc24d2743e" have entirely different histories.
c750947ab0
...
03c295d0a9
135
src/beacon.rs
135
src/beacon.rs
|
@ -12,12 +12,11 @@ use std::fs::{self, Permissions, File};
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
use super::util::{Encoder, TimeSource};
|
use super::util::{now, Encoder};
|
||||||
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr, SocketAddrV6, Ipv6Addr};
|
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr, SocketAddrV6, Ipv6Addr};
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,36 +33,34 @@ fn sha512(data: &[u8]) -> Vec<u8> {
|
||||||
digest::digest(&digest::SHA512, data).as_ref().iter().map(|b| *b).collect()
|
digest::digest(&digest::SHA512, data).as_ref().iter().map(|b| *b).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn now_hour_16() -> u16 {
|
||||||
|
((now() / 3600) & 0xffff) as u16
|
||||||
|
}
|
||||||
|
|
||||||
struct FutureResult<T> {
|
struct FutureResult<T> {
|
||||||
has_result: AtomicBool,
|
has_result: AtomicBool,
|
||||||
result: Mutex<T>
|
result: Mutex<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BeaconSerializer<TS> {
|
pub struct BeaconSerializer {
|
||||||
magic: Vec<u8>,
|
magic: Vec<u8>,
|
||||||
shared_key: Vec<u8>,
|
shared_key: Vec<u8>,
|
||||||
future_peers: Arc<FutureResult<Vec<SocketAddr>>>,
|
future_peers: Arc<FutureResult<Vec<SocketAddr>>>,
|
||||||
_dummy_ts: PhantomData<TS>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TS: TimeSource> BeaconSerializer<TS> {
|
impl BeaconSerializer {
|
||||||
pub fn new(magic: &[u8], shared_key: &[u8]) -> Self {
|
pub fn new(magic: &[u8], shared_key: &[u8]) -> Self {
|
||||||
Self {
|
BeaconSerializer {
|
||||||
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),
|
has_result: AtomicBool::new(false),
|
||||||
result: Mutex::new(Vec::new())
|
result: Mutex::new(Vec::new())
|
||||||
}),
|
})
|
||||||
_dummy_ts: PhantomData
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn now_hour_16() -> u16 {
|
|
||||||
((TS::now() / 3600) & 0xffff) as u16
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_keystream(&self, type_: u8, seed: u8, iter: u8) -> Vec<u8> {
|
fn get_keystream(&self, type_: u8, seed: u8, iter: u8) -> Vec<u8> {
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
data.extend_from_slice(&[type_, seed, iter]);
|
data.extend_from_slice(&[type_, seed, iter]);
|
||||||
|
@ -113,10 +110,10 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
seed == sha512(data as &[u8])[0]
|
seed == sha512(data as &[u8])[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peerlist_encode(&self, peers: &[SocketAddr]) -> String {
|
fn peerlist_encode(&self, peers: &[SocketAddr], now_hour: u16) -> String {
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
// Add timestamp
|
// Add timestamp
|
||||||
data.extend_from_slice(&Self::now_hour_16().to_be_bytes());
|
data.extend_from_slice(&now_hour.to_be_bytes());
|
||||||
// Split addresses into v4 and v6
|
// Split addresses into v4 and v6
|
||||||
let mut v4addrs = Vec::new();
|
let mut v4addrs = Vec::new();
|
||||||
let mut v6addrs = Vec::new();
|
let mut v6addrs = Vec::new();
|
||||||
|
@ -154,7 +151,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
base_62::encode(&data)
|
base_62::encode(&data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peerlist_decode(&self, data: &str, ttl_hours: Option<u16>) -> Vec<SocketAddr> {
|
fn peerlist_decode(&self, data: &str, ttl_hours: Option<u16>, now_hour: u16) -> Vec<SocketAddr> {
|
||||||
let mut data = base_62::decode(data).expect("Invalid input");
|
let mut data = base_62::decode(data).expect("Invalid input");
|
||||||
let mut peers = Vec::new();
|
let mut peers = Vec::new();
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
|
@ -166,7 +163,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
}
|
}
|
||||||
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(now_hour);
|
||||||
if now - then > Wrapping(ttl) && then - now > Wrapping(ttl) {
|
if now - then > Wrapping(ttl) && then - now > Wrapping(ttl) {
|
||||||
return peers
|
return peers
|
||||||
}
|
}
|
||||||
|
@ -202,8 +199,12 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
peers
|
peers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn encode_internal(&self, peers: &[SocketAddr], now_hour: u16) -> String {
|
||||||
|
format!("{}{}{}", self.begin(), self.peerlist_encode(peers, now_hour), self.end())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn encode(&self, peers: &[SocketAddr]) -> String {
|
pub fn encode(&self, peers: &[SocketAddr]) -> String {
|
||||||
format!("{}{}{}", self.begin(), self.peerlist_encode(peers), self.end())
|
self.encode_internal(peers, now_hour_16())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_to_file<P: AsRef<Path>>(&self, peers: &[SocketAddr], path: P) -> Result<(), io::Error> {
|
pub fn write_to_file<P: AsRef<Path>>(&self, peers: &[SocketAddr], path: P) -> Result<(), io::Error> {
|
||||||
|
@ -217,7 +218,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
|
|
||||||
pub fn write_to_cmd(&self, peers: &[SocketAddr], cmd: &str) -> Result<(), io::Error> {
|
pub fn write_to_cmd(&self, peers: &[SocketAddr], cmd: &str) -> Result<(), io::Error> {
|
||||||
let begin = self.begin();
|
let begin = self.begin();
|
||||||
let data = self.peerlist_encode(peers);
|
let data = self.peerlist_encode(peers, now_hour_16());
|
||||||
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);
|
||||||
|
@ -235,7 +236,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(&self, data: &str, ttl_hours: Option<u16>) -> Vec<SocketAddr> {
|
fn decode_internal(&self, data: &str, ttl_hours: Option<u16>, now_hour: u16) -> Vec<SocketAddr> {
|
||||||
let data = base_62_sanitize(data);
|
let data = base_62_sanitize(data);
|
||||||
let mut peers = Vec::new();
|
let mut peers = Vec::new();
|
||||||
let begin = self.begin();
|
let begin = self.begin();
|
||||||
|
@ -246,7 +247,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
let start_pos = pos + begin.len();
|
let start_pos = pos + begin.len();
|
||||||
if let Some(found) = data[pos..].find(&end) {
|
if let Some(found) = data[pos..].find(&end) {
|
||||||
let end_pos = pos + found;
|
let end_pos = pos + found;
|
||||||
peers.append(&mut self.peerlist_decode(&data[start_pos..end_pos], ttl_hours));
|
peers.append(&mut self.peerlist_decode(&data[start_pos..end_pos], ttl_hours, now_hour));
|
||||||
pos = start_pos
|
pos = start_pos
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
|
@ -255,6 +256,10 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
peers
|
peers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decode(&self, data: &str, ttl_hours: Option<u16>) -> Vec<SocketAddr> {
|
||||||
|
self.decode_internal(data, ttl_hours, now_hour_16())
|
||||||
|
}
|
||||||
|
|
||||||
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 = try!(File::open(&path));
|
let mut f = try!(File::open(&path));
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
|
@ -301,112 +306,94 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
#[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 ::util::MockTimeSource;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encode() {
|
fn encode() {
|
||||||
MockTimeSource::set_time(2000*3600);
|
let ser = BeaconSerializer::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!("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", ser.encode(&peers));
|
assert_eq!("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", ser.encode_internal(&peers, 2000));
|
||||||
peers.push(SocketAddr::from_str("[::1]:5678").unwrap());
|
peers.push(SocketAddr::from_str("[::1]:5678").unwrap());
|
||||||
assert_eq!("juWwKjF5qZG7PE5imnpi5XARaXnP3UsMsGBLxM4FNFDzvjlKt1SO55LN", ser.encode(&peers));
|
assert_eq!("juWwKjF5qZG7PE5imnpi5XARaXnP3UsMsGBLxM4FNFDzvjlKt1SO55LN", ser.encode_internal(&peers, 2000));
|
||||||
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:54").unwrap());
|
peers.push(SocketAddr::from_str("6.6.6.6:54").unwrap());
|
||||||
assert_eq!("juWwKIgSqTammVFRNoIVzLPO0BEO55LN", ser.encode(&peers));
|
assert_eq!("juWwKIgSqTammVFRNoIVzLPO0BEO55LN", ser.encode_internal(&peers, 2000));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decode() {
|
fn decode() {
|
||||||
MockTimeSource::set_time(2000*3600);
|
let ser = BeaconSerializer::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_internal("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None, 2000)));
|
||||||
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_internal("juWwKjF5qZG7PE5imnpi5XARaXnP3UsMsGBLxM4FNFDzvjlKt1SO55LN", None, 2000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decode_split() {
|
fn decode_split() {
|
||||||
MockTimeSource::set_time(2000*3600);
|
let ser = BeaconSerializer::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!(format!("{:?}", peers), format!("{:?}", ser.decode_internal("juWwK-hj.VT:Yj bw\tJj\ntY(AZ)lM[fE]j7üIDäO55LN", None, 2000)));
|
||||||
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("j -, \nuW--wKhjVTYjbwJjtYAZlMfEj7IDO(5}5ÖÄÜ\nLN", None)));
|
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode_internal("j -, \nuW--wKhjVTYjbwJjtYAZlMfEj7IDO(5}5ÖÄÜ\nLN", None, 2000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decode_offset() {
|
fn decode_offset() {
|
||||||
MockTimeSource::set_time(2000*3600);
|
let ser = BeaconSerializer::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_internal("Hello World: juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN! End of the World", None, 2000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decode_multiple() {
|
fn decode_multiple() {
|
||||||
MockTimeSource::set_time(2000*3600);
|
let ser = BeaconSerializer::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_internal("juWwKkBEVBp9SsDiN3BO55LN juWwKtGGPQz1gXIBd68O55LN", None, 2000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decode_ttl() {
|
fn decode_ttl() {
|
||||||
MockTimeSource::set_time(2000*3600);
|
let ser = BeaconSerializer::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);
|
assert_eq!(2, ser.decode_internal("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None, 2000).len());
|
||||||
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None).len());
|
assert_eq!(2, ser.decode_internal("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None, 2100).len());
|
||||||
MockTimeSource::set_time(2100*3600);
|
assert_eq!(2, ser.decode_internal("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None, 2005).len());
|
||||||
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None).len());
|
assert_eq!(2, ser.decode_internal("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None, 1995).len());
|
||||||
MockTimeSource::set_time(2005*3600);
|
assert_eq!(2, ser.decode_internal("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24), 2000).len());
|
||||||
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None).len());
|
assert_eq!(2, ser.decode_internal("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24), 1995).len());
|
||||||
MockTimeSource::set_time(1995*3600);
|
assert_eq!(2, ser.decode_internal("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24), 2005).len());
|
||||||
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None).len());
|
assert_eq!(0, ser.decode_internal("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24), 2100).len());
|
||||||
MockTimeSource::set_time(2000*3600);
|
assert_eq!(0, ser.decode_internal("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24), 1900).len());
|
||||||
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24)).len());
|
|
||||||
MockTimeSource::set_time(1995*3600);
|
|
||||||
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24)).len());
|
|
||||||
MockTimeSource::set_time(2005*3600);
|
|
||||||
assert_eq!(2, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24)).len());
|
|
||||||
MockTimeSource::set_time(2100*3600);
|
|
||||||
assert_eq!(0, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24)).len());
|
|
||||||
MockTimeSource::set_time(1900*3600);
|
|
||||||
assert_eq!(0, ser.decode("juWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", Some(24)).len());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decode_invalid() {
|
fn decode_invalid() {
|
||||||
MockTimeSource::set_time(2000*3600);
|
let ser = BeaconSerializer::new(b"vpnc", b"mysecretkey");
|
||||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"vpnc", b"mysecretkey");
|
assert_eq!(0, ser.decode_internal("", None, 2000).len());
|
||||||
assert_eq!(0, ser.decode("", None).len());
|
assert_eq!(0, ser.decode_internal("juWwKO55LN", None, 2000).len());
|
||||||
assert_eq!(0, ser.decode("juWwKO55LN", None).len());
|
assert_eq!(0, ser.decode_internal("juWwK--", None, 2000).len());
|
||||||
assert_eq!(0, ser.decode("juWwK--", None).len());
|
assert_eq!(0, ser.decode_internal("--O55LN", None, 2000).len());
|
||||||
assert_eq!(0, ser.decode("--O55LN", None).len());
|
assert_eq!(0, ser.decode_internal("juWwKhjVTYjbwJjtYAZXMfEj7IDO55LN", None, 2000).len());
|
||||||
assert_eq!(0, ser.decode("juWwKhjVTYjbwJjtYAZXMfEj7IDO55LN", None).len());
|
assert_eq!(2, ser.decode_internal("SGrivjuWwKhjVTYjbwJjtYAZlMfEj7IDO55LNjuWwK", None, 2000).len());
|
||||||
assert_eq!(2, ser.decode("SGrivjuWwKhjVTYjbwJjtYAZlMfEj7IDO55LNjuWwK", None).len());
|
assert_eq!(2, ser.decode_internal("juWwKjuWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None, 2000).len());
|
||||||
assert_eq!(2, ser.decode("juWwKjuWwKhjVTYjbwJjtYAZlMfEj7IDO55LN", None).len());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encode_decode() {
|
fn encode_decode() {
|
||||||
MockTimeSource::set_time(2000*3600);
|
let ser = BeaconSerializer::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());
|
||||||
|
@ -417,8 +404,7 @@ fn encode_decode() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encode_decode_file() {
|
fn encode_decode_file() {
|
||||||
MockTimeSource::set_time(2000*3600);
|
let ser = BeaconSerializer::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());
|
||||||
|
@ -431,8 +417,7 @@ fn encode_decode_file() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encode_decode_cmd() {
|
fn encode_decode_cmd() {
|
||||||
MockTimeSource::set_time(2000*3600);
|
let ser = BeaconSerializer::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());
|
||||||
|
|
102
src/cloud.rs
102
src/cloud.rs
|
@ -21,7 +21,7 @@ use super::device::Device;
|
||||||
use super::udpmessage::{encode, decode, Message};
|
use super::udpmessage::{encode, decode, Message};
|
||||||
use super::crypto::Crypto;
|
use super::crypto::Crypto;
|
||||||
use super::port_forwarding::PortForwarding;
|
use super::port_forwarding::PortForwarding;
|
||||||
use super::util::{TimeSource, Time, Duration, resolve, CtrlC};
|
use super::util::{now, Time, Duration, resolve, CtrlC};
|
||||||
use super::poll::{WaitImpl, WaitResult};
|
use super::poll::{WaitImpl, WaitResult};
|
||||||
use super::traffic::TrafficStats;
|
use super::traffic::TrafficStats;
|
||||||
use super::beacon::BeaconSerializer;
|
use super::beacon::BeaconSerializer;
|
||||||
|
@ -40,27 +40,25 @@ struct PeerData {
|
||||||
alt_addrs: Vec<SocketAddr>,
|
alt_addrs: Vec<SocketAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PeerList<TS: TimeSource> {
|
struct PeerList {
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
peers: HashMap<SocketAddr, PeerData, Hash>,
|
peers: HashMap<SocketAddr, PeerData, Hash>,
|
||||||
nodes: HashMap<NodeId, SocketAddr, Hash>,
|
nodes: HashMap<NodeId, SocketAddr, Hash>,
|
||||||
addresses: HashMap<SocketAddr, NodeId, Hash>,
|
addresses: HashMap<SocketAddr, NodeId, Hash>
|
||||||
_dummy_ts: PhantomData<TS>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TS: TimeSource> PeerList<TS> {
|
impl PeerList {
|
||||||
fn new(timeout: Duration) -> PeerList<TS> {
|
fn new(timeout: Duration) -> PeerList {
|
||||||
PeerList{
|
PeerList{
|
||||||
peers: HashMap::default(),
|
peers: HashMap::default(),
|
||||||
timeout,
|
timeout,
|
||||||
nodes: HashMap::default(),
|
nodes: HashMap::default(),
|
||||||
addresses: HashMap::default(),
|
addresses: HashMap::default()
|
||||||
_dummy_ts: PhantomData
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timeout(&mut self) -> Vec<SocketAddr> {
|
fn timeout(&mut self) -> Vec<SocketAddr> {
|
||||||
let now = TS::now();
|
let now = now();
|
||||||
let mut del: Vec<SocketAddr> = Vec::new();
|
let mut del: Vec<SocketAddr> = Vec::new();
|
||||||
for (&addr, ref data) in &self.peers {
|
for (&addr, ref data) in &self.peers {
|
||||||
if data.timeout < now {
|
if data.timeout < now {
|
||||||
|
@ -106,7 +104,7 @@ impl<TS: TimeSource> PeerList<TS> {
|
||||||
if self.nodes.insert(node_id, addr).is_none() {
|
if self.nodes.insert(node_id, addr).is_none() {
|
||||||
info!("New peer: {}", addr);
|
info!("New peer: {}", addr);
|
||||||
self.peers.insert(addr, PeerData {
|
self.peers.insert(addr, PeerData {
|
||||||
timeout: TS::now() + Time::from(self.timeout),
|
timeout: now() + Time::from(self.timeout),
|
||||||
node_id,
|
node_id,
|
||||||
alt_addrs: vec![]
|
alt_addrs: vec![]
|
||||||
});
|
});
|
||||||
|
@ -117,7 +115,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 = now()+Time::from(self.timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,9 +180,8 @@ impl<TS: TimeSource> PeerList<TS> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> {
|
fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> {
|
||||||
try!(writeln!(out, "Peers:"));
|
try!(writeln!(out, "Peers:"));
|
||||||
let now = TS::now();
|
|
||||||
for (addr, data) in &self.peers {
|
for (addr, data) in &self.peers {
|
||||||
try!(writeln!(out, " - {} (ttl: {} s)", addr, data.timeout-now));
|
try!(writeln!(out, " - {} (ttl: {} s)", addr, data.timeout-now()));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -201,11 +198,11 @@ pub struct ReconnectEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct GenericCloud<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> {
|
pub struct GenericCloud<P: Protocol, T: Table, S: Socket> {
|
||||||
config: Config,
|
config: Config,
|
||||||
magic: HeaderMagic,
|
magic: HeaderMagic,
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
peers: PeerList<TS>,
|
peers: PeerList,
|
||||||
addresses: Vec<Range>,
|
addresses: Vec<Range>,
|
||||||
learning: bool,
|
learning: bool,
|
||||||
broadcast: bool,
|
broadcast: bool,
|
||||||
|
@ -214,7 +211,7 @@ pub struct GenericCloud<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSou
|
||||||
table: T,
|
table: T,
|
||||||
socket4: S,
|
socket4: S,
|
||||||
socket6: S,
|
socket6: S,
|
||||||
device: D,
|
device: Device,
|
||||||
crypto: Crypto,
|
crypto: Crypto,
|
||||||
next_peerlist: Time,
|
next_peerlist: Time,
|
||||||
update_freq: Duration,
|
update_freq: Duration,
|
||||||
|
@ -224,13 +221,12 @@ pub struct GenericCloud<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSou
|
||||||
next_beacon: Time,
|
next_beacon: Time,
|
||||||
port_forwarding: Option<PortForwarding>,
|
port_forwarding: Option<PortForwarding>,
|
||||||
traffic: TrafficStats,
|
traffic: TrafficStats,
|
||||||
beacon_serializer: BeaconSerializer<TS>,
|
beacon_serializer: BeaconSerializer,
|
||||||
_dummy_p: PhantomData<P>,
|
_dummy_p: PhantomData<P>,
|
||||||
_dummy_ts: PhantomData<TS>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D, P, T, S, TS> {
|
impl<P: Protocol, T: Table, S: Socket> GenericCloud<P, T, S> {
|
||||||
pub fn new(config: &Config, device: D, table: T,
|
pub fn new(config: &Config, device: Device, table: T,
|
||||||
learning: bool, broadcast: bool, addresses: Vec<Range>,
|
learning: bool, broadcast: bool, addresses: Vec<Range>,
|
||||||
crypto: Crypto, port_forwarding: Option<PortForwarding>
|
crypto: Crypto, port_forwarding: Option<PortForwarding>
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -242,7 +238,6 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
||||||
Ok(socket) => socket,
|
Ok(socket) => socket,
|
||||||
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 mut res = GenericCloud{
|
let mut res = GenericCloud{
|
||||||
magic: config.get_magic(),
|
magic: config.get_magic(),
|
||||||
node_id: random(),
|
node_id: random(),
|
||||||
|
@ -256,19 +251,18 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
||||||
socket4,
|
socket4,
|
||||||
socket6,
|
socket6,
|
||||||
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(),
|
||||||
port_forwarding,
|
port_forwarding,
|
||||||
traffic: TrafficStats::default(),
|
traffic: TrafficStats::default(),
|
||||||
beacon_serializer: BeaconSerializer::new(&config.get_magic(), crypto.get_key()),
|
beacon_serializer: BeaconSerializer::new(&config.get_magic(), crypto.get_key()),
|
||||||
crypto,
|
crypto,
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
_dummy_p: PhantomData,
|
_dummy_p: PhantomData,
|
||||||
_dummy_ts: PhantomData
|
|
||||||
};
|
};
|
||||||
res.initialize();
|
res.initialize();
|
||||||
return res
|
return res
|
||||||
|
@ -350,14 +344,13 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
||||||
/// This method adds a peer to the list of nodes to reconnect to. A periodic task will try to
|
/// This method adds a peer to the list of nodes to reconnect to. A periodic task will try to
|
||||||
/// connect to the peer if it is not already connected.
|
/// connect to the peer if it is not already connected.
|
||||||
pub fn add_reconnect_peer(&mut self, add: String) {
|
pub fn add_reconnect_peer(&mut self, add: String) {
|
||||||
let now = TS::now();
|
|
||||||
self.reconnect_peers.push(ReconnectEntry {
|
self.reconnect_peers.push(ReconnectEntry {
|
||||||
address: add,
|
address: add,
|
||||||
tries: 0,
|
tries: 0,
|
||||||
timeout: 1,
|
timeout: 1,
|
||||||
resolved: vec![],
|
resolved: vec![],
|
||||||
next_resolve: now,
|
next_resolve: now(),
|
||||||
next: now
|
next: now()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,7 +431,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
||||||
pfw.check_extend();
|
pfw.check_extend();
|
||||||
}
|
}
|
||||||
// Periodically send peer list to peers
|
// Periodically send peer list to peers
|
||||||
let now = TS::now();
|
let now = now();
|
||||||
if self.next_peerlist <= now {
|
if self.next_peerlist <= now {
|
||||||
debug!("Send peer list to all peers");
|
debug!("Send peer list to all peers");
|
||||||
let mut peer_num = self.peers.len();
|
let mut peer_num = self.peers.len();
|
||||||
|
@ -712,10 +705,6 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_message<'a>(&self, msg: &'a mut [u8]) -> Result<Message<'a>, Error> {
|
|
||||||
decode(msg, self.magic, &self.crypto)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_socket_data(&mut self, src: SocketAddr, data: &mut [u8]) {
|
fn handle_socket_data(&mut self, src: SocketAddr, data: &mut [u8]) {
|
||||||
let size = data.len();
|
let size = data.len();
|
||||||
if let Err(e) = decode(data, self.magic, &mut self.crypto).and_then(|msg| {
|
if let Err(e) = decode(data, self.magic, &mut self.crypto).and_then(|msg| {
|
||||||
|
@ -771,7 +760,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
||||||
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)
|
||||||
}
|
}
|
||||||
if self.next_housekeep < TS::now() {
|
if self.next_housekeep < now() {
|
||||||
poll_error = false;
|
poll_error = false;
|
||||||
if ctrlc.was_pressed() {
|
if ctrlc.was_pressed() {
|
||||||
break
|
break
|
||||||
|
@ -779,51 +768,10 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
|
||||||
if let Err(e) = self.housekeep() {
|
if let Err(e) = self.housekeep() {
|
||||||
error!("Error: {}", e)
|
error!("Error: {}", e)
|
||||||
}
|
}
|
||||||
self.next_housekeep = TS::now() + 1
|
self.next_housekeep = now() + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info!("Shutting down...");
|
info!("Shutting down...");
|
||||||
self.broadcast_msg(&mut Message::Close).ok();
|
self.broadcast_msg(&mut Message::Close).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)] use super::ethernet::{self, SwitchTable};
|
|
||||||
#[cfg(test)] use super::util::MockTimeSource;
|
|
||||||
#[cfg(test)] use super::net::MockSocket;
|
|
||||||
#[cfg(test)] use super::device::MockDevice;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
impl<P: Protocol, T: Table, TS: TimeSource> GenericCloud<MockDevice, P, T, MockSocket, TS> {
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.device.is_empty() && self.socket4.is_empty() && self.socket6.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
type TestNode = GenericCloud<MockDevice, ethernet::Frame, SwitchTable<MockTimeSource>, MockSocket, MockTimeSource>;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
fn create_node() -> TestNode {
|
|
||||||
TestNode::new(
|
|
||||||
&Config::default(),
|
|
||||||
MockDevice::new(),
|
|
||||||
SwitchTable::new(1800, 10),
|
|
||||||
true, true, vec![], Crypto::None, None
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn connect() {
|
|
||||||
let mut node = create_node();
|
|
||||||
assert!(node.is_empty());
|
|
||||||
node.connect("1.2.3.4:5678").unwrap();
|
|
||||||
assert!(node.device.is_empty());
|
|
||||||
assert!(node.socket6.is_empty());
|
|
||||||
let (addr, mut message) = node.socket4.pop_outbound().unwrap();
|
|
||||||
assert_eq!("1.2.3.4:5678".to_socket_addrs().unwrap().next().unwrap(), addr);
|
|
||||||
let message = node.decode_message(&mut message).unwrap();
|
|
||||||
assert_eq!(Message::Init(0, node.node_id, vec![]), message);
|
|
||||||
|
|
||||||
}
|
|
175
src/device.rs
175
src/device.rs
|
@ -3,10 +3,9 @@
|
||||||
// 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::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::io::{self, Error as IoError, ErrorKind, Read, Write};
|
use std::io::{self, Error as IoError, Read, Write};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::collections::VecDeque;
|
|
||||||
|
|
||||||
use super::types::Error;
|
use super::types::Error;
|
||||||
|
|
||||||
|
@ -41,48 +40,15 @@ impl fmt::Display for Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub trait Device: AsRawFd {
|
|
||||||
/// Returns the type of this device
|
|
||||||
fn get_type(&self) -> Type;
|
|
||||||
|
|
||||||
/// Returns the interface name of this device.
|
|
||||||
fn ifname(&self) -> &str;
|
|
||||||
|
|
||||||
/// Reads a packet/frame from the device
|
|
||||||
///
|
|
||||||
/// This method reads one packet or frame (depending on the device type) into the `buffer`.
|
|
||||||
/// The `buffer` must be large enough to hold a packet/frame of maximum size, otherwise the
|
|
||||||
/// packet/frame will be split.
|
|
||||||
/// The method will block until a packet/frame is ready to be read.
|
|
||||||
/// On success, the method will return the starting position and the amount of bytes read into
|
|
||||||
/// the buffer.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
/// This method will return an error if the underlying read call fails.
|
|
||||||
fn read(&mut self, buffer: &mut [u8]) -> Result<(usize, usize), Error>;
|
|
||||||
|
|
||||||
/// Writes a packet/frame to the device
|
|
||||||
///
|
|
||||||
/// This method writes one packet or frame (depending on the device type) from `data` to the
|
|
||||||
/// device. The data starts at the position `start` in the buffer. The buffer should have at
|
|
||||||
/// least 4 bytes of space before the start of the packet.
|
|
||||||
/// The method will block until the packet/frame has been written.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
/// This method will return an error if the underlying read call fails.
|
|
||||||
fn write(&mut self, data: &mut [u8], start: usize) -> Result<(), Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Represents a tun/tap device
|
/// Represents a tun/tap device
|
||||||
pub struct TunTapDevice {
|
pub struct Device {
|
||||||
fd: fs::File,
|
fd: fs::File,
|
||||||
ifname: String,
|
ifname: String,
|
||||||
type_: Type,
|
type_: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl TunTapDevice {
|
impl Device {
|
||||||
/// Creates a new tun/tap device
|
/// Creates a new tun/tap device
|
||||||
///
|
///
|
||||||
/// This method creates a new device of the `type_` kind with the name `ifname`.
|
/// This method creates a new device of the `type_` kind with the name `ifname`.
|
||||||
|
@ -125,7 +91,7 @@ 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(Device{fd, ifname: String::from_utf8(ifname_c).unwrap(), type_})
|
||||||
},
|
},
|
||||||
_ => Err(IoError::last_os_error())
|
_ => Err(IoError::last_os_error())
|
||||||
}
|
}
|
||||||
|
@ -140,6 +106,19 @@ impl TunTapDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the interface name of this device.
|
||||||
|
#[inline]
|
||||||
|
pub fn ifname(&self) -> &str {
|
||||||
|
&self.ifname
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the type of this device
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
pub fn get_type(&self) -> Type {
|
||||||
|
self.type_
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a dummy device based on an existing file
|
/// Creates a dummy device based on an existing file
|
||||||
///
|
///
|
||||||
/// This method opens a regular or special file and reads from it to receive packets and
|
/// This method opens a regular or special file and reads from it to receive packets and
|
||||||
|
@ -155,13 +134,31 @@ 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(Device{
|
||||||
fd: try!(fs::OpenOptions::new().create(true).read(true).write(true).open(path)),
|
fd: try!(fs::OpenOptions::new().create(true).read(true).write(true).open(path)),
|
||||||
ifname: ifname.to_string(),
|
ifname: ifname.to_string(),
|
||||||
type_
|
type_
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads a packet/frame from the device
|
||||||
|
///
|
||||||
|
/// This method reads one packet or frame (depending on the device type) into the `buffer`.
|
||||||
|
/// The `buffer` must be large enough to hold a packet/frame of maximum size, otherwise the
|
||||||
|
/// packet/frame will be split.
|
||||||
|
/// The method will block until a packet/frame is ready to be read.
|
||||||
|
/// On success, the method will return the starting position and the amount of bytes read into
|
||||||
|
/// the buffer.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This method will return an error if the underlying read call fails.
|
||||||
|
#[inline]
|
||||||
|
pub fn read(&mut self, mut buffer: &mut [u8]) -> Result<(usize, usize), Error> {
|
||||||
|
let read = try!(self.fd.read(&mut buffer).map_err(|e| Error::TunTapDev("Read error", e)));
|
||||||
|
let (start, read) = self.correct_data_after_read(&mut buffer, 0, read);
|
||||||
|
Ok((start, read))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
#[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) {
|
||||||
|
@ -182,6 +179,24 @@ impl TunTapDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Writes a packet/frame to the device
|
||||||
|
///
|
||||||
|
/// This method writes one packet or frame (depending on the device type) from `data` to the
|
||||||
|
/// device. The data starts at the position `start` in the buffer. The buffer should have at
|
||||||
|
/// least 4 bytes of space before the start of the packet.
|
||||||
|
/// The method will block until the packet/frame has been written.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This method will return an error if the underlying read call fails.
|
||||||
|
#[inline]
|
||||||
|
pub fn write(&mut self, mut data: &mut [u8], start: usize) -> Result<(), Error> {
|
||||||
|
let start = self.correct_data_before_write(&mut data, start);
|
||||||
|
match self.fd.write_all(&data[start..]) {
|
||||||
|
Ok(_) => self.fd.flush().map_err(|e| Error::TunTapDev("Flush error", e)),
|
||||||
|
Err(e) => Err(Error::TunTapDev("Write error", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
#[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 {
|
||||||
|
@ -208,89 +223,9 @@ impl TunTapDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device for TunTapDevice {
|
impl AsRawFd for Device {
|
||||||
fn get_type(&self) -> Type {
|
|
||||||
self.type_
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ifname(&self) -> &str {
|
|
||||||
&self.ifname
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self, mut buffer: &mut [u8]) -> Result<(usize, usize), Error> {
|
|
||||||
let read = try!(self.fd.read(&mut buffer).map_err(|e| Error::TunTapDev("Read error", e)));
|
|
||||||
let (start, read) = self.correct_data_after_read(&mut buffer, 0, read);
|
|
||||||
Ok((start, read))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, mut data: &mut [u8], start: usize) -> Result<(), Error> {
|
|
||||||
let start = self.correct_data_before_write(&mut data, start);
|
|
||||||
match self.fd.write_all(&data[start..]) {
|
|
||||||
Ok(_) => self.fd.flush().map_err(|e| Error::TunTapDev("Flush error", e)),
|
|
||||||
Err(e) => Err(Error::TunTapDev("Write error", e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRawFd for TunTapDevice {
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
self.fd.as_raw_fd()
|
self.fd.as_raw_fd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct MockDevice {
|
|
||||||
inbound: VecDeque<Vec<u8>>,
|
|
||||||
outbound: VecDeque<Vec<u8>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MockDevice {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self { outbound: VecDeque::new(), inbound: VecDeque::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put_inbound(&mut self, data: Vec<u8>) {
|
|
||||||
self.inbound.push_back(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop_outbound(&mut self) -> Option<Vec<u8>> {
|
|
||||||
self.outbound.pop_front()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.inbound.is_empty() && self.outbound.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device for MockDevice {
|
|
||||||
fn get_type(&self) -> Type {
|
|
||||||
Type::Dummy
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ifname(&self) -> &str {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self, buffer: &mut [u8]) -> Result<(usize, usize), Error> {
|
|
||||||
if let Some(data) = self.inbound.pop_front() {
|
|
||||||
buffer[0..data.len()].copy_from_slice(&data);
|
|
||||||
Ok((0, data.len()))
|
|
||||||
} else {
|
|
||||||
Err(Error::TunTapDev("empty", io::Error::from(ErrorKind::UnexpectedEof)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, data: &mut [u8], start: usize) -> Result<(), Error> {
|
|
||||||
self.outbound.push_back(data[start..].to_owned());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRawFd for MockDevice {
|
|
||||||
#[inline]
|
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,12 +7,11 @@ use std::collections::HashMap;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
use fnv::FnvHasher;
|
use fnv::FnvHasher;
|
||||||
|
|
||||||
use super::types::{Error, Table, Protocol, Address};
|
use super::types::{Error, Table, Protocol, Address};
|
||||||
use super::util::{TimeSource, Time, Duration, MockTimeSource};
|
use super::util::{now, Time, Duration};
|
||||||
|
|
||||||
/// An ethernet frame dissector
|
/// An ethernet frame dissector
|
||||||
///
|
///
|
||||||
|
@ -69,27 +68,26 @@ type Hash = BuildHasherDefault<FnvHasher>;
|
||||||
///
|
///
|
||||||
/// This table is a simple hash map between an address and the destination peer. It learns
|
/// This table is a simple hash map between an address and the destination peer. It learns
|
||||||
/// addresses as they are seen and forgets them after some time.
|
/// addresses as they are seen and forgets them after some time.
|
||||||
pub struct SwitchTable<TS> {
|
pub struct SwitchTable {
|
||||||
/// The table storing the actual mapping
|
/// The table storing the actual mapping
|
||||||
table: HashMap<Address, SwitchTableValue, Hash>,
|
table: HashMap<Address, SwitchTableValue, Hash>,
|
||||||
/// Timeout period for forgetting learnt addresses
|
/// Timeout period for forgetting learnt addresses
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
// Timeout period for not overwriting learnt addresses
|
// Timeout period for not overwriting learnt addresses
|
||||||
protection_period: Duration,
|
protection_period: Duration,
|
||||||
_dummy_ts: PhantomData<TS>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TS: TimeSource> SwitchTable<TS> {
|
impl SwitchTable {
|
||||||
/// 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}
|
SwitchTable{table: HashMap::default(), timeout, protection_period}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TS: TimeSource> Table for SwitchTable<TS> {
|
impl Table for SwitchTable {
|
||||||
/// Forget addresses that have not been seen for the configured timeout
|
/// Forget addresses that have not been seen for the configured timeout
|
||||||
fn housekeep(&mut self) {
|
fn housekeep(&mut self) {
|
||||||
let now = TS::now();
|
let now = now();
|
||||||
let mut del: Vec<Address> = Vec::new();
|
let mut del: Vec<Address> = Vec::new();
|
||||||
for (key, val) in &self.table {
|
for (key, val) in &self.table {
|
||||||
if val.timeout < now {
|
if val.timeout < now {
|
||||||
|
@ -104,7 +102,7 @@ impl<TS: TimeSource> Table for SwitchTable<TS> {
|
||||||
|
|
||||||
/// Write out the table
|
/// Write out the table
|
||||||
fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> {
|
fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> {
|
||||||
let now = TS::now();
|
let now = now();
|
||||||
try!(writeln!(out, "Switch table:"));
|
try!(writeln!(out, "Switch table:"));
|
||||||
for (addr, val) in &self.table {
|
for (addr, val) in &self.table {
|
||||||
try!(writeln!(out, " - {} => {} (ttl: {} s)", addr, val.address, val.timeout - now));
|
try!(writeln!(out, " - {} => {} (ttl: {} s)", addr, val.address, val.timeout - now));
|
||||||
|
@ -115,7 +113,7 @@ impl<TS: TimeSource> Table for SwitchTable<TS> {
|
||||||
/// Learns the given address, inserting it in the hash map
|
/// Learns the given address, inserting it in the hash map
|
||||||
#[inline]
|
#[inline]
|
||||||
fn learn(&mut self, key: Address, _prefix_len: Option<u8>, addr: SocketAddr) {
|
fn learn(&mut self, key: Address, _prefix_len: Option<u8>, addr: SocketAddr) {
|
||||||
let deadline = TS::now() + Time::from(self.timeout);
|
let deadline = 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});
|
||||||
|
@ -165,6 +163,7 @@ impl<TS: TimeSource> Table for SwitchTable<TS> {
|
||||||
|
|
||||||
#[cfg(test)] use std::str::FromStr;
|
#[cfg(test)] use std::str::FromStr;
|
||||||
#[cfg(test)] use std::net::ToSocketAddrs;
|
#[cfg(test)] use std::net::ToSocketAddrs;
|
||||||
|
#[cfg(test)] use std::thread;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decode_frame_without_vlan() {
|
fn decode_frame_without_vlan() {
|
||||||
|
@ -193,19 +192,17 @@ fn decode_invalid_frame() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn switch() {
|
fn switch() {
|
||||||
MockTimeSource::set_time(1000);
|
let mut table = SwitchTable::new(10, 1);
|
||||||
let mut table = SwitchTable::<MockTimeSource>::new(10, 1);
|
|
||||||
let addr = Address::from_str("12:34:56:78:90:ab").unwrap();
|
let addr = Address::from_str("12:34:56:78:90:ab").unwrap();
|
||||||
let peer = "1.2.3.4:5678".to_socket_addrs().unwrap().next().unwrap();
|
let peer = "1.2.3.4:5678".to_socket_addrs().unwrap().next().unwrap();
|
||||||
let peer2 = "1.2.3.5:7890".to_socket_addrs().unwrap().next().unwrap();
|
let peer2 = "1.2.3.5:7890".to_socket_addrs().unwrap().next().unwrap();
|
||||||
assert!(table.lookup(&addr).is_none());
|
assert!(table.lookup(&addr).is_none());
|
||||||
MockTimeSource::set_time(1000);
|
|
||||||
table.learn(addr.clone(), None, peer.clone());
|
table.learn(addr.clone(), None, peer.clone());
|
||||||
assert_eq!(table.lookup(&addr), Some(peer));
|
assert_eq!(table.lookup(&addr), Some(peer));
|
||||||
MockTimeSource::set_time(1000);
|
// Do not override within 1 seconds
|
||||||
table.learn(addr.clone(), None, peer2.clone());
|
table.learn(addr.clone(), None, peer2.clone());
|
||||||
assert_eq!(table.lookup(&addr), Some(peer));
|
assert_eq!(table.lookup(&addr), Some(peer));
|
||||||
MockTimeSource::set_time(1010);
|
thread::sleep(std::time::Duration::from_secs(1));
|
||||||
table.learn(addr.clone(), None, peer2.clone());
|
table.learn(addr.clone(), None, peer2.clone());
|
||||||
assert_eq!(table.lookup(&addr), Some(peer2));
|
assert_eq!(table.lookup(&addr), Some(peer2));
|
||||||
}
|
}
|
||||||
|
|
22
src/main.rs
22
src/main.rs
|
@ -48,17 +48,17 @@ use std::process::Command;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::net::UdpSocket;
|
|
||||||
|
|
||||||
use device::{TunTapDevice, Device, Type};
|
use device::{Device, Type};
|
||||||
use ethernet::SwitchTable;
|
use ethernet::SwitchTable;
|
||||||
use ip::RoutingTable;
|
use ip::RoutingTable;
|
||||||
use types::{Mode, Range, Protocol, HeaderMagic, Error};
|
use types::{Mode, Range, Protocol, HeaderMagic, Error};
|
||||||
use cloud::GenericCloud;
|
use cloud::GenericCloud;
|
||||||
use crypto::{Crypto, CryptoMethod};
|
use crypto::{Crypto, CryptoMethod};
|
||||||
use port_forwarding::PortForwarding;
|
use port_forwarding::PortForwarding;
|
||||||
use util::{Duration, SystemTimeSource};
|
use util::Duration;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
|
use std::net::UdpSocket;
|
||||||
|
|
||||||
|
|
||||||
const VERSION: u8 = 1;
|
const VERSION: u8 = 1;
|
||||||
|
@ -156,25 +156,25 @@ fn run_script(script: &str, ifname: &str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AnyTable {
|
enum AnyTable {
|
||||||
Switch(SwitchTable<SystemTimeSource>),
|
Switch(SwitchTable),
|
||||||
Routing(RoutingTable)
|
Routing(RoutingTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AnyCloud<P: Protocol> {
|
enum AnyCloud<P: Protocol> {
|
||||||
Switch(GenericCloud<TunTapDevice, P, SwitchTable<SystemTimeSource>, UdpSocket, SystemTimeSource>),
|
Switch(GenericCloud<P, SwitchTable, UdpSocket>),
|
||||||
Routing(GenericCloud<TunTapDevice, P, RoutingTable, UdpSocket, SystemTimeSource>)
|
Routing(GenericCloud<P, RoutingTable, UdpSocket>)
|
||||||
}
|
}
|
||||||
|
|
||||||
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(config: &Config, device: Device, table: AnyTable,
|
||||||
learning: bool, broadcast: bool, addresses: Vec<Range>,
|
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) => AnyCloud::Switch(GenericCloud::<P, SwitchTable, UdpSocket>::new(
|
||||||
config, device,t, learning, broadcast, addresses, crypto, port_forwarding
|
config, device,t, learning, broadcast, addresses, crypto, port_forwarding
|
||||||
)),
|
)),
|
||||||
AnyTable::Routing(t) => AnyCloud::Routing(GenericCloud::<TunTapDevice, P, RoutingTable, UdpSocket, SystemTimeSource>::new(
|
AnyTable::Routing(t) => AnyCloud::Routing(GenericCloud::<P, RoutingTable, UdpSocket>::new(
|
||||||
config, device,t, learning, broadcast, addresses, crypto, port_forwarding
|
config, device,t, learning, broadcast, addresses, crypto, port_forwarding
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ 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!(Device::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);
|
"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());
|
||||||
|
|
|
@ -54,10 +54,6 @@ impl MockSocket {
|
||||||
pub fn pop_outbound(&mut self) -> Option<(SocketAddr, Vec<u8>)> {
|
pub fn pop_outbound(&mut self) -> Option<(SocketAddr, Vec<u8>)> {
|
||||||
self.outbound.pop_front()
|
self.outbound.pop_front()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.inbound.is_empty() && self.outbound.is_empty()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRawFd for MockSocket {
|
impl AsRawFd for MockSocket {
|
||||||
|
|
|
@ -7,6 +7,7 @@ use libc;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::io;
|
use std::io;
|
||||||
use device::Device;
|
use device::Device;
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
use super::WaitResult;
|
use super::WaitResult;
|
||||||
use ::device::Type;
|
use ::device::Type;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::io;
|
||||||
|
|
||||||
use igd::*;
|
use igd::*;
|
||||||
|
|
||||||
use super::util::{SystemTimeSource, Time, TimeSource};
|
use super::util::{Time, now};
|
||||||
|
|
||||||
const LEASE_TIME: u32 = 300;
|
const LEASE_TIME: u32 = 300;
|
||||||
const DESCRIPTION: &str = "VpnCloud";
|
const DESCRIPTION: &str = "VpnCloud";
|
||||||
|
@ -90,7 +90,7 @@ impl PortForwarding {
|
||||||
};
|
};
|
||||||
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)
|
Some(now() + Time::from(timeout) - 60)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -104,7 +104,7 @@ impl PortForwarding {
|
||||||
|
|
||||||
pub fn check_extend(&mut self) {
|
pub fn check_extend(&mut self) {
|
||||||
if let Some(deadline) = self.next_extension {
|
if let Some(deadline) = self.next_extension {
|
||||||
if deadline > SystemTimeSource::now() {
|
if deadline > now() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -114,7 +114,7 @@ impl PortForwarding {
|
||||||
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)
|
||||||
};
|
};
|
||||||
self.next_extension = Some(SystemTimeSource::now() + Time::from(LEASE_TIME) - 60);
|
self.next_extension = Some(now() + Time::from(LEASE_TIME) - 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deactivate(&self) {
|
fn deactivate(&self) {
|
||||||
|
|
|
@ -78,7 +78,7 @@ impl<'a> fmt::Debug for Message<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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: &mut Crypto) -> Result<Message<'a>, Error> {
|
||||||
let mut end = data.len();
|
let mut end = data.len();
|
||||||
let (header, mut pos) = try!(TopHeader::read_from(&data[..end]));
|
let (header, mut pos) = try!(TopHeader::read_from(&data[..end]));
|
||||||
if header.magic != magic {
|
if header.magic != magic {
|
||||||
|
|
55
src/util.rs
55
src/util.rs
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
use std::net::{SocketAddr, ToSocketAddrs};
|
use std::net::{SocketAddr, ToSocketAddrs};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
|
||||||
|
|
||||||
use super::types::Error;
|
use super::types::Error;
|
||||||
|
|
||||||
|
@ -21,6 +20,19 @@ use std::time::Instant;
|
||||||
pub type Duration = u32;
|
pub type Duration = u32;
|
||||||
pub type Time = i64;
|
pub type Time = i64;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn now() -> Time {
|
||||||
|
let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 };
|
||||||
|
unsafe { libc::clock_gettime(6, &mut tv); }
|
||||||
|
tv.tv_sec as Time
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
pub fn now() -> Time {
|
||||||
|
time::get_time().sec
|
||||||
|
}
|
||||||
|
|
||||||
const HEX_CHARS: &[u8] = b"0123456789abcdef";
|
const HEX_CHARS: &[u8] = b"0123456789abcdef";
|
||||||
|
|
||||||
|
@ -177,44 +189,3 @@ impl CtrlC {
|
||||||
self.trap.wait(self.dummy_time).is_some()
|
self.trap.wait(self.dummy_time).is_some()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub trait TimeSource: Sync + Copy + Send + 'static {
|
|
||||||
fn now() -> Time;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct SystemTimeSource;
|
|
||||||
|
|
||||||
impl TimeSource for SystemTimeSource {
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn now() -> Time {
|
|
||||||
let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 };
|
|
||||||
unsafe { libc::clock_gettime(6, &mut tv); }
|
|
||||||
tv.tv_sec as Time
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
|
||||||
fn now() -> Time {
|
|
||||||
time::get_time().sec
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thread_local! {
|
|
||||||
static MOCK_TIME: AtomicIsize = AtomicIsize::new(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct MockTimeSource;
|
|
||||||
|
|
||||||
impl MockTimeSource {
|
|
||||||
pub fn set_time(time: Time) {
|
|
||||||
MOCK_TIME.with(|t| t.store(time as isize, Ordering::SeqCst))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TimeSource for MockTimeSource {
|
|
||||||
fn now() -> Time {
|
|
||||||
MOCK_TIME.with(|t| t.load(Ordering::SeqCst) as Time)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue