diff --git a/src/client/main.rs b/src/client/main.rs index 99aa9b6..73091ea 100644 --- a/src/client/main.rs +++ b/src/client/main.rs @@ -1,5 +1,5 @@ -mod config; mod net; +mod net_utils; mod tun; mod types; use colored::Colorize; @@ -259,6 +259,10 @@ fn main() -> std::io::Result<()> { }, ); + // timeout is no longer needed + #[cfg(not(feature = "no-timeout"))] + socket.set_read_timeout(None)?; + smol::block_on(async { smol::spawn(tun::read_tun_iface( tun_iface.clone(), @@ -281,12 +285,12 @@ fn main() -> std::io::Result<()> { .detach(); } Err(e) => { - eprint!( - "{} failed to read from socket Error: {}", - "[ERROR]".red(), - e + eprintln!( + "{} failed to read from socket Error: {}\n{}", + "[WARNING]".red(), + e, + "Retrying".bright_yellow() ); - exit(5); //EIO } } } diff --git a/src/client/net.rs b/src/client/net.rs index 9b5ff8c..2e5f9ba 100644 --- a/src/client/net.rs +++ b/src/client/net.rs @@ -5,14 +5,12 @@ use std::{ sync::{Arc, RwLock}, }; +use super::types; +use crate::net_utils; +use crate::types::Peer; use colored::Colorize; use pea_2_pea::*; use rand::{RngCore, rng}; -use tappers::Netmask; - -use crate::types::Peer; - -use super::types; // return data_lenght and number of retryes pub fn send_and_recv_with_retry( @@ -22,34 +20,51 @@ pub fn send_and_recv_with_retry( socket: &UdpSocket, retry_max: usize, ) -> Result<(usize, usize), ServerErrorResponses> { + #[cfg(any(target_os = "linux", target_os = "windows"))] + net_utils::enable_icmp_errors(socket)?; + let mut retry_count: usize = 0; + loop { match socket.send_to(send_buf, dst) { Ok(s) => { #[cfg(debug_assertions)] eprintln!("send {} bytes", s); } - Err(e) => { - panic!("Error sending data: {}", e); - } + Err(e) => match e.kind() { + ErrorKind::ConnectionReset + | ErrorKind::ConnectionRefused + | ErrorKind::NetworkUnreachable + | ErrorKind::HostUnreachable => { + return Err(ServerErrorResponses::IO(std::io::Error::new( + e.kind(), + format!("Destination unreachable: {}", e), + ))); + } + _ => return Err(ServerErrorResponses::IO(e)), + }, + } + + #[cfg(target_os = "linux")] + if let Err(icmp_error) = net_utils::check_icmp_error_queue(socket) { + return Err(ServerErrorResponses::IO(icmp_error)); } match socket.recv_from(buf) { - Ok((data_lenght, src)) => { + Ok((data_length, src)) => { if src != *dst { continue; } match buf[0] { x if x == send_buf[0] as u8 => { - return Ok((data_lenght, retry_count)); + return Ok((data_length, retry_count)); } x if x == ServerResponse::GENERAL_ERROR as u8 => { return Err(ServerErrorResponses::IO(std::io::Error::new( std::io::ErrorKind::InvalidData, - match std::str::from_utf8(&buf[1..data_lenght]) { - // the firts byte is compensated for sice this is len not index + match std::str::from_utf8(&buf[1..data_length]) { Ok(s) => s.to_string(), - Err(e) => format!("invalid error string: {}", e).to_string(), + Err(e) => format!("invalid error string: {}", e), }, ))); } @@ -65,19 +80,32 @@ pub fn send_and_recv_with_retry( } } Err(e) if e.kind() == ErrorKind::WouldBlock || e.kind() == ErrorKind::TimedOut => { - // timedout + #[cfg(target_os = "linux")] + if let Err(icmp_error) = net_utils::check_icmp_error_queue(socket) { + return Err(ServerErrorResponses::IO(icmp_error)); + } + if retry_count >= retry_max { return Err(ServerErrorResponses::IO(std::io::Error::new( ErrorKind::TimedOut, - "max retry count reached without responce", + "Max retry count reached - destination may be unreachable", ))); } retry_count += 1; continue; } - Err(e) => { - return Err(ServerErrorResponses::IO(e)); - } + Err(e) => match e.kind() { + ErrorKind::ConnectionReset + | ErrorKind::ConnectionRefused + | ErrorKind::NetworkUnreachable + | ErrorKind::HostUnreachable => { + return Err(ServerErrorResponses::IO(std::io::Error::new( + e.kind(), + format!("Destination unreachable during receive: {}", e), + ))); + } + _ => return Err(ServerErrorResponses::IO(e)), + }, } } } diff --git a/src/client/config.rs b/src/client/net_utils.rs similarity index 91% rename from src/client/config.rs rename to src/client/net_utils.rs index 2dfe3fc..72ae560 100644 --- a/src/client/config.rs +++ b/src/client/net_utils.rs @@ -1,5 +1,4 @@ -use std::io::ErrorKind; -use std::net::{SocketAddr, UdpSocket}; +use std::net::UdpSocket; #[cfg(target_os = "windows")] use std::os::windows::io::AsRawSocket; @@ -14,7 +13,7 @@ use winapi::um::winsock2::{SOCKET_ERROR, WSAIoctl}; use std::os::unix::io::AsRawFd; #[cfg(target_os = "windows")] -fn enable_icmp_errors(socket: &UdpSocket) -> std::io::Result<()> { +pub fn enable_icmp_errors(socket: &UdpSocket) -> std::io::Result<()> { let socket_handle = socket.as_raw_socket(); let mut bytes_returned: DWORD = 0; let enable: BOOL = FALSE; @@ -41,7 +40,7 @@ fn enable_icmp_errors(socket: &UdpSocket) -> std::io::Result<()> { } #[cfg(target_os = "linux")] -fn enable_icmp_errors(socket: &UdpSocket) -> std::io::Result<()> { +pub fn enable_icmp_errors(socket: &UdpSocket) -> std::io::Result<()> { let fd = socket.as_raw_fd(); let optval: libc::c_int = 1; @@ -63,7 +62,7 @@ fn enable_icmp_errors(socket: &UdpSocket) -> std::io::Result<()> { } #[cfg(target_os = "linux")] -fn check_icmp_error_queue(socket: &UdpSocket) -> std::io::Result<()> { +pub fn check_icmp_error_queue(socket: &UdpSocket) -> std::io::Result<()> { use libc::{MSG_ERRQUEUE, iovec, msghdr, recvmsg}; let fd = socket.as_raw_fd(); diff --git a/src/client/tun.rs b/src/client/tun.rs index a24f3f7..115fe83 100644 --- a/src/client/tun.rs +++ b/src/client/tun.rs @@ -15,11 +15,12 @@ pub fn create_tun_interface( let mut broadcast_addr_oct = private_ip.octets(); broadcast_addr_oct[3] = 255; addr_req.set_broadcast(std::net::Ipv4Addr::from(broadcast_addr_oct)); - tun_iface.add_addr(private_ip)?; + tun_iface.add_addr(addr_req)?; tun_iface.set_up()?; return Ok(tun_iface); } + pub async fn read_tun_iface( tun_iface: Arc, socket: Arc,