From 89f866f4c0aa78a70784155e3f4d73409602ca74 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Wed, 13 Jan 2021 20:27:51 -0500 Subject: [PATCH] Plug new packet parser into socket and echo apis --- src/echo.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++++---- src/packet.rs | 15 +++++++++++ src/socket.rs | 1 - 3 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/echo.rs b/src/echo.rs index b65d2e3..8e6220a 100644 --- a/src/echo.rs +++ b/src/echo.rs @@ -11,21 +11,43 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use std::convert::From; +use std::convert::{TryFrom, From, TryInto}; use std::net::{Ipv4Addr, Ipv6Addr}; use packet::{Builder, Packet as P}; use packet::icmp::echo::Packet; +use crate::packet::{Icmpv6Packet, Icmpv6Message::{EchoReply, EchoRequest}}; + // TODO(jwall): It turns out that the ICMPv6 packets are sufficiently // different from the ICMPv4 packets. In order to handle them appropriately // It is going to take some consideration. use crate::{IcmpSocket4, IcmpSocket6}; pub struct EchoResponse { - identifier: u16, - sequence: u16, - payload: Vec, + pub identifier: u16, + pub sequence: u16, + pub payload: Vec, +} + +impl TryFrom for EchoResponse { + type Error = std::io::Error; + + fn try_from(pkt: Icmpv6Packet) -> Result { + if let EchoReply{ + identifier, + sequence, + payload, + } = pkt.message { + Ok(EchoResponse{ + identifier, + sequence, + payload, + }) + } else { + Err(std::io::Error::new(std::io::ErrorKind::Other, "Incorrect icmpv6 message")) + } + } } pub struct EchoSocket4 { @@ -71,4 +93,42 @@ impl From for EchoSocket4 { fn from(sock: IcmpSocket4) -> Self { EchoSocket4::new(sock) } -} \ No newline at end of file +} + +pub struct EchoSocket6 { + sequence: u16, + buf: Vec, + inner: IcmpSocket6, +} + +impl EchoSocket6 { + + pub fn new(sock: IcmpSocket6) -> Self { + EchoSocket6{inner:sock, sequence: 0, buf: Vec::with_capacity(512)} + } + + pub fn set_max_hops(&mut self, hops: u32) { + self.inner.set_max_hops(hops); + } + + pub fn send_ping(&mut self, dest: Ipv6Addr, identifier: u16, payload: &[u8]) -> std::io::Result<()> { + let packet = Icmpv6Packet::with_echo_request(identifier, self.sequence, payload.to_owned())?; + self.sequence += 1; + self.inner.send_to(dest, packet)?; + Ok(()) + } + + pub fn recv_ping(&mut self) -> std::io::Result { + let bytes_read = self.inner.rcv_from(&mut self.buf)?; + match Icmpv6Packet::parse(&self.buf[0..bytes_read]) { + Ok(p) => return Ok(p.try_into()?), + Err(e) => return Err(std::io::Error::new(std::io::ErrorKind::Other, format!("Malformed ICMP Response: {:?}", e))), + }; + } +} + +impl From for EchoSocket6 { + fn from(sock: IcmpSocket6) -> Self { + EchoSocket6::new(sock) + } +} diff --git a/src/packet.rs b/src/packet.rs index 08cbfb2..929d2bc 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -326,4 +326,19 @@ impl Icmpv6Packet { pub enum Icmpv6PacketBuildError { InvalidCode(u8), +} +use Icmpv6PacketBuildError::InvalidCode; + +impl std::fmt::Display for Icmpv6PacketBuildError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + InvalidCode(c) => format!("Invalid Code: {}", c), + }) + } +} + +impl From for std::io::Error { + fn from(err: Icmpv6PacketBuildError) -> Self { + std::io::Error::new(std::io::ErrorKind::Other, format!("{}", err)) + } } \ No newline at end of file diff --git a/src/socket.rs b/src/socket.rs index 70bea9b..1885f07 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -95,7 +95,6 @@ impl IcmpSocket6 { Ok(()) } - // TODO(jwall): This should take an actual packet not the payload. pub fn send_to(&mut self, dest: Ipv6Addr, mut packet: Icmpv6Packet) -> std::io::Result<()> { let source = match self.bound_to { Some(ref addr) => addr,