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()
pull/127/head
Jake McGinty 2021-08-02 22:12:29 +09:00 committed by GitHub
parent bbfb11e175
commit 40e8ca68f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 30 additions and 26 deletions

View File

@ -3,14 +3,7 @@ use crate::{Backend, Device, DeviceUpdate, InterfaceName, PeerConfig, PeerInfo,
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use crate::Key; use crate::Key;
use std::{ use std::{fs, io::{self, prelude::*, BufReader}, os::unix::net::UnixStream, path::{Path, PathBuf}, process::{Command, Output}, time::{Duration, SystemTime}};
fs,
io::{self, prelude::*, BufReader},
os::unix::net::UnixStream,
path::{Path, PathBuf},
process::Command,
time::{Duration, SystemTime},
};
static VAR_RUN_PATH: &str = "/var/run/wireguard"; static VAR_RUN_PATH: &str = "/var/run/wireguard";
static RUN_PATH: &str = "/run/wireguard"; static RUN_PATH: &str = "/run/wireguard";
@ -66,9 +59,12 @@ pub fn enumerate() -> Result<Vec<InterfaceName>, io::Error> {
for entry in fs::read_dir(get_base_folder()?)? { for entry in fs::read_dir(get_base_folder()?)? {
let path = entry?.path(); let path = entry?.path();
if path.extension() == Some(OsStr::new("name")) { if path.extension() == Some(OsStr::new("name")) {
let stem = path.file_stem().map(|stem| stem.to_str()).flatten(); let stem = path.file_stem()
if let Some(name) = stem { .and_then(|stem| stem.to_str())
interfaces.push(name.parse()?); .and_then(|name| name.parse::<InterfaceName>().ok())
.filter(|iface| open_socket(iface).is_ok());
if let Some(iface) = stem {
interfaces.push(iface);
} }
} }
} }
@ -271,11 +267,7 @@ fn get_userspace_implementation() -> String {
.unwrap_or_else(|_| "wireguard-go".to_string()) .unwrap_or_else(|_| "wireguard-go".to_string())
} }
pub fn apply(builder: &DeviceUpdate, iface: &InterfaceName) -> io::Result<()> { fn start_userspace_wireguard(iface: &InterfaceName) -> io::Result<Output> {
// 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 mut command = Command::new(&get_userspace_implementation());
let output = if cfg!(target_os = "linux") { let output = if cfg!(target_os = "linux") {
command.args(&[iface.to_string()]).output()? command.args(&[iface.to_string()]).output()?
@ -289,8 +281,20 @@ pub fn apply(builder: &DeviceUpdate, iface: &InterfaceName) -> io::Result<()> {
.output()? .output()?
}; };
if !output.status.success() { if !output.status.success() {
return Err(io::ErrorKind::AddrNotAvailable.into()); 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)?;
// 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)); std::thread::sleep(Duration::from_millis(100));
open_socket(iface) open_socket(iface)
.map_err(|e| io::Error::new(e.kind(), format!("failed to open socket ({})", e)))? .map_err(|e| io::Error::new(e.kind(), format!("failed to open socket ({})", e)))?