mirror of https://github.com/dswd/vpncloud.git
Prepare for release
This commit is contained in:
parent
665b190257
commit
4fb92a36a6
|
@ -1,10 +1,18 @@
|
|||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.148.1/containers/rust/.devcontainer/base.Dockerfile
|
||||
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/rust:0-1
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/rust:1
|
||||
|
||||
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
&& apt-get -y install --no-install-recommends asciidoctor
|
||||
|
||||
RUN rm /etc/localtime && ln -s /usr/share/zoneinfo/Europe/Berlin /etc/localtime
|
||||
|
||||
RUN cargo install cargo-outdated cargo-cache
|
||||
RUN chown vscode: -R /usr/local/rustup /usr/local/cargo
|
||||
|
||||
USER vscode
|
||||
|
||||
RUN rustup default 1.51.0 \
|
||||
&& rustup component add clippy rust-src rustfmt
|
||||
|
||||
RUN cargo install cargo-outdated cargo-cache \
|
||||
&& cargo cache -a
|
12
.whitesource
12
.whitesource
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"scanSettings": {
|
||||
"baseBranches": []
|
||||
},
|
||||
"checkRunSettings": {
|
||||
"vulnerableCheckRunConclusionLevel": "failure",
|
||||
"displayMode": "diff"
|
||||
},
|
||||
"issueSettings": {
|
||||
"minSeverityLevel": "LOW"
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
This project follows [semantic versioning](http://semver.org).
|
||||
|
||||
### UNRELEASED
|
||||
### v2.2.0 (2021-04-06)
|
||||
|
||||
- [added] Service target file (thanks to mnhauke)
|
||||
- [added] Added interactive configuration wizard
|
||||
|
@ -10,7 +10,7 @@ This project follows [semantic versioning](http://semver.org).
|
|||
- [added] Building static binaries
|
||||
- [added] Building i686 rpm
|
||||
- [changed] Restructured example config
|
||||
- [changed] Changed Rust version to 1.50.0
|
||||
- [changed] Changed Rust version to 1.51.0
|
||||
- [changed] Updated dependencies
|
||||
- [changed] Change permissions of /etc/vpncloud
|
||||
|
||||
|
|
|
@ -1268,7 +1268,7 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
|||
|
||||
[[package]]
|
||||
name = "vpncloud"
|
||||
version = "2.1.0"
|
||||
version = "2.2.0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"criterion",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "vpncloud"
|
||||
version = "2.1.0"
|
||||
version = "2.2.0"
|
||||
authors = ["Dennis Schwerdel <schwerdel@googlemail.com>"]
|
||||
build = "build.rs"
|
||||
license = "GPL-3.0"
|
||||
|
@ -12,7 +12,7 @@ readme = "README.md"
|
|||
edition = "2018"
|
||||
|
||||
[package.metadata]
|
||||
toolchain = "1.50.0"
|
||||
toolchain = "1.51.0"
|
||||
upx_version = "3.96"
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -19,7 +19,7 @@ peers:
|
|||
- REMOTE_HOST:PORT
|
||||
```
|
||||
|
||||
For more information, please see the [Website](https://vpncloud.ddswd.de) or the [Forum](https://groups.google.com/forum/#!forum/vpncloud).
|
||||
For more information, please see the [Website](https://vpncloud.ddswd.de) or the [Discussions group](https://github.com/dswd/vpncloud/discussions).
|
||||
|
||||
|
||||
### Project Status
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
vpncloud (2.2.0) stable; urgency=medium
|
||||
|
||||
* [added] Service target file (thanks to mnhauke)
|
||||
* [added] Added interactive configuration wizard
|
||||
* [added] Support for (un-)installation
|
||||
* [added] Building static binaries
|
||||
* [added] Building i686 rpm
|
||||
* [changed] Restructured example config
|
||||
* [changed] Changed Rust version to 1.51.0
|
||||
* [changed] Updated dependencies
|
||||
* [changed] Change permissions of /etc/vpncloud
|
||||
|
||||
-- Dennis Schwerdel <schwerdel+vpncloud@googlemail.com> Tue, 06 Apr 2021 12:27:00 +0200
|
||||
|
||||
vpncloud (2.1.0) stable; urgency=medium
|
||||
|
||||
* [added] Support for websocket proxy mode
|
||||
|
@ -9,7 +23,7 @@ vpncloud (2.1.0) stable; urgency=medium
|
|||
* [fixed] Added missing peer address propagation
|
||||
* [fixed] Fixed problem with peer addresses without port
|
||||
|
||||
-- Dennis Schwerdel <schwerdel@googlemail.com> Sat, 06 Feb 2020 13:13:00 +0100
|
||||
-- Dennis Schwerdel <schwerdel@googlemail.com> Sat, 06 Feb 2021 13:13:00 +0100
|
||||
|
||||
vpncloud (2.0.1) stable; urgency=medium
|
||||
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
FROM ubuntu
|
||||
|
||||
RUN apt-get update && apt-get install -y asciinema
|
||||
RUN apt-get update && apt-get install -y asciinema locales bash iputils-ping
|
||||
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
|
||||
ENV LANG en_US.UTF-8
|
||||
ENV LANGUAGE en_US:en
|
||||
ENV LC_ALL en_US.UTF-8
|
||||
RUN mkdir /root/.asciinema
|
||||
RUN mkdir /etc/vpncloud
|
||||
|
||||
WORKDIR /data
|
||||
ADD config /root/.asciinema/config
|
||||
RUN echo 'PS1="\[\e[00;34m\]\[\e[01;31m\]\u\[\e[00;01;34m\]@\[\e[00;34m\]node\[\e[01;31m\]:\[\e[00;34m\]\w\[\e[01;31m\]> \[\e[00m\]"' >> /root/.bashrc
|
||||
RUN echo 'PS1="\[\e[00;34m\]\[\e[01;31m\]\u\[\e[00;01;34m\]@\[\e[00;34m\]node\[\e[01;31m\]:\[\e[00;34m\]\w\[\e[01;31m\]> \[\e[00m\]"' >> /root/.bashrc
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[record]
|
||||
command = /usr/bin/bash -l
|
||||
idle_time_limit = 2.5
|
||||
command = bash -l
|
||||
idle_time_limit = 2.5
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
docker build -t asciinema-recorder .
|
||||
docker run -it --rm --network host -v $(pwd)/../../target/release/:/usr/local/bin/ -v $(pwd):/data asciinema-recorder asciinema "$@"
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd $(dirname $0)
|
||||
|
||||
docker build -t asciinema-recorder .
|
||||
docker run -it --rm --network host \
|
||||
-v $(pwd):/data \
|
||||
-v /etc/hosts:/etc/hosts \
|
||||
asciinema-recorder
|
|
@ -15,16 +15,15 @@ use std::{
|
|||
process::{Command, Stdio},
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Mutex
|
||||
Arc, Mutex,
|
||||
},
|
||||
thread
|
||||
thread,
|
||||
};
|
||||
|
||||
use super::util::{from_base62, to_base62, Encoder, TimeSource};
|
||||
use smallvec::SmallVec;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
|
||||
|
||||
const TYPE_BEGIN: u8 = 0;
|
||||
const TYPE_END: u8 = 1;
|
||||
const TYPE_DATA: u8 = 2;
|
||||
|
@ -40,14 +39,14 @@ fn sha512(data: &[u8]) -> SmallVec<[u8; 64]> {
|
|||
|
||||
struct FutureResult<T> {
|
||||
has_result: AtomicBool,
|
||||
result: Mutex<T>
|
||||
result: Mutex<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BeaconSerializer<TS> {
|
||||
shared_key: Vec<u8>,
|
||||
future_peers: Arc<FutureResult<Vec<SocketAddr>>>,
|
||||
_dummy_ts: PhantomData<TS>
|
||||
_dummy_ts: PhantomData<TS>,
|
||||
}
|
||||
|
||||
impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||
|
@ -55,7 +54,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
Self {
|
||||
shared_key: shared_key.to_owned(),
|
||||
future_peers: Arc::new(FutureResult { has_result: AtomicBool::new(false), result: Mutex::new(Vec::new()) }),
|
||||
_dummy_ts: PhantomData
|
||||
_dummy_ts: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,7 +104,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
|
||||
fn decrypt_data(&self, data: &mut Vec<u8>) -> bool {
|
||||
if data.is_empty() {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
let seed = data.pop().unwrap() ^ self.get_keystream(TYPE_SEED, 0, 0)[0];
|
||||
self.mask_with_keystream(data as &mut [u8], TYPE_DATA, seed);
|
||||
|
@ -122,7 +121,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
for p in peers {
|
||||
match *p {
|
||||
SocketAddr::V4(addr) => v4addrs.push(addr),
|
||||
SocketAddr::V6(addr) => v6addrs.push(addr)
|
||||
SocketAddr::V6(addr) => v6addrs.push(addr),
|
||||
}
|
||||
}
|
||||
// Add count of v4 addresses
|
||||
|
@ -158,23 +157,23 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
let mut peers = Vec::new();
|
||||
let mut pos = 0;
|
||||
if data.len() < 4 {
|
||||
return peers
|
||||
return peers;
|
||||
}
|
||||
if !self.decrypt_data(&mut data) {
|
||||
return peers
|
||||
return peers;
|
||||
}
|
||||
let then = Wrapping(Encoder::read_u16(&data[pos..=pos + 1]));
|
||||
if let Some(ttl) = ttl_hours {
|
||||
let now = Wrapping(Self::now_hour_16());
|
||||
if now - then > Wrapping(ttl) && then - now > Wrapping(ttl) {
|
||||
return peers
|
||||
return peers;
|
||||
}
|
||||
}
|
||||
pos += 2;
|
||||
let v4count = data[pos] as usize;
|
||||
pos += 1;
|
||||
if v4count * 6 > data.len() - pos || (data.len() - pos - v4count * 6) % 18 > 0 {
|
||||
return peers
|
||||
return peers;
|
||||
}
|
||||
for _ in 0..v4count {
|
||||
assert!(data.len() >= pos + 6);
|
||||
|
@ -198,7 +197,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
Ipv6Addr::new(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]),
|
||||
port,
|
||||
0,
|
||||
0
|
||||
0,
|
||||
));
|
||||
peers.push(addr);
|
||||
}
|
||||
|
@ -262,14 +261,14 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
peers.append(&mut self.peerlist_decode(&data[start_pos..end_pos], ttl_hours));
|
||||
pos = start_pos
|
||||
} else {
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
peers
|
||||
}
|
||||
|
||||
pub fn read_from_file<P: AsRef<Path>>(
|
||||
&self, path: P, ttl_hours: Option<u16>
|
||||
&self, path: P, ttl_hours: Option<u16>,
|
||||
) -> Result<Vec<SocketAddr>, io::Error> {
|
||||
let mut f = File::open(&path)?;
|
||||
let mut contents = String::new();
|
||||
|
@ -316,26 +315,22 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)] use crate::util::MockTimeSource;
|
||||
#[cfg(test)] use std::str::FromStr;
|
||||
#[cfg(test)] use std::time::Duration;
|
||||
#[cfg(test)]
|
||||
use crate::util::MockTimeSource;
|
||||
#[cfg(test)]
|
||||
use std::str::FromStr;
|
||||
#[cfg(test)]
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn encode() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||
let mut peers = vec![
|
||||
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||
];
|
||||
let mut peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
||||
assert_eq!("WsHI31EWDMBYxvITiILIrm2k9gEik22E", ser.encode(&peers));
|
||||
peers.push(SocketAddr::from_str("[::1]:5678").unwrap());
|
||||
assert_eq!("WsHI3GXKaXCveo6uejmZizZ72kR6Y0L9T7h49TXONp1ugfKvvvEik22E", ser.encode(&peers));
|
||||
let peers = vec![
|
||||
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||
SocketAddr::from_str("6.6.6.6:54").unwrap()
|
||||
];
|
||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:54").unwrap()];
|
||||
assert_eq!("WsHI32gm9eMSHP3Lm1GXcdP7rD3ik22E", ser.encode(&peers));
|
||||
}
|
||||
|
||||
|
@ -343,10 +338,7 @@ fn encode() {
|
|||
fn decode() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||
let mut peers = vec![
|
||||
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||
];
|
||||
let mut peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
||||
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("WsHI31EWDMBYxvITiILIrm2k9gEik22E", None)));
|
||||
peers.push(SocketAddr::from_str("[::1]:5678").unwrap());
|
||||
assert_eq!(
|
||||
|
@ -359,10 +351,7 @@ fn decode() {
|
|||
fn decode_split() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||
let peers = vec![
|
||||
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||
];
|
||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
||||
assert_eq!(
|
||||
format!("{:?}", peers),
|
||||
format!("{:?}", ser.decode("WsHI3-1E.WD:MB Yx\tvI\nTi(IL)Ir[m2]k9ügEäik22E", None))
|
||||
|
@ -377,10 +366,7 @@ fn decode_split() {
|
|||
fn decode_offset() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||
let peers = vec![
|
||||
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||
];
|
||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
||||
assert_eq!(
|
||||
format!("{:?}", peers),
|
||||
format!("{:?}", ser.decode("Hello World: WsHI31EWDMBYxvITiILIrm2k9gEik22E! End of the World", None))
|
||||
|
@ -391,10 +377,7 @@ fn decode_offset() {
|
|||
fn decode_multiple() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||
let peers = vec![
|
||||
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||
];
|
||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
||||
assert_eq!(
|
||||
format!("{:?}", peers),
|
||||
format!("{:?}", ser.decode("WsHI31HVpqxFNMNSPrvik22E WsHI34yOBcZIulKdtn2ik22E", None))
|
||||
|
@ -438,15 +421,11 @@ fn decode_invalid() {
|
|||
assert_eq!(2, ser.decode("WsHI3WsHI31EWDMBYxvITiILIrm2k9gEik22Eik22E", None).len());
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn encode_decode() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||
let peers = vec![
|
||||
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||
];
|
||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
||||
let data = ser.encode(&peers);
|
||||
let peers2 = ser.decode(&data, None);
|
||||
assert_eq!(format!("{:?}", peers), format!("{:?}", peers2));
|
||||
|
@ -456,10 +435,7 @@ fn encode_decode() {
|
|||
fn encode_decode_file() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||
let peers = vec![
|
||||
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||
];
|
||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
||||
let file = tempfile::NamedTempFile::new().expect("Failed to create temp file");
|
||||
assert!(ser.write_to_file(&peers, file.path()).is_ok());
|
||||
let peers2 = ser.read_from_file(file.path(), None);
|
||||
|
@ -471,10 +447,7 @@ fn encode_decode_file() {
|
|||
fn encode_decode_cmd() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||
let peers = vec![
|
||||
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||
];
|
||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
||||
let file = tempfile::NamedTempFile::new().expect("Failed to create temp file");
|
||||
assert!(ser.write_to_cmd(&peers, &format!("echo $beacon > {}", file.path().display())).is_ok());
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
|
|
143
src/cloud.rs
143
src/cloud.rs
|
@ -12,7 +12,7 @@ use std::{
|
|||
marker::PhantomData,
|
||||
net::{SocketAddr, ToSocketAddrs},
|
||||
path::Path,
|
||||
str::FromStr
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use fnv::FnvHasher;
|
||||
|
@ -27,7 +27,7 @@ use crate::{
|
|||
error::Error,
|
||||
messages::{
|
||||
AddrList, NodeInfo, PeerInfo, MESSAGE_TYPE_CLOSE, MESSAGE_TYPE_DATA, MESSAGE_TYPE_KEEPALIVE,
|
||||
MESSAGE_TYPE_NODE_INFO
|
||||
MESSAGE_TYPE_NODE_INFO,
|
||||
},
|
||||
net::{mapped_addr, Socket},
|
||||
payload::Protocol,
|
||||
|
@ -36,7 +36,7 @@ use crate::{
|
|||
table::ClaimTable,
|
||||
traffic::TrafficStats,
|
||||
types::{Address, Mode, NodeId, Range, RangeList},
|
||||
util::{addr_nice, bytes_to_hex, resolve, CtrlC, Duration, MsgBuffer, StatsdMsg, Time, TimeSource}
|
||||
util::{addr_nice, bytes_to_hex, resolve, CtrlC, Duration, MsgBuffer, StatsdMsg, Time, TimeSource},
|
||||
};
|
||||
|
||||
pub type Hash = BuildHasherDefault<FnvHasher>;
|
||||
|
@ -54,7 +54,7 @@ struct PeerData {
|
|||
timeout: Time,
|
||||
peer_timeout: u16,
|
||||
node_id: NodeId,
|
||||
crypto: PeerCrypto<NodeInfo>
|
||||
crypto: PeerCrypto<NodeInfo>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -64,10 +64,9 @@ pub struct ReconnectEntry {
|
|||
tries: u16,
|
||||
timeout: u16,
|
||||
next: Time,
|
||||
final_timeout: Option<Time>
|
||||
final_timeout: Option<Time>,
|
||||
}
|
||||
|
||||
|
||||
pub struct GenericCloud<D: Device, P: Protocol, S: Socket, TS: TimeSource> {
|
||||
node_id: NodeId,
|
||||
config: Config,
|
||||
|
@ -95,22 +94,22 @@ pub struct GenericCloud<D: Device, P: Protocol, S: Socket, TS: TimeSource> {
|
|||
traffic: TrafficStats,
|
||||
beacon_serializer: BeaconSerializer<TS>,
|
||||
_dummy_p: PhantomData<P>,
|
||||
_dummy_ts: PhantomData<TS>
|
||||
_dummy_ts: PhantomData<TS>,
|
||||
}
|
||||
|
||||
impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(config: &Config, socket: S, device: D, port_forwarding: Option<PortForwarding>, stats_file: Option<File>) -> Self {
|
||||
pub fn new(
|
||||
config: &Config, socket: S, device: D, port_forwarding: Option<PortForwarding>, stats_file: Option<File>,
|
||||
) -> Self {
|
||||
let (learning, broadcast) = match config.mode {
|
||||
Mode::Normal => {
|
||||
match config.device_type {
|
||||
Type::Tap => (true, true),
|
||||
Type::Tun => (false, false)
|
||||
}
|
||||
}
|
||||
Mode::Normal => match config.device_type {
|
||||
Type::Tap => (true, true),
|
||||
Type::Tun => (false, false),
|
||||
},
|
||||
Mode::Router => (false, false),
|
||||
Mode::Switch => (true, true),
|
||||
Mode::Hub => (false, true)
|
||||
Mode::Hub => (false, true),
|
||||
};
|
||||
let mut claims = SmallVec::with_capacity(config.claims.len());
|
||||
for s in &config.claims {
|
||||
|
@ -126,7 +125,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
Err(Error::DeviceIo(_, e)) if e.kind() == io::ErrorKind::AddrNotAvailable => {
|
||||
info!("No address set on interface.")
|
||||
}
|
||||
Err(e) => error!("{}", e)
|
||||
Err(e) => error!("{}", e),
|
||||
}
|
||||
}
|
||||
let now = TS::now();
|
||||
|
@ -161,7 +160,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
crypto,
|
||||
config: config.clone(),
|
||||
_dummy_p: PhantomData,
|
||||
_dummy_ts: PhantomData
|
||||
_dummy_ts: PhantomData,
|
||||
};
|
||||
res.initialize();
|
||||
res
|
||||
|
@ -191,7 +190,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
match self.socket.send(msg_data.message(), *addr) {
|
||||
Ok(written) if written == msg_data.len() => Ok(()),
|
||||
Ok(_) => Err(Error::Socket("Sent out truncated packet")),
|
||||
Err(e) => Err(Error::SocketIo("IOError when sending", e))
|
||||
Err(e) => Err(Error::SocketIo("IOError when sending", e)),
|
||||
}?
|
||||
}
|
||||
Ok(())
|
||||
|
@ -205,7 +204,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
match self.socket.send(msg.message(), addr) {
|
||||
Ok(written) if written == msg.len() => Ok(()),
|
||||
Ok(_) => Err(Error::Socket("Sent out truncated packet")),
|
||||
Err(e) => Err(Error::SocketIo("IOError when sending", e))
|
||||
Err(e) => Err(Error::SocketIo("IOError when sending", e)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,7 +214,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
debug!("Sending msg with {} bytes to {}", msg.len(), addr);
|
||||
let peer = match self.peers.get_mut(&addr) {
|
||||
Some(peer) => peer,
|
||||
None => return Err(Error::Message("Sending to node that is not a peer"))
|
||||
None => return Err(Error::Message("Sending to node that is not a peer")),
|
||||
};
|
||||
peer.crypto.send_message(type_, msg)?;
|
||||
self.send_to(addr, msg)
|
||||
|
@ -258,7 +257,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
timeout: 1,
|
||||
resolved,
|
||||
next: now,
|
||||
final_timeout: None
|
||||
final_timeout: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -277,14 +276,14 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
|| self.peers.contains_key(addr)
|
||||
|| self.pending_inits.contains_key(addr)
|
||||
{
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
if !addrs.is_empty() {
|
||||
self.config.call_hook(
|
||||
"peer_connecting",
|
||||
vec![("PEER", format!("{:?}", addr_nice(addrs[0]))), ("IFNAME", self.device.ifname().to_owned())],
|
||||
true
|
||||
true,
|
||||
);
|
||||
}
|
||||
// Send a message to each resolved address
|
||||
|
@ -310,7 +309,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
peers,
|
||||
claims: self.claims.clone(),
|
||||
peer_timeout: Some(self.peer_timeout_publish),
|
||||
addrs: self.own_addresses.clone()
|
||||
addrs: self.own_addresses.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,7 +319,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
|| self.own_addresses.contains(&addr)
|
||||
|| self.pending_inits.contains_key(&addr)
|
||||
{
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
debug!("Connecting to {:?}", addr);
|
||||
let payload = self.create_node_info();
|
||||
|
@ -340,7 +339,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
Err(_) => del.push(addr),
|
||||
Ok(MessageResult::None) => (),
|
||||
Ok(MessageResult::Reply) => self.send_to(addr, &mut msg)?,
|
||||
Ok(_) => unreachable!()
|
||||
Ok(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
for addr in self.peers.keys().copied().collect::<SmallVec<[SocketAddr; 16]>>() {
|
||||
|
@ -349,7 +348,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
Err(_) => del.push(addr),
|
||||
Ok(MessageResult::None) => (),
|
||||
Ok(MessageResult::Reply) => self.send_to(addr, &mut msg)?,
|
||||
Ok(_) => unreachable!()
|
||||
Ok(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
for addr in del {
|
||||
|
@ -366,7 +365,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
// Connect to those reconnect_peers that are due
|
||||
for entry in self.reconnect_peers.clone() {
|
||||
if entry.next > now {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
self.connect(&entry.resolved as &[SocketAddr])?;
|
||||
}
|
||||
|
@ -377,7 +376,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
entry.tries = 0;
|
||||
entry.timeout = 1;
|
||||
entry.next = now + 1;
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Resolve entries anew
|
||||
|
@ -385,19 +384,17 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
if *next_resolve <= now {
|
||||
match resolve(address as &str) {
|
||||
Ok(addrs) => entry.resolved = addrs,
|
||||
Err(_) => {
|
||||
match resolve(&format!("{}:{}", address, DEFAULT_PORT)) {
|
||||
Ok(addrs) => entry.resolved = addrs,
|
||||
Err(err) => warn!("Failed to resolve {}: {}", address, err)
|
||||
}
|
||||
}
|
||||
Err(_) => match resolve(&format!("{}:{}", address, DEFAULT_PORT)) {
|
||||
Ok(addrs) => entry.resolved = addrs,
|
||||
Err(err) => warn!("Failed to resolve {}: {}", address, err),
|
||||
},
|
||||
}
|
||||
*next_resolve = now + RESOLVE_INTERVAL;
|
||||
}
|
||||
}
|
||||
// Ignore if next attempt is already in the future
|
||||
if entry.next > now {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
// Exponential back-off: every 10 tries, the interval doubles
|
||||
entry.tries += 1;
|
||||
|
@ -502,7 +499,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
self.beacon_serializer
|
||||
.read_from_cmd(path, Some(50))
|
||||
.map_err(|e| Error::BeaconIo("Failed to call beacon command", e))?;
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
} else {
|
||||
peers = self
|
||||
.beacon_serializer
|
||||
|
@ -510,7 +507,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
.map_err(|e| Error::BeaconIo("Failed to read beacon from file", e))?;
|
||||
}
|
||||
} else {
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
debug!("Loaded beacon with peers: {:?}", peers);
|
||||
for peer in peers {
|
||||
|
@ -595,7 +592,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
match self.socket.send(msg_data, *addr) {
|
||||
Ok(written) if written == msg_data.len() => Ok(()),
|
||||
Ok(_) => Err(Error::Socket("Sent out truncated packet")),
|
||||
Err(e) => Err(Error::SocketIo("IOError when sending", e))
|
||||
Err(e) => Err(Error::SocketIo("IOError when sending", e)),
|
||||
}?
|
||||
} else {
|
||||
error!("Failed to resolve statsd server {}", endpoint);
|
||||
|
@ -648,17 +645,20 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
("CLAIMS", info.claims.iter().map(|r| format!("{:?}", r)).collect::<Vec<String>>().join(" ")),
|
||||
("NODE_ID", bytes_to_hex(&info.node_id)),
|
||||
],
|
||||
true
|
||||
true,
|
||||
);
|
||||
if let Some(init) = self.pending_inits.remove(&addr) {
|
||||
self.peers.insert(addr, PeerData {
|
||||
addrs: info.addrs.clone(),
|
||||
crypto: init,
|
||||
node_id: info.node_id,
|
||||
peer_timeout: info.peer_timeout.unwrap_or(DEFAULT_PEER_TIMEOUT),
|
||||
last_seen: TS::now(),
|
||||
timeout: TS::now() + self.config.peer_timeout as Time
|
||||
});
|
||||
self.peers.insert(
|
||||
addr,
|
||||
PeerData {
|
||||
addrs: info.addrs.clone(),
|
||||
crypto: init,
|
||||
node_id: info.node_id,
|
||||
peer_timeout: info.peer_timeout.unwrap_or(DEFAULT_PEER_TIMEOUT),
|
||||
last_seen: TS::now(),
|
||||
timeout: TS::now() + self.config.peer_timeout as Time,
|
||||
},
|
||||
);
|
||||
self.update_peer_info(addr, Some(info))?;
|
||||
} else {
|
||||
error!("No init for new peer {}", addr_nice(addr));
|
||||
|
@ -677,7 +677,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
("IFNAME", self.device.ifname().to_owned()),
|
||||
("NODE_ID", bytes_to_hex(&peer.node_id)),
|
||||
],
|
||||
true
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -686,16 +686,16 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
'outer: for peer in peers {
|
||||
for addr in &peer.addrs {
|
||||
if self.peers.contains_key(addr) {
|
||||
continue 'outer
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
if let Some(node_id) = peer.node_id {
|
||||
if self.node_id == node_id {
|
||||
continue 'outer
|
||||
continue 'outer;
|
||||
}
|
||||
for p in self.peers.values() {
|
||||
if p.node_id == node_id {
|
||||
continue 'outer
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -710,7 +710,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
peer.timeout = TS::now() + self.config.peer_timeout as Time
|
||||
} else {
|
||||
error!("Received peer update from non peer {}", addr_nice(addr));
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(info) = info {
|
||||
debug!("Adding claims of peer {}: {:?}", addr_nice(addr), info.claims);
|
||||
|
@ -729,7 +729,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
self.traffic.count_in_payload(src, dst, len);
|
||||
if let Err(e) = self.device.write(data) {
|
||||
error!("Failed to send via device: {}", e);
|
||||
return Err(e)
|
||||
return Err(e);
|
||||
}
|
||||
if self.learning {
|
||||
// Learn single address
|
||||
|
@ -739,7 +739,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
}
|
||||
|
||||
fn handle_message(
|
||||
&mut self, src: SocketAddr, msg_result: MessageResult<NodeInfo>, data: &mut MsgBuffer
|
||||
&mut self, src: SocketAddr, msg_result: MessageResult<NodeInfo>, data: &mut MsgBuffer,
|
||||
) -> Result<(), Error> {
|
||||
// HOT PATH
|
||||
match msg_result {
|
||||
|
@ -756,7 +756,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
self.traffic.count_invalid_protocol(data.len());
|
||||
return Err(err)
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
self.update_peer_info(src, Some(info))?
|
||||
|
@ -772,7 +772,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
_ => {
|
||||
// COLD PATH
|
||||
self.traffic.count_invalid_protocol(data.len());
|
||||
return Err(Error::Message("Unknown message type"))
|
||||
return Err(Error::Message("Unknown message type"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -824,14 +824,14 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
("PEER", format!("{:?}", addr_nice(src))),
|
||||
("IFNAME", self.device.ifname().to_owned()),
|
||||
],
|
||||
true
|
||||
true,
|
||||
);
|
||||
self.pending_inits.insert(src, init);
|
||||
Ok(res)
|
||||
}
|
||||
Err(err) => {
|
||||
self.traffic.count_invalid_protocol(data.len());
|
||||
return Err(err)
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -842,14 +842,14 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
// COLD PATH
|
||||
info!("Ignoring non-init message from unknown peer {}", addr_nice(src));
|
||||
self.traffic.count_invalid_protocol(data.len());
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
};
|
||||
// HOT PATH
|
||||
match msg_result {
|
||||
Ok(val) => {
|
||||
// HOT PATH
|
||||
self.handle_message(src, val, data)
|
||||
},
|
||||
}
|
||||
Err(err) => {
|
||||
// COLD PATH
|
||||
self.traffic.count_invalid_protocol(data.len());
|
||||
|
@ -877,7 +877,7 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
self.config.call_hook(
|
||||
"peer_disconnected",
|
||||
vec![("PEER", format!("{:?}", addr_nice(src))), ("IFNAME", self.device.ifname().to_owned())],
|
||||
true
|
||||
true,
|
||||
);
|
||||
}
|
||||
Err(e @ Error::CryptoInit(_)) => {
|
||||
|
@ -910,7 +910,10 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
/// Also, this method will call `housekeep` every second.
|
||||
pub fn run(&mut self) {
|
||||
let ctrlc = CtrlC::new();
|
||||
let waiter = try_fail!(WaitImpl::new(self.socket.as_raw_fd(), self.device.as_raw_fd(), 1000), "Failed to setup poll: {}");
|
||||
let waiter = try_fail!(
|
||||
WaitImpl::new(self.socket.as_raw_fd(), self.device.as_raw_fd(), 1000),
|
||||
"Failed to setup poll: {}"
|
||||
);
|
||||
let mut buffer = MsgBuffer::new(SPACE_BEFORE);
|
||||
let mut poll_error = false;
|
||||
self.config.call_hook("vpn_started", vec![("IFNAME", self.device.ifname())], true);
|
||||
|
@ -927,13 +930,13 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
}
|
||||
WaitResult::Timeout => {}
|
||||
WaitResult::Socket => self.handle_socket_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() {
|
||||
// COLD PATH
|
||||
poll_error = false;
|
||||
if ctrlc.was_pressed() {
|
||||
break
|
||||
break;
|
||||
}
|
||||
if let Err(e) = self.housekeep() {
|
||||
error!("{}", e)
|
||||
|
@ -957,10 +960,12 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)] use super::device::MockDevice;
|
||||
#[cfg(test)] use super::net::MockSocket;
|
||||
#[cfg(test)] use super::util::MockTimeSource;
|
||||
#[cfg(test)]
|
||||
use super::device::MockDevice;
|
||||
#[cfg(test)]
|
||||
use super::net::MockSocket;
|
||||
#[cfg(test)]
|
||||
use super::util::MockTimeSource;
|
||||
|
||||
#[cfg(test)]
|
||||
impl<P: Protocol> GenericCloud<MockDevice, P, MockSocket, MockTimeSource> {
|
||||
|
|
182
src/config.rs
182
src/config.rs
|
@ -2,22 +2,15 @@
|
|||
// Copyright (C) 2015-2021 Dennis Schwerdel
|
||||
// This software is licensed under GPL-3 or newer (see LICENSE.md)
|
||||
|
||||
use super::{device::Type, types::Mode, util::Duration, util::run_cmd};
|
||||
use super::{device::Type, types::Mode, util::run_cmd, util::Duration};
|
||||
pub use crate::crypto::Config as CryptoConfig;
|
||||
|
||||
use std::{
|
||||
cmp::max,
|
||||
collections::HashMap,
|
||||
ffi::OsStr,
|
||||
process,
|
||||
thread
|
||||
};
|
||||
use std::{cmp::max, collections::HashMap, ffi::OsStr, process, thread};
|
||||
use structopt::{clap::Shell, StructOpt};
|
||||
|
||||
pub const DEFAULT_PEER_TIMEOUT: u16 = 300;
|
||||
pub const DEFAULT_PORT: u16 = 3210;
|
||||
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq, Clone)]
|
||||
pub struct Config {
|
||||
pub device_type: Type,
|
||||
|
@ -52,7 +45,7 @@ pub struct Config {
|
|||
pub user: Option<String>,
|
||||
pub group: Option<String>,
|
||||
pub hook: Option<String>,
|
||||
pub hooks: HashMap<String, String>
|
||||
pub hooks: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
|
@ -87,7 +80,7 @@ impl Default for Config {
|
|||
user: None,
|
||||
group: None,
|
||||
hook: None,
|
||||
hooks: HashMap::new()
|
||||
hooks: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +288,7 @@ impl Config {
|
|||
if s.contains(':') {
|
||||
let pos = s.find(':').unwrap();
|
||||
let name = &s[..pos];
|
||||
let hook = &s[pos+1..];
|
||||
let hook = &s[pos + 1..];
|
||||
self.hooks.insert(name.to_string(), hook.to_string());
|
||||
} else {
|
||||
self.hook = Some(s);
|
||||
|
@ -311,13 +304,13 @@ impl Config {
|
|||
store: self.beacon_store,
|
||||
load: self.beacon_load,
|
||||
interval: Some(self.beacon_interval),
|
||||
password: self.beacon_password
|
||||
password: self.beacon_password,
|
||||
}),
|
||||
device: Some(ConfigFileDevice {
|
||||
name: Some(self.device_name),
|
||||
path: self.device_path,
|
||||
type_: Some(self.device_type),
|
||||
fix_rp_filter: Some(self.fix_rp_filter)
|
||||
fix_rp_filter: Some(self.fix_rp_filter),
|
||||
}),
|
||||
crypto: self.crypto,
|
||||
group: self.group,
|
||||
|
@ -333,13 +326,10 @@ impl Config {
|
|||
pid_file: self.pid_file,
|
||||
port_forwarding: Some(self.port_forwarding),
|
||||
stats_file: self.stats_file,
|
||||
statsd: Some(ConfigFileStatsd {
|
||||
server: self.statsd_server,
|
||||
prefix: self.statsd_prefix
|
||||
}),
|
||||
statsd: Some(ConfigFileStatsd { server: self.statsd_server, prefix: self.statsd_prefix }),
|
||||
switch_timeout: Some(self.switch_timeout),
|
||||
hook: self.hook,
|
||||
hooks: self.hooks
|
||||
hooks: self.hooks,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,7 +341,7 @@ impl Config {
|
|||
}
|
||||
|
||||
pub fn call_hook(
|
||||
&self, event: &'static str, envs: impl IntoIterator<Item = (&'static str, impl AsRef<OsStr>)>, detach: bool
|
||||
&self, event: &'static str, envs: impl IntoIterator<Item = (&'static str, impl AsRef<OsStr>)>, detach: bool,
|
||||
) {
|
||||
let mut script = None;
|
||||
if let Some(ref s) = self.hook {
|
||||
|
@ -361,7 +351,7 @@ impl Config {
|
|||
script = Some(s);
|
||||
}
|
||||
if script.is_none() {
|
||||
return
|
||||
return;
|
||||
}
|
||||
let script = script.unwrap();
|
||||
let mut cmd = process::Command::new("sh");
|
||||
|
@ -548,8 +538,8 @@ pub enum Command {
|
|||
#[structopt(alias = "wsproxy")]
|
||||
WsProxy {
|
||||
/// Websocket listen address IP:PORT
|
||||
#[structopt(long, short, default_value="3210")]
|
||||
listen: String
|
||||
#[structopt(long, short, default_value = "3210")]
|
||||
listen: String,
|
||||
},
|
||||
|
||||
/// Migrate an old config file
|
||||
|
@ -563,8 +553,8 @@ pub enum Command {
|
|||
/// Generate shell completions
|
||||
Completion {
|
||||
/// Shell to create completions for
|
||||
#[structopt(long, default_value="bash")]
|
||||
shell: Shell
|
||||
#[structopt(long, default_value = "bash")]
|
||||
shell: Shell,
|
||||
},
|
||||
|
||||
/// Edit the config of a network
|
||||
|
@ -572,7 +562,7 @@ pub enum Command {
|
|||
Config {
|
||||
/// Name of the network
|
||||
#[structopt(short, long)]
|
||||
name: Option<String>
|
||||
name: Option<String>,
|
||||
},
|
||||
|
||||
/// Install required utility files
|
||||
|
@ -580,8 +570,8 @@ pub enum Command {
|
|||
Install {
|
||||
/// Remove installed files again
|
||||
#[structopt(long)]
|
||||
uninstall: bool
|
||||
}
|
||||
uninstall: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
|
||||
|
@ -637,7 +627,7 @@ pub struct ConfigFile {
|
|||
pub user: Option<String>,
|
||||
pub group: Option<String>,
|
||||
pub hook: Option<String>,
|
||||
pub hooks: HashMap<String, String>
|
||||
pub hooks: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -758,35 +748,38 @@ fn config_merge() {
|
|||
prefix: Some("prefix".to_string()),
|
||||
}),
|
||||
hook: None,
|
||||
hooks: HashMap::new()
|
||||
});
|
||||
assert_eq!(config, Config {
|
||||
device_type: Type::Tun,
|
||||
device_name: "vpncloud%d".to_string(),
|
||||
device_path: None,
|
||||
ip: None,
|
||||
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
|
||||
ifdown: Some("true".to_string()),
|
||||
listen: "3210".to_string(),
|
||||
peers: vec!["remote.machine.foo:3210".to_string(), "remote.machine.bar:3210".to_string()],
|
||||
peer_timeout: 600,
|
||||
keepalive: Some(840),
|
||||
switch_timeout: 300,
|
||||
beacon_store: Some("/run/vpncloud.beacon.out".to_string()),
|
||||
beacon_load: Some("/run/vpncloud.beacon.in".to_string()),
|
||||
beacon_interval: 7200,
|
||||
beacon_password: Some("test123".to_string()),
|
||||
mode: Mode::Normal,
|
||||
port_forwarding: true,
|
||||
claims: vec!["10.0.1.0/24".to_string()],
|
||||
user: Some("nobody".to_string()),
|
||||
group: Some("nogroup".to_string()),
|
||||
pid_file: Some("/run/vpncloud.run".to_string()),
|
||||
stats_file: Some("/var/log/vpncloud.stats".to_string()),
|
||||
statsd_server: Some("example.com:1234".to_string()),
|
||||
statsd_prefix: Some("prefix".to_string()),
|
||||
..Default::default()
|
||||
hooks: HashMap::new(),
|
||||
});
|
||||
assert_eq!(
|
||||
config,
|
||||
Config {
|
||||
device_type: Type::Tun,
|
||||
device_name: "vpncloud%d".to_string(),
|
||||
device_path: None,
|
||||
ip: None,
|
||||
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
|
||||
ifdown: Some("true".to_string()),
|
||||
listen: "3210".to_string(),
|
||||
peers: vec!["remote.machine.foo:3210".to_string(), "remote.machine.bar:3210".to_string()],
|
||||
peer_timeout: 600,
|
||||
keepalive: Some(840),
|
||||
switch_timeout: 300,
|
||||
beacon_store: Some("/run/vpncloud.beacon.out".to_string()),
|
||||
beacon_load: Some("/run/vpncloud.beacon.in".to_string()),
|
||||
beacon_interval: 7200,
|
||||
beacon_password: Some("test123".to_string()),
|
||||
mode: Mode::Normal,
|
||||
port_forwarding: true,
|
||||
claims: vec!["10.0.1.0/24".to_string()],
|
||||
user: Some("nobody".to_string()),
|
||||
group: Some("nogroup".to_string()),
|
||||
pid_file: Some("/run/vpncloud.run".to_string()),
|
||||
stats_file: Some("/var/log/vpncloud.stats".to_string()),
|
||||
statsd_server: Some("example.com:1234".to_string()),
|
||||
statsd_prefix: Some("prefix".to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
config.merge_args(Args {
|
||||
type_: Some(Type::Tap),
|
||||
device: Some("vpncloud0".to_string()),
|
||||
|
@ -815,40 +808,43 @@ fn config_merge() {
|
|||
group: Some("root".to_string()),
|
||||
..Default::default()
|
||||
});
|
||||
assert_eq!(config, Config {
|
||||
device_type: Type::Tap,
|
||||
device_name: "vpncloud0".to_string(),
|
||||
device_path: Some("/dev/null".to_string()),
|
||||
fix_rp_filter: false,
|
||||
ip: None,
|
||||
ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()),
|
||||
ifdown: Some("ifconfig $IFNAME down".to_string()),
|
||||
crypto: CryptoConfig { password: Some("anothersecret".to_string()), ..CryptoConfig::default() },
|
||||
listen: "[::]:3211".to_string(),
|
||||
peers: vec![
|
||||
"remote.machine.foo:3210".to_string(),
|
||||
"remote.machine.bar:3210".to_string(),
|
||||
"another:3210".to_string()
|
||||
],
|
||||
peer_timeout: 1801,
|
||||
keepalive: Some(850),
|
||||
switch_timeout: 301,
|
||||
beacon_store: Some("/run/vpncloud.beacon.out2".to_string()),
|
||||
beacon_load: Some("/run/vpncloud.beacon.in2".to_string()),
|
||||
beacon_interval: 3600,
|
||||
beacon_password: Some("test1234".to_string()),
|
||||
mode: Mode::Switch,
|
||||
port_forwarding: false,
|
||||
claims: vec!["10.0.1.0/24".to_string()],
|
||||
auto_claim: true,
|
||||
user: Some("root".to_string()),
|
||||
group: Some("root".to_string()),
|
||||
pid_file: Some("/run/vpncloud-mynet.run".to_string()),
|
||||
stats_file: Some("/var/log/vpncloud-mynet.stats".to_string()),
|
||||
statsd_server: Some("example.com:2345".to_string()),
|
||||
statsd_prefix: Some("prefix2".to_string()),
|
||||
daemonize: true,
|
||||
hook: None,
|
||||
hooks: HashMap::new()
|
||||
});
|
||||
assert_eq!(
|
||||
config,
|
||||
Config {
|
||||
device_type: Type::Tap,
|
||||
device_name: "vpncloud0".to_string(),
|
||||
device_path: Some("/dev/null".to_string()),
|
||||
fix_rp_filter: false,
|
||||
ip: None,
|
||||
ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()),
|
||||
ifdown: Some("ifconfig $IFNAME down".to_string()),
|
||||
crypto: CryptoConfig { password: Some("anothersecret".to_string()), ..CryptoConfig::default() },
|
||||
listen: "[::]:3211".to_string(),
|
||||
peers: vec![
|
||||
"remote.machine.foo:3210".to_string(),
|
||||
"remote.machine.bar:3210".to_string(),
|
||||
"another:3210".to_string()
|
||||
],
|
||||
peer_timeout: 1801,
|
||||
keepalive: Some(850),
|
||||
switch_timeout: 301,
|
||||
beacon_store: Some("/run/vpncloud.beacon.out2".to_string()),
|
||||
beacon_load: Some("/run/vpncloud.beacon.in2".to_string()),
|
||||
beacon_interval: 3600,
|
||||
beacon_password: Some("test1234".to_string()),
|
||||
mode: Mode::Switch,
|
||||
port_forwarding: false,
|
||||
claims: vec!["10.0.1.0/24".to_string()],
|
||||
auto_claim: true,
|
||||
user: Some("root".to_string()),
|
||||
group: Some("root".to_string()),
|
||||
pid_file: Some("/run/vpncloud-mynet.run".to_string()),
|
||||
stats_file: Some("/var/log/vpncloud-mynet.stats".to_string()),
|
||||
statsd_server: Some("example.com:2345".to_string()),
|
||||
statsd_prefix: Some("prefix2".to_string()),
|
||||
daemonize: true,
|
||||
hook: None,
|
||||
hooks: HashMap::new()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
use super::{
|
||||
core::{test_speed, CryptoCore},
|
||||
init::{self, InitResult, InitState, CLOSING},
|
||||
rotate::RotationState
|
||||
rotate::RotationState,
|
||||
};
|
||||
use crate::{
|
||||
error::Error,
|
||||
types::NodeId,
|
||||
util::{from_base62, to_base62, MsgBuffer}
|
||||
util::{from_base62, to_base62, MsgBuffer},
|
||||
};
|
||||
use ring::{
|
||||
aead::{self, Algorithm, LessSafeKey, UnboundKey},
|
||||
agreement::{EphemeralPrivateKey, UnparsedPublicKey},
|
||||
pbkdf2,
|
||||
rand::{SecureRandom, SystemRandom},
|
||||
signature::{Ed25519KeyPair, KeyPair, ED25519_PUBLIC_KEY_LEN}
|
||||
signature::{Ed25519KeyPair, KeyPair, ED25519_PUBLIC_KEY_LEN},
|
||||
};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::{fmt::Debug, io::Read, num::NonZeroU32, sync::Arc, time::Duration};
|
||||
|
||||
|
||||
const SALT: &[u8; 32] = b"vpncloudVPNCLOUDvpncl0udVpnCloud";
|
||||
const INIT_MESSAGE_FIRST_BYTE: u8 = 0xff;
|
||||
const MESSAGE_TYPE_ROTATION: u8 = 0x10< |