Compare commits

..

No commits in common. "ea9e3cd5e163e45afca08c17a35692deaa1019ff" and "70109eeb51d1ab51f352ae8836894add99e65ae8" have entirely different histories.

11 changed files with 38 additions and 132 deletions

12
.github/FUNDING.yml vendored
View File

@ -1,12 +0,0 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: dswd
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ['https://paypal.me/dswd73']

View File

@ -27,8 +27,7 @@ script:
- | - |
cargo build && cargo test cargo build && cargo test
after_success: after_success:
- | - cargo coveralls
[ $TRAVIS_RUST_VERSION = stable ] && cargo coveralls
env: env:
global: global:
- TRAVIS_CARGO_NIGHTLY_FEATURE="" - TRAVIS_CARGO_NIGHTLY_FEATURE=""

View File

@ -2,15 +2,6 @@
This project follows [semantic versioning](http://semver.org). This project follows [semantic versioning](http://semver.org).
### Unreleased
- [added] Added service restrictions to systemd
- [changed] Also drop privileges in foreground mode
- [changed] Set builders to Ubuntu 16.04 and CentOS 7
- [changed] Set keepalive to 120 secs when NAT is detected
- [fixed] Added parameter keepalive to manpage
- [fixed] Fixed problems on stats file when dropping permissions
### v1.1.0 (2019-12-04) ### v1.1.0 (2019-12-04)
- [added] Exchange peer timeout and adapt keepalive accordingly - [added] Exchange peer timeout and adapt keepalive accordingly

24
Cargo.lock generated
View File

@ -230,18 +230,6 @@ dependencies = [
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "nix"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "nom" name = "nom"
version = "4.2.3" version = "4.2.3"
@ -266,15 +254,6 @@ name = "ppv-lite86"
version = "0.2.6" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "privdrop"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.6" version = "1.0.6"
@ -572,7 +551,6 @@ dependencies = [
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"privdrop 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
@ -750,12 +728,10 @@ dependencies = [
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" "checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
"checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229"
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
"checksum privdrop 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "432c2e1a6d9d56e3c14710a9b807ade349c48ccd5647bcda9a175f40f81ca5a9"
"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"

View File

@ -28,7 +28,6 @@ igd = "0.9"
siphasher = "0.3" siphasher = "0.3"
daemonize = "0.4" daemonize = "0.4"
ring = "0.16" ring = "0.16"
privdrop = "0.3"
[build-dependencies] [build-dependencies]
cc = "^1" cc = "^1"

View File

@ -2,22 +2,12 @@
Description=VpnCloud network '%I' Description=VpnCloud network '%I'
After=network-online.target After=network-online.target
Wants=network-online.target Wants=network-online.target
Documentation=man:vpncloud(1)
[Service] [Service]
Type=simple Type=forking
ExecStart=/usr/bin/vpncloud --config /etc/vpncloud/%i.net --log-file /var/log/vpncloud-%i.log --stats-file /var/log/vpncloud-%i.stats ExecStart=/usr/bin/vpncloud --config /etc/vpncloud/%i.net --daemon --log-file /var/log/vpncloud-%i.log --stats-file /var/log/vpncloud-%i.stats --pid-file /run/vpncloud-%i.pid
WorkingDirectory=/etc/vpncloud WorkingDirectory=/etc/vpncloud
RestartSec=5s PIDFile=/run/vpncloud-%i.pid
Restart=on-failure
LimitNPROC=10
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=strict
ReadWritePaths=/var/log/vpncloud-%i.log /var/log/vpncloud-%i.stats
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT
DeviceAllow=/dev/null rw
DeviceAllow=/dev/net/tun rw
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@ -6,11 +6,12 @@ use std::{
cmp::min, cmp::min,
collections::HashMap, collections::HashMap,
fmt, fmt,
fs::File, fs::{self, File, Permissions},
hash::BuildHasherDefault, hash::BuildHasherDefault,
io::{self, Write}, io::{self, Write},
marker::PhantomData, marker::PhantomData,
net::{SocketAddr, ToSocketAddrs} net::{SocketAddr, ToSocketAddrs},
os::unix::fs::PermissionsExt
}; };
use fnv::FnvHasher; use fnv::FnvHasher;
@ -229,7 +230,6 @@ pub struct GenericCloud<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSou
peer_timeout_publish: u16, peer_timeout_publish: u16,
update_freq: u16, update_freq: u16,
buffer_out: [u8; 64 * 1024], buffer_out: [u8; 64 * 1024],
stats_file: Option<File>,
next_housekeep: Time, next_housekeep: Time,
next_stats_out: Time, next_stats_out: Time,
next_beacon: Time, next_beacon: Time,
@ -244,7 +244,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
config: &Config, device: D, table: T, learning: bool, broadcast: bool, addresses: Vec<Range>, crypto: Crypto, config: &Config, device: D, table: T, learning: bool, broadcast: bool, addresses: Vec<Range>, crypto: Crypto,
port_forwarding: Option<PortForwarding>, stats_file: Option<File> port_forwarding: Option<PortForwarding>
) -> Self ) -> Self
{ {
let socket4 = match S::listen_v4("0.0.0.0", config.port) { let socket4 = match S::listen_v4("0.0.0.0", config.port) {
@ -256,11 +256,11 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
Err(err) => fail!("Failed to open ipv6 address ::{}: {}", config.port, err) Err(err) => fail!("Failed to open ipv6 address ::{}: {}", config.port, err)
}; };
let now = TS::now(); let now = TS::now();
let update_freq = if socket4.detect_nat() && config.get_keepalive() > 120 { let peer_timeout_publish = if socket4.detect_nat() {
info!("Private IP detected, setting keepalive interval to 120s"); info!("Private IP detected, setting published peer timeout to 300s");
120 300
} else { } else {
config.get_keepalive() as u16 config.peer_timeout as u16
}; };
let mut res = GenericCloud { let mut res = GenericCloud {
magic: config.get_magic(), magic: config.get_magic(),
@ -271,14 +271,13 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
broadcast, broadcast,
reconnect_peers: Vec::new(), reconnect_peers: Vec::new(),
own_addresses: Vec::new(), own_addresses: Vec::new(),
peer_timeout_publish: config.peer_timeout as u16, peer_timeout_publish,
table, table,
socket4, socket4,
socket6, socket6,
device, device,
next_peerlist: now, next_peerlist: now,
update_freq, update_freq: config.get_keepalive() as u16,
stats_file,
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,
@ -481,8 +480,8 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
let mut msg = Message::Peers(peers); let mut msg = Message::Peers(peers);
self.broadcast_msg(&mut msg)?; self.broadcast_msg(&mut msg)?;
// Reschedule for next update // Reschedule for next update
let interval = min(self.update_freq as u16, self.peers.min_peer_timeout()); self.update_freq = min(self.config.get_keepalive() as u16, self.peers.min_peer_timeout());
self.next_peerlist = now + Time::from(interval); self.next_peerlist = now + Time::from(self.update_freq);
} }
// Connect to those reconnect_peers that are due // Connect to those reconnect_peers that are due
for entry in self.reconnect_peers.clone() { for entry in self.reconnect_peers.clone() {
@ -527,7 +526,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
// Write out the statistics // Write out the statistics
self.write_out_stats().map_err(|err| Error::File("Failed to write stats file", err))?; self.write_out_stats().map_err(|err| Error::File("Failed to write stats file", err))?;
self.next_stats_out = now + STATS_INTERVAL; self.next_stats_out = now + STATS_INTERVAL;
self.traffic.period(Some(5)); self.traffic.period(Some(60));
} }
if let Some(peers) = self.beacon_serializer.get_cmd_results() { if let Some(peers) = self.beacon_serializer.get_cmd_results() {
debug!("Loaded beacon with peers: {:?}", peers); debug!("Loaded beacon with peers: {:?}", peers);
@ -587,16 +586,18 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
/// Calculates, resets and writes out the statistics to a file /// Calculates, resets and writes out the statistics to a file
fn write_out_stats(&mut self) -> Result<(), io::Error> { fn write_out_stats(&mut self) -> Result<(), io::Error> {
if let Some(ref mut f) = self.stats_file { if self.config.stats_file.is_none() {
debug!("Writing out stats"); return Ok(())
f.set_len(0)?;
self.peers.write_out(f)?;
writeln!(f)?;
self.table.write_out(f)?;
writeln!(f)?;
self.traffic.write_out(f)?;
writeln!(f)?;
} }
debug!("Writing out stats");
let mut f = File::create(self.config.stats_file.as_ref().unwrap())?;
self.peers.write_out(&mut f)?;
writeln!(&mut f)?;
self.table.write_out(&mut f)?;
writeln!(&mut f)?;
self.traffic.write_out(&mut f)?;
writeln!(&mut f)?;
fs::set_permissions(self.config.stats_file.as_ref().unwrap(), Permissions::from_mode(0o644))?;
Ok(()) Ok(())
} }

View File

@ -33,10 +33,9 @@ pub mod udpmessage;
use docopt::Docopt; use docopt::Docopt;
use std::{ use std::{
fs::{self, File, Permissions}, fs::File,
io::{self, Write}, io::{self, Write},
net::UdpSocket, net::UdpSocket,
os::unix::fs::PermissionsExt,
path::Path, path::Path,
process::Command, process::Command,
str::FromStr, str::FromStr,
@ -167,7 +166,7 @@ impl<P: Protocol> AnyCloud<P> {
#[allow(unknown_lints, clippy::too_many_arguments)] #[allow(unknown_lints, clippy::too_many_arguments)]
fn new( fn new(
config: &Config, device: TunTapDevice, table: AnyTable, learning: bool, broadcast: bool, addresses: Vec<Range>, config: &Config, device: TunTapDevice, table: AnyTable, learning: bool, broadcast: bool, addresses: Vec<Range>,
crypto: Crypto, port_forwarding: Option<PortForwarding>, stats_file: Option<File> crypto: Crypto, port_forwarding: Option<PortForwarding>
) -> Self ) -> Self
{ {
match table { match table {
@ -179,15 +178,7 @@ impl<P: Protocol> AnyCloud<P> {
UdpSocket, UdpSocket,
SystemTimeSource SystemTimeSource
>::new( >::new(
config, config, device, t, learning, broadcast, addresses, crypto, port_forwarding
device,
t,
learning,
broadcast,
addresses,
crypto,
port_forwarding,
stats_file
)) ))
} }
AnyTable::Routing(t) => { AnyTable::Routing(t) => {
@ -199,8 +190,7 @@ impl<P: Protocol> AnyCloud<P> {
broadcast, broadcast,
addresses, addresses,
crypto, crypto,
port_forwarding, port_forwarding
stats_file
)) ))
} }
} }
@ -266,19 +256,7 @@ fn run<P: Protocol>(config: Config) {
None => Crypto::None None => Crypto::None
}; };
let port_forwarding = if config.port_forwarding { PortForwarding::new(config.port) } else { None }; let port_forwarding = if config.port_forwarding { PortForwarding::new(config.port) } else { None };
let stats_file = match config.stats_file { let mut cloud = AnyCloud::<P>::new(&config, device, table, learning, broadcasting, ranges, crypto, port_forwarding);
None => None,
Some(ref name) => {
let file = try_fail!(File::create(name), "Failed to create stats file: {}");
try_fail!(
fs::set_permissions(name, Permissions::from_mode(0o644)),
"Failed to set permissions on stats file: {}"
);
Some(file)
}
};
let mut cloud =
AnyCloud::<P>::new(&config, device, table, learning, broadcasting, ranges, crypto, port_forwarding, stats_file);
if let Some(script) = config.ifup { if let Some(script) = config.ifup {
run_script(&script, cloud.ifname()); run_script(&script, cloud.ifname());
} }
@ -299,16 +277,6 @@ fn run<P: Protocol>(config: Config) {
daemonize = daemonize.pid_file(pid_file).chown_pid_file(true); daemonize = daemonize.pid_file(pid_file).chown_pid_file(true);
} }
try_fail!(daemonize.start(), "Failed to daemonize: {}"); try_fail!(daemonize.start(), "Failed to daemonize: {}");
} else if config.user.is_some() || config.group.is_some() {
info!("Dropping privileges");
let mut pd = privdrop::PrivDrop::default();
if let Some(user) = config.user {
pd = pd.user(user);
}
if let Some(group) = config.group {
pd = pd.group(group);
}
try_fail!(pd.apply(), "Failed to drop privileges: {}");
} }
cloud.run(); cloud.run();
if let Some(script) = config.ifdown { if let Some(script) = config.ifdown {

View File

@ -80,7 +80,7 @@ fn create_tap_node(nat: bool) -> TapTestNode {
fn create_tap_node_with_config(nat: bool, mut config: Config) -> TapTestNode { fn create_tap_node_with_config(nat: bool, mut config: Config) -> TapTestNode {
MockSocket::set_nat(nat); MockSocket::set_nat(nat);
config.port = NEXT_PORT.with(|p| p.fetch_add(1, Ordering::Relaxed)) as u16; config.port = NEXT_PORT.with(|p| p.fetch_add(1, Ordering::Relaxed)) as u16;
TestNode::new(&config, MockDevice::new(), SwitchTable::new(1800, 10), true, true, vec![], Crypto::None, None, None) TestNode::new(&config, MockDevice::new(), SwitchTable::new(1800, 10), true, true, vec![], Crypto::None, None)
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -94,7 +94,6 @@ fn create_tun_node(nat: bool, addresses: Vec<Range>) -> TunTestNode {
false, false,
addresses, addresses,
Crypto::None, Crypto::None,
None,
None None
) )
} }

View File

@ -31,8 +31,8 @@ Options:
interface. interface.
--pid-file <file> Store the process id in this file when --pid-file <file> Store the process id in this file when
daemonizing. daemonizing.
--user <user> Run as other user. --user <user> Run as other user when daemonizing.
--group <group> Run as other group. --group <group> Run as other group when daemonizing.
--log-file <file> Print logs also to this file. --log-file <file> Print logs also to this file.
--stats-file <file> Print statistics to this file. --stats-file <file> Print statistics to this file.
--no-port-forwarding Disable automatic port forward. --no-port-forwarding Disable automatic port forward.

View File

@ -80,12 +80,6 @@ vpncloud(1) -- Peer-to-peer VPN
Peer timeout in seconds. The peers will exchange information periodically Peer timeout in seconds. The peers will exchange information periodically
and drop peers that are silent for this period of time. [default: `1800`] and drop peers that are silent for this period of time. [default: `1800`]
* `--keepalive <secs>`:
Interval of peer exchange messages in seconds. The peers will exchange
information periodically to keep connections alive. This setting overrides
how often this will happen. [default: `peer-timeout/2-60`]
* `--dst-timeout <secs>`: * `--dst-timeout <secs>`:
Switch table entry timeout in seconds. This parameter is only used in switch Switch table entry timeout in seconds. This parameter is only used in switch
@ -146,7 +140,8 @@ vpncloud(1) -- Peer-to-peer VPN
* `--group <group>`: * `--group <group>`:
Change the user and/or group of the process once all the setup has been Change the user and/or group of the process once all the setup has been
done. done and before spawning the background process. This option is only used
when running in background.
* `--log-file <file>`: * `--log-file <file>`: