client: tighten some error types and apply helptext to io::Error
parent
93b4b0b43c
commit
1aed782683
|
@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
|||
use shared::{ensure_dirs_exist, Cidr, IoErrorContext, Peer, WrappedIoError, CLIENT_DATA_DIR};
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
io::{Read, Seek, SeekFrom, Write},
|
||||
io::{self, Read, Seek, SeekFrom, Write},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use wgctrl::InterfaceName;
|
||||
|
@ -121,7 +121,7 @@ impl DataStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn write(&mut self) -> Result<(), Error> {
|
||||
pub fn write(&mut self) -> Result<(), io::Error> {
|
||||
self.file.seek(SeekFrom::Start(0))?;
|
||||
self.file.set_len(0)?;
|
||||
self.file
|
||||
|
|
|
@ -245,7 +245,7 @@ fn update_hosts_file(
|
|||
interface: &InterfaceName,
|
||||
hosts_path: PathBuf,
|
||||
peers: &[Peer],
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), WrappedIoError> {
|
||||
log::info!("updating {} with the latest peers.", "/etc/hosts".yellow());
|
||||
|
||||
let mut hosts_builder = HostsBuilder::new(format!("innernet {}", interface));
|
||||
|
@ -358,7 +358,11 @@ fn redeem_invite(
|
|||
network: NetworkOpt,
|
||||
) -> Result<(), Error> {
|
||||
log::info!("bringing up the interface.");
|
||||
let resolved_endpoint = config.server.external_endpoint.resolve()?;
|
||||
let resolved_endpoint = config
|
||||
.server
|
||||
.external_endpoint
|
||||
.resolve()
|
||||
.with_str(config.server.external_endpoint.to_string())?;
|
||||
wg::up(
|
||||
&iface,
|
||||
&config.interface.private_key,
|
||||
|
@ -370,7 +374,8 @@ fn redeem_invite(
|
|||
resolved_endpoint,
|
||||
)),
|
||||
network,
|
||||
)?;
|
||||
)
|
||||
.with_str(iface.to_string())?;
|
||||
|
||||
log::info!("Generating new keypair.");
|
||||
let keypair = wgctrl::KeyPair::generate();
|
||||
|
@ -397,7 +402,8 @@ fn redeem_invite(
|
|||
log::info!("Changing keys and waiting for server's WireGuard interface to transition.",);
|
||||
DeviceUpdate::new()
|
||||
.set_private_key(keypair.private)
|
||||
.apply(&iface, network.backend)?;
|
||||
.apply(&iface, network.backend)
|
||||
.with_str(iface.to_string())?;
|
||||
thread::sleep(*REDEEM_TRANSITION_WAIT);
|
||||
|
||||
Ok(())
|
||||
|
@ -442,7 +448,11 @@ fn fetch(
|
|||
}
|
||||
|
||||
log::info!("bringing up the interface.");
|
||||
let resolved_endpoint = config.server.external_endpoint.resolve()?;
|
||||
let resolved_endpoint = config
|
||||
.server
|
||||
.external_endpoint
|
||||
.resolve()
|
||||
.with_str(config.server.external_endpoint.to_string())?;
|
||||
wg::up(
|
||||
interface,
|
||||
&config.interface.private_key,
|
||||
|
@ -454,7 +464,8 @@ fn fetch(
|
|||
resolved_endpoint,
|
||||
)),
|
||||
network,
|
||||
)?
|
||||
)
|
||||
.with_str(interface.to_string())?;
|
||||
}
|
||||
|
||||
log::info!("fetching state from server.");
|
||||
|
@ -521,7 +532,9 @@ fn fetch(
|
|||
}
|
||||
|
||||
if device_config_changed {
|
||||
device_config_builder.apply(&interface, network.backend)?;
|
||||
device_config_builder
|
||||
.apply(&interface, network.backend)
|
||||
.with_str(interface.to_string())?;
|
||||
|
||||
if let Some(path) = hosts_path {
|
||||
update_hosts_file(interface, path, &peers)?;
|
||||
|
@ -534,7 +547,7 @@ fn fetch(
|
|||
}
|
||||
store.set_cidrs(cidrs);
|
||||
store.update_peers(peers)?;
|
||||
store.write()?;
|
||||
store.write().with_str(interface.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1020,6 +1033,9 @@ fn main() {
|
|||
if let Some(e) = e.downcast_ref::<WrappedIoError>() {
|
||||
util::permissions_helptext(e);
|
||||
}
|
||||
if let Some(e) = e.downcast_ref::<io::Error>() {
|
||||
util::permissions_helptext(e);
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ pub fn human_size(bytes: u64) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn permissions_helptext(e: &WrappedIoError) {
|
||||
pub fn permissions_helptext(e: &io::Error) {
|
||||
if e.raw_os_error() == Some(1) {
|
||||
let current_exe = std::env::current_exe()
|
||||
.ok()
|
||||
|
|
|
@ -128,7 +128,7 @@ impl InterfaceConfig {
|
|||
.with_extension("conf")
|
||||
}
|
||||
|
||||
fn build_config_file_path(interface: &InterfaceName) -> Result<PathBuf, Error> {
|
||||
fn build_config_file_path(interface: &InterfaceName) -> Result<PathBuf, WrappedIoError> {
|
||||
ensure_dirs_exist(&[*CLIENT_CONFIG_DIR])?;
|
||||
Ok(Self::get_path(interface))
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use crate::Error;
|
||||
use anyhow::anyhow;
|
||||
use ipnetwork::IpNetwork;
|
||||
use netlink_packet_core::{
|
||||
NetlinkMessage, NetlinkPayload, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REQUEST,
|
||||
|
@ -12,9 +10,12 @@ use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};
|
|||
use std::io;
|
||||
use wgctrl::InterfaceName;
|
||||
|
||||
fn if_nametoindex(interface: &InterfaceName) -> Result<u32, Error> {
|
||||
fn if_nametoindex(interface: &InterfaceName) -> Result<u32, io::Error> {
|
||||
match unsafe { libc::if_nametoindex(interface.as_ptr()) } {
|
||||
0 => Err(anyhow!("couldn't find interface '{}'.", interface)),
|
||||
0 => Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
format!("couldn't find interface '{}'.", interface),
|
||||
)),
|
||||
index => Ok(index),
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +53,7 @@ fn netlink_call(
|
|||
Ok(response)
|
||||
}
|
||||
|
||||
pub fn set_up(interface: &InterfaceName, mtu: u32) -> Result<(), Error> {
|
||||
pub fn set_up(interface: &InterfaceName, mtu: u32) -> Result<(), io::Error> {
|
||||
let index = if_nametoindex(interface)?;
|
||||
let message = LinkMessage {
|
||||
header: LinkHeader {
|
||||
|
@ -66,7 +67,7 @@ pub fn set_up(interface: &InterfaceName, mtu: u32) -> Result<(), Error> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_addr(interface: &InterfaceName, addr: IpNetwork) -> Result<(), Error> {
|
||||
pub fn set_addr(interface: &InterfaceName, addr: IpNetwork) -> Result<(), io::Error> {
|
||||
let index = if_nametoindex(interface)?;
|
||||
let (family, nlas) = match addr {
|
||||
IpNetwork::V4(network) => {
|
||||
|
@ -101,7 +102,7 @@ pub fn set_addr(interface: &InterfaceName, addr: IpNetwork) -> Result<(), Error>
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_route(interface: &InterfaceName, cidr: IpNetwork) -> Result<bool, Error> {
|
||||
pub fn add_route(interface: &InterfaceName, cidr: IpNetwork) -> Result<bool, io::Error> {
|
||||
let if_index = if_nametoindex(interface)?;
|
||||
let (address_family, dst) = match cidr {
|
||||
IpNetwork::V4(network) => (AF_INET as u8, network.network().octets().to_vec()),
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
use crate::{Error, IoErrorContext, NetworkOpt};
|
||||
use ipnetwork::IpNetwork;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::{
|
||||
io,
|
||||
net::{IpAddr, SocketAddr},
|
||||
};
|
||||
use wgctrl::{Backend, Device, DeviceUpdate, InterfaceName, PeerConfigBuilder};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn cmd(bin: &str, args: &[&str]) -> Result<std::process::Output, Error> {
|
||||
fn cmd(bin: &str, args: &[&str]) -> Result<std::process::Output, io::Error> {
|
||||
let output = std::process::Command::new(bin).args(args).output()?;
|
||||
log::debug!("cmd: {} {}", bin, args.join(" "));
|
||||
log::debug!("status: {:?}", output.status.code());
|
||||
|
@ -13,19 +16,21 @@ fn cmd(bin: &str, args: &[&str]) -> Result<std::process::Output, Error> {
|
|||
if output.status.success() {
|
||||
Ok(output)
|
||||
} else {
|
||||
Err(anyhow::anyhow!(
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!(
|
||||
"failed to run {} {} command: {}",
|
||||
bin,
|
||||
args.join(" "),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn set_addr(interface: &InterfaceName, addr: IpNetwork) -> Result<(), Error> {
|
||||
let real_interface =
|
||||
wgctrl::backends::userspace::resolve_tun(interface).with_str(interface.to_string())?;
|
||||
pub fn set_addr(interface: &InterfaceName, addr: IpNetwork) -> Result<(), io::Error> {
|
||||
let real_interface = wgctrl::backends::userspace::resolve_tun(interface)?;
|
||||
|
||||
if addr.is_ipv4() {
|
||||
cmd(
|
||||
|
@ -49,9 +54,8 @@ pub fn set_addr(interface: &InterfaceName, addr: IpNetwork) -> Result<(), Error>
|
|||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn set_up(interface: &InterfaceName, mtu: u32) -> Result<(), Error> {
|
||||
let real_interface =
|
||||
wgctrl::backends::userspace::resolve_tun(interface).with_str(interface.to_string())?;
|
||||
pub fn set_up(interface: &InterfaceName, mtu: u32) -> Result<(), io::Error> {
|
||||
let real_interface = wgctrl::backends::userspace::resolve_tun(interface)?;
|
||||
cmd("ifconfig", &[&real_interface, "mtu", &mtu.to_string()])?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -69,11 +73,17 @@ pub fn up(
|
|||
listen_port: Option<u16>,
|
||||
peer: Option<(&str, IpAddr, SocketAddr)>,
|
||||
network: NetworkOpt,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), io::Error> {
|
||||
let mut device = DeviceUpdate::new();
|
||||
if let Some((public_key, address, endpoint)) = peer {
|
||||
let prefix = if address.is_ipv4() { 32 } else { 128 };
|
||||
let peer_config = PeerConfigBuilder::new(&wgctrl::Key::from_base64(&public_key)?)
|
||||
let peer_config =
|
||||
PeerConfigBuilder::new(&wgctrl::Key::from_base64(&public_key).map_err(|_| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"failed to parse base64 public key",
|
||||
)
|
||||
})?)
|
||||
.add_allowed_ip(address, prefix)
|
||||
.set_endpoint(endpoint);
|
||||
device = device.add_peer(peer_config);
|
||||
|
@ -85,7 +95,12 @@ pub fn up(
|
|||
.set_private_key(wgctrl::Key::from_base64(&private_key).unwrap())
|
||||
.apply(interface, network.backend)?;
|
||||
set_addr(interface, address)?;
|
||||
set_up(interface, network.mtu.unwrap_or_else(|| if address.is_ipv4() { 1420 } else { 1400 }))?;
|
||||
set_up(
|
||||
interface,
|
||||
network
|
||||
.mtu
|
||||
.unwrap_or_else(|| if address.is_ipv4() { 1420 } else { 1400 }),
|
||||
)?;
|
||||
if !network.no_routing {
|
||||
add_route(interface, address)?;
|
||||
}
|
||||
|
@ -119,9 +134,8 @@ pub fn down(interface: &InterfaceName, backend: Backend) -> Result<(), Error> {
|
|||
/// Returns an error if the process doesn't exit successfully, otherwise returns
|
||||
/// true if the route was changed, false if the route already exists.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn add_route(interface: &InterfaceName, cidr: IpNetwork) -> Result<bool, Error> {
|
||||
let real_interface =
|
||||
wgctrl::backends::userspace::resolve_tun(interface).with_str(interface.to_string())?;
|
||||
pub fn add_route(interface: &InterfaceName, cidr: IpNetwork) -> Result<bool, io::Error> {
|
||||
let real_interface = wgctrl::backends::userspace::resolve_tun(interface)?;
|
||||
let output = cmd(
|
||||
"route",
|
||||
&[
|
||||
|
@ -135,11 +149,12 @@ pub fn add_route(interface: &InterfaceName, cidr: IpNetwork) -> Result<bool, Err
|
|||
)?;
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
if !output.status.success() {
|
||||
Err(anyhow::anyhow!(
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!(
|
||||
"failed to add route for device {} ({}): {}",
|
||||
&interface,
|
||||
real_interface,
|
||||
stderr
|
||||
&interface, real_interface, stderr
|
||||
),
|
||||
))
|
||||
} else {
|
||||
Ok(!stderr.contains("File exists"))
|
||||
|
|
Loading…
Reference in New Issue