Skip to content

Commit

Permalink
feat: add support for Windows (#98)
Browse files Browse the repository at this point in the history
  • Loading branch information
zarkdav authored and fujiapple852 committed Dec 26, 2022
1 parent 8f81482 commit 54acb6f
Show file tree
Hide file tree
Showing 13 changed files with 999 additions and 323 deletions.
252 changes: 95 additions & 157 deletions Cargo.lock

Large diffs are not rendered by default.

18 changes: 15 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ name = "trip"
[dependencies]

# Library dependencies
socket2 = { version = "0.4.7", features = [ "all" ] }
thiserror = "1.0.38"
thiserror = "1.0.32"
derive_more = "0.99.17"
arrayvec = "0.7.2"

Expand All @@ -46,8 +45,21 @@ comfy-table = "6.1.3"
caps = "0.5.5"

# Library dependencies (Unix)
[target.'cfg(target_family = "unix")'.dependencies]
[target.'cfg(unix)'.dependencies]
nix = { version = "0.26.1", default-features = false, features = [ "user", "poll", "net" ] }
socket2 = { version = "0.4.7", features = [ "all" ] }

[target.'cfg(windows)'.dependencies.windows]
version = "0.43.0"
features = [
"Win32_Foundation",
"Win32_Networking_WinSock",
"Win32_System_IO",
"Win32_NetworkManagement_IpHelper",
"Win32_NetworkManagement_Ndis",
"Win32_System_IO",
"Win32_System_Threading",
]

[dev-dependencies]
rand = "0.8.5"
2 changes: 1 addition & 1 deletion src/tracing.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mod config;
mod error;
mod net;
pub mod net;
mod probe;
mod tracer;
mod types;
Expand Down
2 changes: 2 additions & 0 deletions src/tracing/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ pub enum TracerError {
AddressNotAvailable(SocketAddr),
#[error("invalid source IP address: {0}")]
InvalidSourceAddr(IpAddr),
#[error("error: {0}")]
ErrorString(String),
}
10 changes: 7 additions & 3 deletions src/tracing/net/channel.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
use crate::tracing::error::{TraceResult, TracerError};
use crate::tracing::net::platform;
use crate::tracing::net::platform::Socket;
use crate::tracing::net::{ipv4, ipv6, platform, Network};
use crate::tracing::net::Network;
use crate::tracing::net::{ipv4, ipv6};
use crate::tracing::probe::ProbeResponse;
use crate::tracing::types::{PacketSize, PayloadPattern, Sequence, TraceId, TypeOfService};
use crate::tracing::{
MultipathStrategy, PortDirection, Probe, TracerChannelConfig, TracerProtocol,
};
use arrayvec::ArrayVec;
use itertools::Itertools;

use std::net::IpAddr;
use std::time::{Duration, SystemTime};

Expand Down Expand Up @@ -86,6 +89,7 @@ impl Network for TracerChannel {
}

fn recv_probe(&mut self) -> TraceResult<Option<ProbeResponse>> {
// eprintln!("recv_probe");
match self.protocol {
TracerProtocol::Icmp | TracerProtocol::Udp => self.recv_icmp_probe(),
TracerProtocol::Tcp => Ok(self.recv_tcp_sockets()?.or(self.recv_icmp_probe()?)),
Expand Down Expand Up @@ -245,8 +249,8 @@ fn make_udp_send_socket(addr: IpAddr) -> TraceResult<Socket> {
}

/// Make a socket for receiving raw `ICMP` packets.
fn make_recv_socket(addr: IpAddr) -> TraceResult<Socket> {
match addr {
fn make_recv_socket(src_addr: IpAddr) -> TraceResult<Socket> {
match src_addr {
IpAddr::V4(ipv4addr) => platform::make_recv_socket_ipv4(ipv4addr),
IpAddr::V6(ipv6addr) => platform::make_recv_socket_ipv6(ipv6addr),
}
Expand Down
24 changes: 23 additions & 1 deletion src/tracing/net/ipv4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ pub fn dispatch_tcp_probe(
PortDirection::FixedDest(dest_port) => (probe.sequence.0, dest_port.0),
PortDirection::FixedBoth(_, _) | PortDirection::None => unimplemented!(),
};
let socket = platform::make_stream_socket_ipv4()?;
#[allow(unused_mut)]
let mut socket = platform::make_stream_socket_ipv4()?;
let local_addr = SocketAddr::new(IpAddr::V4(src_addr), src_port);
socket.bind(local_addr)?;
socket.set_ttl(u32::from(probe.ttl.0))?;
Expand All @@ -180,6 +181,7 @@ pub fn dispatch_tcp_probe(
Ok(socket)
}

#[cfg(unix)]
pub fn recv_icmp_probe(
recv_socket: &mut Socket,
protocol: TracerProtocol,
Expand All @@ -204,6 +206,20 @@ pub fn recv_icmp_probe(
}
}

#[cfg(windows)]
pub fn recv_icmp_probe(
recv_socket: &mut Socket,
protocol: TracerProtocol,
multipath_strategy: MultipathStrategy,
direction: PortDirection,
) -> TraceResult<Option<ProbeResponse>> {
let bytes = &recv_socket.buf_bytes();
let ipv4 = Ipv4Packet::new_view(bytes).req()?;
// post the WSARecvFrom again, so that the next OVERLAPPED event can get triggered
recv_socket.recv_from()?;
extract_probe_resp(protocol, multipath_strategy, direction, &ipv4)
}

pub fn recv_tcp_socket(
tcp_socket: &Socket,
sequence: Sequence,
Expand All @@ -230,6 +246,12 @@ pub fn recv_tcp_socket(
sequence.0,
))));
}
if platform::is_host_unreachable_error(code) {
let error_addr = tcp_socket.icmp_error_info()?;
return Ok(Some(ProbeResponse::TcpTimeExceeded(
ProbeResponseData::new(SystemTime::now(), error_addr, 0, sequence.0),
)));
}
}
}
};
Expand Down
31 changes: 29 additions & 2 deletions src/tracing/net/ipv6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,12 @@ pub fn dispatch_tcp_probe(
PortDirection::FixedDest(dest_port) => (probe.sequence.0, dest_port.0),
PortDirection::FixedBoth(_, _) | PortDirection::None => unimplemented!(),
};
let socket = platform::make_stream_socket_ipv6()?;
let local_addr = SocketAddr::new(IpAddr::V6(src_addr), src_port);
let remote_addr = SocketAddr::new(IpAddr::V6(dest_addr), dest_port);
#[allow(unused_mut)]
let mut socket = platform::make_stream_socket_ipv6()?;
socket.bind(local_addr)?;
socket.set_unicast_hops_v6(probe.ttl.0)?;
let remote_addr = SocketAddr::new(IpAddr::V6(dest_addr), dest_port);
match socket.connect(remote_addr) {
Ok(_) => {}
Err(err) => {
Expand All @@ -134,6 +135,7 @@ pub fn dispatch_tcp_probe(
Ok(socket)
}

#[cfg(unix)]
pub fn recv_icmp_probe(
recv_socket: &mut Socket,
protocol: TracerProtocol,
Expand All @@ -160,6 +162,25 @@ pub fn recv_icmp_probe(
}
}

#[cfg(windows)]
#[allow(unsafe_code)]
pub fn recv_icmp_probe(
recv_socket: &mut Socket,
protocol: TracerProtocol,
direction: PortDirection,
) -> TraceResult<Option<ProbeResponse>> {
let bytes = &recv_socket.buf_bytes();
let icmp_v6 = IcmpPacket::new_view(bytes).req()?;
let addr = recv_socket.from()?;
// post the WSARecvFrom again, so that the next OVERLAPPED event can get triggered
recv_socket.recv_from()?;
if let IpAddr::V6(src_addr) = addr {
extract_probe_resp(protocol, direction, &icmp_v6, src_addr)
} else {
Err(TracerError::InvalidSourceAddr(addr))
}
}

pub fn recv_tcp_socket(
tcp_socket: &Socket,
sequence: Sequence,
Expand All @@ -186,6 +207,12 @@ pub fn recv_tcp_socket(
sequence.0,
))));
}
if platform::is_host_unreachable_error(code) {
let error_addr = tcp_socket.icmp_error_info()?;
return Ok(Some(ProbeResponse::TcpTimeExceeded(
ProbeResponseData::new(SystemTime::now(), error_addr, 0, sequence.0),
)));
}
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/tracing/net/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ pub use unix::*;
mod windows;

#[cfg(windows)]
pub use windows::*;
pub use self::windows::*;
14 changes: 8 additions & 6 deletions src/tracing/net/platform/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ fn test_send_local_ip4_packet(src_addr: Ipv4Addr, total_length: u16) -> TraceRes
Ok(probe_socket.send_to(ipv4.packet(), remote_addr)?)
}

#[allow(clippy::unnecessary_wraps)]
pub fn startup() -> TraceResult<()> {
Ok(())
}

pub fn lookup_interface_addr_ipv4(name: &str) -> TraceResult<IpAddr> {
nix::ifaddrs::getifaddrs()
.map_err(|_| TracerError::UnknownInterface(name.to_string()))?
Expand Down Expand Up @@ -101,11 +106,6 @@ pub fn lookup_interface_addr_ipv6(name: &str) -> TraceResult<IpAddr> {
.ok_or_else(|| TracerError::UnknownInterface(name.to_string()))
}

#[allow(clippy::unnecessary_wraps)]
pub fn startup() -> TraceResult<()> {
Ok(())
}

pub fn make_icmp_send_socket_ipv4() -> TraceResult<Socket> {
let socket = Socket::new(
Domain::IPV4,
Expand Down Expand Up @@ -207,15 +207,16 @@ pub fn is_writable(sock: &Socket) -> TraceResult<bool> {
Ok(writable == 1)
}

#[must_use]
pub fn is_not_in_progress_error(code: i32) -> bool {
nix::Error::from_i32(code) != nix::Error::EINPROGRESS
}

#[must_use]
pub fn is_conn_refused_error(code: i32) -> bool {
nix::Error::from_i32(code) == nix::Error::ECONNREFUSED
}

#[allow(dead_code)]
#[must_use]
pub fn is_host_unreachable_error(_code: i32) -> bool {
false
Expand Down Expand Up @@ -286,6 +287,7 @@ impl Socket {
Ok(self.inner.local_addr()?.as_socket())
}

#[must_use]
pub fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()
}
Expand Down
Loading

0 comments on commit 54acb6f

Please sign in to comment.