Daemonizing and proper systemd support

This commit is contained in:
Dennis Schwerdel 2016-11-23 15:21:22 +01:00
parent 4497ddaf13
commit 88f5272023
14 changed files with 157 additions and 32 deletions

View File

@ -7,6 +7,10 @@ This project follows [semantic versioning](http://semver.org).
- [added] Support for automatic port forwarding via UPnP - [added] Support for automatic port forwarding via UPnP
- [added] Added `-s` shorthand for `--subnet` - [added] Added `-s` shorthand for `--subnet`
- [added] Support for YAML config file via `--config` - [added] Support for YAML config file via `--config`
- [added] Support for running in the background
- [added] Support for dropping permissions
- [added] Support for writing a pid file
- [added] Support for writing logs to logfile
- [changed] Not overriding recently learnt addresses in switch mode - [changed] Not overriding recently learnt addresses in switch mode
- [changed] Caching resolved addresses to increase performance - [changed] Caching resolved addresses to increase performance
- [changed] Configurable magic header is now used instead of Network-ID (**incompatible**) - [changed] Configurable magic header is now used instead of Network-ID (**incompatible**)

17
Cargo.lock generated
View File

@ -4,6 +4,7 @@ version = "0.7.0"
dependencies = [ dependencies = [
"aligned_alloc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "aligned_alloc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"daemonize 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
@ -11,11 +12,10 @@ dependencies = [
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)",
"signal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "signal 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"siphasher 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "siphasher 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"yaml-rust 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -63,6 +63,14 @@ dependencies = [
"url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "daemonize"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "docopt" name = "docopt"
version = "0.6.86" version = "0.6.86"
@ -272,7 +280,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "signal" name = "signal"
version = "0.2.0" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
@ -422,6 +430,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
"checksum cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e3d6405328b6edb412158b3b7710e2634e23f3614b9bb1c412df7952489a626" "checksum cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e3d6405328b6edb412158b3b7710e2634e23f3614b9bb1c412df7952489a626"
"checksum daemonize 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0239832c1b4ca406d5ec73728cf4c7336d25cf85dd32db9e047e9e706ee0e935"
"checksum docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)" = "4a7ef30445607f6fc8720f0a0a2c7442284b629cf0d049286860fae23e71c4d9" "checksum docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)" = "4a7ef30445607f6fc8720f0a0a2c7442284b629cf0d049286860fae23e71c4d9"
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
"checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5" "checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"
@ -448,7 +457,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "bff9fc1c79f2dec76b253273d07682e94a978bd8f132ded071188122b2af9818" "checksum rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "bff9fc1c79f2dec76b253273d07682e94a978bd8f132ded071188122b2af9818"
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" "checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
"checksum signal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "beb615e58999635b6063277cf520f2d88824955c1056cf4f166b0f55b218512d" "checksum signal 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "904a4bba60e8e7a53b7a7eec8f59084a9ceafe3df5aa9d24846a83a5e351aa34"
"checksum siphasher 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1c3c58c9ac43c530919fe6bd8ef11ae2612f64c2bf8eab9346f5b71ce0617f2" "checksum siphasher 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1c3c58c9ac43c530919fe6bd8ef11ae2612f64c2bf8eab9346f5b71ce0617f2"
"checksum solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "172382bac9424588d7840732b250faeeef88942e37b6e35317dce98cafdd75b2" "checksum solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "172382bac9424588d7840732b250faeeef88942e37b6e35317dce98cafdd75b2"
"checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c" "checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c"

View File

@ -15,8 +15,7 @@ time = "0.1"
docopt = "0.6" docopt = "0.6"
rustc-serialize = "0.3" rustc-serialize = "0.3"
log = "0.3" log = "0.3"
signal = "0.2" signal = "0.3"
nix = "0.6"
libc = "0.2" libc = "0.2"
aligned_alloc = "0.1" aligned_alloc = "0.1"
rand = "0.3" rand = "0.3"
@ -26,6 +25,7 @@ bitflags = "0.7"
yaml-rust = "0.3" yaml-rust = "0.3"
igd = "0.5" igd = "0.5"
siphasher = "0.1" siphasher = "0.1"
daemonize = "0.2"
[build-dependencies] [build-dependencies]
gcc = "0.3" gcc = "0.3"

4
deb/.gitignore vendored
View File

@ -1,9 +1,7 @@
vpncloud/debian/files vpncloud/debian/files
vpncloud/debian/vpncloud vpncloud/debian/vpncloud
vpncloud/debian/debhelper*
vpncloud/vpncloud vpncloud/vpncloud
vpncloud-nocrypto/debian/vpncloud*
vpncloud-nocrypto/debian/files
vpncloud-nocrypto/vpncloud
*.deb *.deb
*.build *.build
*.changes *.changes

View File

@ -11,3 +11,5 @@ install:
install -d $(DESTDIR)/usr/bin install -d $(DESTDIR)/usr/bin
install -m 755 vpncloud $(DESTDIR)/usr/bin/vpncloud install -m 755 vpncloud $(DESTDIR)/usr/bin/vpncloud
install -m 755 vpncloud-control $(DESTDIR)/usr/bin/vpncloud-control install -m 755 vpncloud-control $(DESTDIR)/usr/bin/vpncloud-control
install -d $(DESTDIR)/lib/systemd/system
install -m 644 vpncloud@.service $(DESTDIR)/lib/systemd/system/vpncloud@.service

View File

@ -1 +1 @@
7 9

View File

@ -2,7 +2,7 @@ Source: vpncloud
Section: misc Section: misc
Priority: extra Priority: extra
Maintainer: Dennis Schwerdel <schwerdel@informatik.uni-kl.de> Maintainer: Dennis Schwerdel <schwerdel@informatik.uni-kl.de>
Build-Depends: debhelper (>= 7), ruby-ronn Build-Depends: debhelper (>= 9), ruby-ronn
Standards-Version: 3.8.3 Standards-Version: 3.8.3
Package: vpncloud Package: vpncloud

View File

@ -1,11 +1,10 @@
[Unit] [Unit]
Description=VpnCloud networks Description=VpnCloud
Before=systemd-user-sessions.service
[Service] [Service]
Type=forking ExecStartPre=/bin/echo "Please use instantiated services (vpncloud@NAME) instead."
ExecStart=/usr/bin/vpncloud-control start ExecStart=/bin/false
ExecStop=/usr/bin/vpncloud-control stop
RemainAfterExit=yes
[Install] [Install]
WantedBy=multi-user.target WantedBy=

View File

@ -38,7 +38,7 @@ start() {
# 2 if daemon could not be started # 2 if daemon could not be started
for net in $NETWORKS; do for net in $NETWORKS; do
[ -f "$NETCONFIGS/$net.net" ] || continue [ -f "$NETCONFIGS/$net.net" ] || continue
start-stop-daemon --start --pidfile /run/$NAME-$net.pid --make-pidfile --name $NAME --background --startas /bin/sh -- -c "exec $DAEMON --config $NETCONFIGS/$net.net >/var/log/vpncloud-$net.log 2>&1" start-stop-daemon --start --pidfile /run/$NAME-$net.pid --name $NAME -- "$DAEMON --daemon --config $NETCONFIGS/$net.net --pid-file /run/$NAME-$net.pid"
done done
return 0 return 0
} }

View File

@ -14,7 +14,7 @@ use std::time::Instant;
use std::cmp::{min, max}; use std::cmp::{min, max};
use fnv::FnvHasher; use fnv::FnvHasher;
use nix::sys::signal::{SIGTERM, SIGQUIT, SIGINT}; use libc::{SIGTERM, SIGQUIT, SIGINT};
use signal::trap::Trap; use signal::trap::Trap;
use rand::{random, sample, thread_rng}; use rand::{random, sample, thread_rng};
use net2::UdpBuilder; use net2::UdpBuilder;

View File

@ -25,6 +25,10 @@ pub struct Config {
pub dst_timeout: Duration, pub dst_timeout: Duration,
pub subnets: Vec<String>, pub subnets: Vec<String>,
pub port_forwarding: bool, pub port_forwarding: bool,
pub daemonize: bool,
pub pid_file: Option<String>,
pub user: Option<String>,
pub group: Option<String>
} }
impl Default for Config { impl Default for Config {
@ -37,7 +41,11 @@ impl Default for Config {
port: 3210, peers: vec![], peer_timeout: 1800, port: 3210, peers: vec![], peer_timeout: 1800,
mode: Mode::Normal, dst_timeout: 300, mode: Mode::Normal, dst_timeout: 300,
subnets: vec![], subnets: vec![],
port_forwarding: true port_forwarding: true,
daemonize: false,
pid_file: None,
user: None,
group: None
} }
} }
} }
@ -86,6 +94,15 @@ impl Config {
if let Some(val) = file.port_forwarding { if let Some(val) = file.port_forwarding {
self.port_forwarding = val; self.port_forwarding = val;
} }
if let Some(val) = file.pid_file {
self.pid_file = Some(val);
}
if let Some(val) = file.user {
self.user = Some(val);
}
if let Some(val) = file.group {
self.group = Some(val);
}
} }
pub fn merge_args(&mut self, mut args: Args) { pub fn merge_args(&mut self, mut args: Args) {
@ -131,6 +148,18 @@ impl Config {
if args.flag_no_port_forwarding { if args.flag_no_port_forwarding {
self.port_forwarding = false; self.port_forwarding = false;
} }
if args.flag_daemon {
self.daemonize = true;
}
if let Some(val) = args.flag_pid_file {
self.pid_file = Some(val);
}
if let Some(val) = args.flag_user {
self.user = Some(val);
}
if let Some(val) = args.flag_group {
self.group = Some(val);
}
} }
pub fn get_magic(&self) -> HeaderMagic { pub fn get_magic(&self) -> HeaderMagic {
@ -169,5 +198,8 @@ pub struct ConfigFile {
pub mode: Option<Mode>, pub mode: Option<Mode>,
pub dst_timeout: Option<Duration>, pub dst_timeout: Option<Duration>,
pub subnets: Option<Vec<String>>, pub subnets: Option<Vec<String>>,
pub port_forwarding: Option<bool> pub port_forwarding: Option<bool>,
pub pid_file: Option<String>,
pub user: Option<String>,
pub group: Option<String>,
} }

View File

@ -10,7 +10,6 @@ extern crate time;
extern crate docopt; extern crate docopt;
extern crate rustc_serialize; extern crate rustc_serialize;
extern crate signal; extern crate signal;
extern crate nix;
extern crate libc; extern crate libc;
extern crate aligned_alloc; extern crate aligned_alloc;
extern crate rand; extern crate rand;
@ -19,6 +18,7 @@ extern crate net2;
extern crate yaml_rust; extern crate yaml_rust;
extern crate igd; extern crate igd;
extern crate siphasher; extern crate siphasher;
extern crate daemonize;
#[cfg(feature = "bench")] extern crate test; #[cfg(feature = "bench")] extern crate test;
#[macro_use] pub mod util; #[macro_use] pub mod util;
@ -38,8 +38,12 @@ pub mod port_forwarding;
use docopt::Docopt; use docopt::Docopt;
use std::sync::Mutex;
use std::str::FromStr; use std::str::FromStr;
use std::process::Command; use std::process::Command;
use std::fs::File;
use std::path::Path;
use std::io::{self, Write};
use device::{Device, Type}; use device::{Device, Type};
use ethernet::SwitchTable; use ethernet::SwitchTable;
@ -77,13 +81,31 @@ pub struct Args {
flag_ifup: Option<String>, flag_ifup: Option<String>,
flag_ifdown: Option<String>, flag_ifdown: Option<String>,
flag_version: bool, flag_version: bool,
flag_no_port_forwarding: bool flag_no_port_forwarding: bool,
flag_daemon: bool,
flag_pid_file: Option<String>,
flag_user: Option<String>,
flag_group: Option<String>,
flag_log_file: Option<String>
} }
struct SimpleLogger; struct DualLogger {
file: Mutex<Option<File>>
}
impl log::Log for SimpleLogger { impl DualLogger {
pub fn new<P: AsRef<Path>>(path: Option<P>) -> Result<Self, io::Error> {
if let Some(path) = path {
let file = try!(File::create(path));
Ok(DualLogger{file: Mutex::new(Some(file))})
} else {
Ok(DualLogger{file: Mutex::new(None)})
}
}
}
impl log::Log for DualLogger {
#[inline] #[inline]
fn enabled(&self, _metadata: &log::LogMetadata) -> bool { fn enabled(&self, _metadata: &log::LogMetadata) -> bool {
true true
@ -92,11 +114,12 @@ impl log::Log for SimpleLogger {
#[inline] #[inline]
fn log(&self, record: &log::LogRecord) { fn log(&self, record: &log::LogRecord) {
if self.enabled(record.metadata()) { if self.enabled(record.metadata()) {
println!("{} - {} - {}", println!("{} - {}", record.level(), record.args());
time::strftime("%F %T", &time::now()).expect("Failed to format timestamp"), let mut file = self.file.lock().expect("Lock poisoned");
record.level(), if let &mut Some(ref mut file) = &mut file as &mut Option<File> {
record.args() let time = time::strftime("%F %T", &time::now()).expect("Failed to format timestamp");
); writeln!(file, "{} - {} - {}", time, record.level(), record.args()).expect("Failed to write to logfile");
}
} }
} }
} }
@ -153,6 +176,20 @@ fn run<T: Protocol> (config: Config) {
try_fail!(cloud.connect(&addr as &str), "Failed to send message to {}: {}", &addr); try_fail!(cloud.connect(&addr as &str), "Failed to send message to {}: {}", &addr);
cloud.add_reconnect_peer(addr); cloud.add_reconnect_peer(addr);
} }
if config.daemonize {
info!("Running process as daemon");
let mut daemonize = daemonize::Daemonize::new();
if let Some(user) = config.user {
daemonize = daemonize.user(&user as &str);
}
if let Some(group) = config.group {
daemonize = daemonize.group(&group as &str);
}
if let Some(pid_file) = config.pid_file {
daemonize = daemonize.pid_file(pid_file).chown_pid_file(true);
}
try_fail!(daemonize.start(), "Failed to daemonize: {}");
}
cloud.run(); cloud.run();
if let Some(script) = config.ifdown { if let Some(script) = config.ifdown {
run_script(script, cloud.ifname()); run_script(script, cloud.ifname());
@ -180,7 +217,7 @@ fn main() {
} else { } else {
max_log_level.set(log::LogLevelFilter::Info); max_log_level.set(log::LogLevelFilter::Info);
} }
Box::new(SimpleLogger) Box::new(try_fail!(DualLogger::new(args.flag_log_file.as_ref()), "Failed to open logfile: {}"))
}).unwrap(); }).unwrap();
let mut config = Config::default(); let mut config = Config::default();
if let Some(ref file) = args.flag_config { if let Some(ref file) = args.flag_config {

View File

@ -23,7 +23,13 @@ Options:
--ifup <command> A command to setup the network interface. --ifup <command> A command to setup the network interface.
--ifdown <command> A command to bring down the network --ifdown <command> A command to bring down the network
interface. interface.
--pid-file <file> Store the process id in this file when
daemonizing.
--user <user> Run as other user when daemonizing.
--group <group> Run as other group when daemonizing.
--log-file <file> Print logs also to this file.
--no-port-forwarding Disable automatic port forward. --no-port-forwarding Disable automatic port forward.
--daemon Run the process in the background.
-v, --verbose Print debug information. -v, --verbose Print debug information.
-q, --quiet Only print errors and warnings. -q, --quiet Only print errors and warnings.
-h, --help Display the help. -h, --help Display the help.

View File

@ -88,6 +88,8 @@ vpncloud(1) -- Peer-to-peer VPN
parameter to `sh -c`) when the device has been created to configure it. parameter to `sh -c`) when the device has been created to configure it.
The name of the allocated device will be available via the environment The name of the allocated device will be available via the environment
variable `IFNAME`. variable `IFNAME`.
Please note that this command is executed with the full permissions of the
caller.
* `--ifdown <command>`: * `--ifdown <command>`:
@ -95,6 +97,36 @@ vpncloud(1) -- Peer-to-peer VPN
parameter to `sh -c`) to remove any configuration from the device. parameter to `sh -c`) to remove any configuration from the device.
The name of the allocated device will be available via the environment The name of the allocated device will be available via the environment
variable `IFNAME`. variable `IFNAME`.
Please note that this command is executed with the (limited) permissions of
the user and group given as `--user` and `--group`.
* `--pid-file <file>`:
Store the process id in this file when running in the background. If set,
the given file will be created containing the process id of the new
background process. This option is only used when running in background.
* `--user <user>`:
* `--group <group>`:
Change the user and/or group of the process once all the setup has been
done and before spawning the background process. This option is only used
when running in background.
* `--log-file <file>`:
If set, print logs also to the given file. The file will be created and
truncated if is exists.
* `--daemon`:
Spawn a background process instead of running the process in the foreground.
If this flag is set, the process will first carry out all the
initialization, then drop permissions if `--user` or `--group` is used and
then spawn a background process and write its process id to a file if
`--pid-file` is set. Then, the main process will exit and the background
process continues to provide the VPN. At the time, when the main process
exits, the interface exists and is properly configured to be used.
* `--no-port-forwarding`: * `--no-port-forwarding`:
@ -245,6 +277,9 @@ detailed descriptions of the options.
* `dst_timeout`: Switch table entry timeout in seconds. Same as `--dst-timeout` * `dst_timeout`: Switch table entry timeout in seconds. Same as `--dst-timeout`
* `subnets`: A list of local subnets to use. See `--subnet` * `subnets`: A list of local subnets to use. See `--subnet`
* `port_forwarding`: Whether to activate port forwardig. See `--no-port-forwarding` * `port_forwarding`: Whether to activate port forwardig. See `--no-port-forwarding`
* `user`: The name of a user to run the background process under. See `--user`
* `group`: The name of a group to run the background process under. See `--group`
* `pid_file`: The path of the pid file to create. See `--pid-file`
### Example ### Example
@ -263,6 +298,9 @@ mode: normal
subnets: subnets:
- 10.0.1.0/24 - 10.0.1.0/24
port_forwarding: true port_forwarding: true
user: nobody
group: nogroup
pid_file: /run/vpncloud.pid
## NETWORK PROTOCOL ## NETWORK PROTOCOL
@ -297,7 +335,7 @@ Every packet sent over UDP contains the following header (in order):
`libsodium::crypto_aead_aes256gcm` method, using the 8 byte header `libsodium::crypto_aead_aes256gcm` method, using the 8 byte header
as additional data. as additional data.
* 2 `reserved bytes` that are currently unused * 2 `reserved bytes` that are currently unused and set to 0
* 1 byte for the `message type` * 1 byte for the `message type`