From 40e8ca68f9d0dba3cc624e40b13592933a4a9eed Mon Sep 17 00:00:00 2001 From: Jake McGinty Date: Mon, 2 Aug 2021 22:12:29 +0900 Subject: [PATCH] wgctrl-rs(userspace): gracefully handle stale `.name` files on macOS * wgctrl-rs(userspace): clean stale namefiles on starting up interface Fixes #114 * wgctrl-rs(userspace): check connectability of interface socket in enumerate() --- wgctrl-rs/src/backends/userspace.rs | 56 +++++++++++++++-------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/wgctrl-rs/src/backends/userspace.rs b/wgctrl-rs/src/backends/userspace.rs index adb237d..b63e1f9 100644 --- a/wgctrl-rs/src/backends/userspace.rs +++ b/wgctrl-rs/src/backends/userspace.rs @@ -3,14 +3,7 @@ use crate::{Backend, Device, DeviceUpdate, InterfaceName, PeerConfig, PeerInfo, #[cfg(target_os = "linux")] use crate::Key; -use std::{ - fs, - io::{self, prelude::*, BufReader}, - os::unix::net::UnixStream, - path::{Path, PathBuf}, - process::Command, - time::{Duration, SystemTime}, -}; +use std::{fs, io::{self, prelude::*, BufReader}, os::unix::net::UnixStream, path::{Path, PathBuf}, process::{Command, Output}, time::{Duration, SystemTime}}; static VAR_RUN_PATH: &str = "/var/run/wireguard"; static RUN_PATH: &str = "/run/wireguard"; @@ -66,9 +59,12 @@ pub fn enumerate() -> Result, io::Error> { for entry in fs::read_dir(get_base_folder()?)? { let path = entry?.path(); if path.extension() == Some(OsStr::new("name")) { - let stem = path.file_stem().map(|stem| stem.to_str()).flatten(); - if let Some(name) = stem { - interfaces.push(name.parse()?); + let stem = path.file_stem() + .and_then(|stem| stem.to_str()) + .and_then(|name| name.parse::().ok()) + .filter(|iface| open_socket(iface).is_ok()); + if let Some(iface) = stem { + interfaces.push(iface); } } } @@ -271,26 +267,34 @@ fn get_userspace_implementation() -> String { .unwrap_or_else(|_| "wireguard-go".to_string()) } +fn start_userspace_wireguard(iface: &InterfaceName) -> io::Result { + let mut command = Command::new(&get_userspace_implementation()); + let output = if cfg!(target_os = "linux") { + command.args(&[iface.to_string()]).output()? + } else { + command + .env( + "WG_TUN_NAME_FILE", + &format!("{}/{}.name", VAR_RUN_PATH, iface), + ) + .args(&["utun"]) + .output()? + }; + if !output.status.success() { + Err(io::ErrorKind::AddrNotAvailable.into()) + } else { + Ok(output) + } +} + pub fn apply(builder: &DeviceUpdate, iface: &InterfaceName) -> io::Result<()> { // If we can't open a configuration socket to an existing interface, try starting it. let mut sock = match open_socket(iface) { Err(_) => { fs::create_dir_all(VAR_RUN_PATH)?; - let mut command = Command::new(&get_userspace_implementation()); - let output = if cfg!(target_os = "linux") { - command.args(&[iface.to_string()]).output()? - } else { - command - .env( - "WG_TUN_NAME_FILE", - &format!("{}/{}.name", VAR_RUN_PATH, iface), - ) - .args(&["utun"]) - .output()? - }; - if !output.status.success() { - return Err(io::ErrorKind::AddrNotAvailable.into()); - } + // Clear out any old namefiles if they didn't lead to a connected socket. + let _ = fs::remove_file(get_namefile(iface)?); + start_userspace_wireguard(iface)?; std::thread::sleep(Duration::from_millis(100)); open_socket(iface) .map_err(|e| io::Error::new(e.kind(), format!("failed to open socket ({})", e)))?