diff --git a/burrow/src/daemon/mod.rs b/burrow/src/daemon/mod.rs index 5066b26..33d8e2e 100644 --- a/burrow/src/daemon/mod.rs +++ b/burrow/src/daemon/mod.rs @@ -1,8 +1,8 @@ +use std::net::ToSocketAddrs; use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, sync::Arc, }; -use std::net::ToSocketAddrs; mod command; mod instance; @@ -54,8 +54,9 @@ pub async fn daemon_main() -> Result<()> { let public_key = parse_public_key("uy75leriJay0+oHLhRMpV+A5xAQ0hCJ+q7Ww81AOvT4=")?; let preshared_key = Some(parse_key("s7lx/mg+reVEMnGnqeyYOQkzD86n2+gYnx1M9ygi08k=")?); tracing::debug!("beginning to find endpoint location"); - let endpoint = "wg.burrow.rs:51820".to_socket_addrs()? - .filter(|sock| {sock.is_ipv4()}) + let endpoint = "wg.burrow.rs:51820" + .to_socket_addrs()? + .filter(|sock| sock.is_ipv4()) .next() .ok_or(anyhow!("DNS Lookup Fails!"))?; // DNS lookup under macos fails, somehow diff --git a/burrow/src/daemon/net/unix.rs b/burrow/src/daemon/net/unix.rs index aa388d6..cd8fb83 100644 --- a/burrow/src/daemon/net/unix.rs +++ b/burrow/src/daemon/net/unix.rs @@ -36,7 +36,7 @@ fn fetch_socket_path() -> Option { for path in tries { let path = PathBuf::from(path); if path.exists() { - return Some(path) + return Some(path); } } None diff --git a/burrow/src/lib.rs b/burrow/src/lib.rs index ce8474a..8bccc30 100644 --- a/burrow/src/lib.rs +++ b/burrow/src/lib.rs @@ -2,11 +2,7 @@ pub mod wireguard; mod daemon; pub use daemon::{ - DaemonClient, DaemonCommand, - DaemonResponse, - DaemonResponseData, - DaemonStartOptions, - ServerInfo, + DaemonClient, DaemonCommand, DaemonResponse, DaemonResponseData, DaemonStartOptions, ServerInfo, }; #[cfg(target_vendor = "apple")] diff --git a/burrow/src/wireguard/config.rs b/burrow/src/wireguard/config.rs index e69de29..906f3ca 100644 --- a/burrow/src/wireguard/config.rs +++ b/burrow/src/wireguard/config.rs @@ -0,0 +1,92 @@ +use crate::wireguard::{Interface as WgInterface, Peer as WgPeer}; +use anyhow::{anyhow, Error, Result}; +use base64::engine::general_purpose; +use base64::Engine; +use fehler::throws; +use ip_network::IpNetwork; +use nix::libc::malloc_printf; +use std::net::ToSocketAddrs; +use std::str::FromStr; +use x25519_dalek::{PublicKey, StaticSecret}; + +#[throws] +fn parse_key(string: &str) -> [u8; 32] { + let value = general_purpose::STANDARD.decode(string)?; + let mut key = [0u8; 32]; + key.copy_from_slice(&value[..]); + key +} + +#[throws] +fn parse_secret_key(string: &str) -> StaticSecret { + let key = parse_key(string)?; + StaticSecret::from(key) +} + +#[throws] +fn parse_public_key(string: &str) -> PublicKey { + let key = parse_key(string)?; + PublicKey::from(key) +} + +/// A raw version of Peer Config that can be used later to reflect configuration files. +/// This should be later converted to a `WgPeer`. +/// Refers to https://github.com/pirate/wireguard-docs?tab=readme-ov-file#overview +pub struct Peer { + pub public_key: String, + pub preshared_key: Option, + pub allowed_ips: Vec, + pub endpoint: String, + pub persistent_keepalive: u32, + pub name: Option, +} + +pub struct Interface { + pub private_key: String, + pub address: String, + pub listen_port: u32, + pub dns: Vec, + pub mtu: u32, +} + +pub struct Config { + pub peers: Vec, + pub interface: Interface, // Support for multiple interfaces? +} + +impl TryFrom for WgInterface { + type Error = anyhow::Error; + + fn try_from(cfig: Config) -> Result { + let sk = parse_secret_key(&cfig.interface.private_key)?; + let wg_peers: Vec = cfig + .peers + .iter() + .map(|p| { + Ok(WgPeer { + private_key: sk.clone(), + public_key: parse_public_key(&p.public_key)?, + endpoint: p + .endpoint + .to_socket_addrs()? + .filter(|sock| sock.is_ipv4()) + .next() + .ok_or(anyhow!("DNS Lookup Fails!"))?, + preshared_key: match &p.preshared_key { + None => Ok(None), + Some(k) => parse_key(k).map(|res| Some(res)), + }?, + allowed_ips: p + .allowed_ips + .iter() + .map(|ip_addr| { + IpNetwork::from_str(ip_addr) + .map_err(|e| anyhow!("Error parsing IP Network {}: {}", ip_addr, e)) + }) + .collect::>>()?, + }) + }) + .collect::>>()?; + Ok(WgInterface::new(wg_peers)?) + } +} diff --git a/burrow/src/wireguard/iface.rs b/burrow/src/wireguard/iface.rs index 8363dcd..4e86114 100755 --- a/burrow/src/wireguard/iface.rs +++ b/burrow/src/wireguard/iface.rs @@ -113,7 +113,7 @@ impl Interface { Ok(Ok(len)) => &buf[..len], Ok(Err(e)) => { error!("failed to read from interface: {}", e); - continue + continue; } Err(_would_block) => continue, }; @@ -126,7 +126,7 @@ impl Interface { Some(addr) => addr, None => { tracing::debug!("no destination found"); - continue + continue; } }; @@ -146,7 +146,7 @@ impl Interface { } Err(e) => { log::error!("failed to send packet {}", e); - continue + continue; } }; } @@ -170,12 +170,12 @@ impl Interface { let tsk = async move { if let Err(e) = pcb.open_if_closed().await { log::error!("failed to open pcb: {}", e); - return + return; } let r2 = pcb.run(tun).await; if let Err(e) = r2 { log::error!("failed to run pcb: {}", e); - return + return; } else { tracing::debug!("pcb ran successfully"); } diff --git a/burrow/src/wireguard/mod.rs b/burrow/src/wireguard/mod.rs index 4383ff8..891f36e 100755 --- a/burrow/src/wireguard/mod.rs +++ b/burrow/src/wireguard/mod.rs @@ -1,3 +1,4 @@ +mod config; mod iface; mod noise; mod pcb; @@ -16,7 +17,7 @@ Address = 10.68.136.199/32,fc00:bbbb:bbbb:bb01::5:88c6/128 DNS = 10.64.0.1 [Peer] -PublicKey = EKZXvHlSDeqAjfC/m9aQR0oXfQ6Idgffa9L0DH5yaCo= +public_key = EKZXvHlSDeqAjfC/m9aQR0oXfQ6Idgffa9L0DH5yaCo= AllowedIPs = 0.0.0.0/0,::0/0 Endpoint = 146.70.173.66:51820 "#; diff --git a/burrow/src/wireguard/noise/handshake.rs b/burrow/src/wireguard/noise/handshake.rs index 2ec0c6a..08a4faa 100755 --- a/burrow/src/wireguard/noise/handshake.rs +++ b/burrow/src/wireguard/noise/handshake.rs @@ -9,20 +9,14 @@ use std::{ use aead::{Aead, Payload}; use blake2::{ digest::{FixedOutput, KeyInit}, - Blake2s256, - Blake2sMac, - Digest, + Blake2s256, Blake2sMac, Digest, }; use chacha20poly1305::XChaCha20Poly1305; use rand_core::OsRng; use ring::aead::{Aad, LessSafeKey, Nonce, UnboundKey, CHACHA20_POLY1305}; use super::{ - errors::WireGuardError, - session::Session, - x25519, - HandshakeInit, - HandshakeResponse, + errors::WireGuardError, session::Session, x25519, HandshakeInit, HandshakeResponse, PacketCookieReply, }; @@ -209,7 +203,7 @@ impl Tai64N { /// Parse a timestamp from a 12 byte u8 slice fn parse(buf: &[u8; 12]) -> Result { if buf.len() < 12 { - return Err(WireGuardError::InvalidTai64nTimestamp) + return Err(WireGuardError::InvalidTai64nTimestamp); } let (sec_bytes, nano_bytes) = buf.split_at(std::mem::size_of::()); @@ -556,19 +550,22 @@ impl Handshake { let timestamp = Tai64N::parse(×tamp)?; if !timestamp.after(&self.last_handshake_timestamp) { // Possibly a replay - return Err(WireGuardError::WrongTai64nTimestamp) + return Err(WireGuardError::WrongTai64nTimestamp); } self.last_handshake_timestamp = timestamp; // initiator.hash = HASH(initiator.hash || msg.encrypted_timestamp) hash = b2s_hash(&hash, packet.encrypted_timestamp); - self.previous = std::mem::replace(&mut self.state, HandshakeState::InitReceived { - chaining_key, - hash, - peer_ephemeral_public, - peer_index, - }); + self.previous = std::mem::replace( + &mut self.state, + HandshakeState::InitReceived { + chaining_key, + hash, + peer_ephemeral_public, + peer_index, + }, + ); self.format_handshake_response(dst) } @@ -669,7 +666,7 @@ impl Handshake { let local_index = self.cookies.index; if packet.receiver_idx != local_index { - return Err(WireGuardError::WrongIndex) + return Err(WireGuardError::WrongIndex); } // msg.encrypted_cookie = XAEAD(HASH(LABEL_COOKIE || responder.static_public), // msg.nonce, cookie, last_received_msg.mac1) @@ -725,7 +722,7 @@ impl Handshake { dst: &'a mut [u8], ) -> Result<&'a mut [u8], WireGuardError> { if dst.len() < super::HANDSHAKE_INIT_SZ { - return Err(WireGuardError::DestinationBufferTooSmall) + return Err(WireGuardError::DestinationBufferTooSmall); } let (message_type, rest) = dst.split_at_mut(4); @@ -808,7 +805,7 @@ impl Handshake { dst: &'a mut [u8], ) -> Result<(&'a mut [u8], Session), WireGuardError> { if dst.len() < super::HANDSHAKE_RESP_SZ { - return Err(WireGuardError::DestinationBufferTooSmall) + return Err(WireGuardError::DestinationBufferTooSmall); } let state = std::mem::replace(&mut self.state, HandshakeState::None); diff --git a/burrow/src/wireguard/noise/mod.rs b/burrow/src/wireguard/noise/mod.rs index aaa8138..b366775 100755 --- a/burrow/src/wireguard/noise/mod.rs +++ b/burrow/src/wireguard/noise/mod.rs @@ -45,11 +45,7 @@ const N_SESSIONS: usize = 8; pub mod x25519 { pub use x25519_dalek::{ - EphemeralSecret, - PublicKey, - ReusableSecret, - SharedSecret, - StaticSecret, + EphemeralSecret, PublicKey, ReusableSecret, SharedSecret, StaticSecret, }; } @@ -141,7 +137,7 @@ impl Tunnel { #[inline(always)] pub fn parse_incoming_packet(src: &[u8]) -> Result { if src.len() < 4 { - return Err(WireGuardError::InvalidPacket) + return Err(WireGuardError::InvalidPacket); } // Checks the type, as well as the reserved zero fields @@ -183,7 +179,7 @@ impl Tunnel { pub fn dst_address(packet: &[u8]) -> Option { if packet.is_empty() { - return None + return None; } match packet[0] >> 4 { @@ -207,7 +203,7 @@ impl Tunnel { pub fn src_address(packet: &[u8]) -> Option { if packet.is_empty() { - return None + return None; } match packet[0] >> 4 { @@ -302,7 +298,7 @@ impl Tunnel { self.timer_tick(TimerName::TimeLastDataPacketSent); } self.tx_bytes += src.len(); - return TunnResult::WriteToNetwork(packet) + return TunnResult::WriteToNetwork(packet); } // If there is no session, queue the packet for future retry @@ -326,7 +322,7 @@ impl Tunnel { ) -> TunnResult<'a> { if datagram.is_empty() { // Indicates a repeated call - return self.send_queued_packet(dst) + return self.send_queued_packet(dst); } let mut cookie = [0u8; COOKIE_REPLY_SZ]; @@ -337,7 +333,7 @@ impl Tunnel { Ok(packet) => packet, Err(TunnResult::WriteToNetwork(cookie)) => { dst[..cookie.len()].copy_from_slice(cookie); - return TunnResult::WriteToNetwork(&mut dst[..cookie.len()]) + return TunnResult::WriteToNetwork(&mut dst[..cookie.len()]); } Err(TunnResult::Err(e)) => return TunnResult::Err(e), _ => unreachable!(), @@ -437,7 +433,7 @@ impl Tunnel { let cur_idx = self.current; if cur_idx == new_idx { // There is nothing to do, already using this session, this is the common case - return + return; } if self.sessions[cur_idx % N_SESSIONS].is_none() || self.timers.session_timers[new_idx % N_SESSIONS] @@ -483,7 +479,7 @@ impl Tunnel { force_resend: bool, ) -> TunnResult<'a> { if self.handshake.is_in_progress() && !force_resend { - return TunnResult::Done + return TunnResult::Done; } if self.handshake.is_expired() { @@ -542,7 +538,7 @@ impl Tunnel { }; if computed_len > packet.len() { - return TunnResult::Err(WireGuardError::InvalidPacket) + return TunnResult::Err(WireGuardError::InvalidPacket); } self.timer_tick(TimerName::TimeLastDataPacketReceived); diff --git a/burrow/src/wireguard/noise/rate_limiter.rs b/burrow/src/wireguard/noise/rate_limiter.rs index ff19efd..826414b 100755 --- a/burrow/src/wireguard/noise/rate_limiter.rs +++ b/burrow/src/wireguard/noise/rate_limiter.rs @@ -12,19 +12,9 @@ use ring::constant_time::verify_slices_are_equal; use super::{ handshake::{ - b2s_hash, - b2s_keyed_mac_16, - b2s_keyed_mac_16_2, - b2s_mac_24, - LABEL_COOKIE, - LABEL_MAC1, + b2s_hash, b2s_keyed_mac_16, b2s_keyed_mac_16_2, b2s_mac_24, LABEL_COOKIE, LABEL_MAC1, }, - HandshakeInit, - HandshakeResponse, - Packet, - TunnResult, - Tunnel, - WireGuardError, + HandshakeInit, HandshakeResponse, Packet, TunnResult, Tunnel, WireGuardError, }; const COOKIE_REFRESH: u64 = 128; // Use 128 and not 120 so the compiler can optimize out the division @@ -136,7 +126,7 @@ impl RateLimiter { dst: &'a mut [u8], ) -> Result<&'a mut [u8], WireGuardError> { if dst.len() < super::COOKIE_REPLY_SZ { - return Err(WireGuardError::DestinationBufferTooSmall) + return Err(WireGuardError::DestinationBufferTooSmall); } let (message_type, rest) = dst.split_at_mut(4); @@ -202,7 +192,7 @@ impl RateLimiter { let cookie_packet = self .format_cookie_reply(sender_idx, cookie, mac1, dst) .map_err(TunnResult::Err)?; - return Err(TunnResult::WriteToNetwork(cookie_packet)) + return Err(TunnResult::WriteToNetwork(cookie_packet)); } } } diff --git a/burrow/src/wireguard/noise/session.rs b/burrow/src/wireguard/noise/session.rs index 8988728..14c191b 100755 --- a/burrow/src/wireguard/noise/session.rs +++ b/burrow/src/wireguard/noise/session.rs @@ -88,11 +88,11 @@ impl ReceivingKeyCounterValidator { fn will_accept(&self, counter: u64) -> Result<(), WireGuardError> { if counter >= self.next { // As long as the counter is growing no replay took place for sure - return Ok(()) + return Ok(()); } if counter + N_BITS < self.next { // Drop if too far back - return Err(WireGuardError::InvalidCounter) + return Err(WireGuardError::InvalidCounter); } if !self.check_bit(counter) { Ok(()) @@ -107,22 +107,22 @@ impl ReceivingKeyCounterValidator { fn mark_did_receive(&mut self, counter: u64) -> Result<(), WireGuardError> { if counter + N_BITS < self.next { // Drop if too far back - return Err(WireGuardError::InvalidCounter) + return Err(WireGuardError::InvalidCounter); } if counter == self.next { // Usually the packets arrive in order, in that case we simply mark the bit and // increment the counter self.set_bit(counter); self.next += 1; - return Ok(()) + return Ok(()); } if counter < self.next { // A packet arrived out of order, check if it is valid, and mark if self.check_bit(counter) { - return Err(WireGuardError::InvalidCounter) + return Err(WireGuardError::InvalidCounter); } self.set_bit(counter); - return Ok(()) + return Ok(()); } // Packets where dropped, or maybe reordered, skip them and mark unused if counter - self.next >= N_BITS { @@ -247,7 +247,7 @@ impl Session { panic!("The destination buffer is too small"); } if packet.receiver_idx != self.receiving_index { - return Err(WireGuardError::WrongIndex) + return Err(WireGuardError::WrongIndex); } // Don't reuse counters, in case this is a replay attack we want to quickly // check the counter without running expensive decryption diff --git a/burrow/src/wireguard/noise/timers.rs b/burrow/src/wireguard/noise/timers.rs index 1d0cf1f..f713e6f 100755 --- a/burrow/src/wireguard/noise/timers.rs +++ b/burrow/src/wireguard/noise/timers.rs @@ -190,7 +190,7 @@ impl Tunnel { { if self.handshake.is_expired() { - return TunnResult::Err(WireGuardError::ConnectionExpired) + return TunnResult::Err(WireGuardError::ConnectionExpired); } // Clear cookie after COOKIE_EXPIRATION_TIME @@ -206,7 +206,7 @@ impl Tunnel { tracing::error!("CONNECTION_EXPIRED(REJECT_AFTER_TIME * 3)"); self.handshake.set_expired(); self.clear_all(); - return TunnResult::Err(WireGuardError::ConnectionExpired) + return TunnResult::Err(WireGuardError::ConnectionExpired); } if let Some(time_init_sent) = self.handshake.timer() { @@ -219,7 +219,7 @@ impl Tunnel { tracing::error!("CONNECTION_EXPIRED(REKEY_ATTEMPT_TIME)"); self.handshake.set_expired(); self.clear_all(); - return TunnResult::Err(WireGuardError::ConnectionExpired) + return TunnResult::Err(WireGuardError::ConnectionExpired); } if time_init_sent.elapsed() >= REKEY_TIMEOUT { @@ -299,11 +299,11 @@ impl Tunnel { } if handshake_initiation_required { - return self.format_handshake_initiation(dst, true) + return self.format_handshake_initiation(dst, true); } if keepalive_required { - return self.encapsulate(&[], dst) + return self.encapsulate(&[], dst); } TunnResult::Done diff --git a/burrow/src/wireguard/pcb.rs b/burrow/src/wireguard/pcb.rs index 21b1d6e..27db935 100755 --- a/burrow/src/wireguard/pcb.rs +++ b/burrow/src/wireguard/pcb.rs @@ -74,7 +74,7 @@ impl PeerPcb { Ok(l) => l, Err(e) => { log::error!("{}: error reading from socket: {:?}", rid, e); - continue + continue; } }; let mut res_dat = &res_buf[..len]; @@ -90,7 +90,7 @@ impl PeerPcb { TunnResult::Done => break, TunnResult::Err(e) => { tracing::error!(message = "Decapsulate error", error = ?e); - break + break; } TunnResult::WriteToNetwork(packet) => { tracing::debug!("WriteToNetwork: {:?}", packet); @@ -98,17 +98,17 @@ impl PeerPcb { socket.send(packet).await?; tracing::debug!("WriteToNetwork done"); res_dat = &[]; - continue + continue; } TunnResult::WriteToTunnelV4(packet, addr) => { tracing::debug!("WriteToTunnelV4: {:?}, {:?}", packet, addr); tun_interface.read().await.send(packet).await?; - break + break; } TunnResult::WriteToTunnelV6(packet, addr) => { tracing::debug!("WriteToTunnelV6: {:?}, {:?}", packet, addr); tun_interface.read().await.send(packet).await?; - break + break; } } } diff --git a/tun/src/tokio/mod.rs b/tun/src/tokio/mod.rs index 947fb74..3820ba9 100644 --- a/tun/src/tokio/mod.rs +++ b/tun/src/tokio/mod.rs @@ -34,7 +34,7 @@ impl TunInterface { Ok(result) => return result, Err(_would_block) => { tracing::debug!("WouldBlock"); - continue + continue; } } } diff --git a/tun/src/unix/apple/mod.rs b/tun/src/unix/apple/mod.rs index ba0dfd8..8efed1f 100644 --- a/tun/src/unix/apple/mod.rs +++ b/tun/src/unix/apple/mod.rs @@ -35,7 +35,7 @@ impl TunInterface { #[throws] #[instrument] pub fn new_with_options(options: TunOptions) -> TunInterface { - let ti = if options.tun_retrieve{ + let ti = if options.tun_retrieve { TunInterface::retrieve().ok_or(Error::new( std::io::ErrorKind::NotFound, "No tun interface found",