Merge branch 'master' into threading

This commit is contained in:
Dennis Schwerdel 2023-10-08 20:02:48 +02:00
parent aa949cdcec
commit 8f40cce6c4
16 changed files with 458 additions and 455 deletions

View File

@ -11,8 +11,8 @@ RUN chown vscode: -R /usr/local/rustup /usr/local/cargo
USER vscode USER vscode
RUN rustup default 1.70.0 \ RUN rustup default 1.73.0 \
&& rustup component add clippy rust-src rustfmt && rustup component add clippy rust-src rustfmt
RUN cargo install cargo-outdated cargo-cache cargo-criterion \ RUN cargo install cargo-outdated cargo-cache cargo-criterion \
&& cargo cache -a && cargo cache -a

View File

@ -8,26 +8,30 @@
"--security-opt", "--security-opt",
"seccomp=unconfined" "seccomp=unconfined"
], ],
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"lldb.executable": "/usr/bin/lldb",
// VS Code don't watch files under ./target
"files.watcherExclude": {
"**/target/**": true
}
},
// Add the IDs of extensions you want installed when the container is created. // Add the IDs of extensions you want installed when the container is created.
"extensions": [ // Set *default* container specific settings.json values on container create.
"bungcip.better-toml", "customizations": {
"vadimcn.vscode-lldb", "vscode": {
"serayuzgur.crates", "terminal.integrated.shell.linux": "/bin/bash",
"editorconfig.editorconfig", "lldb.executable": "/usr/bin/lldb",
"swellaby.vscode-rust-test-adapter", // VS Code don't watch files under ./target
"asciidoctor.asciidoctor-vscode", "files.watcherExclude": {
"ms-vscode.test-adapter-converter", "**/target/**": true
"rust-lang.rust-analyzer" },
], // Add the IDs of extensions you want installed when the container is created.
"extensions": [
"bungcip.better-toml",
"vadimcn.vscode-lldb",
"serayuzgur.crates",
"editorconfig.editorconfig",
"swellaby.vscode-rust-test-adapter",
"rust-lang.rust-analyzer",
"asciidoctor.asciidoctor-vscode",
"ms-vscode.test-adapter-converter"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally. // Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [], // "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created. // Use 'postCreateCommand' to run commands after the container is created.

View File

@ -30,23 +30,3 @@ jobs:
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
command: test command: test
coverage:
name: Coverage
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Run cargo-tarpaulin
uses: actions-rs/tarpaulin@v0.1
with:
args: '-o Html -- --test-threads=1'
- name: Archive code coverage results
uses: actions/upload-artifact@v1
with:
name: code-coverage-report
path: tarpaulin-report.html

View File

@ -4,8 +4,9 @@ This project follows [semantic versioning](http://semver.org).
### UNRELEASED ### UNRELEASED
- [changed] Changed Rust version to 1.64.0 - [changed] Changed Rust version to 1.73.0
- [changed] Updated dependencies - [changed] Updated dependencies
- [fixed] Fix error when IPv6 is not available
### v2.3.0 (2021-12-23) ### v2.3.0 (2021-12-23)

771
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@ readme = "README.md"
edition = "2018" edition = "2018"
[package.metadata] [package.metadata]
toolchain = "1.70.0" toolchain = "1.73.0"
upx_version = "3.96" upx_version = "3.96"
[dependencies] [dependencies]
@ -25,15 +25,15 @@ libc = "0.2"
rand = "0.8" rand = "0.8"
fnv = "1" fnv = "1"
yaml-rust = "0.4" yaml-rust = "0.4"
daemonize = "0.4" daemonize = "0.5"
ring = "0.16" ring = "0.17"
privdrop = "0.5" privdrop = "0.5"
byteorder = "1.4" byteorder = "1.4"
thiserror = "1.0" thiserror = "1.0"
parking_lot = "0.12" parking_lot = "0.12"
smallvec = "1.7" smallvec = "1.7"
dialoguer = { version = "0.10", optional = true } dialoguer = { version = "0.11", optional = true }
tungstenite = { version = "0.17", optional = true, default-features = false } tungstenite = { version = "0.20", optional = true }
url = { version = "2.2", optional = true } url = { version = "2.2", optional = true }
igd = { version = "0.12", optional = true } igd = { version = "0.12", optional = true }
timeout_io = "0.6" timeout_io = "0.6"

View File

@ -31,7 +31,7 @@ fn udp_send(c: &mut Criterion) {
let mut g = c.benchmark_group("udp_send"); let mut g = c.benchmark_group("udp_send");
g.throughput(Throughput::Bytes(1400)); g.throughput(Throughput::Bytes(1400));
g.bench_function("udp_send", |b| { g.bench_function("udp_send", |b| {
b.iter(|| sock.send_to(&data, &addr).unwrap()); b.iter(|| sock.send_to(&data, addr).unwrap());
}); });
g.finish(); g.finish();
} }

View File

@ -28,7 +28,7 @@ fn udp_send() {
let sock = UdpSocket::bind("127.0.0.1:0").unwrap(); let sock = UdpSocket::bind("127.0.0.1:0").unwrap();
let data = [0; 1400]; let data = [0; 1400];
let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1); let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1);
sock.send_to(&data, &black_box(addr)).unwrap(); sock.send_to(&data, black_box(addr)).unwrap();
} }
fn decode_ipv4() { fn decode_ipv4() {

View File

@ -12,12 +12,12 @@ fn main() {
fs::create_dir_all(&out_dir).unwrap(); fs::create_dir_all(&out_dir).unwrap();
fs::copy("vpncloud.adoc", Path::new(&out_dir).join("vpncloud.adoc")).unwrap(); fs::copy("vpncloud.adoc", Path::new(&out_dir).join("vpncloud.adoc")).unwrap();
match Command::new("asciidoctor") match Command::new("asciidoctor")
.args(&["-b", "manpage", "vpncloud.adoc"]) .args(["-b", "manpage", "vpncloud.adoc"])
.current_dir(&Path::new(&out_dir)) .current_dir(Path::new(&out_dir))
.status() .status()
{ {
Ok(_) => { Ok(_) => {
Command::new("gzip").args(&["vpncloud.1"]).current_dir(&Path::new(&out_dir)).status().unwrap(); Command::new("gzip").args(["vpncloud.1"]).current_dir(Path::new(&out_dir)).status().unwrap();
fs::copy(Path::new(&out_dir).join("vpncloud.1.gz"), "target/vpncloud.1.gz").unwrap(); fs::copy(Path::new(&out_dir).join("vpncloud.1.gz"), "target/vpncloud.1.gz").unwrap();
} }
Err(err) => { Err(err) => {

View File

@ -228,7 +228,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
let beacon = format!("{}{}{}", begin, data, end); let beacon = format!("{}{}{}", begin, data, end);
debug!("Calling beacon command: {}", cmd); debug!("Calling beacon command: {}", cmd);
let process = Command::new("sh") let process = Command::new("sh")
.args(&["-c", cmd]) .args(["-c", cmd])
.env("begin", begin) .env("begin", begin)
.env("data", data) .env("data", data)
.env("end", end) .env("end", end)
@ -281,7 +281,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
let end = self.end(); let end = self.end();
debug!("Calling beacon command: {}", cmd); debug!("Calling beacon command: {}", cmd);
let process = Command::new("sh") let process = Command::new("sh")
.args(&["-c", cmd]) .args(["-c", cmd])
.env("begin", begin) .env("begin", begin)
.env("end", end) .env("end", end)
.stdout(Stdio::piped()) .stdout(Stdio::piped())

View File

@ -473,8 +473,8 @@ impl<P: Payload> InitState<P> {
} }
fn derive_master_key(&self, algo: &'static Algorithm, privk: EcdhPrivateKey, pubk: &EcdhPublicKey) -> LessSafeKey { fn derive_master_key(&self, algo: &'static Algorithm, privk: EcdhPrivateKey, pubk: &EcdhPublicKey) -> LessSafeKey {
agree_ephemeral(privk, pubk, (), |k| { agree_ephemeral(privk, pubk, |k| {
UnboundKey::new(algo, &k[..algo.key_len()]).map(LessSafeKey::new).map_err(|_| ()) UnboundKey::new(algo, &k[..algo.key_len()]).map(LessSafeKey::new).unwrap()
}) })
.unwrap() .unwrap()
} }

View File

@ -137,10 +137,10 @@ impl RotationState {
} }
fn derive_key(private_key: EcdhPrivateKey, public_key: EcdhPublicKey) -> Key { fn derive_key(private_key: EcdhPrivateKey, public_key: EcdhPublicKey) -> Key {
agree_ephemeral(private_key, &public_key, (), |k| { agree_ephemeral(private_key, &public_key, |k| {
let mut vec = Key::new(); let mut vec = Key::new();
vec.extend_from_slice(k); vec.extend_from_slice(k);
Ok(vec) vec
}) })
.unwrap() .unwrap()
} }

View File

@ -49,7 +49,6 @@ use std::{
process, process,
str::FromStr, str::FromStr,
sync::Mutex, sync::Mutex,
thread,
}; };
use crate::{ use crate::{
@ -115,7 +114,7 @@ impl log::Log for DualLogger {
fn run_script(script: &str, ifname: &str) { fn run_script(script: &str, ifname: &str) {
let mut cmd = process::Command::new("sh"); let mut cmd = process::Command::new("sh");
cmd.arg("-c").arg(&script).env("IFNAME", ifname); cmd.arg("-c").arg(script).env("IFNAME", ifname);
debug!("Running script: {:?}", cmd); debug!("Running script: {:?}", cmd);
match cmd.status() { match cmd.status() {
Ok(status) => { Ok(status) => {
@ -204,8 +203,6 @@ fn run<P: Protocol, S: Socket>(config: Config, socket: S) {
} }
if let Some(pid_file) = &config.pid_file { if let Some(pid_file) = &config.pid_file {
daemonize = daemonize.pid_file(pid_file).chown_pid_file(true); daemonize = daemonize.pid_file(pid_file).chown_pid_file(true);
// Give child process some time to write PID file
daemonize = daemonize.exit_action(|| thread::sleep(std::time::Duration::from_millis(10)));
} }
try_fail!(daemonize.start(), "Failed to daemonize: {}"); try_fail!(daemonize.start(), "Failed to daemonize: {}");
} else if config.user.is_some() || config.group.is_some() { } else if config.user.is_some() || config.group.is_some() {

View File

@ -26,7 +26,7 @@ pub fn mapped_addr(addr: SocketAddr) -> SocketAddr {
} }
pub fn get_ip() -> IpAddr { pub fn get_ip() -> IpAddr {
let s = std::net::UdpSocket::bind("[::]:0").unwrap(); let s = UdpSocket::bind("[::]:0").unwrap();
s.connect("8.8.8.8:0").unwrap(); s.connect("8.8.8.8:0").unwrap();
s.local_addr().unwrap().ip() s.local_addr().unwrap().ip()
} }

View File

@ -23,7 +23,7 @@ fn str_opt(s: String) -> Option<String> {
} }
} }
fn configure_connectivity(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), io::Error> { fn configure_connectivity(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), dialoguer::Error> {
if mode >= MODE_ADVANCED { if mode >= MODE_ADVANCED {
config.listen = config.listen =
Input::with_theme(theme).with_prompt("Listen address").default(config.listen.clone()).interact_text()?; Input::with_theme(theme).with_prompt("Listen address").default(config.listen.clone()).interact_text()?;
@ -60,7 +60,7 @@ fn configure_connectivity(config: &mut Config, mode: usize, theme: &ColorfulThem
Ok(()) Ok(())
} }
fn configure_crypto(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), io::Error> { fn configure_crypto(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), dialoguer::Error> {
if (config.crypto.password.is_some() || config.crypto.private_key.is_some()) if (config.crypto.password.is_some() || config.crypto.private_key.is_some())
&& !Confirm::with_theme(theme).with_prompt("Create new crypto config?").default(false).interact()? && !Confirm::with_theme(theme).with_prompt("Create new crypto config?").default(false).interact()?
{ {
@ -151,7 +151,7 @@ fn configure_crypto(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
Ok(()) Ok(())
} }
fn configure_device(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), io::Error> { fn configure_device(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), dialoguer::Error> {
if mode >= MODE_ADVANCED { if mode >= MODE_ADVANCED {
config.device_type = match Select::with_theme(theme) config.device_type = match Select::with_theme(theme)
.with_prompt("Device type") .with_prompt("Device type")
@ -204,7 +204,7 @@ fn configure_device(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
Ok(()) Ok(())
} }
fn configure_addresses(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), io::Error> { fn configure_addresses(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), dialoguer::Error> {
config.ip = str_opt( config.ip = str_opt(
Input::with_theme(theme) Input::with_theme(theme)
.with_prompt("Virtual IP address (e.g. 10.0.0.1, leave empty for none)") .with_prompt("Virtual IP address (e.g. 10.0.0.1, leave empty for none)")
@ -250,7 +250,7 @@ fn configure_addresses(config: &mut Config, mode: usize, theme: &ColorfulTheme)
Ok(()) Ok(())
} }
fn configure_beacon(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), io::Error> { fn configure_beacon(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), dialoguer::Error> {
if mode == MODE_EXPERT if mode == MODE_EXPERT
&& Confirm::with_theme(theme) && Confirm::with_theme(theme)
.with_prompt("Configure beacons?") .with_prompt("Configure beacons?")
@ -332,7 +332,7 @@ fn configure_beacon(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
Ok(()) Ok(())
} }
fn configure_stats(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), io::Error> { fn configure_stats(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), dialoguer::Error> {
if mode >= MODE_ADVANCED { if mode >= MODE_ADVANCED {
config.stats_file = str_opt( config.stats_file = str_opt(
Input::with_theme(theme) Input::with_theme(theme)
@ -369,7 +369,7 @@ fn configure_stats(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> R
Ok(()) Ok(())
} }
fn configure_process(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), io::Error> { fn configure_process(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), dialoguer::Error> {
if mode == MODE_EXPERT { if mode == MODE_EXPERT {
config.user = str_opt( config.user = str_opt(
Input::with_theme(theme) Input::with_theme(theme)
@ -396,7 +396,7 @@ fn configure_process(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
Ok(()) Ok(())
} }
fn configure_hooks(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), io::Error> { fn configure_hooks(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), dialoguer::Error> {
if mode == MODE_EXPERT { if mode == MODE_EXPERT {
if Confirm::with_theme(theme) if Confirm::with_theme(theme)
.with_prompt("Set hooks to react on events?") .with_prompt("Set hooks to react on events?")
@ -439,7 +439,7 @@ fn configure_hooks(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> R
Ok(()) Ok(())
} }
pub fn configure(name: Option<String>) -> Result<(), io::Error> { pub fn configure(name: Option<String>) -> Result<(), dialoguer::Error> {
let theme = ColorfulTheme::default(); let theme = ColorfulTheme::default();
let name = if let Some(name) = name { let name = if let Some(name) = name {
@ -467,7 +467,7 @@ pub fn configure(name: Option<String>) -> Result<(), io::Error> {
config.merge_file(config_file); config.merge_file(config_file);
} }
if file.parent().unwrap().metadata()?.permissions().readonly() { if file.parent().unwrap().metadata()?.permissions().readonly() {
return Err(io::Error::new(io::ErrorKind::PermissionDenied, "Config file not writable")); return Err(io::Error::new(io::ErrorKind::PermissionDenied, "Config file not writable").into());
} }
loop { loop {

View File

@ -63,14 +63,14 @@ fn serve_proxy_connection(stream: TcpStream) -> Result<(), io::Error> {
info!("Listening on {} for peer {}", addr, peer); info!("Listening on {} for peer {}", addr, peer);
addr.set_ip(get_ip()); addr.set_ip(get_ip());
write_addr(addr, &mut msg)?; write_addr(addr, &mut msg)?;
io_error!(websocket.write_message(Message::Binary(msg)), "Failed to write to ws connection: {}")?; io_error!(websocket.send(Message::Binary(msg)), "Failed to write to ws connection: {}")?;
let websocketfd = websocket.get_ref().as_raw_fd(); let websocketfd = websocket.get_ref().as_raw_fd();
let poll = WaitImpl::new(websocketfd, udpsocket.as_raw_fd(), 60 * 1000)?; let poll = WaitImpl::new(websocketfd, udpsocket.as_raw_fd(), 60 * 1000)?;
let mut buffer = [0; 65535]; let mut buffer = [0; 65535];
for evt in poll { for evt in poll {
match evt { match evt {
WaitResult::Socket => { WaitResult::Socket => {
let msg = io_error!(websocket.read_message(), "Failed to read message on websocket {}: {}", peer)?; let msg = io_error!(websocket.read(), "Failed to read message on websocket {}: {}", peer)?;
match msg { match msg {
Message::Binary(data) => { Message::Binary(data) => {
let dst = read_addr(Cursor::new(&data))?; let dst = read_addr(Cursor::new(&data))?;
@ -85,10 +85,10 @@ fn serve_proxy_connection(stream: TcpStream) -> Result<(), io::Error> {
let mut data = Vec::with_capacity(18 + size); let mut data = Vec::with_capacity(18 + size);
write_addr(addr, &mut data)?; write_addr(addr, &mut data)?;
data.write_all(&buffer[..size])?; data.write_all(&buffer[..size])?;
io_error!(websocket.write_message(Message::Binary(data)), "Failed to write to {}: {}", peer)?; io_error!(websocket.send(Message::Binary(data)), "Failed to write to {}: {}", peer)?;
} }
WaitResult::Timeout => { WaitResult::Timeout => {
io_error!(websocket.write_message(Message::Ping(vec![])), "Failed to send ping: {}")?; io_error!(websocket.send(Message::Ping(vec![])), "Failed to send ping: {}")?;
} }
WaitResult::Error(err) => return Err(err), WaitResult::Error(err) => return Err(err),
} }
@ -137,7 +137,7 @@ impl ProxyConnection {
fn read_message(&mut self) -> Result<Vec<u8>, io::Error> { fn read_message(&mut self) -> Result<Vec<u8>, io::Error> {
loop { loop {
if let Message::Binary(data) = io_error!(self.socket.read_message(), "Failed to read from ws proxy: {}")? { if let Message::Binary(data) = io_error!(self.socket.read(), "Failed to read from ws proxy: {}")? {
return Ok(data); return Ok(data);
} }
} }
@ -170,7 +170,7 @@ impl Socket for ProxyConnection {
let mut msg = Vec::with_capacity(data.len() + 18); let mut msg = Vec::with_capacity(data.len() + 18);
write_addr(addr, &mut msg)?; write_addr(addr, &mut msg)?;
msg.write_all(data)?; msg.write_all(data)?;
io_error!(self.socket.write_message(Message::Binary(msg)), "Failed to write to ws proxy: {}")?; io_error!(self.socket.send(Message::Binary(msg)), "Failed to write to ws proxy: {}")?;
Ok(data.len()) Ok(data.len())
} }