diff --git a/Cargo.toml b/Cargo.toml index 80b6350..3a4aa78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "icmp-socket" description = "ICMP sockets for both IPv4 and IPv6" -version = "0.1.1" +version = "0.1.2" repository = "https://github.com/zaphar/icmp-socket" authors = ["Jeremy Wall "] edition = "2018" @@ -10,5 +10,8 @@ license = "Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -socket2 = "0.3.19" -byteorder = "1.3.4" \ No newline at end of file +byteorder = "1.3.4" + +[dependencies.socket2] +version = "0.4.4" +features=[ "all" ] diff --git a/examples/ping4.rs b/examples/ping4.rs index 8330d07..b6cd7e9 100644 --- a/examples/ping4.rs +++ b/examples/ping4.rs @@ -83,7 +83,8 @@ pub fn main() { break; } }; - if packet_handler(resp, send_time, *sock_addr.as_inet().unwrap().ip()).is_some() { + if packet_handler(resp, send_time, *sock_addr.as_socket_ipv4().unwrap().ip()).is_some() + { std::thread::sleep(Duration::from_secs(1)); break; } diff --git a/examples/ping6.rs b/examples/ping6.rs index e0dcd3e..61bac60 100644 --- a/examples/ping6.rs +++ b/examples/ping6.rs @@ -81,7 +81,8 @@ pub fn main() { break; } }; - if packet_handler(resp, send_time, *sock_addr.as_inet6().unwrap().ip()).is_some() { + if packet_handler(resp, send_time, *sock_addr.as_socket_ipv6().unwrap().ip()).is_some() + { std::thread::sleep(Duration::from_millis(1000)); break; } diff --git a/src/socket.rs b/src/socket.rs index 1aa6608..318fe52 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -18,6 +18,7 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use std::{ convert::{Into, TryFrom, TryInto}, + mem::MaybeUninit, time::Duration, }; @@ -71,7 +72,7 @@ impl IcmpSocket4 { /// Construct a new socket. The socket must be bound to an address using `bind_to` /// before it can be used to send and receive packets. pub fn new() -> std::io::Result { - let socket = Socket::new(Domain::ipv4(), Type::raw(), Some(Protocol::icmpv4()))?; + let socket = Socket::new(Domain::IPV4, Type::RAW, Some(Protocol::ICMPV4))?; socket.set_recv_buffer_size(512)?; Ok(Self { bound_to: None, @@ -108,7 +109,12 @@ impl IcmpSocket for IcmpSocket4 { fn rcv_from(&mut self) -> std::io::Result<(Self::PacketType, SockAddr)> { self.inner.set_read_timeout(None)?; - let (read_count, addr) = self.inner.recv_from(&mut self.buf)?; + // NOTE(jwall): the `recv_from` implementation promises not to write uninitialised + // bytes to the `buf`fer, so this casting is safe. + // TODO(jwall): change to `Vec::spare_capacity_mut` when it stabilizes. + let mut buf = + unsafe { &mut *(self.buf.as_mut_slice() as *mut [u8] as *mut [MaybeUninit]) }; + let (read_count, addr) = self.inner.recv_from(&mut buf)?; Ok((self.buf[0..read_count].try_into()?, addr)) } @@ -129,7 +135,7 @@ impl IcmpSocket6 { /// Construct a new socket. The socket must be bound to an address using `bind_to` /// before it can be used to send and receive packets. pub fn new() -> std::io::Result { - let socket = Socket::new(Domain::ipv6(), Type::raw(), Some(Protocol::icmpv6()))?; + let socket = Socket::new(Domain::IPV6, Type::RAW, Some(Protocol::ICMPV6))?; socket.set_recv_buffer_size(512)?; Ok(Self { bound_to: None, @@ -180,7 +186,12 @@ impl IcmpSocket for IcmpSocket6 { fn rcv_from(&mut self) -> std::io::Result<(Self::PacketType, SockAddr)> { self.inner.set_read_timeout(None)?; - let (read_count, addr) = self.inner.recv_from(&mut self.buf)?; + // NOTE(jwall): the `recv_from` implementation promises not to write uninitialised + // bytes to the `buf`fer, so this casting is safe. + // TODO(jwall): change to `Vec::spare_capacity_mut` when it stabilizes. + let mut buf = + unsafe { &mut *(self.buf.as_mut_slice() as *mut [u8] as *mut [MaybeUninit]) }; + let (read_count, addr) = self.inner.recv_from(&mut buf)?; Ok((self.buf[0..read_count].try_into()?, addr)) }