diff --git a/.gitignore b/.gitignore index 6aa1064..ff669ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.vscode/ +.VSCodeCounter/ /target/ **/*.rs.bk Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index dc2272f..a004e23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "packet" +name = "packet" version = "0.1.2" edition = "2018" @@ -7,11 +7,11 @@ authors = ["meh. "] license = "WTFPL" description = "Network packet handling." -repository = "https://github.com/meh/rust-packet" -keywords = ["packet", "network", "ip", "tcp", "udp"] +repository = "https://github.com/meh/rust-packet" +keywords = ["packet", "network", "ip", "tcp", "udp"] [dependencies] thiserror = "1" -bitflags = "1" +bitflags = "2.4" byteorder = "1" -hwaddr = "0.1" +hwaddr = "0.1" diff --git a/src/buffer/dynamic.rs b/src/buffer/dynamic.rs index 177283e..3e20830 100644 --- a/src/buffer/dynamic.rs +++ b/src/buffer/dynamic.rs @@ -19,103 +19,103 @@ use crate::error::*; /// A growable buffer. #[derive(Clone, Eq, PartialEq, Default, Debug)] pub struct Buffer { - inner: Vec, + inner: Vec, - offset: usize, - length: usize, + offset: usize, + length: usize, } impl Buffer { - /// Create a new growable buffer. - pub fn new() -> Self { - Default::default() - } + /// Create a new growable buffer. + pub fn new() -> Self { + Default::default() + } } impl super::Buffer for Buffer { - type Inner = Vec; + type Inner = Vec; - fn into_inner(self) -> Self::Inner { - self.inner - } + fn into_inner(self) -> Self::Inner { + self.inner + } - fn next(&mut self, size: usize) -> Result<()> { - self.offset += self.length; - self.length = size; + fn next(&mut self, size: usize) -> Result<()> { + self.offset += self.length; + self.length = size; - let current = self.inner.len(); - self.inner.resize(current + size, 0); + let current = self.inner.len(); + self.inner.resize(current + size, 0); - Ok(()) - } + Ok(()) + } - fn more(&mut self, size: usize) -> Result<()> { - let current = self.inner.len(); - self.inner.resize(current + size, 0); - self.length += size; + fn more(&mut self, size: usize) -> Result<()> { + let current = self.inner.len(); + self.inner.resize(current + size, 0); + self.length += size; - Ok(()) - } + Ok(()) + } - fn clear(&mut self) { - self.inner.clear(); - self.offset = 0; - self.length = 0; - } + fn clear(&mut self) { + self.inner.clear(); + self.offset = 0; + self.length = 0; + } - fn used(&self) -> usize { - self.inner.len() - } + fn used(&self) -> usize { + self.inner.len() + } - fn offset(&self) -> usize { - self.offset - } + fn offset(&self) -> usize { + self.offset + } - fn length(&self) -> usize { - self.length - } + fn length(&self) -> usize { + self.length + } - fn data(&self) -> &[u8] { - &self.inner[self.offset .. self.offset + self.length] - } + fn data(&self) -> &[u8] { + &self.inner[self.offset..self.offset + self.length] + } - fn data_mut(&mut self) -> &mut [u8] { - &mut self.inner[self.offset .. self.offset + self.length] - } + fn data_mut(&mut self) -> &mut [u8] { + &mut self.inner[self.offset..self.offset + self.length] + } } -impl Into> for Buffer { - fn into(self) -> Vec { - self.inner - } +impl From for Vec { + fn from(buffer: Buffer) -> Self { + buffer.inner + } } impl AsRef<[u8]> for Buffer { - fn as_ref(&self) -> &[u8] { - use super::Buffer; - self.data() - } + fn as_ref(&self) -> &[u8] { + use super::Buffer; + self.data() + } } impl AsMut<[u8]> for Buffer { - fn as_mut(&mut self) -> &mut [u8] { - use super::Buffer; - self.data_mut() - } + fn as_mut(&mut self) -> &mut [u8] { + use super::Buffer; + self.data_mut() + } } impl Deref for Buffer { - type Target = [u8]; + type Target = [u8]; - fn deref(&self) -> &Self::Target { - use super::Buffer; - self.data() - } + fn deref(&self) -> &Self::Target { + use super::Buffer; + self.data() + } } impl DerefMut for Buffer { - fn deref_mut(&mut self) -> &mut Self::Target { - use super::Buffer; - self.data_mut() - } + fn deref_mut(&mut self) -> &mut Self::Target { + use super::Buffer; + self.data_mut() + } } diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 692762a..2bb4398 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -40,35 +40,35 @@ use crate::error::*; /// assert_eq!(data.len(), 24); /// ``` pub trait Buffer { - /// Inner type used by the buffer. - type Inner: AsMut<[u8]>; + /// Inner type used by the buffer. + type Inner: AsMut<[u8]>; - /// Convert the buffer into the inner type. - fn into_inner(self) -> Self::Inner; + /// Convert the buffer into the inner type. + fn into_inner(self) -> Self::Inner; - /// Go to the next layer requesting the given size, zeroeing the layer. - fn next(&mut self, size: usize) -> Result<()>; + /// Go to the next layer requesting the given size, zeroeing the layer. + fn next(&mut self, size: usize) -> Result<()>; - /// Request more memory for the same layer, zeroeing the new buffer area. - fn more(&mut self, size: usize) -> Result<()>; + /// Request more memory for the same layer, zeroeing the new buffer area. + fn more(&mut self, size: usize) -> Result<()>; - /// Clear the buffer. - fn clear(&mut self); + /// Clear the buffer. + fn clear(&mut self); - /// Number of bytes used by the whole buffer. - fn used(&self) -> usize; + /// Number of bytes used by the whole buffer. + fn used(&self) -> usize; - /// Offset from the beginning of the whole buffer. - fn offset(&self) -> usize; + /// Offset from the beginning of the whole buffer. + fn offset(&self) -> usize; - /// Length of the current layer. - fn length(&self) -> usize; + /// Length of the current layer. + fn length(&self) -> usize; - /// Get a slice over the current layer. - fn data(&self) -> &[u8]; + /// Get a slice over the current layer. + fn data(&self) -> &[u8]; - /// Get a mutable slice over the current layer. - fn data_mut(&mut self) -> &mut [u8]; + /// Get a mutable slice over the current layer. + fn data_mut(&mut self) -> &mut [u8]; } mod dynamic; diff --git a/src/buffer/slice.rs b/src/buffer/slice.rs index 14e5e8b..207219b 100644 --- a/src/buffer/slice.rs +++ b/src/buffer/slice.rs @@ -19,119 +19,119 @@ use crate::error::*; /// A static buffer. #[derive(Eq, PartialEq, Debug)] pub struct Buffer<'a> { - inner: &'a mut [u8], + inner: &'a mut [u8], - offset: usize, - length: usize, - used: usize, + offset: usize, + length: usize, + used: usize, } impl<'a> Buffer<'a> { - /// Create a new static buffer wrapping the given slice. - pub fn new(slice: &mut [u8]) -> Buffer<'_> { - Buffer { - inner: slice, - - offset: 0, - length: 0, - used: 0, - } - } + /// Create a new static buffer wrapping the given slice. + pub fn new(slice: &mut [u8]) -> Buffer<'_> { + Buffer { + inner: slice, + + offset: 0, + length: 0, + used: 0, + } + } } impl<'a> super::Buffer for Buffer<'a> { - type Inner = &'a mut [u8]; - - fn into_inner(self) -> Self::Inner { - &mut self.inner[0 .. self.used] - } - - fn next(&mut self, size: usize) -> Result<()> { - if self.inner.len() < self.used + size { - Err(Error::SmallBuffer)? - } - - self.offset = self.used; - self.length = size; - self.used += size; - - for byte in self.data_mut() { - *byte = 0; - } - - Ok(()) - } - - fn more(&mut self, size: usize) -> Result<()> { - if self.inner.len() < self.used + size { - Err(Error::SmallBuffer)? - } - - self.offset = self.used; - self.length += size; - self.used += size; - - let length = self.length; - for byte in &mut self.data_mut()[length - size ..] { - *byte = 0; - } - - Ok(()) - } - - fn clear(&mut self) { - self.offset = 0; - self.length = 0; - self.used = 0; - } - - fn used(&self) -> usize { - self.used - } - - fn offset(&self) -> usize { - self.offset - } - - fn length(&self) -> usize { - self.length - } - - fn data(&self) -> &[u8] { - &self.inner[self.offset .. self.offset + self.length] - } - - fn data_mut(&mut self) -> &mut [u8] { - &mut self.inner[self.offset .. self.offset + self.length] - } + type Inner = &'a mut [u8]; + + fn into_inner(self) -> Self::Inner { + &mut self.inner[0..self.used] + } + + fn next(&mut self, size: usize) -> Result<()> { + if self.inner.len() < self.used + size { + Err(Error::SmallBuffer)? + } + + self.offset = self.used; + self.length = size; + self.used += size; + + for byte in self.data_mut() { + *byte = 0; + } + + Ok(()) + } + + fn more(&mut self, size: usize) -> Result<()> { + if self.inner.len() < self.used + size { + Err(Error::SmallBuffer)? + } + + self.offset = self.used; + self.length += size; + self.used += size; + + let length = self.length; + for byte in &mut self.data_mut()[length - size..] { + *byte = 0; + } + + Ok(()) + } + + fn clear(&mut self) { + self.offset = 0; + self.length = 0; + self.used = 0; + } + + fn used(&self) -> usize { + self.used + } + + fn offset(&self) -> usize { + self.offset + } + + fn length(&self) -> usize { + self.length + } + + fn data(&self) -> &[u8] { + &self.inner[self.offset..self.offset + self.length] + } + + fn data_mut(&mut self) -> &mut [u8] { + &mut self.inner[self.offset..self.offset + self.length] + } } impl<'a> AsRef<[u8]> for Buffer<'a> { - fn as_ref(&self) -> &[u8] { - use super::Buffer; - self.data() - } + fn as_ref(&self) -> &[u8] { + use super::Buffer; + self.data() + } } impl<'a> AsMut<[u8]> for Buffer<'a> { - fn as_mut(&mut self) -> &mut [u8] { - use super::Buffer; - self.data_mut() - } + fn as_mut(&mut self) -> &mut [u8] { + use super::Buffer; + self.data_mut() + } } impl<'a> Deref for Buffer<'a> { - type Target = [u8]; + type Target = [u8]; - fn deref(&self) -> &Self::Target { - use super::Buffer; - self.data() - } + fn deref(&self) -> &Self::Target { + use super::Buffer; + self.data() + } } impl<'a> DerefMut for Buffer<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - use super::Buffer; - self.data_mut() - } + fn deref_mut(&mut self) -> &mut Self::Target { + use super::Buffer; + self.data_mut() + } } diff --git a/src/builder.rs b/src/builder.rs index 17c4373..1fb3a4f 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -14,85 +14,82 @@ use std::fmt; -use crate::error::*; use crate::buffer::Buffer; +use crate::error::*; /// A finalizer used by builders to complete building the packet, this is /// usually used to calculate the checksum and update length fields after the /// whole packet has been created. pub trait Finalizer { - /// Run the finalizer on the given buffer. - fn finalize(self: Box, buffer: &mut [u8]) -> Result<()>; + /// Run the finalizer on the given buffer. + fn finalize(self: Box, buffer: &mut [u8]) -> Result<()>; } impl Result<()>> Finalizer for F { - fn finalize(self: Box, buffer: &mut [u8]) -> Result<()> { - let f = *self; - f(buffer) - } + fn finalize(self: Box, buffer: &mut [u8]) -> Result<()> { + let f = *self; + f(buffer) + } } /// Takes care of grouping finalizers through the builder chain. +#[derive(Default)] pub struct Finalization(Vec>); -impl Default for Finalization { - fn default() -> Self { - Finalization(Vec::new()) - } -} - impl fmt::Debug for Finalization { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("builder::Finalization") - .field("length", &self.0.len()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("builder::Finalization") + .field("length", &self.0.len()) + .finish() + } } impl Finalization { - /// Add a new finalizer. - pub fn add Result<()> + 'static>(&mut self, finalizer: F) { - self.0.push(Box::new(finalizer)); - } - - /// Add a serie of finalizers. - pub fn extend>>(&mut self, finalizers: I) { - self.0.extend(finalizers.into_iter()); - } - - /// Finalize a buffer. - pub fn finalize(self, buffer: &mut [u8]) -> Result<()> { - for finalizer in self.0.into_iter().rev() { - finalizer.finalize(buffer)?; - } - - Ok(()) - } + /// Add a new finalizer. + pub fn add Result<()> + 'static>(&mut self, finalizer: F) { + self.0.push(Box::new(finalizer)); + } + + /// Add a serie of finalizers. + pub fn extend>>(&mut self, finalizers: I) { + self.0.extend(finalizers); + } + + /// Finalize a buffer. + pub fn finalize(self, buffer: &mut [u8]) -> Result<()> { + for finalizer in self.0.into_iter().rev() { + finalizer.finalize(buffer)?; + } + + Ok(()) + } } impl IntoIterator for Finalization { - type Item = Box; - type IntoIter = ::std::vec::IntoIter>; + type Item = Box; + type IntoIter = ::std::vec::IntoIter>; - fn into_iter(self) -> ::std::vec::IntoIter> { - self.0.into_iter() - } + fn into_iter(self) -> ::std::vec::IntoIter> { + self.0.into_iter() + } } -impl Into>> for Finalization { - fn into(self) -> Vec> { - self.0 - } +impl From for Vec> { + fn from(finalization: Finalization) -> Self { + finalization.0 + } } /// A packet `Builder`. pub trait Builder { - /// Create a new packet `Builder` with the given buffer. - fn with(buffer: B) -> Result where Self: Sized; + /// Create a new packet `Builder` with the given buffer. + fn with(buffer: B) -> Result + where + Self: Sized; - /// Access the finalizers. - fn finalizer(&mut self) -> &mut Finalization; + /// Access the finalizers. + fn finalizer(&mut self) -> &mut Finalization; - /// Build the packet. - fn build(self) -> Result; + /// Build the packet. + fn build(self) -> Result; } diff --git a/src/error.rs b/src/error.rs index 3c5cb5e..9242d5e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,28 +12,28 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. -use std::{io, ffi}; +use std::{ffi, io}; use thiserror::Error; #[derive(Error, Debug)] pub enum Error { - #[error("the buffer is too small")] - SmallBuffer, + #[error("the buffer is too small")] + SmallBuffer, - #[error("the packet is invalid")] - InvalidPacket, + #[error("the packet is invalid")] + InvalidPacket, - #[error("the vaue is invalid for the field")] - InvalidValue, + #[error("the vaue is invalid for the field")] + InvalidValue, - #[error("the value has already been defined")] - AlreadyDefined, + #[error("the value has already been defined")] + AlreadyDefined, - #[error(transparent)] - Io(#[from] io::Error), + #[error(transparent)] + Io(#[from] io::Error), - #[error(transparent)] - Nul(#[from] ffi::NulError), + #[error(transparent)] + Nul(#[from] ffi::NulError), } -pub type Result = ::std::result::Result; +pub type Result = ::std::result::Result; diff --git a/src/ether/builder.rs b/src/ether/builder.rs index ab9b2f2..0fddc9c 100644 --- a/src/ether/builder.rs +++ b/src/ether/builder.rs @@ -12,181 +12,194 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. -use std::io::Cursor; -use byteorder::{WriteBytesExt, BigEndian}; +use byteorder::{BigEndian, WriteBytesExt}; use hwaddr::HwAddr; +use std::io::Cursor; -use crate::error::*; use crate::buffer::{self, Buffer}; use crate::builder::{Builder as Build, Finalization}; -use crate::packet::{AsPacket, AsPacketMut}; +use crate::error::*; use crate::ether::Packet; use crate::ether::Protocol; +use crate::packet::{AsPacket, AsPacketMut}; /// Ethernet frame builder. #[derive(Debug)] pub struct Builder { - buffer: B, - finalizer: Finalization, + buffer: B, + finalizer: Finalization, - payload: bool, + payload: bool, } impl Build for Builder { - fn with(mut buffer: B) -> Result { - use crate::size::header::Min; - buffer.next(Packet::<()>::min())?; - - Ok(Builder { - buffer: buffer, - finalizer: Default::default(), - - payload: false, - }) - } - - fn finalizer(&mut self) -> &mut Finalization { - &mut self.finalizer - } - - fn build(self) -> Result { - let mut buffer = self.buffer.into_inner(); - self.finalizer.finalize(buffer.as_mut())?; - Ok(buffer) - } + fn with(mut buffer: B) -> Result { + use crate::size::header::Min; + buffer.next(Packet::<()>::min())?; + + Ok(Builder { + buffer, + finalizer: Default::default(), + + payload: false, + }) + } + + fn finalizer(&mut self) -> &mut Finalization { + &mut self.finalizer + } + + fn build(self) -> Result { + let mut buffer = self.buffer.into_inner(); + self.finalizer.finalize(buffer.as_mut())?; + Ok(buffer) + } } impl Default for Builder { - fn default() -> Self { - Builder::with(buffer::Dynamic::default()).unwrap() - } + fn default() -> Self { + Builder::with(buffer::Dynamic::default()).unwrap() + } } impl<'a, B: Buffer> AsPacket<'a, Packet<&'a [u8]>> for Builder { - fn as_packet(&self) -> Result> { - Packet::new(self.buffer.data()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.buffer.data()) + } } impl<'a, B: Buffer> AsPacketMut<'a, Packet<&'a mut [u8]>> for Builder { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.buffer.data_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.buffer.data_mut()) + } } impl Builder { - /// MAC address for the destination. - pub fn destination(mut self, value: HwAddr) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_destination(value)?; + /// MAC address for the destination. + pub fn destination(mut self, value: HwAddr) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_destination(value)?; - Ok(self) - } + Ok(self) + } - /// MAC address for the source. - pub fn source(mut self, value: HwAddr) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_source(value)?; + /// MAC address for the source. + pub fn source(mut self, value: HwAddr) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_source(value)?; - Ok(self) - } + Ok(self) + } - /// Protocol of the inner packet. - pub fn protocol(mut self, value: Protocol) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_protocol(value)?; + /// Protocol of the inner packet. + pub fn protocol(mut self, value: Protocol) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_protocol(value)?; - Ok(self) - } + Ok(self) + } - /// Payload for the frame. - pub fn payload<'a, T: IntoIterator>(mut self, value: T) -> Result { - if self.payload { - Err(Error::AlreadyDefined)? - } + /// Payload for the frame. + pub fn payload<'a, T: IntoIterator>(mut self, value: T) -> Result { + if self.payload { + Err(Error::AlreadyDefined)? + } - self.payload = true; + self.payload = true; - for byte in value { - self.buffer.more(1)?; - *self.buffer.data_mut().last_mut().unwrap() = *byte; - } + for byte in value { + self.buffer.more(1)?; + *self.buffer.data_mut().last_mut().unwrap() = *byte; + } - Ok(self) - } + Ok(self) + } - /// Build an IP packet inside the Ethernet frame. - pub fn ip(mut self) -> Result> { - if self.payload { - Err(Error::AlreadyDefined)? - } + /// Build an IP packet inside the Ethernet frame. + pub fn ip(mut self) -> Result> { + if self.payload { + Err(Error::AlreadyDefined)? + } - let offset = self.buffer.offset(); - let length = self.buffer.length(); + let offset = self.buffer.offset(); + let length = self.buffer.length(); - self.finalizer.add(move |out| { - match out[offset + length] >> 4 { - 4 => - Cursor::new(&mut out[offset + 12 ..]) - .write_u16::(Protocol::Ipv4.into())?, + self.finalizer.add(move |out| { + match out[offset + length] >> 4 { + 4 => Cursor::new(&mut out[offset + 12..]) + .write_u16::(Protocol::Ipv4.into())?, - 6 => - Cursor::new(&mut out[offset + 12 ..]) - .write_u16::(Protocol::Ipv6.into())?, + 6 => Cursor::new(&mut out[offset + 12..]) + .write_u16::(Protocol::Ipv6.into())?, - _ => - unreachable!() - } + _ => unreachable!(), + } - Ok(()) - }); + Ok(()) + }); - let mut ip = crate::ip::Builder::with(self.buffer)?; - ip.finalizer().extend(self.finalizer); + let mut ip = crate::ip::Builder::with(self.buffer)?; + ip.finalizer().extend(self.finalizer); - Ok(ip) - } + Ok(ip) + } } #[cfg(test)] mod test { - use std::net::Ipv4Addr; - use crate::builder::Builder; - use crate::packet::Packet; - use crate::ether; - use crate::ip; - use crate::udp; - - #[test] - fn simple() { - let packet = ether::Builder::default() - .destination("00:23:69:63:59:be".parse().unwrap()).unwrap() - .source("e4:b3:18:26:63:a3".parse().unwrap()).unwrap() - .ip().unwrap().v4().unwrap() - .id(0x2d87).unwrap() - .ttl(64).unwrap() - .source("66.102.1.108".parse().unwrap()).unwrap() - .destination("192.168.0.79".parse().unwrap()).unwrap() - .udp().unwrap() - .source(1337).unwrap() - .destination(9001).unwrap() - .build().unwrap(); - - let ether = ether::Packet::new(packet).unwrap(); - assert_eq!(ether.destination(), "00:23:69:63:59:be".parse().unwrap()); - assert_eq!(ether.source(), "e4:b3:18:26:63:a3".parse().unwrap()); - assert_eq!(ether.protocol(), ether::Protocol::Ipv4); - - let ip = ip::v4::Packet::new(ether.payload()).unwrap(); - assert_eq!(ip.id(), 0x2d87); - assert!(ip.flags().is_empty()); - assert_eq!(ip.length(), 28); - assert_eq!(ip.ttl(), 64); - assert_eq!(ip.protocol(), ip::Protocol::Udp); - assert_eq!(ip.source(), "66.102.1.108".parse::().unwrap()); - assert_eq!(ip.destination(), "192.168.0.79".parse::().unwrap()); - assert!(ip.is_valid()); - - let udp = udp::Packet::new(ip.payload()).unwrap(); - assert_eq!(udp.source(), 1337); - assert_eq!(udp.destination(), 9001); - assert!(udp.is_valid(&ip::Packet::from(&ip))); - } + use crate::builder::Builder; + use crate::ether; + use crate::ip; + use crate::packet::Packet; + use crate::udp; + use std::net::Ipv4Addr; + + #[test] + fn simple() { + let packet = ether::Builder::default() + .destination("00:23:69:63:59:be".parse().unwrap()) + .unwrap() + .source("e4:b3:18:26:63:a3".parse().unwrap()) + .unwrap() + .ip() + .unwrap() + .v4() + .unwrap() + .id(0x2d87) + .unwrap() + .ttl(64) + .unwrap() + .source("66.102.1.108".parse().unwrap()) + .unwrap() + .destination("192.168.0.79".parse().unwrap()) + .unwrap() + .udp() + .unwrap() + .source(1337) + .unwrap() + .destination(9001) + .unwrap() + .build() + .unwrap(); + + let ether = ether::Packet::new(packet).unwrap(); + assert_eq!(ether.destination(), "00:23:69:63:59:be".parse().unwrap()); + assert_eq!(ether.source(), "e4:b3:18:26:63:a3".parse().unwrap()); + assert_eq!(ether.protocol(), ether::Protocol::Ipv4); + + let ip = ip::v4::Packet::new(ether.payload()).unwrap(); + assert_eq!(ip.id(), 0x2d87); + assert!(ip.flags().is_empty()); + assert_eq!(ip.length(), 28); + assert_eq!(ip.ttl(), 64); + assert_eq!(ip.protocol(), ip::Protocol::Udp); + assert_eq!(ip.source(), "66.102.1.108".parse::().unwrap()); + assert_eq!( + ip.destination(), + "192.168.0.79".parse::().unwrap() + ); + assert!(ip.is_valid()); + + let udp = udp::Packet::new(ip.payload()).unwrap(); + assert_eq!(udp.source(), 1337); + assert_eq!(udp.destination(), 9001); + assert!(udp.is_valid(&ip::Packet::from(&ip))); + } } diff --git a/src/ether/packet.rs b/src/ether/packet.rs index c0c5671..5c27b4c 100644 --- a/src/ether/packet.rs +++ b/src/ether/packet.rs @@ -12,178 +12,187 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use hwaddr::HwAddr; use std::fmt; use std::io::Cursor; -use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; -use hwaddr::HwAddr; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; use crate::ether::Protocol; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; /// Ethernet frame parser. pub struct Packet { - pub(crate) buffer: B, + pub(crate) buffer: B, } sized!(Packet, - header { - min: 14, - max: 14, - size: 14, - } - - payload { - min: 0, - max: 1486, - size: p => p.buffer.as_ref().len() - 14, - }); +header { + min: 14, + max: 14, + size: 14, +} + +payload { + min: 0, + max: 1486, + size: p => p.buffer.as_ref().len() - 14, +}); impl> fmt::Debug for Packet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ether::Packet") - .field("destination", &self.source()) - .field("source", &self.destination()) - .field("protocol", &self.protocol()) - .field("payload", &self.payload()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ether::Packet") + .field("destination", &self.source()) + .field("source", &self.destination()) + .field("protocol", &self.protocol()) + .field("payload", &self.payload()) + .finish() + } } impl> Packet { - /// Create an Ethernet frame without checking the buffer. - pub fn unchecked(buffer: B) -> Packet { - Packet { buffer } - } + /// Create an Ethernet frame without checking the buffer. + pub fn unchecked(buffer: B) -> Packet { + Packet { buffer } + } - /// Parse an Ethernet frame, checking the buffer contents are correct. - pub fn new(buffer: B) -> Result> { - use crate::size::header::Min; + /// Parse an Ethernet frame, checking the buffer contents are correct. + pub fn new(buffer: B) -> Result> { + use crate::size::header::Min; - let packet = Packet::unchecked(buffer); + let packet = Packet::unchecked(buffer); - if packet.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } - Ok(packet) - } + Ok(packet) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - Packet::unchecked(self.buffer.as_ref().to_vec()) - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + Packet::unchecked(self.buffer.as_ref().to_vec()) + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - self.buffer.as_ref().split_at(14) - } + fn split(&self) -> (&[u8], &[u8]) { + self.buffer.as_ref().split_at(14) + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - self.buffer.as_mut().split_at_mut(14) - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + self.buffer.as_mut().split_at_mut(14) + } } impl> Packet { - /// MAC address for the destination. - pub fn destination(&self) -> HwAddr { - self.buffer.as_ref()[0 .. 6].into() - } - - /// MAC address for the source. - pub fn source(&self) -> HwAddr { - self.buffer.as_ref()[6 .. 12].into() - } - - /// Protocol of the inner packet. - pub fn protocol(&self) -> Protocol { - (&self.buffer.as_ref()[12 ..]).read_u16::().unwrap().into() - } + /// MAC address for the destination. + pub fn destination(&self) -> HwAddr { + self.buffer.as_ref()[0..6].into() + } + + /// MAC address for the source. + pub fn source(&self) -> HwAddr { + self.buffer.as_ref()[6..12].into() + } + + /// Protocol of the inner packet. + pub fn protocol(&self) -> Protocol { + (&self.buffer.as_ref()[12..]) + .read_u16::() + .unwrap() + .into() + } } impl + AsMut<[u8]>> Packet { - /// Destination MAC address. - pub fn set_destination(&mut self, value: HwAddr) -> Result<&mut Self> { - self.buffer.as_mut()[0 .. 6].copy_from_slice(&value.octets()); + /// Destination MAC address. + pub fn set_destination(&mut self, value: HwAddr) -> Result<&mut Self> { + self.buffer.as_mut()[0..6].copy_from_slice(&value.octets()); - Ok(self) - } + Ok(self) + } - /// Source MAC address. - pub fn set_source(&mut self, value: HwAddr) -> Result<&mut Self> { - self.buffer.as_mut()[6 .. 12].copy_from_slice(&value.octets()); + /// Source MAC address. + pub fn set_source(&mut self, value: HwAddr) -> Result<&mut Self> { + self.buffer.as_mut()[6..12].copy_from_slice(&value.octets()); - Ok(self) - } + Ok(self) + } - /// Inner protocol. - pub fn set_protocol(&mut self, value: Protocol) -> Result<&mut Self> { - Cursor::new(&mut self.buffer.as_mut()[12 ..]) - .write_u16::(value.into())?; + /// Inner protocol. + pub fn set_protocol(&mut self, value: Protocol) -> Result<&mut Self> { + Cursor::new(&mut self.buffer.as_mut()[12..]).write_u16::(value.into())?; - Ok(self) - } + Ok(self) + } } #[cfg(test)] mod test { - use crate::packet::Packet; - use crate::ether; - use crate::ip; - use crate::udp; - - #[test] - fn values() { - let raw = [0x00u8, 0x23, 0x69, 0x63, 0x59, 0xbe, 0xe4, 0xb3, 0x18, 0x26, 0x63, 0xa3, 0x08, 0x00, 0x45, 0x00, 0x00, 0x42, 0x47, 0x07, 0x40, 0x00, 0x40, 0x11, 0x6e, 0xcc, 0xc0, 0xa8, 0x01, 0x89, 0xc0, 0xa8, 0x01, 0xfe, 0xba, 0x2f, 0x00, 0x35, 0x00, 0x2e, 0x1d, 0xf8, 0xbc, 0x81, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x70, 0x69, 0x0c, 0x73, 0x74, 0x65, 0x61, 0x6d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x65, 0x64, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01]; - - let ether = ether::Packet::new(&raw[..]).unwrap(); - let ip = ip::v4::Packet::new(ether.payload()).unwrap(); - let udp = udp::Packet::new(ip.payload()).unwrap(); - - assert!(ip.is_valid()); - assert!(udp.is_valid(&ip::Packet::from(&ip))); - - assert_eq!(ether.destination(), "00:23:69:63:59:be".parse().unwrap()); - assert_eq!(ether.source(), "e4:b3:18:26:63:a3".parse().unwrap()); - assert_eq!(ether.protocol(), ether::Protocol::Ipv4); - } + use crate::ether; + use crate::ip; + use crate::packet::Packet; + use crate::udp; + + #[test] + fn values() { + let raw = [ + 0x00u8, 0x23, 0x69, 0x63, 0x59, 0xbe, 0xe4, 0xb3, 0x18, 0x26, 0x63, 0xa3, 0x08, 0x00, + 0x45, 0x00, 0x00, 0x42, 0x47, 0x07, 0x40, 0x00, 0x40, 0x11, 0x6e, 0xcc, 0xc0, 0xa8, + 0x01, 0x89, 0xc0, 0xa8, 0x01, 0xfe, 0xba, 0x2f, 0x00, 0x35, 0x00, 0x2e, 0x1d, 0xf8, + 0xbc, 0x81, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, + 0x70, 0x69, 0x0c, 0x73, 0x74, 0x65, 0x61, 0x6d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x65, + 0x64, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, + ]; + + let ether = ether::Packet::new(&raw[..]).unwrap(); + let ip = ip::v4::Packet::new(ether.payload()).unwrap(); + let udp = udp::Packet::new(ip.payload()).unwrap(); + + assert!(ip.is_valid()); + assert!(udp.is_valid(&ip::Packet::from(&ip))); + + assert_eq!(ether.destination(), "00:23:69:63:59:be".parse().unwrap()); + assert_eq!(ether.source(), "e4:b3:18:26:63:a3".parse().unwrap()); + assert_eq!(ether.protocol(), ether::Protocol::Ipv4); + } } diff --git a/src/ether/protocol.rs b/src/ether/protocol.rs index 89394cc..335a552 100644 --- a/src/ether/protocol.rs +++ b/src/ether/protocol.rs @@ -15,141 +15,141 @@ /// Protocols supported by Ethernet frames. #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum Protocol { - /// - Ipv4, + /// + Ipv4, - /// - Arp, + /// + Arp, - /// - WakeOnLan, + /// + WakeOnLan, - /// - Trill, + /// + Trill, - /// - DecNet, + /// + DecNet, - /// - Rarp, + /// + Rarp, - /// - AppleTalk, + /// + AppleTalk, - /// - Aarp, + /// + Aarp, - /// - Ipx, + /// + Ipx, - /// - Qnx, + /// + Qnx, - /// - Ipv6, + /// + Ipv6, - /// - FlowControl, + /// + FlowControl, - /// - CobraNet, + /// + CobraNet, - /// - Mpls, + /// + Mpls, - /// - MplsMulticast, + /// + MplsMulticast, - /// - PppoeDiscovery, + /// + PppoeDiscovery, - /// - PppoeSession, + /// + PppoeSession, - /// - Vlan, + /// + Vlan, - /// - PBridge, + /// + PBridge, - /// - Lldp, + /// + Lldp, - /// - Ptp, + /// + Ptp, - /// - Cfm, + /// + Cfm, - /// - QinQ, + /// + QinQ, - /// - Unknown(u16), + /// + Unknown(u16), } impl From for Protocol { - fn from(value: u16) -> Protocol { - use self::Protocol::*; - - match value { - 0x0800 => Ipv4, - 0x0806 => Arp, - 0x0842 => WakeOnLan, - 0x22f3 => Trill, - 0x6003 => DecNet, - 0x8035 => Rarp, - 0x809b => AppleTalk, - 0x80f3 => Aarp, - 0x8137 => Ipx, - 0x8204 => Qnx, - 0x86dd => Ipv6, - 0x8808 => FlowControl, - 0x8819 => CobraNet, - 0x8847 => Mpls, - 0x8848 => MplsMulticast, - 0x8863 => PppoeDiscovery, - 0x8864 => PppoeSession, - 0x8100 => Vlan, - 0x88a8 => PBridge, - 0x88cc => Lldp, - 0x88f7 => Ptp, - 0x8902 => Cfm, - 0x9100 => QinQ, - n => Unknown(n), - } - } + fn from(value: u16) -> Protocol { + use self::Protocol::*; + + match value { + 0x0800 => Ipv4, + 0x0806 => Arp, + 0x0842 => WakeOnLan, + 0x22f3 => Trill, + 0x6003 => DecNet, + 0x8035 => Rarp, + 0x809b => AppleTalk, + 0x80f3 => Aarp, + 0x8137 => Ipx, + 0x8204 => Qnx, + 0x86dd => Ipv6, + 0x8808 => FlowControl, + 0x8819 => CobraNet, + 0x8847 => Mpls, + 0x8848 => MplsMulticast, + 0x8863 => PppoeDiscovery, + 0x8864 => PppoeSession, + 0x8100 => Vlan, + 0x88a8 => PBridge, + 0x88cc => Lldp, + 0x88f7 => Ptp, + 0x8902 => Cfm, + 0x9100 => QinQ, + n => Unknown(n), + } + } } -impl Into for Protocol { - fn into(self) -> u16 { - use self::Protocol::*; - - match self { - Ipv4 => 0x0800, - Arp => 0x0806, - WakeOnLan => 0x0842, - Trill => 0x22f3, - DecNet => 0x6003, - Rarp => 0x8035, - AppleTalk => 0x809b, - Aarp => 0x80f3, - Ipx => 0x8137, - Qnx => 0x8204, - Ipv6 => 0x86dd, - FlowControl => 0x8808, - CobraNet => 0x8819, - Mpls => 0x8847, - MplsMulticast => 0x8848, - PppoeDiscovery => 0x8863, - PppoeSession => 0x8864, - Vlan => 0x8100, - PBridge => 0x88a8, - Lldp => 0x88cc, - Ptp => 0x88f7, - Cfm => 0x8902, - QinQ => 0x9100, - Unknown(n) => n, - } - } +impl From for u16 { + fn from(val: Protocol) -> Self { + use self::Protocol::*; + + match val { + Ipv4 => 0x0800, + Arp => 0x0806, + WakeOnLan => 0x0842, + Trill => 0x22f3, + DecNet => 0x6003, + Rarp => 0x8035, + AppleTalk => 0x809b, + Aarp => 0x80f3, + Ipx => 0x8137, + Qnx => 0x8204, + Ipv6 => 0x86dd, + FlowControl => 0x8808, + CobraNet => 0x8819, + Mpls => 0x8847, + MplsMulticast => 0x8848, + PppoeDiscovery => 0x8863, + PppoeSession => 0x8864, + Vlan => 0x8100, + PBridge => 0x88a8, + Lldp => 0x88cc, + Ptp => 0x88f7, + Cfm => 0x8902, + QinQ => 0x9100, + Unknown(n) => n, + } + } } diff --git a/src/icmp/builder.rs b/src/icmp/builder.rs index aa4cbf4..e289dba 100644 --- a/src/icmp/builder.rs +++ b/src/icmp/builder.rs @@ -12,99 +12,105 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, WriteBytesExt}; use std::io::Cursor; -use byteorder::{WriteBytesExt, BigEndian}; -use crate::error::*; use crate::buffer::{self, Buffer}; use crate::builder::{Builder as Build, Finalization}; +use crate::error::*; use crate::icmp::checksum; -use crate::icmp::{echo, timestamp, information}; +use crate::icmp::{echo, information, timestamp}; /// ICMP packet builder. #[derive(Debug)] pub struct Builder { - buffer: B, - finalizer: Finalization, + buffer: B, + finalizer: Finalization, } impl Build for Builder { - fn with(buffer: B) -> Result { - Ok(Builder { - buffer: buffer, - finalizer: Default::default(), - }) - } - - fn finalizer(&mut self) -> &mut Finalization { - &mut self.finalizer - } - - fn build(self) -> Result { - Err(Error::InvalidPacket) - } + fn with(buffer: B) -> Result { + Ok(Builder { + buffer, + finalizer: Default::default(), + }) + } + + fn finalizer(&mut self) -> &mut Finalization { + &mut self.finalizer + } + + fn build(self) -> Result { + Err(Error::InvalidPacket) + } } impl Default for Builder { - fn default() -> Self { - Builder::with(buffer::Dynamic::default()).unwrap() - } + fn default() -> Self { + Builder::with(buffer::Dynamic::default()).unwrap() + } } impl Builder { - /// Build an Echo Request/Reply packet. - pub fn echo(self) -> Result> { - let mut echo = echo::Builder::with(self.buffer)?; - echo.finalizer().extend(self.finalizer); + /// Build an Echo Request/Reply packet. + pub fn echo(self) -> Result> { + let mut echo = echo::Builder::with(self.buffer)?; + echo.finalizer().extend(self.finalizer); - Ok(echo) - } + Ok(echo) + } - /// Create an Information Request/Reply packet. - pub fn information(self) -> Result> { - let mut information = information::Builder::with(self.buffer)?; - information.finalizer().extend(self.finalizer); + /// Create an Information Request/Reply packet. + pub fn information(self) -> Result> { + let mut information = information::Builder::with(self.buffer)?; + information.finalizer().extend(self.finalizer); - Ok(information) - } + Ok(information) + } - /// Create a Timestamp Request/Reply packet. - pub fn timestamp(self) -> Result> { - let mut timestamp = timestamp::Builder::with(self.buffer)?; - timestamp.finalizer().extend(self.finalizer); + /// Create a Timestamp Request/Reply packet. + pub fn timestamp(self) -> Result> { + let mut timestamp = timestamp::Builder::with(self.buffer)?; + timestamp.finalizer().extend(self.finalizer); - Ok(timestamp) - } + Ok(timestamp) + } } pub(in crate::icmp) fn prepare(finalizer: &mut Finalization, buffer: &B) { - let offset = buffer.offset(); - let length = buffer.length(); + let offset = buffer.offset(); + let length = buffer.length(); - finalizer.add(move |out| { - let checksum = checksum(&out[offset .. offset + length]); - Cursor::new(&mut out[offset + 2 ..]) - .write_u16::(checksum)?; + finalizer.add(move |out| { + let checksum = checksum(&out[offset..offset + length]); + Cursor::new(&mut out[offset + 2..]).write_u16::(checksum)?; - Ok(()) - }); + Ok(()) + }); } #[cfg(test)] mod test { - use crate::builder::Builder; - use crate::icmp; - - #[test] - fn simple() { - let packet = icmp::Builder::default() - .echo().unwrap().request().unwrap() - .identifier(42).unwrap() - .sequence(2).unwrap() - .payload(b"test").unwrap() - .build().unwrap(); - - let packet = icmp::Packet::new(packet).unwrap(); - assert_eq!(packet.kind(), icmp::Kind::EchoRequest); - } + use crate::builder::Builder; + use crate::icmp; + + #[test] + fn simple() { + let packet = icmp::Builder::default() + .echo() + .unwrap() + .request() + .unwrap() + .identifier(42) + .unwrap() + .sequence(2) + .unwrap() + .payload(b"test") + .unwrap() + .build() + .unwrap(); + + let packet = icmp::Packet::new(packet).unwrap(); + assert_eq!(packet.kind(), icmp::Kind::EchoRequest); + } } diff --git a/src/icmp/code.rs b/src/icmp/code.rs index 82fd34c..46e4baa 100644 --- a/src/icmp/code.rs +++ b/src/icmp/code.rs @@ -15,195 +15,195 @@ /// Codes for Destination Unreachable packets. #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum DestinationUnreachable { - /// - DestinationNetworkUnreachable, + /// + DestinationNetworkUnreachable, - /// - DestinationHostUnreachable, + /// + DestinationHostUnreachable, - /// - DestinationProtocolUnreachable, + /// + DestinationProtocolUnreachable, - /// - DestinationPortUnreachable, + /// + DestinationPortUnreachable, - /// - FragmentationRequired, + /// + FragmentationRequired, - /// - SourceRouteFailed, + /// + SourceRouteFailed, - /// - DestinationNetworkUnknown, + /// + DestinationNetworkUnknown, - /// - DestinationHostUnknown, + /// + DestinationHostUnknown, - /// - SourceHostIsolated, + /// + SourceHostIsolated, - /// - NetworkAdministrativelyProhibited, + /// + NetworkAdministrativelyProhibited, - /// - HostAdministrativelyProhibited, + /// + HostAdministrativelyProhibited, - /// - NetworkUnreachableForTos, + /// + NetworkUnreachableForTos, - /// - HostUnreachableForTos, + /// + HostUnreachableForTos, - /// - CommunicationAdministrativelyProhibited, + /// + CommunicationAdministrativelyProhibited, - /// - HostPrecedenceViolation, + /// + HostPrecedenceViolation, - /// - PrecedentCutoffInEffect, + /// + PrecedentCutoffInEffect, - /// - Unknown(u8), + /// + Unknown(u8), } /// Codes for Redirect Message packets. #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum RedirectMessage { - /// - RedirectDatagramForNetwork, + /// + RedirectDatagramForNetwork, - /// - RedirectDatagramForHost, + /// + RedirectDatagramForHost, - /// - RedirectDatagramForTosAndNetwork, + /// + RedirectDatagramForTosAndNetwork, - /// - RedirectDatagramForTosAndHost, + /// + RedirectDatagramForTosAndHost, - /// - Unknown(u8), + /// + Unknown(u8), } /// Codes for Parameter Problem packets. #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum ParameterProblem { - /// - PointerIndicatesError, + /// + PointerIndicatesError, - /// - MissingRequiredData, + /// + MissingRequiredData, - /// - BadLength, + /// + BadLength, - /// - Unknown(u8), + /// + Unknown(u8), } impl From for DestinationUnreachable { - fn from(value: u8) -> Self { - use self::DestinationUnreachable::*; - - match value { - 0 => DestinationNetworkUnreachable, - 1 => DestinationHostUnreachable, - 2 => DestinationProtocolUnreachable, - 3 => DestinationPortUnreachable, - 4 => FragmentationRequired, - 5 => SourceRouteFailed, - 6 => DestinationNetworkUnknown, - 7 => DestinationHostUnknown, - 8 => SourceHostIsolated, - 9 => NetworkAdministrativelyProhibited, - 10 => HostAdministrativelyProhibited, - 11 => NetworkUnreachableForTos, - 12 => HostUnreachableForTos, - 13 => CommunicationAdministrativelyProhibited, - 14 => HostPrecedenceViolation, - 15 => PrecedentCutoffInEffect, - v => Unknown(v), - } - } + fn from(value: u8) -> Self { + use self::DestinationUnreachable::*; + + match value { + 0 => DestinationNetworkUnreachable, + 1 => DestinationHostUnreachable, + 2 => DestinationProtocolUnreachable, + 3 => DestinationPortUnreachable, + 4 => FragmentationRequired, + 5 => SourceRouteFailed, + 6 => DestinationNetworkUnknown, + 7 => DestinationHostUnknown, + 8 => SourceHostIsolated, + 9 => NetworkAdministrativelyProhibited, + 10 => HostAdministrativelyProhibited, + 11 => NetworkUnreachableForTos, + 12 => HostUnreachableForTos, + 13 => CommunicationAdministrativelyProhibited, + 14 => HostPrecedenceViolation, + 15 => PrecedentCutoffInEffect, + v => Unknown(v), + } + } } -impl Into for DestinationUnreachable { - fn into(self) -> u8 { - use self::DestinationUnreachable::*; - - match self { - DestinationNetworkUnreachable => 0, - DestinationHostUnreachable => 1, - DestinationProtocolUnreachable => 2, - DestinationPortUnreachable => 3, - FragmentationRequired => 4, - SourceRouteFailed => 5, - DestinationNetworkUnknown => 6, - DestinationHostUnknown => 7, - SourceHostIsolated => 8, - NetworkAdministrativelyProhibited => 9, - HostAdministrativelyProhibited => 10, - NetworkUnreachableForTos => 11, - HostUnreachableForTos => 12, - CommunicationAdministrativelyProhibited => 13, - HostPrecedenceViolation => 14, - PrecedentCutoffInEffect => 15, - Unknown(v) => v, - } - } +impl From for u8 { + fn from(val: DestinationUnreachable) -> Self { + use self::DestinationUnreachable::*; + + match val { + DestinationNetworkUnreachable => 0, + DestinationHostUnreachable => 1, + DestinationProtocolUnreachable => 2, + DestinationPortUnreachable => 3, + FragmentationRequired => 4, + SourceRouteFailed => 5, + DestinationNetworkUnknown => 6, + DestinationHostUnknown => 7, + SourceHostIsolated => 8, + NetworkAdministrativelyProhibited => 9, + HostAdministrativelyProhibited => 10, + NetworkUnreachableForTos => 11, + HostUnreachableForTos => 12, + CommunicationAdministrativelyProhibited => 13, + HostPrecedenceViolation => 14, + PrecedentCutoffInEffect => 15, + Unknown(v) => v, + } + } } impl From for RedirectMessage { - fn from(value: u8) -> Self { - use self::RedirectMessage::*; - - match value { - 0 => RedirectDatagramForNetwork, - 1 => RedirectDatagramForHost, - 2 => RedirectDatagramForTosAndNetwork, - 3 => RedirectDatagramForTosAndHost, - v => Unknown(v), - } - } + fn from(value: u8) -> Self { + use self::RedirectMessage::*; + + match value { + 0 => RedirectDatagramForNetwork, + 1 => RedirectDatagramForHost, + 2 => RedirectDatagramForTosAndNetwork, + 3 => RedirectDatagramForTosAndHost, + v => Unknown(v), + } + } } -impl Into for RedirectMessage { - fn into(self) -> u8 { - use self::RedirectMessage::*; - - match self { - RedirectDatagramForNetwork => 0, - RedirectDatagramForHost => 1, - RedirectDatagramForTosAndNetwork => 2, - RedirectDatagramForTosAndHost => 3, - Unknown(v) => v, - } - } +impl From for u8 { + fn from(val: RedirectMessage) -> Self { + use self::RedirectMessage::*; + + match val { + RedirectDatagramForNetwork => 0, + RedirectDatagramForHost => 1, + RedirectDatagramForTosAndNetwork => 2, + RedirectDatagramForTosAndHost => 3, + Unknown(v) => v, + } + } } impl From for ParameterProblem { - fn from(value: u8) -> Self { - use self::ParameterProblem::*; - - match value { - 0 => PointerIndicatesError, - 1 => MissingRequiredData, - 2 => BadLength, - v => Unknown(v), - } - } + fn from(value: u8) -> Self { + use self::ParameterProblem::*; + + match value { + 0 => PointerIndicatesError, + 1 => MissingRequiredData, + 2 => BadLength, + v => Unknown(v), + } + } } -impl Into for ParameterProblem { - fn into(self) -> u8 { - use self::ParameterProblem::*; - - match self { - PointerIndicatesError => 0, - MissingRequiredData => 1, - BadLength => 2, - Unknown(v) => v, - } - } +impl From for u8 { + fn from(val: ParameterProblem) -> Self { + use self::ParameterProblem::*; + + match val { + PointerIndicatesError => 0, + MissingRequiredData => 1, + BadLength => 2, + Unknown(v) => v, + } + } } diff --git a/src/icmp/echo/builder.rs b/src/icmp/echo/builder.rs index 8f66d1e..390cfa5 100644 --- a/src/icmp/echo/builder.rs +++ b/src/icmp/echo/builder.rs @@ -12,121 +12,119 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, WriteBytesExt}; use std::io::Cursor; -use byteorder::{WriteBytesExt, BigEndian}; -use crate::error::*; use crate::buffer::{self, Buffer}; use crate::builder::{Builder as Build, Finalization}; -use crate::packet::{AsPacket, AsPacketMut}; +use crate::error::*; use crate::icmp::builder; -use crate::icmp::Kind; use crate::icmp::echo::Packet; +use crate::icmp::Kind; +use crate::packet::{AsPacket, AsPacketMut}; /// Echo Request/Reply packet builder. #[derive(Debug)] pub struct Builder { - buffer: B, - finalizer: Finalization, + buffer: B, + finalizer: Finalization, - kind: bool, - payload: bool, + kind: bool, + payload: bool, } impl Build for Builder { - fn with(mut buffer: B) -> Result { - buffer.next(8)?; + fn with(mut buffer: B) -> Result { + buffer.next(8)?; - Ok(Builder { - buffer: buffer, - finalizer: Default::default(), + Ok(Builder { + buffer, + finalizer: Default::default(), - kind: false, - payload: false, - }) - } + kind: false, + payload: false, + }) + } - fn finalizer(&mut self) -> &mut Finalization { - &mut self.finalizer - } + fn finalizer(&mut self) -> &mut Finalization { + &mut self.finalizer + } - fn build(mut self) -> Result { - if !self.kind { - Err(Error::InvalidPacket)? - } + fn build(mut self) -> Result { + if !self.kind { + Err(Error::InvalidPacket)? + } - builder::prepare(&mut self.finalizer, &self.buffer); + builder::prepare(&mut self.finalizer, &self.buffer); - let mut buffer = self.buffer.into_inner(); - self.finalizer.finalize(buffer.as_mut())?; - Ok(buffer) - } + let mut buffer = self.buffer.into_inner(); + self.finalizer.finalize(buffer.as_mut())?; + Ok(buffer) + } } impl Default for Builder { - fn default() -> Self { - Builder::with(buffer::Dynamic::default()).unwrap() - } + fn default() -> Self { + Builder::with(buffer::Dynamic::default()).unwrap() + } } impl<'a, B: Buffer> AsPacket<'a, Packet<&'a [u8]>> for Builder { - fn as_packet(&self) -> Result> { - Packet::new(self.buffer.data()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.buffer.data()) + } } impl<'a, B: Buffer> AsPacketMut<'a, Packet<&'a mut [u8]>> for Builder { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.buffer.data_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.buffer.data_mut()) + } } impl Builder { - /// Make it a request. - pub fn request(mut self) -> Result { - self.kind = true; - self.buffer.data_mut()[0] = Kind::EchoRequest.into(); + /// Make it a request. + pub fn request(mut self) -> Result { + self.kind = true; + self.buffer.data_mut()[0] = Kind::EchoRequest.into(); - Ok(self) - } + Ok(self) + } - /// Make it a reply. - pub fn reply(mut self) -> Result { - self.kind = true; - self.buffer.data_mut()[0] = Kind::EchoReply.into(); + /// Make it a reply. + pub fn reply(mut self) -> Result { + self.kind = true; + self.buffer.data_mut()[0] = Kind::EchoReply.into(); - Ok(self) - } + Ok(self) + } - /// Packet identifier. - pub fn identifier(mut self, value: u16) -> Result { - Cursor::new(&mut self.buffer.data_mut()[4 ..]) - .write_u16::(value)?; + /// Packet identifier. + pub fn identifier(mut self, value: u16) -> Result { + Cursor::new(&mut self.buffer.data_mut()[4..]).write_u16::(value)?; - Ok(self) - } + Ok(self) + } - /// Packet sequence. - pub fn sequence(mut self, value: u16) -> Result { - Cursor::new(&mut self.buffer.data_mut()[6 ..]) - .write_u16::(value)?; + /// Packet sequence. + pub fn sequence(mut self, value: u16) -> Result { + Cursor::new(&mut self.buffer.data_mut()[6..]).write_u16::(value)?; - Ok(self) - } + Ok(self) + } - /// Payload for the packet. - pub fn payload<'a, T: IntoIterator>(mut self, value: T) -> Result { - if self.payload { - Err(Error::InvalidPacket)? - } + /// Payload for the packet. + pub fn payload<'a, T: IntoIterator>(mut self, value: T) -> Result { + if self.payload { + Err(Error::InvalidPacket)? + } - self.payload = true; + self.payload = true; - for byte in value { - self.buffer.more(1)?; - *self.buffer.data_mut().last_mut().unwrap() = *byte; - } + for byte in value { + self.buffer.more(1)?; + *self.buffer.data_mut().last_mut().unwrap() = *byte; + } - Ok(self) - } + Ok(self) + } } diff --git a/src/icmp/echo/packet.rs b/src/icmp/echo/packet.rs index 2e3beaa..ae1c46d 100644 --- a/src/icmp/echo/packet.rs +++ b/src/icmp/echo/packet.rs @@ -12,209 +12,206 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::fmt; use std::io::Cursor; -use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; -use crate::icmp::Kind; use crate::icmp::packet::Checked; +use crate::icmp::Kind; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; /// Echo Request/Reply packet parser. pub struct Packet { - buffer: B, + buffer: B, } sized!(Packet, - header { - min: 8, - max: 8, - size: 8, - } +header { + min: 8, + max: 8, + size: 8, +} - payload { - min: 0, - size: p => p.buffer.as_ref().len() - 8, - }); +payload { + min: 0, + size: p => p.buffer.as_ref().len() - 8, +}); impl> fmt::Debug for Packet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("icmp::echo::Packet") - .field("request", &self.is_request()) - .field("identifier", &self.identifier()) - .field("sequence", &self.sequence()) - .field("payload", &self.payload()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("icmp::echo::Packet") + .field("request", &self.is_request()) + .field("identifier", &self.identifier()) + .field("sequence", &self.sequence()) + .field("payload", &self.payload()) + .finish() + } } impl> Packet { - /// Create an Echo Request/Reply packet without checking the buffer. - pub fn unchecked(buffer: B) -> Packet { - Packet { buffer } - } + /// Create an Echo Request/Reply packet without checking the buffer. + pub fn unchecked(buffer: B) -> Packet { + Packet { buffer } + } - /// Parse an Echo Request/Reply packet, checking the buffer contents are - /// correct. - pub fn new(buffer: B) -> Result> { - use crate::size::header::Min; + /// Parse an Echo Request/Reply packet, checking the buffer contents are + /// correct. + pub fn new(buffer: B) -> Result> { + use crate::size::header::Min; - let packet = Packet::unchecked(buffer); + let packet = Packet::unchecked(buffer); - if packet.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } - match Kind::from(packet.buffer.as_ref()[0]) { - Kind::EchoRequest | - Kind::EchoReply => - (), + match Kind::from(packet.buffer.as_ref()[0]) { + Kind::EchoRequest | Kind::EchoReply => (), - _ => - Err(Error::InvalidPacket)? - } + _ => Err(Error::InvalidPacket)?, + } - Ok(packet) - } + Ok(packet) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - Packet::unchecked(self.buffer.as_ref().to_vec()) - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + Packet::unchecked(self.buffer.as_ref().to_vec()) + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - self.buffer.as_ref().split_at(8) - } + fn split(&self) -> (&[u8], &[u8]) { + self.buffer.as_ref().split_at(8) + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - self.buffer.as_mut().split_at_mut(8) - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + self.buffer.as_mut().split_at_mut(8) + } } impl> Packet { - /// Check if it's a Request packet. - pub fn is_request(&self) -> bool { - Kind::from(self.buffer.as_ref()[0]) == Kind::EchoRequest - } - - /// Check if it's a Reply packet. - pub fn is_reply(&self) -> bool { - Kind::from(self.buffer.as_ref()[0]) == Kind::EchoReply - } - - /// Packet identifier. - pub fn identifier(&self) -> u16 { - (&self.buffer.as_ref()[4 ..]).read_u16::().unwrap() - } - - /// Packet sequence. - pub fn sequence(&self) -> u16 { - (&self.buffer.as_ref()[6 ..]).read_u16::().unwrap() - } + /// Check if it's a Request packet. + pub fn is_request(&self) -> bool { + Kind::from(self.buffer.as_ref()[0]) == Kind::EchoRequest + } + + /// Check if it's a Reply packet. + pub fn is_reply(&self) -> bool { + Kind::from(self.buffer.as_ref()[0]) == Kind::EchoReply + } + + /// Packet identifier. + pub fn identifier(&self) -> u16 { + (&self.buffer.as_ref()[4..]) + .read_u16::() + .unwrap() + } + + /// Packet sequence. + pub fn sequence(&self) -> u16 { + (&self.buffer.as_ref()[6..]) + .read_u16::() + .unwrap() + } } impl + AsMut<[u8]>> Packet { - /// Make the packet an Echo Request. - pub fn make_request(&mut self) -> Result<&mut Self> { - self.buffer.as_mut()[0] = Kind::EchoRequest.into(); - - Ok(self) - } - - /// Make the packet an Echo Reply. - pub fn make_reply(&mut self) -> Result<&mut Self> { - self.buffer.as_mut()[0] = Kind::EchoReply.into(); - - Ok(self) - } - - /// Packet identifier. - pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.buffer.as_mut()[4 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Packet sequence. - pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.buffer.as_mut()[6 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Create a checksumed setter. - pub fn checked(&mut self) -> Checked<'_, Self> { - Checked { - packet: self - } - } + /// Make the packet an Echo Request. + pub fn make_request(&mut self) -> Result<&mut Self> { + self.buffer.as_mut()[0] = Kind::EchoRequest.into(); + + Ok(self) + } + + /// Make the packet an Echo Reply. + pub fn make_reply(&mut self) -> Result<&mut Self> { + self.buffer.as_mut()[0] = Kind::EchoReply.into(); + + Ok(self) + } + + /// Packet identifier. + pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.buffer.as_mut()[4..]).write_u16::(value)?; + + Ok(self) + } + + /// Packet sequence. + pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.buffer.as_mut()[6..]).write_u16::(value)?; + + Ok(self) + } + + /// Create a checksumed setter. + pub fn checked(&mut self) -> Checked<'_, Self> { + Checked { packet: self } + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]> + 'a> Checked<'a, Packet> { - /// Make the packet an Echo Request. - pub fn make_request(&mut self) -> Result<&mut Self> { - self.packet.make_request()?; - Ok(self) - } - - /// Make the packet an Echo Reply. - pub fn make_reply(&mut self) -> Result<&mut Self> { - self.packet.make_reply()?; - Ok(self) - } - - /// Packet identifier. - pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_identifier(value)?; - Ok(self) - } - - /// Packet sequence. - pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_sequence(value)?; - Ok(self) - } + /// Make the packet an Echo Request. + pub fn make_request(&mut self) -> Result<&mut Self> { + self.packet.make_request()?; + Ok(self) + } + + /// Make the packet an Echo Reply. + pub fn make_reply(&mut self) -> Result<&mut Self> { + self.packet.make_reply()?; + Ok(self) + } + + /// Packet identifier. + pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_identifier(value)?; + Ok(self) + } + + /// Packet sequence. + pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_sequence(value)?; + Ok(self) + } } diff --git a/src/icmp/information/builder.rs b/src/icmp/information/builder.rs index b8aaab4..ef6ae56 100644 --- a/src/icmp/information/builder.rs +++ b/src/icmp/information/builder.rs @@ -12,102 +12,100 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, WriteBytesExt}; use std::io::Cursor; -use byteorder::{WriteBytesExt, BigEndian}; -use crate::error::*; use crate::buffer::{self, Buffer}; use crate::builder::{Builder as Build, Finalization}; -use crate::packet::{AsPacket, AsPacketMut}; +use crate::error::*; use crate::icmp::builder; -use crate::icmp::Kind; use crate::icmp::information::Packet; +use crate::icmp::Kind; +use crate::packet::{AsPacket, AsPacketMut}; /// Information Request/Reply packet builder. pub struct Builder { - buffer: B, - finalizer: Finalization, + buffer: B, + finalizer: Finalization, - kind: bool, + kind: bool, } impl Build for Builder { - fn with(mut buffer: B) -> Result { - buffer.next(8)?; + fn with(mut buffer: B) -> Result { + buffer.next(8)?; - Ok(Builder { - buffer: buffer, - finalizer: Default::default(), + Ok(Builder { + buffer, + finalizer: Default::default(), - kind: false, - }) - } + kind: false, + }) + } - fn finalizer(&mut self) -> &mut Finalization { - &mut self.finalizer - } + fn finalizer(&mut self) -> &mut Finalization { + &mut self.finalizer + } - fn build(mut self) -> Result { - if !self.kind { - Err(Error::InvalidPacket)? - } + fn build(mut self) -> Result { + if !self.kind { + Err(Error::InvalidPacket)? + } - builder::prepare(&mut self.finalizer, &self.buffer); + builder::prepare(&mut self.finalizer, &self.buffer); - let mut buffer = self.buffer.into_inner(); - self.finalizer.finalize(buffer.as_mut())?; - Ok(buffer) - } + let mut buffer = self.buffer.into_inner(); + self.finalizer.finalize(buffer.as_mut())?; + Ok(buffer) + } } impl Default for Builder { - fn default() -> Self { - Builder::with(buffer::Dynamic::default()).unwrap() - } + fn default() -> Self { + Builder::with(buffer::Dynamic::default()).unwrap() + } } impl<'a, B: Buffer> AsPacket<'a, Packet<&'a [u8]>> for Builder { - fn as_packet(&self) -> Result> { - Packet::new(self.buffer.data()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.buffer.data()) + } } impl<'a, B: Buffer> AsPacketMut<'a, Packet<&'a mut [u8]>> for Builder { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.buffer.data_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.buffer.data_mut()) + } } impl Builder { - /// Make it a request. - pub fn request(mut self) -> Result { - self.kind = true; - self.buffer.data_mut()[0] = Kind::InformationRequest.into(); + /// Make it a request. + pub fn request(mut self) -> Result { + self.kind = true; + self.buffer.data_mut()[0] = Kind::InformationRequest.into(); - Ok(self) - } + Ok(self) + } - /// Make it a reply. - pub fn reply(mut self) -> Result { - self.kind = true; - self.buffer.data_mut()[0] = Kind::InformationReply.into(); + /// Make it a reply. + pub fn reply(mut self) -> Result { + self.kind = true; + self.buffer.data_mut()[0] = Kind::InformationReply.into(); - Ok(self) - } + Ok(self) + } - /// Packet identifier. - pub fn identifier(mut self, value: u16) -> Result { - Cursor::new(&mut self.buffer.data_mut()[4 ..]) - .write_u16::(value)?; + /// Packet identifier. + pub fn identifier(mut self, value: u16) -> Result { + Cursor::new(&mut self.buffer.data_mut()[4..]).write_u16::(value)?; - Ok(self) - } + Ok(self) + } - /// Packet sequence. - pub fn sequence(mut self, value: u16) -> Result { - Cursor::new(&mut self.buffer.data_mut()[6 ..]) - .write_u16::(value)?; + /// Packet sequence. + pub fn sequence(mut self, value: u16) -> Result { + Cursor::new(&mut self.buffer.data_mut()[6..]).write_u16::(value)?; - Ok(self) - } + Ok(self) + } } diff --git a/src/icmp/information/packet.rs b/src/icmp/information/packet.rs index 4379556..b56522d 100644 --- a/src/icmp/information/packet.rs +++ b/src/icmp/information/packet.rs @@ -12,208 +12,205 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::fmt; use std::io::Cursor; -use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; -use crate::icmp::Kind; use crate::icmp::packet::Checked; +use crate::icmp::Kind; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; /// Information Request/Reply packet parser. pub struct Packet { - buffer: B, + buffer: B, } sized!(Packet, - header { - min: 8, - max: 8, - size: 8, - } - - payload { - min: 0, - max: 0, - size: 0, - }); +header { + min: 8, + max: 8, + size: 8, +} + +payload { + min: 0, + max: 0, + size: 0, +}); impl> fmt::Debug for Packet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("icmp::information::Packet") - .field("request", &self.is_request()) - .field("identifier", &self.identifier()) - .field("sequence", &self.sequence()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("icmp::information::Packet") + .field("request", &self.is_request()) + .field("identifier", &self.identifier()) + .field("sequence", &self.sequence()) + .finish() + } } impl> Packet { - pub fn unchecked(buffer: B) -> Packet { - Packet { buffer } - } + pub fn unchecked(buffer: B) -> Packet { + Packet { buffer } + } - /// Parse an Information Request/Reply packet, checking the buffer contents - /// are correct. - pub fn new(buffer: B) -> Result> { - use crate::size::header::Min; + /// Parse an Information Request/Reply packet, checking the buffer contents + /// are correct. + pub fn new(buffer: B) -> Result> { + use crate::size::header::Min; - let packet = Packet::unchecked(buffer); + let packet = Packet::unchecked(buffer); - if packet.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } - match Kind::from(packet.buffer.as_ref()[0]) { - Kind::InformationRequest | - Kind::InformationReply => - (), + match Kind::from(packet.buffer.as_ref()[0]) { + Kind::InformationRequest | Kind::InformationReply => (), - _ => - Err(Error::InvalidPacket)? - } + _ => Err(Error::InvalidPacket)?, + } - Ok(packet) - } + Ok(packet) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - Packet::unchecked(self.buffer.as_ref().to_vec()) - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + Packet::unchecked(self.buffer.as_ref().to_vec()) + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - self.buffer.as_ref().split_at(8) - } + fn split(&self) -> (&[u8], &[u8]) { + self.buffer.as_ref().split_at(8) + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - self.buffer.as_mut().split_at_mut(8) - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + self.buffer.as_mut().split_at_mut(8) + } } impl> Packet { - /// Check if it's a Request packet. - pub fn is_request(&self) -> bool { - Kind::from(self.buffer.as_ref()[0]) == Kind::InformationRequest - } - - /// Check if it's a Reply packet. - pub fn is_reply(&self) -> bool { - Kind::from(self.buffer.as_ref()[0]) == Kind::InformationReply - } - - /// Packet identifier. - pub fn identifier(&self) -> u16 { - (&self.buffer.as_ref()[4 ..]).read_u16::().unwrap() - } - - /// Packet sequence. - pub fn sequence(&self) -> u16 { - (&self.buffer.as_ref()[6 ..]).read_u16::().unwrap() - } + /// Check if it's a Request packet. + pub fn is_request(&self) -> bool { + Kind::from(self.buffer.as_ref()[0]) == Kind::InformationRequest + } + + /// Check if it's a Reply packet. + pub fn is_reply(&self) -> bool { + Kind::from(self.buffer.as_ref()[0]) == Kind::InformationReply + } + + /// Packet identifier. + pub fn identifier(&self) -> u16 { + (&self.buffer.as_ref()[4..]) + .read_u16::() + .unwrap() + } + + /// Packet sequence. + pub fn sequence(&self) -> u16 { + (&self.buffer.as_ref()[6..]) + .read_u16::() + .unwrap() + } } impl + AsMut<[u8]>> Packet { - /// Make the packet an Echo Request. - pub fn make_request(&mut self) -> Result<&mut Self> { - self.buffer.as_mut()[0] = Kind::EchoRequest.into(); - - Ok(self) - } - - /// Make the packet an Echo Reply. - pub fn make_reply(&mut self) -> Result<&mut Self> { - self.buffer.as_mut()[0] = Kind::EchoReply.into(); - - Ok(self) - } - - /// Packet identifier. - pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.buffer.as_mut()[4 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Packet sequence. - pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.buffer.as_mut()[6 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Create a checksumed setter. - pub fn checked(&mut self) -> Checked<'_, Self> { - Checked { - packet: self - } - } + /// Make the packet an Echo Request. + pub fn make_request(&mut self) -> Result<&mut Self> { + self.buffer.as_mut()[0] = Kind::EchoRequest.into(); + + Ok(self) + } + + /// Make the packet an Echo Reply. + pub fn make_reply(&mut self) -> Result<&mut Self> { + self.buffer.as_mut()[0] = Kind::EchoReply.into(); + + Ok(self) + } + + /// Packet identifier. + pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.buffer.as_mut()[4..]).write_u16::(value)?; + + Ok(self) + } + + /// Packet sequence. + pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.buffer.as_mut()[6..]).write_u16::(value)?; + + Ok(self) + } + + /// Create a checksumed setter. + pub fn checked(&mut self) -> Checked<'_, Self> { + Checked { packet: self } + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]> + 'a> Checked<'a, Packet> { - /// Make the packet an Echo Request. - pub fn make_request(&mut self) -> Result<&mut Self> { - self.packet.make_request()?; - Ok(self) - } - - /// Make the packet an Echo Reply. - pub fn make_reply(&mut self) -> Result<&mut Self> { - self.packet.make_reply()?; - Ok(self) - } - - /// Packet identifier. - pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_identifier(value)?; - Ok(self) - } - - /// Packet sequence. - pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_sequence(value)?; - Ok(self) - } + /// Make the packet an Echo Request. + pub fn make_request(&mut self) -> Result<&mut Self> { + self.packet.make_request()?; + Ok(self) + } + + /// Make the packet an Echo Reply. + pub fn make_reply(&mut self) -> Result<&mut Self> { + self.packet.make_reply()?; + Ok(self) + } + + /// Packet identifier. + pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_identifier(value)?; + Ok(self) + } + + /// Packet sequence. + pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_sequence(value)?; + Ok(self) + } } diff --git a/src/icmp/kind.rs b/src/icmp/kind.rs index 6e2195d..0b0b70d 100644 --- a/src/icmp/kind.rs +++ b/src/icmp/kind.rs @@ -15,106 +15,106 @@ /// ICMP packet types. #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum Kind { - /// - EchoReply, + /// + EchoReply, - /// - DestinationUnreachable, + /// + DestinationUnreachable, - /// - SourceQuench, + /// + SourceQuench, - /// - RedirectMessage, + /// + RedirectMessage, - /// - EchoRequest, + /// + EchoRequest, - /// - RouterAdvertisement, + /// + RouterAdvertisement, - /// - RouterSolicitation, + /// + RouterSolicitation, - /// - TimeExceeded, + /// + TimeExceeded, - /// - ParameterProblem, + /// + ParameterProblem, - /// - TimestampRequest, + /// + TimestampRequest, - /// - TimestampReply, + /// + TimestampReply, - /// - InformationRequest, + /// + InformationRequest, - /// - InformationReply, + /// + InformationReply, - /// - AddressMaskRequest, + /// + AddressMaskRequest, - /// - AddressMaskReply, + /// + AddressMaskReply, - /// - TraceRoute, + /// + TraceRoute, - /// - Unknown(u8), + /// + Unknown(u8), } impl From for Kind { - fn from(value: u8) -> Kind { - use self::Kind::*; - - match value { - 0 => EchoReply, - 3 => DestinationUnreachable, - 4 => SourceQuench, - 5 => RedirectMessage, - 8 => EchoRequest, - 9 => RouterAdvertisement, - 10 => RouterSolicitation, - 11 => TimeExceeded, - 12 => ParameterProblem, - 13 => TimestampRequest, - 14 => TimestampReply, - 15 => InformationRequest, - 16 => InformationReply, - 17 => AddressMaskRequest, - 18 => AddressMaskReply, - 30 => TraceRoute, - v => Unknown(v), - } - } + fn from(value: u8) -> Kind { + use self::Kind::*; + + match value { + 0 => EchoReply, + 3 => DestinationUnreachable, + 4 => SourceQuench, + 5 => RedirectMessage, + 8 => EchoRequest, + 9 => RouterAdvertisement, + 10 => RouterSolicitation, + 11 => TimeExceeded, + 12 => ParameterProblem, + 13 => TimestampRequest, + 14 => TimestampReply, + 15 => InformationRequest, + 16 => InformationReply, + 17 => AddressMaskRequest, + 18 => AddressMaskReply, + 30 => TraceRoute, + v => Unknown(v), + } + } } -impl Into for Kind { - fn into(self) -> u8 { - use self::Kind::*; - - match self { - EchoReply => 0, - DestinationUnreachable => 3, - SourceQuench => 4, - RedirectMessage => 5, - EchoRequest => 8, - RouterAdvertisement => 9, - RouterSolicitation => 10, - TimeExceeded => 11, - ParameterProblem => 12, - TimestampRequest => 13, - TimestampReply => 14, - InformationRequest => 15, - InformationReply => 16, - AddressMaskRequest => 17, - AddressMaskReply => 18, - TraceRoute => 30, - Unknown(v) => v, - } - } +impl From for u8 { + fn from(val: Kind) -> Self { + use self::Kind::*; + + match val { + EchoReply => 0, + DestinationUnreachable => 3, + SourceQuench => 4, + RedirectMessage => 5, + EchoRequest => 8, + RouterAdvertisement => 9, + RouterSolicitation => 10, + TimeExceeded => 11, + ParameterProblem => 12, + TimestampRequest => 13, + TimestampReply => 14, + InformationRequest => 15, + InformationReply => 16, + AddressMaskRequest => 17, + AddressMaskReply => 18, + TraceRoute => 30, + Unknown(v) => v, + } + } } diff --git a/src/icmp/mod.rs b/src/icmp/mod.rs index 9e0ab3f..9ef7791 100644 --- a/src/icmp/mod.rs +++ b/src/icmp/mod.rs @@ -44,24 +44,24 @@ pub mod timestamp; /// Calculate the checksum for an ICMP packet. pub fn checksum(buffer: &[u8]) -> u16 { - use std::io::Cursor; - use byteorder::{ReadBytesExt, BigEndian}; + use byteorder::{BigEndian, ReadBytesExt}; + use std::io::Cursor; - let mut result = 0xffffu32; - let mut buffer = Cursor::new(buffer); + let mut result = 0xffffu32; + let mut buffer = Cursor::new(buffer); - while let Ok(value) = buffer.read_u16::() { - // Skip checksum field. - if buffer.position() == 4 { - continue; - } + while let Ok(value) = buffer.read_u16::() { + // Skip checksum field. + if buffer.position() == 4 { + continue; + } - result += u32::from(value); + result += u32::from(value); - if result > 0xffff { - result -= 0xffff; - } - } + if result > 0xffff { + result -= 0xffff; + } + } - !result as u16 + !result as u16 } diff --git a/src/icmp/packet.rs b/src/icmp/packet.rs index 3c16c16..208bdf3 100644 --- a/src/icmp/packet.rs +++ b/src/icmp/packet.rs @@ -12,114 +12,118 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::fmt; use std::io::Cursor; -use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; -use crate::icmp::Kind; use crate::icmp::checksum; +use crate::icmp::Kind; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; /// ICMP packet parser. pub struct Packet { - buffer: B, + buffer: B, } sized!(Packet, - header { - min: 4, - max: 4, - size: 4, - } +header { + min: 4, + max: 4, + size: 4, +} - payload { - min: 0, - size: p => p.buffer.as_ref().len() - 4, - }); +payload { + min: 0, + size: p => p.buffer.as_ref().len() - 4, +}); impl> fmt::Debug for Packet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct(if self.is_valid() { "icmp::Packet" } else { "icmp::Packet!" }) - .field("kind", &self.kind()) - .field("code", &self.code()) - .field("checksum", &self.checksum()) - .field("payload", &self.payload()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(if self.is_valid() { + "icmp::Packet" + } else { + "icmp::Packet!" + }) + .field("kind", &self.kind()) + .field("code", &self.code()) + .field("checksum", &self.checksum()) + .field("payload", &self.payload()) + .finish() + } } impl> Packet { - /// Create an ICMP packet without checking the buffer. - pub fn unchecked(buffer: B) -> Packet { - Packet { buffer } - } + /// Create an ICMP packet without checking the buffer. + pub fn unchecked(buffer: B) -> Packet { + Packet { buffer } + } - /// Parse an ICMP packet, checking the buffer contents are correct. - pub fn new(buffer: B) -> Result> { - use crate::size::header::Min; + /// Parse an ICMP packet, checking the buffer contents are correct. + pub fn new(buffer: B) -> Result> { + use crate::size::header::Min; - let packet = Packet::unchecked(buffer); + let packet = Packet::unchecked(buffer); - if packet.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } - Ok(packet) - } + Ok(packet) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - Packet::unchecked(self.buffer.as_ref().to_vec()) - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + Packet::unchecked(self.buffer.as_ref().to_vec()) + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - self.buffer.as_ref().split_at(4) - } + fn split(&self) -> (&[u8], &[u8]) { + self.buffer.as_ref().split_at(4) + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - self.buffer.as_mut().split_at_mut(4) - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + self.buffer.as_mut().split_at_mut(4) + } } macro_rules! kind { @@ -137,42 +141,44 @@ macro_rules! kind { } impl> Packet { - /// Packet type. - pub fn kind(&self) -> Kind { - Kind::from(self.buffer.as_ref()[0]) - } - - /// Packet code. - pub fn code(&self) -> u8 { - self.buffer.as_ref()[1] - } - - /// Packet checksum. - pub fn checksum(&self) -> u16 { - (&self.buffer.as_ref()[2 ..]).read_u16::().unwrap() - } - - /// Verify the packet is valid by calculating the checksum. - pub fn is_valid(&self) -> bool { - checksum(self.buffer.as_ref()) == self.checksum() - } - - kind!(/// Parse an Echo Request/Reply packet. + /// Packet type. + pub fn kind(&self) -> Kind { + Kind::from(self.buffer.as_ref()[0]) + } + + /// Packet code. + pub fn code(&self) -> u8 { + self.buffer.as_ref()[1] + } + + /// Packet checksum. + pub fn checksum(&self) -> u16 { + (&self.buffer.as_ref()[2..]) + .read_u16::() + .unwrap() + } + + /// Verify the packet is valid by calculating the checksum. + pub fn is_valid(&self) -> bool { + checksum(self.buffer.as_ref()) == self.checksum() + } + + kind!(/// Parse an Echo Request/Reply packet. fn echo[echo_mut]); - kind!(/// Parse a Timestamp Request/Reply packet. + kind!(/// Parse a Timestamp Request/Reply packet. fn timestamp[timestamp_mut]); - kind!(/// Parse an Information Request/Reply packet. + kind!(/// Parse an Information Request/Reply packet. fn information[information_mut]); - kind!(/// Parse a Parameter Problem packet. + kind!(/// Parse a Parameter Problem packet. fn parameter_problem[parameter_problem_mut]); - kind!(/// Parse a Redirect Message packet. + kind!(/// Parse a Redirect Message packet. fn redirect_message[redirect_message_mut]); - kind!(/// Parse a Source Quench, Destination Unreachable or Time Exceeded packet. + kind!(/// Parse a Source Quench, Destination Unreachable or Time Exceeded packet. fn previous[previous_mut]); } @@ -182,13 +188,14 @@ impl> Packet { /// /// The checksum recalculation happens on `Drop`, so don't leak it. pub struct Checked<'a, P: PM + AsRef<[u8]> + AsMut<[u8]>> { - pub(in crate::icmp) packet: &'a mut P, + pub(in crate::icmp) packet: &'a mut P, } impl<'a, P: PM + AsRef<[u8]> + AsMut<[u8]> + 'a> Drop for Checked<'a, P> { - fn drop(&mut self) { - let checksum = checksum(self.packet.as_ref()); - Cursor::new(&mut self.packet.as_mut()[2 ..]) - .write_u16::(checksum).unwrap(); - } + fn drop(&mut self) { + let checksum = checksum(self.packet.as_ref()); + Cursor::new(&mut self.packet.as_mut()[2..]) + .write_u16::(checksum) + .unwrap(); + } } diff --git a/src/icmp/parameter_problem/packet.rs b/src/icmp/parameter_problem/packet.rs index 4f145e0..7300aa2 100644 --- a/src/icmp/parameter_problem/packet.rs +++ b/src/icmp/parameter_problem/packet.rs @@ -15,137 +15,135 @@ use std::fmt; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; -use crate::size; -use crate::ip; use crate::icmp::Kind; +use crate::ip; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; +use crate::size; /// Parameter Problem packet parser. pub struct Packet { - buffer: B, + buffer: B, } sized!(Packet, - header { - min: 8, - max: 8, - size: 8, - } - - payload { - min: as size::header::Min>::min(), - max: as size::header::Max>::max(), - size: p => { - if let Ok(ip) = p.packet() { - size::header::Size::size(&ip) - } - else { - p.buffer.as_ref().len() - 8 - } - }, - }); +header { + min: 8, + max: 8, + size: 8, +} + +payload { + min: as size::header::Min>::min(), + max: as size::header::Max>::max(), + size: p => { + if let Ok(ip) = p.packet() { + size::header::Size::size(&ip) + } + else { + p.buffer.as_ref().len() - 8 + } + }, +}); impl> fmt::Debug for Packet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("icmp::parameter_problem::Packet") - .field("pointer", &self.pointer()) - .field("packet", &self.packet()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("icmp::parameter_problem::Packet") + .field("pointer", &self.pointer()) + .field("packet", &self.packet()) + .finish() + } } impl> Packet { - /// Create a Parameter Problem packet without checking the buffer. - pub fn unchecked(buffer: B) -> Packet { - Packet { buffer } - } + /// Create a Parameter Problem packet without checking the buffer. + pub fn unchecked(buffer: B) -> Packet { + Packet { buffer } + } - /// Parse a Parameter Problem packet, checking the buffer contents - /// are correct. - pub fn new(buffer: B) -> Result> { - use crate::size::header::Min; + /// Parse a Parameter Problem packet, checking the buffer contents + /// are correct. + pub fn new(buffer: B) -> Result> { + use crate::size::header::Min; - let packet = Packet::unchecked(buffer); + let packet = Packet::unchecked(buffer); - if packet.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } - match Kind::from(packet.buffer.as_ref()[0]) { - Kind::ParameterProblem => - (), + match Kind::from(packet.buffer.as_ref()[0]) { + Kind::ParameterProblem => (), - _ => - Err(Error::InvalidPacket)? - } + _ => Err(Error::InvalidPacket)?, + } - Ok(packet) - } + Ok(packet) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - Packet::unchecked(self.buffer.as_ref().to_vec()) - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + Packet::unchecked(self.buffer.as_ref().to_vec()) + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - let (header, payload) = self.buffer.as_ref().split_at(8); - (&header[ .. 5], payload) - } + fn split(&self) -> (&[u8], &[u8]) { + let (header, payload) = self.buffer.as_ref().split_at(8); + (&header[..5], payload) + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - let (header, payload) = self.buffer.as_mut().split_at_mut(8); - (&mut header[.. 5], payload) - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + let (header, payload) = self.buffer.as_mut().split_at_mut(8); + (&mut header[..5], payload) + } } impl> Packet { - /// Pointer to the packet area that caused the problem. - pub fn pointer(&self) -> u8 { - self.buffer.as_ref()[4] - } - - /// The packet that caused the problem. - pub fn packet(&self) -> Result> { - ip::v4::Packet::new(&self.buffer.as_ref()[8 ..]) - } + /// Pointer to the packet area that caused the problem. + pub fn pointer(&self) -> u8 { + self.buffer.as_ref()[4] + } + + /// The packet that caused the problem. + pub fn packet(&self) -> Result> { + ip::v4::Packet::new(&self.buffer.as_ref()[8..]) + } } diff --git a/src/icmp/previous/packet.rs b/src/icmp/previous/packet.rs index 50c17b2..2d38b56 100644 --- a/src/icmp/previous/packet.rs +++ b/src/icmp/previous/packet.rs @@ -15,134 +15,130 @@ use std::fmt; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; -use crate::size; -use crate::ip; use crate::icmp::Kind; +use crate::ip; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; +use crate::size; /// Source Quench, Destination Unreachable and Time Exceeded packet parser. pub struct Packet { - buffer: B, + buffer: B, } sized!(Packet, - header { - min: 8, - max: 8, - size: 8, - } - - payload { - min: as size::header::Min>::min(), - max: as size::header::Max>::max(), - size: p => { - if let Ok(ip) = p.packet() { - size::header::Size::size(&ip) - } - else { - p.buffer.as_ref().len() - 8 - } - }, - }); +header { + min: 8, + max: 8, + size: 8, +} + +payload { + min: as size::header::Min>::min(), + max: as size::header::Max>::max(), + size: p => { + if let Ok(ip) = p.packet() { + size::header::Size::size(&ip) + } + else { + p.buffer.as_ref().len() - 8 + } + }, +}); impl> fmt::Debug for Packet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("icmp::previous::Packet") - .field("packet", &self.packet()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("icmp::previous::Packet") + .field("packet", &self.packet()) + .finish() + } } impl> Packet { - /// Create a Source Quench, Destination Unreachable and Time Exceeded packet - /// without checking the buffer. - pub fn unchecked(buffer: B) -> Packet { - Packet { buffer } - } - - /// Parse a Source Quench, Destination Unreachable and Time Exceeded - /// packet, checking the bufffer contents are correct. - pub fn new(buffer: B) -> Result> { - use crate::size::header::Min; - - let packet = Packet::unchecked(buffer); - - if packet.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } - - match Kind::from(packet.buffer.as_ref()[0]) { - Kind::SourceQuench | - Kind::DestinationUnreachable | - Kind::TimeExceeded => - (), - - _ => - Err(Error::InvalidPacket)? - } - - Ok(packet) - } + /// Create a Source Quench, Destination Unreachable and Time Exceeded packet + /// without checking the buffer. + pub fn unchecked(buffer: B) -> Packet { + Packet { buffer } + } + + /// Parse a Source Quench, Destination Unreachable and Time Exceeded + /// packet, checking the bufffer contents are correct. + pub fn new(buffer: B) -> Result> { + use crate::size::header::Min; + + let packet = Packet::unchecked(buffer); + + if packet.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } + + match Kind::from(packet.buffer.as_ref()[0]) { + Kind::SourceQuench | Kind::DestinationUnreachable | Kind::TimeExceeded => (), + + _ => Err(Error::InvalidPacket)?, + } + + Ok(packet) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - Packet::unchecked(self.buffer.as_ref().to_vec()) - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + Packet::unchecked(self.buffer.as_ref().to_vec()) + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - let (header, payload) = self.buffer.as_ref().split_at(8); - (&header[.. 4], payload) - } + fn split(&self) -> (&[u8], &[u8]) { + let (header, payload) = self.buffer.as_ref().split_at(8); + (&header[..4], payload) + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - let (header, payload) = self.buffer.as_mut().split_at_mut(8); - (&mut header[.. 4], payload) - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + let (header, payload) = self.buffer.as_mut().split_at_mut(8); + (&mut header[..4], payload) + } } impl> Packet { - /// Packet to cause the message. - pub fn packet(&self) -> Result> { - ip::v4::Packet::new(&self.buffer.as_ref()[8 ..]) - } + /// Packet to cause the message. + pub fn packet(&self) -> Result> { + ip::v4::Packet::new(&self.buffer.as_ref()[8..]) + } } diff --git a/src/icmp/redirect_message/packet.rs b/src/icmp/redirect_message/packet.rs index 20a6e48..b21b5cd 100644 --- a/src/icmp/redirect_message/packet.rs +++ b/src/icmp/redirect_message/packet.rs @@ -16,138 +16,137 @@ use std::fmt; use std::net::Ipv4Addr; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; -use crate::size; -use crate::ip; use crate::icmp::Kind; +use crate::ip; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; +use crate::size; /// Redirect Message packet parser. pub struct Packet { - buffer: B, + buffer: B, } sized!(Packet, - header { - min: 8, - max: 8, - size: 8, - } - - payload { - min: as size::header::Min>::min(), - max: as size::header::Max>::max(), - size: p => { - if let Ok(ip) = p.packet() { - size::header::Size::size(&ip) - } - else { - p.buffer.as_ref().len() - 8 - } - }, - }); +header { + min: 8, + max: 8, + size: 8, +} + +payload { + min: as size::header::Min>::min(), + max: as size::header::Max>::max(), + size: p => { + if let Ok(ip) = p.packet() { + size::header::Size::size(&ip) + } + else { + p.buffer.as_ref().len() - 8 + } + }, +}); impl> fmt::Debug for Packet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("icmp::redirect_message::Packet") - .field("gateway", &self.gateway()) - .field("packet", &self.packet()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("icmp::redirect_message::Packet") + .field("gateway", &self.gateway()) + .field("packet", &self.packet()) + .finish() + } } impl> Packet { - /// Create a Redirect Message packet without checking the buffer contents. - pub fn unchecked(buffer: B) -> Packet { - Packet { buffer } - } + /// Create a Redirect Message packet without checking the buffer contents. + pub fn unchecked(buffer: B) -> Packet { + Packet { buffer } + } - /// Parse a Redirect Message packet, checking the buffer contents are correct. - pub fn new(buffer: B) -> Result> { - use crate::size::header::Min; + /// Parse a Redirect Message packet, checking the buffer contents are correct. + pub fn new(buffer: B) -> Result> { + use crate::size::header::Min; - let packet = Packet::unchecked(buffer); + let packet = Packet::unchecked(buffer); - if packet.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } - match Kind::from(packet.buffer.as_ref()[0]) { - Kind::RedirectMessage => - (), + match Kind::from(packet.buffer.as_ref()[0]) { + Kind::RedirectMessage => (), - _ => - Err(Error::InvalidPacket)? - } + _ => Err(Error::InvalidPacket)?, + } - Ok(packet) - } + Ok(packet) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - Packet::unchecked(self.buffer.as_ref().to_vec()) - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + Packet::unchecked(self.buffer.as_ref().to_vec()) + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - self.buffer.as_ref().split_at(8) - } + fn split(&self) -> (&[u8], &[u8]) { + self.buffer.as_ref().split_at(8) + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - self.buffer.as_mut().split_at_mut(8) - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + self.buffer.as_mut().split_at_mut(8) + } } impl> Packet { - /// Gateway to redirect the packet to. - pub fn gateway(&self) -> Ipv4Addr { - Ipv4Addr::new( - self.buffer.as_ref()[4], - self.buffer.as_ref()[5], - self.buffer.as_ref()[6], - self.buffer.as_ref()[7]) - } - - /// Packet to redirect. - pub fn packet(&self) -> Result> { - ip::v4::Packet::new(&self.buffer.as_ref()[8 ..]) - } + /// Gateway to redirect the packet to. + pub fn gateway(&self) -> Ipv4Addr { + Ipv4Addr::new( + self.buffer.as_ref()[4], + self.buffer.as_ref()[5], + self.buffer.as_ref()[6], + self.buffer.as_ref()[7], + ) + } + + /// Packet to redirect. + pub fn packet(&self) -> Result> { + ip::v4::Packet::new(&self.buffer.as_ref()[8..]) + } } diff --git a/src/icmp/timestamp/builder.rs b/src/icmp/timestamp/builder.rs index a7139a7..4551474 100644 --- a/src/icmp/timestamp/builder.rs +++ b/src/icmp/timestamp/builder.rs @@ -12,127 +12,122 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, WriteBytesExt}; use std::io::Cursor; -use byteorder::{WriteBytesExt, BigEndian}; -use crate::error::*; use crate::buffer::{self, Buffer}; use crate::builder::{Builder as Build, Finalization}; -use crate::packet::{AsPacket, AsPacketMut}; +use crate::error::*; use crate::icmp::builder; -use crate::icmp::Kind; use crate::icmp::timestamp::Packet; +use crate::icmp::Kind; +use crate::packet::{AsPacket, AsPacketMut}; /// Information Request/Reply builder. #[derive(Debug)] pub struct Builder { - buffer: B, - finalizer: Finalization, + buffer: B, + finalizer: Finalization, - kind: bool, + kind: bool, } impl Build for Builder { - fn with(mut buffer: B) -> Result { - buffer.next(20)?; + fn with(mut buffer: B) -> Result { + buffer.next(20)?; - Ok(Builder { - buffer: buffer, - finalizer: Default::default(), + Ok(Builder { + buffer, + finalizer: Default::default(), - kind: false, - }) - } + kind: false, + }) + } - fn finalizer(&mut self) -> &mut Finalization { - &mut self.finalizer - } + fn finalizer(&mut self) -> &mut Finalization { + &mut self.finalizer + } - fn build(mut self) -> Result { - if !self.kind { - Err(Error::InvalidPacket)? - } + fn build(mut self) -> Result { + if !self.kind { + Err(Error::InvalidPacket)? + } - builder::prepare(&mut self.finalizer, &self.buffer); + builder::prepare(&mut self.finalizer, &self.buffer); - let mut buffer = self.buffer.into_inner(); - self.finalizer.finalize(buffer.as_mut())?; - Ok(buffer) - } + let mut buffer = self.buffer.into_inner(); + self.finalizer.finalize(buffer.as_mut())?; + Ok(buffer) + } } impl Default for Builder { - fn default() -> Self { - Builder::with(buffer::Dynamic::default()).unwrap() - } + fn default() -> Self { + Builder::with(buffer::Dynamic::default()).unwrap() + } } impl<'a, B: Buffer> AsPacket<'a, Packet<&'a [u8]>> for Builder { - fn as_packet(&self) -> Result> { - Packet::new(self.buffer.data()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.buffer.data()) + } } impl<'a, B: Buffer> AsPacketMut<'a, Packet<&'a mut [u8]>> for Builder { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.buffer.data_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.buffer.data_mut()) + } } impl Builder { - /// Make it a request. - pub fn request(mut self) -> Result { - self.kind = true; - self.buffer.data_mut()[0] = Kind::TimestampRequest.into(); + /// Make it a request. + pub fn request(mut self) -> Result { + self.kind = true; + self.buffer.data_mut()[0] = Kind::TimestampRequest.into(); - Ok(self) - } + Ok(self) + } - /// Make it a reply. - pub fn reply(mut self) -> Result { - self.kind = true; - self.buffer.data_mut()[0] = Kind::TimestampReply.into(); + /// Make it a reply. + pub fn reply(mut self) -> Result { + self.kind = true; + self.buffer.data_mut()[0] = Kind::TimestampReply.into(); - Ok(self) - } + Ok(self) + } - /// Packet identifier. - pub fn identifier(mut self, value: u16) -> Result { - Cursor::new(&mut self.buffer.data_mut()[4 ..]) - .write_u16::(value)?; + /// Packet identifier. + pub fn identifier(mut self, value: u16) -> Result { + Cursor::new(&mut self.buffer.data_mut()[4..]).write_u16::(value)?; - Ok(self) - } + Ok(self) + } - /// Packet sequence. - pub fn sequence(mut self, value: u16) -> Result { - Cursor::new(&mut self.buffer.data_mut()[6 ..]) - .write_u16::(value)?; + /// Packet sequence. + pub fn sequence(mut self, value: u16) -> Result { + Cursor::new(&mut self.buffer.data_mut()[6..]).write_u16::(value)?; - Ok(self) - } + Ok(self) + } - /// Creation timestamp. - pub fn originate(mut self, value: u32) -> Result { - Cursor::new(&mut self.buffer.data_mut()[8 ..]) - .write_u32::(value)?; + /// Creation timestamp. + pub fn originate(mut self, value: u32) -> Result { + Cursor::new(&mut self.buffer.data_mut()[8..]).write_u32::(value)?; - Ok(self) - } + Ok(self) + } - /// Reception timestamp. - pub fn receive(mut self, value: u32) -> Result { - Cursor::new(&mut self.buffer.data_mut()[12 ..]) - .write_u32::(value)?; + /// Reception timestamp. + pub fn receive(mut self, value: u32) -> Result { + Cursor::new(&mut self.buffer.data_mut()[12..]).write_u32::(value)?; - Ok(self) - } + Ok(self) + } - /// Transmission timestamp. - pub fn transmit(mut self, value: u32) -> Result { - Cursor::new(&mut self.buffer.data_mut()[16 ..]) - .write_u32::(value)?; + /// Transmission timestamp. + pub fn transmit(mut self, value: u32) -> Result { + Cursor::new(&mut self.buffer.data_mut()[16..]).write_u32::(value)?; - Ok(self) - } + Ok(self) + } } diff --git a/src/icmp/timestamp/packet.rs b/src/icmp/timestamp/packet.rs index 2e3a8f0..ffb8d95 100644 --- a/src/icmp/timestamp/packet.rs +++ b/src/icmp/timestamp/packet.rs @@ -12,269 +12,269 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::fmt; use std::io::Cursor; -use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; -use crate::icmp::Kind; use crate::icmp::packet::Checked; +use crate::icmp::Kind; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; /// Timestamp Request/Reply packet parser. pub struct Packet { - buffer: B, + buffer: B, } sized!(Packet, - header { - min: 20, - max: 20, - size: 20, - } - - payload { - min: 0, - max: 0, - size: 0, - }); +header { + min: 20, + max: 20, + size: 20, +} + +payload { + min: 0, + max: 0, + size: 0, +}); impl> fmt::Debug for Packet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("icmp::timestamp::Packet") - .field("request", &self.is_request()) - .field("identifier", &self.identifier()) - .field("sequence", &self.sequence()) - .field("originate", &self.payload()) - .field("receive", &self.payload()) - .field("transmit", &self.payload()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("icmp::timestamp::Packet") + .field("request", &self.is_request()) + .field("identifier", &self.identifier()) + .field("sequence", &self.sequence()) + .field("originate", &self.payload()) + .field("receive", &self.payload()) + .field("transmit", &self.payload()) + .finish() + } } impl> Packet { - /// Create a Timestamp Request/Reply packet without checking the buffer. - pub fn unchecked(buffer: B) -> Packet { - Packet { buffer } - } + /// Create a Timestamp Request/Reply packet without checking the buffer. + pub fn unchecked(buffer: B) -> Packet { + Packet { buffer } + } - /// Parse a Timestamp Request/Reply packet, checking the buffer contents - /// are correct. - pub fn new(buffer: B) -> Result> { - use crate::size::header::Min; + /// Parse a Timestamp Request/Reply packet, checking the buffer contents + /// are correct. + pub fn new(buffer: B) -> Result> { + use crate::size::header::Min; - let packet = Packet::unchecked(buffer); + let packet = Packet::unchecked(buffer); - if packet.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } - match Kind::from(packet.buffer.as_ref()[0]) { - Kind::TimestampRequest | - Kind::TimestampReply => - (), + match Kind::from(packet.buffer.as_ref()[0]) { + Kind::TimestampRequest | Kind::TimestampReply => (), - _ => - Err(Error::InvalidPacket)? - } + _ => Err(Error::InvalidPacket)?, + } - Ok(packet) - } + Ok(packet) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - Packet::unchecked(self.buffer.as_ref().to_vec()) - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + Packet::unchecked(self.buffer.as_ref().to_vec()) + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - self.buffer.as_ref().split_at(8) - } + fn split(&self) -> (&[u8], &[u8]) { + self.buffer.as_ref().split_at(8) + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - self.buffer.as_mut().split_at_mut(8) - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + self.buffer.as_mut().split_at_mut(8) + } } impl> Packet { - /// Check if it's a Request packet. - pub fn is_request(&self) -> bool { - Kind::from(self.buffer.as_ref()[0]) == Kind::TimestampRequest - } - - /// Check if it's a Reply packet. - pub fn is_reply(&self) -> bool { - Kind::from(self.buffer.as_ref()[0]) == Kind::TimestampReply - } - - /// Packet identifier. - pub fn identifier(&self) -> u16 { - (&self.buffer.as_ref()[4 ..]).read_u16::().unwrap() - } - - /// Packet sequence. - pub fn sequence(&self) -> u16 { - (&self.buffer.as_ref()[6 ..]).read_u16::().unwrap() - } - - /// Creation timestamp. - pub fn originate(&self) -> u32 { - (&self.buffer.as_ref()[8 ..]).read_u32::().unwrap() - } - - /// Reception timestamp. - pub fn receive(&self) -> u32 { - (&self.buffer.as_ref()[12 ..]).read_u32::().unwrap() - } - - /// Transmission timestamp. - pub fn transmit(&self) -> u32 { - (&self.buffer.as_ref()[16 ..]).read_u32::().unwrap() - } + /// Check if it's a Request packet. + pub fn is_request(&self) -> bool { + Kind::from(self.buffer.as_ref()[0]) == Kind::TimestampRequest + } + + /// Check if it's a Reply packet. + pub fn is_reply(&self) -> bool { + Kind::from(self.buffer.as_ref()[0]) == Kind::TimestampReply + } + + /// Packet identifier. + pub fn identifier(&self) -> u16 { + (&self.buffer.as_ref()[4..]) + .read_u16::() + .unwrap() + } + + /// Packet sequence. + pub fn sequence(&self) -> u16 { + (&self.buffer.as_ref()[6..]) + .read_u16::() + .unwrap() + } + + /// Creation timestamp. + pub fn originate(&self) -> u32 { + (&self.buffer.as_ref()[8..]) + .read_u32::() + .unwrap() + } + + /// Reception timestamp. + pub fn receive(&self) -> u32 { + (&self.buffer.as_ref()[12..]) + .read_u32::() + .unwrap() + } + + /// Transmission timestamp. + pub fn transmit(&self) -> u32 { + (&self.buffer.as_ref()[16..]) + .read_u32::() + .unwrap() + } } impl + AsMut<[u8]>> Packet { - /// Make the packet an Echo Request. - pub fn make_request(&mut self) -> Result<&mut Self> { - self.buffer.as_mut()[0] = Kind::EchoRequest.into(); - - Ok(self) - } - - /// Make the packet an Echo Reply. - pub fn make_reply(&mut self) -> Result<&mut Self> { - self.buffer.as_mut()[0] = Kind::EchoReply.into(); - - Ok(self) - } - - /// Packet identifier. - pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.buffer.as_mut()[4 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Packet sequence. - pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.buffer.as_mut()[6 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Creation timestamp. - pub fn set_originate(&mut self, value: u32) -> Result<&mut Self> { - Cursor::new(&mut self.buffer.as_mut()[8 ..]) - .write_u32::(value)?; - - Ok(self) - } - - /// Reception timestamp. - pub fn set_receive(&mut self, value: u32) -> Result<&mut Self> { - Cursor::new(&mut self.buffer.as_mut()[12 ..]) - .write_u32::(value)?; - - Ok(self) - } - - /// Transmission timestamp. - pub fn set_transmit(&mut self, value: u32) -> Result<&mut Self> { - Cursor::new(&mut self.buffer.as_mut()[16 ..]) - .write_u32::(value)?; - - Ok(self) - } - - /// Create a checksumed setter. - pub fn checked(&mut self) -> Checked<'_, Self> { - Checked { - packet: self - } - } + /// Make the packet an Echo Request. + pub fn make_request(&mut self) -> Result<&mut Self> { + self.buffer.as_mut()[0] = Kind::EchoRequest.into(); + + Ok(self) + } + + /// Make the packet an Echo Reply. + pub fn make_reply(&mut self) -> Result<&mut Self> { + self.buffer.as_mut()[0] = Kind::EchoReply.into(); + + Ok(self) + } + + /// Packet identifier. + pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.buffer.as_mut()[4..]).write_u16::(value)?; + + Ok(self) + } + + /// Packet sequence. + pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.buffer.as_mut()[6..]).write_u16::(value)?; + + Ok(self) + } + + /// Creation timestamp. + pub fn set_originate(&mut self, value: u32) -> Result<&mut Self> { + Cursor::new(&mut self.buffer.as_mut()[8..]).write_u32::(value)?; + + Ok(self) + } + + /// Reception timestamp. + pub fn set_receive(&mut self, value: u32) -> Result<&mut Self> { + Cursor::new(&mut self.buffer.as_mut()[12..]).write_u32::(value)?; + + Ok(self) + } + + /// Transmission timestamp. + pub fn set_transmit(&mut self, value: u32) -> Result<&mut Self> { + Cursor::new(&mut self.buffer.as_mut()[16..]).write_u32::(value)?; + + Ok(self) + } + + /// Create a checksumed setter. + pub fn checked(&mut self) -> Checked<'_, Self> { + Checked { packet: self } + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]> + 'a> Checked<'a, Packet> { - /// Make the packet an Echo Request. - pub fn make_request(&mut self) -> Result<&mut Self> { - self.packet.make_request()?; - Ok(self) - } - - /// Make the packet an Echo Reply. - pub fn make_reply(&mut self) -> Result<&mut Self> { - self.packet.make_reply()?; - Ok(self) - } - - /// Packet identifier. - pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_identifier(value)?; - Ok(self) - } - - /// Packet sequence. - pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_sequence(value)?; - Ok(self) - } - - /// Creation timestamp. - pub fn set_originate(&mut self, value: u32) -> Result<&mut Self> { - self.packet.set_originate(value)?; - Ok(self) - } - - /// Reception timestamp. - pub fn set_receive(&mut self, value: u32) -> Result<&mut Self> { - self.packet.set_receive(value)?; - Ok(self) - } - - /// Transmission timestamp. - pub fn set_transmit(&mut self, value: u32) -> Result<&mut Self> { - self.packet.set_transmit(value)?; - Ok(self) - } + /// Make the packet an Echo Request. + pub fn make_request(&mut self) -> Result<&mut Self> { + self.packet.make_request()?; + Ok(self) + } + + /// Make the packet an Echo Reply. + pub fn make_reply(&mut self) -> Result<&mut Self> { + self.packet.make_reply()?; + Ok(self) + } + + /// Packet identifier. + pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_identifier(value)?; + Ok(self) + } + + /// Packet sequence. + pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_sequence(value)?; + Ok(self) + } + + /// Creation timestamp. + pub fn set_originate(&mut self, value: u32) -> Result<&mut Self> { + self.packet.set_originate(value)?; + Ok(self) + } + + /// Reception timestamp. + pub fn set_receive(&mut self, value: u32) -> Result<&mut Self> { + self.packet.set_receive(value)?; + Ok(self) + } + + /// Transmission timestamp. + pub fn set_transmit(&mut self, value: u32) -> Result<&mut Self> { + self.packet.set_transmit(value)?; + Ok(self) + } } diff --git a/src/ip/builder.rs b/src/ip/builder.rs index 3c7eb29..7951697 100644 --- a/src/ip/builder.rs +++ b/src/ip/builder.rs @@ -12,55 +12,55 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. -use crate::error::*; use crate::buffer::{self, Buffer}; use crate::builder::{Builder as Build, Finalization}; +use crate::error::*; use crate::ip::{v4, v6}; /// Generic IP packet builder. #[derive(Debug)] pub struct Builder { - buffer: B, - finalizer: Finalization, + buffer: B, + finalizer: Finalization, } impl Build for Builder { - fn with(buffer: B) -> Result { - Ok(Builder { - buffer: buffer, - finalizer: Default::default(), - }) - } + fn with(buffer: B) -> Result { + Ok(Builder { + buffer, + finalizer: Default::default(), + }) + } - fn finalizer(&mut self) -> &mut Finalization { - &mut self.finalizer - } + fn finalizer(&mut self) -> &mut Finalization { + &mut self.finalizer + } - fn build(self) -> Result { - Err(Error::InvalidPacket) - } + fn build(self) -> Result { + Err(Error::InvalidPacket) + } } impl Default for Builder { - fn default() -> Self { - Builder::with(buffer::Dynamic::default()).unwrap() - } + fn default() -> Self { + Builder::with(buffer::Dynamic::default()).unwrap() + } } impl Builder { - /// Create an IPv4 packet. - pub fn v4(self) -> Result> { - let mut v4 = v4::Builder::with(self.buffer)?; - v4.finalizer().extend(self.finalizer); + /// Create an IPv4 packet. + pub fn v4(self) -> Result> { + let mut v4 = v4::Builder::with(self.buffer)?; + v4.finalizer().extend(self.finalizer); - Ok(v4) - } + Ok(v4) + } - /// Create an IPv6 packet. - pub fn v6(self) -> Result> { - let mut v6 = v6::Builder::with(self.buffer)?; - v6.finalizer().extend(self.finalizer); + /// Create an IPv6 packet. + pub fn v6(self) -> Result> { + let mut v6 = v6::Builder::with(self.buffer)?; + v6.finalizer().extend(self.finalizer); - Ok(v6) - } + Ok(v6) + } } diff --git a/src/ip/packet.rs b/src/ip/packet.rs index 5d8a7b4..3505909 100644 --- a/src/ip/packet.rs +++ b/src/ip/packet.rs @@ -13,190 +13,167 @@ // 0. You just DO WHAT THE FUCK YOU WANT TO. use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; -use crate::size; use crate::ip::{v4, v6}; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; +use crate::size; /// Generic IP packet. #[derive(Debug)] pub enum Packet> { - /// IPv4 packet. - V4(v4::Packet), + /// IPv4 packet. + V4(v4::Packet), - /// IPv6 packet. - V6(v6::Packet), + /// IPv6 packet. + V6(v6::Packet), } impl> Packet { - /// Create an IP packet without checking the buffer. - /// - /// # Note - /// - /// This still checks the version field to pick an IPv4 or IPv6 packet. - pub fn unchecked(buffer: B) -> Packet { - match buffer.as_ref()[0] >> 4 { - 4 => - Packet::V4(v4::Packet::unchecked(buffer)), - - 6 => - Packet::V6(v6::Packet::unchecked(buffer)), - - _ => - panic!("not an IPv4 or IPv6 packet") - } - } - - /// Parse an IP packet without checking the payload. - pub fn no_payload(buffer: B) -> Result> { - match buffer.as_ref()[0] >> 4 { - 4 => - v4::Packet::no_payload(buffer).map(Packet::V4), - - 6 => - v6::Packet::no_payload(buffer).map(Packet::V6), - - _ => - Err(Error::InvalidPacket) - } - } - - /// Parse an IP packet, checking the buffer contents are correct. - pub fn new(buffer: B) -> Result> { - match buffer.as_ref()[0] >> 4 { - 4 => - v4::Packet::new(buffer).map(Packet::V4), - - 6 => - v6::Packet::new(buffer).map(Packet::V6), - - _ => - Err(Error::InvalidPacket) - } - } + /// Create an IP packet without checking the buffer. + /// + /// # Note + /// + /// This still checks the version field to pick an IPv4 or IPv6 packet. + pub fn unchecked(buffer: B) -> Packet { + match buffer.as_ref()[0] >> 4 { + 4 => Packet::V4(v4::Packet::unchecked(buffer)), + + 6 => Packet::V6(v6::Packet::unchecked(buffer)), + + _ => panic!("not an IPv4 or IPv6 packet"), + } + } + + /// Parse an IP packet without checking the payload. + pub fn no_payload(buffer: B) -> Result> { + match buffer.as_ref()[0] >> 4 { + 4 => v4::Packet::no_payload(buffer).map(Packet::V4), + + 6 => v6::Packet::no_payload(buffer).map(Packet::V6), + + _ => Err(Error::InvalidPacket), + } + } + + /// Parse an IP packet, checking the buffer contents are correct. + pub fn new(buffer: B) -> Result> { + match buffer.as_ref()[0] >> 4 { + 4 => v4::Packet::new(buffer).map(Packet::V4), + + 6 => v6::Packet::new(buffer).map(Packet::V6), + + _ => Err(Error::InvalidPacket), + } + } } impl> From> for Packet { - fn from(value: v4::Packet) -> Packet { - Packet::V4(value) - } + fn from(value: v4::Packet) -> Packet { + Packet::V4(value) + } } impl> From> for Packet { - fn from(value: v6::Packet) -> Packet { - Packet::V6(value) - } + fn from(value: v6::Packet) -> Packet { + Packet::V6(value) + } } impl<'a, B: AsRef<[u8]> + Clone> From<&'a v4::Packet> for Packet { - fn from(value: &'a v4::Packet) -> Packet { - Packet::V4(value.clone()) - } + fn from(value: &'a v4::Packet) -> Packet { + Packet::V4(value.clone()) + } } impl<'a, B: AsRef<[u8]> + Clone> From<&'a v6::Packet> for Packet { - fn from(value: &'a v6::Packet) -> Packet { - Packet::V6(value.clone()) - } + fn from(value: &'a v6::Packet) -> Packet { + Packet::V6(value.clone()) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - match *self { - Packet::V4(ref packet) => - Packet::V4(packet.to_owned()), - - Packet::V6(ref packet) => - Packet::V6(packet.to_owned()), - } - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + match *self { + Packet::V4(ref packet) => Packet::V4(packet.to_owned()), + + Packet::V6(ref packet) => Packet::V6(packet.to_owned()), + } + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - match *self { - Packet::V4(ref packet) => - packet.as_ref(), - - Packet::V6(ref packet) => - packet.as_ref(), - } - } + fn as_ref(&self) -> &[u8] { + match *self { + Packet::V4(ref packet) => packet.as_ref(), + + Packet::V6(ref packet) => packet.as_ref(), + } + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - match *self { - Packet::V4(ref mut packet) => - packet.as_mut(), - - Packet::V6(ref mut packet) => - packet.as_mut(), - } - } + fn as_mut(&mut self) -> &mut [u8] { + match *self { + Packet::V4(ref mut packet) => packet.as_mut(), + + Packet::V6(ref mut packet) => packet.as_mut(), + } + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - match *self { - Packet::V4(ref packet) => - packet.split(), - - Packet::V6(ref packet) => - packet.split(), - } - } + fn split(&self) -> (&[u8], &[u8]) { + match *self { + Packet::V4(ref packet) => packet.split(), + + Packet::V6(ref packet) => packet.split(), + } + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - match *self { - Packet::V4(ref mut packet) => - packet.split_mut(), - - Packet::V6(ref mut packet) => - packet.split_mut(), - } - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + match *self { + Packet::V4(ref mut packet) => packet.split_mut(), + + Packet::V6(ref mut packet) => packet.split_mut(), + } + } } impl> size::header::Size for Packet { - fn size(&self) -> usize { - match *self { - Packet::V4(ref packet) => - size::header::Size::size(packet), - - Packet::V6(ref packet) => - size::header::Size::size(packet), - } - } + fn size(&self) -> usize { + match *self { + Packet::V4(ref packet) => size::header::Size::size(packet), + + Packet::V6(ref packet) => size::header::Size::size(packet), + } + } } impl> size::payload::Size for Packet { - fn size(&self) -> usize { - match *self { - Packet::V4(ref packet) => - size::payload::Size::size(packet), - - Packet::V6(ref packet) => - size::payload::Size::size(packet), - } - } + fn size(&self) -> usize { + match *self { + Packet::V4(ref packet) => size::payload::Size::size(packet), + + Packet::V6(ref packet) => size::payload::Size::size(packet), + } + } } diff --git a/src/ip/protocol.rs b/src/ip/protocol.rs index e11278a..9cabd95 100644 --- a/src/ip/protocol.rs +++ b/src/ip/protocol.rs @@ -15,751 +15,751 @@ /// Protocols supported by IP packets. #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum Protocol { - /// - Hopopt, + /// + Hopopt, - /// - Icmp, + /// + Icmp, - /// - Igmp, + /// + Igmp, - /// - Ggp, + /// + Ggp, - /// - Ipv4, + /// + Ipv4, - /// - St, + /// + St, - /// - Tcp, + /// + Tcp, - /// - Cbt, + /// + Cbt, - /// - Egp, + /// + Egp, - /// - Igp, + /// + Igp, - /// - BbnRccMon, + /// + BbnRccMon, - /// - NvpII, + /// + NvpII, - /// - Pup, + /// + Pup, - /// - Argus, + /// + Argus, - /// - Emcon, + /// + Emcon, - /// - Xnet, + /// + Xnet, - /// - Chaos, + /// + Chaos, - /// - Udp, + /// + Udp, - /// - Mux, + /// + Mux, - /// - DcnMeas, + /// + DcnMeas, - /// - Hmp, + /// + Hmp, - /// - Prm, + /// + Prm, - /// - XnsIdp, + /// + XnsIdp, - /// - Trunk1, + /// + Trunk1, - /// - Trunk2, + /// + Trunk2, - /// - Leaf1, + /// + Leaf1, - /// - Leaf2, + /// + Leaf2, - /// - Rdp, + /// + Rdp, - /// - Irtp, + /// + Irtp, - /// - IsoTp4, + /// + IsoTp4, - /// - Netblt, + /// + Netblt, - /// - MfeNsp, + /// + MfeNsp, - /// - MeritInp, + /// + MeritInp, - /// - Dccp, + /// + Dccp, - /// - ThreePc, + /// + ThreePc, - /// - Idpr, + /// + Idpr, - /// - Xtp, + /// + Xtp, - /// - Ddp, + /// + Ddp, - /// - IdprCmtp, + /// + IdprCmtp, - /// - TpPlusPlus, + /// + TpPlusPlus, - /// - Il, + /// + Il, - /// - Ipv6, + /// + Ipv6, - /// - Sdrp, + /// + Sdrp, - /// - Ipv6Route, + /// + Ipv6Route, - /// - Ipv6Frag, + /// + Ipv6Frag, - /// - Idrp, + /// + Idrp, - /// - Rsvp, + /// + Rsvp, - /// - Gre, + /// + Gre, - /// - Dsr, + /// + Dsr, - /// - Bna, + /// + Bna, - /// - Esp, + /// + Esp, - /// - Ah, + /// + Ah, - /// - INlsp, + /// + INlsp, - /// - Swipe, + /// + Swipe, - /// - Narp, + /// + Narp, - /// - Mobile, + /// + Mobile, - /// - Tlsp, + /// + Tlsp, - /// - Skip, + /// + Skip, - /// - Ipv6Icmp, + /// + Ipv6Icmp, - /// - Ipv6NoNxt, + /// + Ipv6NoNxt, - /// - Ipv6Opts, + /// + Ipv6Opts, - /// - HostInternal, + /// + HostInternal, - /// - Cftp, + /// + Cftp, - /// - LocalNetwork, + /// + LocalNetwork, - /// - SatExpak, + /// + SatExpak, - /// - Kryptolan, + /// + Kryptolan, - /// - Rvd, + /// + Rvd, - /// - Ippc, + /// + Ippc, - /// - DistributedFs, + /// + DistributedFs, - /// - SatMon, + /// + SatMon, - /// - Visa, + /// + Visa, - /// - Ipcv, + /// + Ipcv, - /// - Cpnx, + /// + Cpnx, - /// - Cphb, + /// + Cphb, - /// - Wsn, + /// + Wsn, - /// - Pvp, + /// + Pvp, - /// - BrSatMon, + /// + BrSatMon, - /// - SunNd, + /// + SunNd, - /// - WbMon, + /// + WbMon, - /// - WbExpak, + /// + WbExpak, - /// - IsoIp, + /// + IsoIp, - /// - Vmtp, + /// + Vmtp, - /// - SecureVmtp, + /// + SecureVmtp, - /// - Vines, + /// + Vines, - /// - TtpOrIptm, + /// + TtpOrIptm, - /// - NsfnetIgp, + /// + NsfnetIgp, - /// - Dgp, + /// + Dgp, - /// - Tcf, + /// + Tcf, - /// - Eigrp, + /// + Eigrp, - /// - OspfigP, + /// + OspfigP, - /// - SpriteRpc, + /// + SpriteRpc, - /// - Larp, + /// + Larp, - /// - Mtp, + /// + Mtp, - /// - Ax25, + /// + Ax25, - /// - IpIp, + /// + IpIp, - /// - Micp, + /// + Micp, - /// - SccSp, + /// + SccSp, - /// - Etherip, + /// + Etherip, - /// - Encap, + /// + Encap, - /// - PrivEncryption, + /// + PrivEncryption, - /// - Gmtp, + /// + Gmtp, - /// - Ifmp, + /// + Ifmp, - /// - Pnni, + /// + Pnni, - /// - Pim, + /// + Pim, - /// - Aris, + /// + Aris, - /// - Scps, + /// + Scps, - /// - Qnx, + /// + Qnx, - /// - AN, + /// + AN, - /// - IpComp, + /// + IpComp, - /// - Snp, + /// + Snp, - /// - CompaqPeer, + /// + CompaqPeer, - /// - IpxInIp, + /// + IpxInIp, - /// - Vrrp, + /// + Vrrp, - /// - Pgm, + /// + Pgm, - /// - ZeroHop, + /// + ZeroHop, - /// - L2tp, + /// + L2tp, - /// - Ddx, + /// + Ddx, - /// - Iatp, + /// + Iatp, - /// - Stp, + /// + Stp, - /// - Srp, + /// + Srp, - /// - Uti, + /// + Uti, - /// - Smp, + /// + Smp, - /// - Sm, + /// + Sm, - /// - Ptp, + /// + Ptp, - /// - IsisOverIpv4, + /// + IsisOverIpv4, - /// - Fire, + /// + Fire, - /// - Crtp, + /// + Crtp, - /// - Crudp, + /// + Crudp, - /// - Sscopmce, + /// + Sscopmce, - /// - Iplt, + /// + Iplt, - /// - Sps, + /// + Sps, - /// - Pipe, + /// + Pipe, - /// - Sctp, + /// + Sctp, - /// - Fc, + /// + Fc, - /// - RsvpE2eIgnore, + /// + RsvpE2eIgnore, - /// - MobilityHeader, + /// + MobilityHeader, - /// - UdpLite, + /// + UdpLite, - /// - MplsInIp, + /// + MplsInIp, - /// - Manet, + /// + Manet, - /// - Hip, + /// + Hip, - /// - Shim6, + /// + Shim6, - /// - Wesp, + /// + Wesp, - /// - Rohc, + /// + Rohc, - /// - Test1, + /// + Test1, - /// - Test2, + /// + Test2, - /// - Unknown(u8), + /// + Unknown(u8), } impl From for Protocol { - fn from(value: u8) -> Protocol { - use self::Protocol::*; - - match value { - 0 => Hopopt, - 1 => Icmp, - 2 => Igmp, - 3 => Ggp, - 4 => Ipv4, - 5 => St, - 6 => Tcp, - 7 => Cbt, - 8 => Egp, - 9 => Igp, - 10 => BbnRccMon, - 11 => NvpII, - 12 => Pup, - 13 => Argus, - 14 => Emcon, - 15 => Xnet, - 16 => Chaos, - 17 => Udp, - 18 => Mux, - 19 => DcnMeas, - 20 => Hmp, - 21 => Prm, - 22 => XnsIdp, - 23 => Trunk1, - 24 => Trunk2, - 25 => Leaf1, - 26 => Leaf2, - 27 => Rdp, - 28 => Irtp, - 29 => IsoTp4, - 30 => Netblt, - 31 => MfeNsp, - 32 => MeritInp, - 33 => Dccp, - 34 => ThreePc, - 35 => Idpr, - 36 => Xtp, - 37 => Ddp, - 38 => IdprCmtp, - 39 => TpPlusPlus, - 40 => Il, - 41 => Ipv6, - 42 => Sdrp, - 43 => Ipv6Route, - 44 => Ipv6Frag, - 45 => Idrp, - 46 => Rsvp, - 47 => Gre, - 48 => Dsr, - 49 => Bna, - 50 => Esp, - 51 => Ah, - 52 => INlsp, - 53 => Swipe, - 54 => Narp, - 55 => Mobile, - 56 => Tlsp, - 57 => Skip, - 58 => Ipv6Icmp, - 59 => Ipv6NoNxt, - 60 => Ipv6Opts, - 61 => HostInternal, - 62 => Cftp, - 63 => LocalNetwork, - 64 => SatExpak, - 65 => Kryptolan, - 66 => Rvd, - 67 => Ippc, - 68 => DistributedFs, - 69 => SatMon, - 70 => Visa, - 71 => Ipcv, - 72 => Cpnx, - 73 => Cphb, - 74 => Wsn, - 75 => Pvp, - 76 => BrSatMon, - 77 => SunNd, - 78 => WbMon, - 79 => WbExpak, - 80 => IsoIp, - 81 => Vmtp, - 82 => SecureVmtp, - 83 => Vines, - 84 => TtpOrIptm, - 85 => NsfnetIgp, - 86 => Dgp, - 87 => Tcf, - 88 => Eigrp, - 89 => OspfigP, - 90 => SpriteRpc, - 91 => Larp, - 92 => Mtp, - 93 => Ax25, - 94 => IpIp, - 95 => Micp, - 96 => SccSp, - 97 => Etherip, - 98 => Encap, - 99 => PrivEncryption, - 100 => Gmtp, - 101 => Ifmp, - 102 => Pnni, - 103 => Pim, - 104 => Aris, - 105 => Scps, - 106 => Qnx, - 107 => AN, - 108 => IpComp, - 109 => Snp, - 110 => CompaqPeer, - 111 => IpxInIp, - 112 => Vrrp, - 113 => Pgm, - 114 => ZeroHop, - 115 => L2tp, - 116 => Ddx, - 117 => Iatp, - 118 => Stp, - 119 => Srp, - 120 => Uti, - 121 => Smp, - 122 => Sm, - 123 => Ptp, - 124 => IsisOverIpv4, - 125 => Fire, - 126 => Crtp, - 127 => Crudp, - 128 => Sscopmce, - 129 => Iplt, - 130 => Sps, - 131 => Pipe, - 132 => Sctp, - 133 => Fc, - 134 => RsvpE2eIgnore, - 135 => MobilityHeader, - 136 => UdpLite, - 137 => MplsInIp, - 138 => Manet, - 139 => Hip, - 140 => Shim6, - 141 => Wesp, - 142 => Rohc, - 253 => Test1, - 254 => Test2, - p => Unknown(p), - } - } + fn from(value: u8) -> Protocol { + use self::Protocol::*; + + match value { + 0 => Hopopt, + 1 => Icmp, + 2 => Igmp, + 3 => Ggp, + 4 => Ipv4, + 5 => St, + 6 => Tcp, + 7 => Cbt, + 8 => Egp, + 9 => Igp, + 10 => BbnRccMon, + 11 => NvpII, + 12 => Pup, + 13 => Argus, + 14 => Emcon, + 15 => Xnet, + 16 => Chaos, + 17 => Udp, + 18 => Mux, + 19 => DcnMeas, + 20 => Hmp, + 21 => Prm, + 22 => XnsIdp, + 23 => Trunk1, + 24 => Trunk2, + 25 => Leaf1, + 26 => Leaf2, + 27 => Rdp, + 28 => Irtp, + 29 => IsoTp4, + 30 => Netblt, + 31 => MfeNsp, + 32 => MeritInp, + 33 => Dccp, + 34 => ThreePc, + 35 => Idpr, + 36 => Xtp, + 37 => Ddp, + 38 => IdprCmtp, + 39 => TpPlusPlus, + 40 => Il, + 41 => Ipv6, + 42 => Sdrp, + 43 => Ipv6Route, + 44 => Ipv6Frag, + 45 => Idrp, + 46 => Rsvp, + 47 => Gre, + 48 => Dsr, + 49 => Bna, + 50 => Esp, + 51 => Ah, + 52 => INlsp, + 53 => Swipe, + 54 => Narp, + 55 => Mobile, + 56 => Tlsp, + 57 => Skip, + 58 => Ipv6Icmp, + 59 => Ipv6NoNxt, + 60 => Ipv6Opts, + 61 => HostInternal, + 62 => Cftp, + 63 => LocalNetwork, + 64 => SatExpak, + 65 => Kryptolan, + 66 => Rvd, + 67 => Ippc, + 68 => DistributedFs, + 69 => SatMon, + 70 => Visa, + 71 => Ipcv, + 72 => Cpnx, + 73 => Cphb, + 74 => Wsn, + 75 => Pvp, + 76 => BrSatMon, + 77 => SunNd, + 78 => WbMon, + 79 => WbExpak, + 80 => IsoIp, + 81 => Vmtp, + 82 => SecureVmtp, + 83 => Vines, + 84 => TtpOrIptm, + 85 => NsfnetIgp, + 86 => Dgp, + 87 => Tcf, + 88 => Eigrp, + 89 => OspfigP, + 90 => SpriteRpc, + 91 => Larp, + 92 => Mtp, + 93 => Ax25, + 94 => IpIp, + 95 => Micp, + 96 => SccSp, + 97 => Etherip, + 98 => Encap, + 99 => PrivEncryption, + 100 => Gmtp, + 101 => Ifmp, + 102 => Pnni, + 103 => Pim, + 104 => Aris, + 105 => Scps, + 106 => Qnx, + 107 => AN, + 108 => IpComp, + 109 => Snp, + 110 => CompaqPeer, + 111 => IpxInIp, + 112 => Vrrp, + 113 => Pgm, + 114 => ZeroHop, + 115 => L2tp, + 116 => Ddx, + 117 => Iatp, + 118 => Stp, + 119 => Srp, + 120 => Uti, + 121 => Smp, + 122 => Sm, + 123 => Ptp, + 124 => IsisOverIpv4, + 125 => Fire, + 126 => Crtp, + 127 => Crudp, + 128 => Sscopmce, + 129 => Iplt, + 130 => Sps, + 131 => Pipe, + 132 => Sctp, + 133 => Fc, + 134 => RsvpE2eIgnore, + 135 => MobilityHeader, + 136 => UdpLite, + 137 => MplsInIp, + 138 => Manet, + 139 => Hip, + 140 => Shim6, + 141 => Wesp, + 142 => Rohc, + 253 => Test1, + 254 => Test2, + p => Unknown(p), + } + } } -impl Into for Protocol { - fn into(self) -> u8 { - use self::Protocol::*; - - match self { - Hopopt => 0, - Icmp => 1, - Igmp => 2, - Ggp => 3, - Ipv4 => 4, - St => 5, - Tcp => 6, - Cbt => 7, - Egp => 8, - Igp => 9, - BbnRccMon => 10, - NvpII => 11, - Pup => 12, - Argus => 13, - Emcon => 14, - Xnet => 15, - Chaos => 16, - Udp => 17, - Mux => 18, - DcnMeas => 19, - Hmp => 20, - Prm => 21, - XnsIdp => 22, - Trunk1 => 23, - Trunk2 => 24, - Leaf1 => 25, - Leaf2 => 26, - Rdp => 27, - Irtp => 28, - IsoTp4 => 29, - Netblt => 30, - MfeNsp => 31, - MeritInp => 32, - Dccp => 33, - ThreePc => 34, - Idpr => 35, - Xtp => 36, - Ddp => 37, - IdprCmtp => 38, - TpPlusPlus => 39, - Il => 40, - Ipv6 => 41, - Sdrp => 42, - Ipv6Route => 43, - Ipv6Frag => 44, - Idrp => 45, - Rsvp => 46, - Gre => 47, - Dsr => 48, - Bna => 49, - Esp => 50, - Ah => 51, - INlsp => 52, - Swipe => 53, - Narp => 54, - Mobile => 55, - Tlsp => 56, - Skip => 57, - Ipv6Icmp => 58, - Ipv6NoNxt => 59, - Ipv6Opts => 60, - HostInternal => 61, - Cftp => 62, - LocalNetwork => 63, - SatExpak => 64, - Kryptolan => 65, - Rvd => 66, - Ippc => 67, - DistributedFs => 68, - SatMon => 69, - Visa => 70, - Ipcv => 71, - Cpnx => 72, - Cphb => 73, - Wsn => 74, - Pvp => 75, - BrSatMon => 76, - SunNd => 77, - WbMon => 78, - WbExpak => 79, - IsoIp => 80, - Vmtp => 81, - SecureVmtp => 82, - Vines => 83, - TtpOrIptm => 84, - NsfnetIgp => 85, - Dgp => 86, - Tcf => 87, - Eigrp => 88, - OspfigP => 89, - SpriteRpc => 90, - Larp => 91, - Mtp => 92, - Ax25 => 93, - IpIp => 94, - Micp => 95, - SccSp => 96, - Etherip => 97, - Encap => 98, - PrivEncryption => 99, - Gmtp => 100, - Ifmp => 101, - Pnni => 102, - Pim => 103, - Aris => 104, - Scps => 105, - Qnx => 106, - AN => 107, - IpComp => 108, - Snp => 109, - CompaqPeer => 110, - IpxInIp => 111, - Vrrp => 112, - Pgm => 113, - ZeroHop => 114, - L2tp => 115, - Ddx => 116, - Iatp => 117, - Stp => 118, - Srp => 119, - Uti => 120, - Smp => 121, - Sm => 122, - Ptp => 123, - IsisOverIpv4 => 124, - Fire => 125, - Crtp => 126, - Crudp => 127, - Sscopmce => 128, - Iplt => 129, - Sps => 130, - Pipe => 131, - Sctp => 132, - Fc => 133, - RsvpE2eIgnore => 134, - MobilityHeader => 135, - UdpLite => 136, - MplsInIp => 137, - Manet => 138, - Hip => 139, - Shim6 => 140, - Wesp => 141, - Rohc => 142, - Test1 => 253, - Test2 => 254, - Unknown(p) => p, - } - } +impl From for u8 { + fn from(val: Protocol) -> Self { + use self::Protocol::*; + + match val { + Hopopt => 0, + Icmp => 1, + Igmp => 2, + Ggp => 3, + Ipv4 => 4, + St => 5, + Tcp => 6, + Cbt => 7, + Egp => 8, + Igp => 9, + BbnRccMon => 10, + NvpII => 11, + Pup => 12, + Argus => 13, + Emcon => 14, + Xnet => 15, + Chaos => 16, + Udp => 17, + Mux => 18, + DcnMeas => 19, + Hmp => 20, + Prm => 21, + XnsIdp => 22, + Trunk1 => 23, + Trunk2 => 24, + Leaf1 => 25, + Leaf2 => 26, + Rdp => 27, + Irtp => 28, + IsoTp4 => 29, + Netblt => 30, + MfeNsp => 31, + MeritInp => 32, + Dccp => 33, + ThreePc => 34, + Idpr => 35, + Xtp => 36, + Ddp => 37, + IdprCmtp => 38, + TpPlusPlus => 39, + Il => 40, + Ipv6 => 41, + Sdrp => 42, + Ipv6Route => 43, + Ipv6Frag => 44, + Idrp => 45, + Rsvp => 46, + Gre => 47, + Dsr => 48, + Bna => 49, + Esp => 50, + Ah => 51, + INlsp => 52, + Swipe => 53, + Narp => 54, + Mobile => 55, + Tlsp => 56, + Skip => 57, + Ipv6Icmp => 58, + Ipv6NoNxt => 59, + Ipv6Opts => 60, + HostInternal => 61, + Cftp => 62, + LocalNetwork => 63, + SatExpak => 64, + Kryptolan => 65, + Rvd => 66, + Ippc => 67, + DistributedFs => 68, + SatMon => 69, + Visa => 70, + Ipcv => 71, + Cpnx => 72, + Cphb => 73, + Wsn => 74, + Pvp => 75, + BrSatMon => 76, + SunNd => 77, + WbMon => 78, + WbExpak => 79, + IsoIp => 80, + Vmtp => 81, + SecureVmtp => 82, + Vines => 83, + TtpOrIptm => 84, + NsfnetIgp => 85, + Dgp => 86, + Tcf => 87, + Eigrp => 88, + OspfigP => 89, + SpriteRpc => 90, + Larp => 91, + Mtp => 92, + Ax25 => 93, + IpIp => 94, + Micp => 95, + SccSp => 96, + Etherip => 97, + Encap => 98, + PrivEncryption => 99, + Gmtp => 100, + Ifmp => 101, + Pnni => 102, + Pim => 103, + Aris => 104, + Scps => 105, + Qnx => 106, + AN => 107, + IpComp => 108, + Snp => 109, + CompaqPeer => 110, + IpxInIp => 111, + Vrrp => 112, + Pgm => 113, + ZeroHop => 114, + L2tp => 115, + Ddx => 116, + Iatp => 117, + Stp => 118, + Srp => 119, + Uti => 120, + Smp => 121, + Sm => 122, + Ptp => 123, + IsisOverIpv4 => 124, + Fire => 125, + Crtp => 126, + Crudp => 127, + Sscopmce => 128, + Iplt => 129, + Sps => 130, + Pipe => 131, + Sctp => 132, + Fc => 133, + RsvpE2eIgnore => 134, + MobilityHeader => 135, + UdpLite => 136, + MplsInIp => 137, + Manet => 138, + Hip => 139, + Shim6 => 140, + Wesp => 141, + Rohc => 142, + Test1 => 253, + Test2 => 254, + Unknown(p) => p, + } + } } diff --git a/src/ip/v4/builder.rs b/src/ip/v4/builder.rs index 736627b..125578d 100644 --- a/src/ip/v4/builder.rs +++ b/src/ip/v4/builder.rs @@ -12,80 +12,81 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, WriteBytesExt}; use std::io::Cursor; use std::net::Ipv4Addr; -use byteorder::{WriteBytesExt, BigEndian}; -use crate::error::*; use crate::buffer::{self, Buffer}; use crate::builder::{Builder as Build, Finalization}; -use crate::packet::{AsPacket, AsPacketMut}; -use crate::ip::Protocol; -use crate::ip::v4::Packet; -use crate::ip::v4::Flags; +use crate::error::*; use crate::ip::v4::checksum; +use crate::ip::v4::Flags; +use crate::ip::v4::Packet; +use crate::ip::Protocol; +use crate::packet::{AsPacket, AsPacketMut}; /// IPv4 packet builder. +#[allow(dead_code)] #[derive(Debug)] pub struct Builder { - buffer: B, - finalizer: Finalization, + buffer: B, + finalizer: Finalization, - options: bool, - payload: bool, + options: bool, + payload: bool, } impl Build for Builder { - fn with(mut buffer: B) -> Result { - use crate::size::header::Min; - buffer.next(Packet::<()>::min())?; - - // Set version to 4 and header length to the minimum. - // - // XXX: This is needed for shit to work. The builder uses setters on the - // `ip::v4::Packet` which expect the header length to be set. While the TCP - // and UDP builders base their finalizer on extracting the parent IP - // packet. - buffer.data_mut()[0] = (4 << 4) | ((Packet::<()>::min() / 4) as u8); - - Ok(Builder { - buffer: buffer, - finalizer: Default::default(), - - options: false, - payload: false, - }) - } - - fn finalizer(&mut self) -> &mut Finalization { - &mut self.finalizer - } - - fn build(mut self) -> Result { - self.prepare(); - - let mut buffer = self.buffer.into_inner(); - self.finalizer.finalize(buffer.as_mut())?; - Ok(buffer) - } + fn with(mut buffer: B) -> Result { + use crate::size::header::Min; + buffer.next(Packet::<()>::min())?; + + // Set version to 4 and header length to the minimum. + // + // XXX: This is needed for shit to work. The builder uses setters on the + // `ip::v4::Packet` which expect the header length to be set. While the TCP + // and UDP builders base their finalizer on extracting the parent IP + // packet. + buffer.data_mut()[0] = (4 << 4) | ((Packet::<()>::min() / 4) as u8); + + Ok(Builder { + buffer, + finalizer: Default::default(), + + options: false, + payload: false, + }) + } + + fn finalizer(&mut self) -> &mut Finalization { + &mut self.finalizer + } + + fn build(mut self) -> Result { + self.prepare(); + + let mut buffer = self.buffer.into_inner(); + self.finalizer.finalize(buffer.as_mut())?; + Ok(buffer) + } } impl Default for Builder { - fn default() -> Self { - Builder::with(buffer::Dynamic::default()).unwrap() - } + fn default() -> Self { + Builder::with(buffer::Dynamic::default()).unwrap() + } } impl<'a, B: Buffer> AsPacket<'a, Packet<&'a [u8]>> for Builder { - fn as_packet(&self) -> Result> { - Packet::new(self.buffer.data()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.buffer.data()) + } } impl<'a, B: Buffer> AsPacketMut<'a, Packet<&'a mut [u8]>> for Builder { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.buffer.data_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.buffer.data_mut()) + } } macro_rules! protocol { @@ -108,163 +109,188 @@ macro_rules! protocol { } impl Builder { - /// Differentiated Services Code Point. - pub fn dscp(mut self, value: u8) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_dscp(value)?; - Ok(self) - } - - /// Explicit Congestion Notification. - pub fn ecn(mut self, value: u8) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_ecn(value)?; - Ok(self) - } - - /// Packet ID. - pub fn id(mut self, value: u16) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_id(value)?; - Ok(self) - } - - /// Packet flags. - pub fn flags(mut self, value: Flags) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_flags(value)?; - Ok(self) - } - - /// Packet fragment offset. - pub fn offset(mut self, value: u16) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_offset(value)?; - Ok(self) - } - - /// Time to Live. - pub fn ttl(mut self, value: u8) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_ttl(value)?; - Ok(self) - } - - /// Source address. - pub fn source(mut self, value: Ipv4Addr) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_source(value)?; - Ok(self) - } - - /// Destination address. - pub fn destination(mut self, value: Ipv4Addr) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_destination(value)?; - Ok(self) - } - - /// Inner protocol. - pub fn protocol(mut self, value: Protocol) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_protocol(value)?; - Ok(self) - } - - /// Payload for the packet. - pub fn payload<'a, T: IntoIterator>(mut self, value: T) -> Result { - if self.payload { - Err(Error::AlreadyDefined)? - } - - self.payload = true; - - for byte in value { - self.buffer.more(1)?; - *self.buffer.data_mut().last_mut().unwrap() = *byte; - } - - Ok(self) - } - - fn prepare(&mut self) { - let offset = self.buffer.offset(); - let length = self.buffer.length(); - - self.finalizer.add(move |out| { - // Set the version to 4 and the header length. - let header = length / 4; - out[offset] = (4 << 4) | header as u8; - - // Calculate and write the total length of the packet. - let length = length + (out.len() - (offset + length)); - Cursor::new(&mut out[offset + 2 ..]) - .write_u16::(length as u16)?; - - // Calculate and write the checksum. - let checksum = checksum(&out[offset .. offset + header * 4]); - Cursor::new(&mut out[offset + 10 ..]) - .write_u16::(checksum)?; - - Ok(()) - }); - } - - protocol!(/// Build an ICMP packet. + /// Differentiated Services Code Point. + pub fn dscp(mut self, value: u8) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_dscp(value)?; + Ok(self) + } + + /// Explicit Congestion Notification. + pub fn ecn(mut self, value: u8) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_ecn(value)?; + Ok(self) + } + + /// Packet ID. + pub fn id(mut self, value: u16) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_id(value)?; + Ok(self) + } + + /// Packet flags. + pub fn flags(mut self, value: Flags) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_flags(value)?; + Ok(self) + } + + /// Packet fragment offset. + pub fn offset(mut self, value: u16) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_offset(value)?; + Ok(self) + } + + /// Time to Live. + pub fn ttl(mut self, value: u8) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_ttl(value)?; + Ok(self) + } + + /// Source address. + pub fn source(mut self, value: Ipv4Addr) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_source(value)?; + Ok(self) + } + + /// Destination address. + pub fn destination(mut self, value: Ipv4Addr) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_destination(value)?; + Ok(self) + } + + /// Inner protocol. + pub fn protocol(mut self, value: Protocol) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_protocol(value)?; + Ok(self) + } + + /// Payload for the packet. + pub fn payload<'a, T: IntoIterator>(mut self, value: T) -> Result { + if self.payload { + Err(Error::AlreadyDefined)? + } + + self.payload = true; + + for byte in value { + self.buffer.more(1)?; + *self.buffer.data_mut().last_mut().unwrap() = *byte; + } + + Ok(self) + } + + fn prepare(&mut self) { + let offset = self.buffer.offset(); + let length = self.buffer.length(); + + self.finalizer.add(move |out| { + // Set the version to 4 and the header length. + let header = length / 4; + out[offset] = (4 << 4) | header as u8; + + // Calculate and write the total length of the packet. + let length = length + (out.len() - (offset + length)); + Cursor::new(&mut out[offset + 2..]).write_u16::(length as u16)?; + + // Calculate and write the checksum. + let checksum = checksum(&out[offset..offset + header * 4]); + Cursor::new(&mut out[offset + 10..]).write_u16::(checksum)?; + + Ok(()) + }); + } + + protocol!(/// Build an ICMP packet. fn icmp(Icmp)); - protocol!(/// Build a TCP packet. + protocol!(/// Build a TCP packet. fn tcp(Tcp)); - protocol!(/// Build a UDP packet. + protocol!(/// Build a UDP packet. fn udp(Udp)); } #[cfg(test)] mod test { - use std::net::Ipv4Addr; - use crate::builder::Builder; - use crate::ip; - use crate::tcp; - - #[test] - fn icmp() { - let packet = ip::v4::Builder::default() - .id(0x2d87).unwrap() - .ttl(64).unwrap() - .source("66.102.1.108".parse().unwrap()).unwrap() - .destination("192.168.0.79".parse().unwrap()).unwrap() - .icmp().unwrap() - .echo().unwrap().request().unwrap() - .identifier(42).unwrap() - .sequence(2).unwrap() - .payload(b"test").unwrap() - .build().unwrap(); - - let packet = ip::v4::Packet::new(packet).unwrap(); - - assert_eq!(packet.id(), 0x2d87); - assert!(packet.flags().is_empty()); - assert_eq!(packet.length(), 32); - assert_eq!(packet.ttl(), 64); - assert_eq!(packet.protocol(), ip::Protocol::Icmp); - assert_eq!(packet.source(), "66.102.1.108".parse::().unwrap()); - assert_eq!(packet.destination(), "192.168.0.79".parse::().unwrap()); - assert!(packet.is_valid()); - } - - #[test] - fn tcp() { - let packet = ip::v4::Builder::default() - .id(0x2d87).unwrap() - .ttl(64).unwrap() - .source("66.102.1.108".parse().unwrap()).unwrap() - .destination("192.168.0.79".parse().unwrap()).unwrap() - .tcp().unwrap() - .source(1337).unwrap() - .destination(9001).unwrap() - .flags(tcp::flag::SYN).unwrap() - .build().unwrap(); - - let packet = ip::v4::Packet::new(packet).unwrap(); - assert_eq!(packet.id(), 0x2d87); - assert!(packet.flags().is_empty()); - assert_eq!(packet.length(), 40); - assert_eq!(packet.ttl(), 64); - assert_eq!(packet.protocol(), ip::Protocol::Tcp); - assert_eq!(packet.source(), "66.102.1.108".parse::().unwrap()); - assert_eq!(packet.destination(), "192.168.0.79".parse::().unwrap()); - assert!(packet.is_valid()); - } + use crate::builder::Builder; + use crate::ip; + use crate::tcp; + use std::net::Ipv4Addr; + + #[test] + fn icmp() { + let packet = ip::v4::Builder::default() + .id(0x2d87) + .unwrap() + .ttl(64) + .unwrap() + .source("66.102.1.108".parse().unwrap()) + .unwrap() + .destination("192.168.0.79".parse().unwrap()) + .unwrap() + .icmp() + .unwrap() + .echo() + .unwrap() + .request() + .unwrap() + .identifier(42) + .unwrap() + .sequence(2) + .unwrap() + .payload(b"test") + .unwrap() + .build() + .unwrap(); + + let packet = ip::v4::Packet::new(packet).unwrap(); + + assert_eq!(packet.id(), 0x2d87); + assert!(packet.flags().is_empty()); + assert_eq!(packet.length(), 32); + assert_eq!(packet.ttl(), 64); + assert_eq!(packet.protocol(), ip::Protocol::Icmp); + assert_eq!(packet.source(), "66.102.1.108".parse::().unwrap()); + assert_eq!( + packet.destination(), + "192.168.0.79".parse::().unwrap() + ); + assert!(packet.is_valid()); + } + + #[test] + fn tcp() { + let packet = ip::v4::Builder::default() + .id(0x2d87) + .unwrap() + .ttl(64) + .unwrap() + .source("66.102.1.108".parse().unwrap()) + .unwrap() + .destination("192.168.0.79".parse().unwrap()) + .unwrap() + .tcp() + .unwrap() + .source(1337) + .unwrap() + .destination(9001) + .unwrap() + .flags(tcp::flag::SYN) + .unwrap() + .build() + .unwrap(); + + let packet = ip::v4::Packet::new(packet).unwrap(); + assert_eq!(packet.id(), 0x2d87); + assert!(packet.flags().is_empty()); + assert_eq!(packet.length(), 40); + assert_eq!(packet.ttl(), 64); + assert_eq!(packet.protocol(), ip::Protocol::Tcp); + assert_eq!(packet.source(), "66.102.1.108".parse::().unwrap()); + assert_eq!( + packet.destination(), + "192.168.0.79".parse::().unwrap() + ); + assert!(packet.is_valid()); + } } diff --git a/src/ip/v4/flag.rs b/src/ip/v4/flag.rs index 5e95532..f8c7880 100644 --- a/src/ip/v4/flag.rs +++ b/src/ip/v4/flag.rs @@ -15,15 +15,16 @@ use bitflags::bitflags; bitflags! { - /// IPv4 packet flags. - pub struct Flags: u16 { - /// Do not fragment packets. - const DONT_FRAGMENT = 0b010; + /// IPv4 packet flags. + #[derive(Debug)] + pub struct Flags: u16 { + /// Do not fragment packets. + const DONT_FRAGMENT = 0b010; - /// More fragments are waiting. - const MORE_FRAGMENTS = 0b100; - } + /// More fragments are waiting. + const MORE_FRAGMENTS = 0b100; + } } -pub const DONT_FRAGMENT: Flags = Flags::DONT_FRAGMENT; +pub const DONT_FRAGMENT: Flags = Flags::DONT_FRAGMENT; pub const MORE_FRAGMENTS: Flags = Flags::MORE_FRAGMENTS; diff --git a/src/ip/v4/mod.rs b/src/ip/v4/mod.rs index 05ddd7f..2fd0d48 100644 --- a/src/ip/v4/mod.rs +++ b/src/ip/v4/mod.rs @@ -28,24 +28,24 @@ pub use self::builder::Builder; /// Calculate the checksum for an IPv4 packet. pub fn checksum(buffer: &[u8]) -> u16 { - use std::io::Cursor; - use byteorder::{ReadBytesExt, BigEndian}; + use byteorder::{BigEndian, ReadBytesExt}; + use std::io::Cursor; - let mut result = 0xffffu32; - let mut buffer = Cursor::new(buffer); + let mut result = 0xffffu32; + let mut buffer = Cursor::new(buffer); - while let Ok(value) = buffer.read_u16::() { - // Skip checksum field. - if buffer.position() == 12 { - continue; - } + while let Ok(value) = buffer.read_u16::() { + // Skip checksum field. + if buffer.position() == 12 { + continue; + } - result += u32::from(value); + result += u32::from(value); - if result > 0xffff { - result -= 0xffff; - } - } + if result > 0xffff { + result -= 0xffff; + } + } - !result as u16 + !result as u16 } diff --git a/src/ip/v4/option.rs b/src/ip/v4/option.rs index 9a21501..f335b62 100644 --- a/src/ip/v4/option.rs +++ b/src/ip/v4/option.rs @@ -15,332 +15,322 @@ use std::fmt; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; /// IPv4 Option parser. pub struct Option { - buffer: B, + buffer: B, } sized!(Option, - header { - min: 1, - max: 2, - size: p => match p.length() { - 1 => 1, - _ => 2, - }, - } - - payload { - min: 0, - max: 32, - size: p => match p.length() { - 1 => 0, - n => n as usize - 2, - }, - }); +header { + min: 1, + max: 2, + size: p => match p.length() { + 1 => 1, + _ => 2, + }, +} + +payload { + min: 0, + max: 32, + size: p => match p.length() { + 1 => 0, + n => n as usize - 2, + }, +}); /// IPv4 Option class. #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum Class { - /// - Control, + /// + Control, - /// - Debugging, + /// + Debugging, - /// - Reserved(u8), + /// + Reserved(u8), } /// IPv4 Option number. #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum Number { - /// - End, + /// + End, - /// - NoOperation, + /// + NoOperation, - /// - Security, + /// + Security, - /// - LooseSourceRoute, + /// + LooseSourceRoute, - /// - TimeStamp, + /// + TimeStamp, - /// - ExtendedSecurity, + /// + ExtendedSecurity, - /// - CommercialSecurity, + /// + CommercialSecurity, - /// - RecordRoute, + /// + RecordRoute, - /// - StreamId, + /// + StreamId, - /// - StrictSourceRoute, + /// + StrictSourceRoute, - /// - ExperimentalMeasurement, + /// + ExperimentalMeasurement, - /// - MtuProbe, + /// + MtuProbe, - /// - MtuReply, + /// + MtuReply, - /// - ExperimentalFlowControl, + /// + ExperimentalFlowControl, - /// - ExperimentalAccessControl, + /// + ExperimentalAccessControl, - /// - ImiTrafficDescriptor, + /// + ImiTrafficDescriptor, - /// - ExtendedInternetProtocol, + /// + ExtendedInternetProtocol, - /// - TraceRoute, + /// + TraceRoute, - /// - AddressExtension, + /// + AddressExtension, - /// - RouterAlert, + /// + RouterAlert, - /// - SelectiveDirectedBroadcast, + /// + SelectiveDirectedBroadcast, - /// - DynamicPacketState, + /// + DynamicPacketState, - /// - UpstreamMulticastPacket, + /// + UpstreamMulticastPacket, - /// - QuickStart, + /// + QuickStart, - /// - Unknown(u8), + /// + Unknown(u8), } impl> fmt::Debug for Option { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ip::v4::Option") - .field("is_copied", &self.is_copied()) - .field("class", &self.class()) - .field("number", &self.number()) - .field("length", &self.length()) - .field("payload", &self.payload()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ip::v4::Option") + .field("is_copied", &self.is_copied()) + .field("class", &self.class()) + .field("number", &self.number()) + .field("length", &self.length()) + .field("payload", &self.payload()) + .finish() + } } impl> Option { - /// Parse an IPv4 option, checking the buffer contents are correct. - pub fn new(buffer: B) -> Result> { - use crate::size::header::Min; + /// Parse an IPv4 option, checking the buffer contents are correct. + pub fn new(buffer: B) -> Result> { + use crate::size::header::Min; - let option = Option { - buffer: buffer, - }; + let option = Option { buffer }; - if option.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } + if option.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } - if option.buffer.as_ref().len() < option.length() as usize { - Err(Error::SmallBuffer)? - } + if option.buffer.as_ref().len() < option.length() as usize { + Err(Error::SmallBuffer)? + } - Ok(option) - } + Ok(option) + } } impl> AsRef<[u8]> for Option { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Option { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Option<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Option::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Option::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Option<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Option::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Option::new(self.as_mut()) + } } impl> P for Option { - fn split(&self) -> (&[u8], &[u8]) { - match self.length() { - 1 => - self.buffer.as_ref().split_at(1), - - length => - self.buffer.as_ref()[.. length as usize].split_at(2), - } - } + fn split(&self) -> (&[u8], &[u8]) { + match self.length() { + 1 => self.buffer.as_ref().split_at(1), + + length => self.buffer.as_ref()[..length as usize].split_at(2), + } + } } impl + AsMut<[u8]>> PM for Option { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - match self.length() { - 1 => - self.buffer.as_mut().split_at_mut(1), - - length => - self.buffer.as_mut()[.. length as usize].split_at_mut(2), - } - } -} + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + match self.length() { + 1 => self.buffer.as_mut().split_at_mut(1), + length => self.buffer.as_mut()[..length as usize].split_at_mut(2), + } + } +} impl> Option { - /// Whether the option has to be copied in fragments. - pub fn is_copied(&self) -> bool { - self.buffer.as_ref()[0] >> 7 == 1 - } - - /// Option class. - pub fn class(&self) -> Class { - match (self.buffer.as_ref()[0] >> 5) & 0b011 { - 0 => Class::Control, - 2 => Class::Debugging, - v => Class::Reserved(v), - } - } - - /// Option number. - pub fn number(&self) -> Number { - (self.buffer.as_ref()[0] & 0b11111).into() - } - - /// Packet length - pub fn length(&self) -> u8 { - match self.number() { - Number::End | - Number::NoOperation => - 1, - - _ => - self.buffer.as_ref()[1] - } - } + /// Whether the option has to be copied in fragments. + pub fn is_copied(&self) -> bool { + self.buffer.as_ref()[0] >> 7 == 1 + } + + /// Option class. + pub fn class(&self) -> Class { + match (self.buffer.as_ref()[0] >> 5) & 0b011 { + 0 => Class::Control, + 2 => Class::Debugging, + v => Class::Reserved(v), + } + } + + /// Option number. + pub fn number(&self) -> Number { + (self.buffer.as_ref()[0] & 0b11111).into() + } + + /// Packet length + pub fn length(&self) -> u8 { + match self.number() { + Number::End | Number::NoOperation => 1, + + _ => self.buffer.as_ref()[1], + } + } } impl From for Class { - fn from(value: u8) -> Self { - use self::Class::*; - - match value { - 0 => Control, - 1 => Reserved(1), - 2 => Debugging, - 3 => Reserved(3), - _ => panic!("invalid IPv4 option class"), - } - } + fn from(value: u8) -> Self { + use self::Class::*; + + match value { + 0 => Control, + 1 => Reserved(1), + 2 => Debugging, + 3 => Reserved(3), + _ => panic!("invalid IPv4 option class"), + } + } } -impl Into for Class { - fn into(self) -> u8 { - match self { - Class::Control => 0, - Class::Debugging => 2, - Class::Reserved(n) => n, - } - } +impl From for u8 { + fn from(val: Class) -> Self { + match val { + Class::Control => 0, + Class::Debugging => 2, + Class::Reserved(n) => n, + } + } } impl From for Number { - fn from(value: u8) -> Self { - use self::Number::*; - - match value { - 0 => End, - 1 => NoOperation, - 2 => Security, - 3 => LooseSourceRoute, - 4 => TimeStamp, - 5 => ExtendedSecurity, - 6 => CommercialSecurity, - 7 => RecordRoute, - 8 => StreamId, - 9 => StrictSourceRoute, - 10 => ExperimentalMeasurement, - 11 => MtuProbe, - 12 => MtuReply, - 13 => ExperimentalFlowControl, - 14 => ExperimentalAccessControl, - 16 => ImiTrafficDescriptor, - 17 => ExtendedInternetProtocol, - 18 => TraceRoute, - 19 => AddressExtension, - 20 => RouterAlert, - 21 => SelectiveDirectedBroadcast, - 23 => DynamicPacketState, - 24 => UpstreamMulticastPacket, - 25 => QuickStart, - n => Number::Unknown(n), - } - } + fn from(value: u8) -> Self { + use self::Number::*; + + match value { + 0 => End, + 1 => NoOperation, + 2 => Security, + 3 => LooseSourceRoute, + 4 => TimeStamp, + 5 => ExtendedSecurity, + 6 => CommercialSecurity, + 7 => RecordRoute, + 8 => StreamId, + 9 => StrictSourceRoute, + 10 => ExperimentalMeasurement, + 11 => MtuProbe, + 12 => MtuReply, + 13 => ExperimentalFlowControl, + 14 => ExperimentalAccessControl, + 16 => ImiTrafficDescriptor, + 17 => ExtendedInternetProtocol, + 18 => TraceRoute, + 19 => AddressExtension, + 20 => RouterAlert, + 21 => SelectiveDirectedBroadcast, + 23 => DynamicPacketState, + 24 => UpstreamMulticastPacket, + 25 => QuickStart, + n => Number::Unknown(n), + } + } } -impl Into for Number { - fn into(self) -> u8 { - use self::Number::*; - - match self { - End => 0, - NoOperation => 1, - Security => 2, - LooseSourceRoute => 3, - TimeStamp => 4, - ExtendedSecurity => 5, - CommercialSecurity => 6, - RecordRoute => 7, - StreamId => 8, - StrictSourceRoute => 9, - ExperimentalMeasurement => 10, - MtuProbe => 11, - MtuReply => 12, - ExperimentalFlowControl => 13, - ExperimentalAccessControl => 14, - ImiTrafficDescriptor => 16, - ExtendedInternetProtocol => 17, - TraceRoute => 18, - AddressExtension => 19, - RouterAlert => 20, - SelectiveDirectedBroadcast => 21, - DynamicPacketState => 23, - UpstreamMulticastPacket => 24, - QuickStart => 25, - Number::Unknown(n) => n, - } - } +impl From for u8 { + fn from(val: Number) -> Self { + use self::Number::*; + + match val { + End => 0, + NoOperation => 1, + Security => 2, + LooseSourceRoute => 3, + TimeStamp => 4, + ExtendedSecurity => 5, + CommercialSecurity => 6, + RecordRoute => 7, + StreamId => 8, + StrictSourceRoute => 9, + ExperimentalMeasurement => 10, + MtuProbe => 11, + MtuReply => 12, + ExperimentalFlowControl => 13, + ExperimentalAccessControl => 14, + ImiTrafficDescriptor => 16, + ExtendedInternetProtocol => 17, + TraceRoute => 18, + AddressExtension => 19, + RouterAlert => 20, + SelectiveDirectedBroadcast => 21, + DynamicPacketState => 23, + UpstreamMulticastPacket => 24, + QuickStart => 25, + Number::Unknown(n) => n, + } + } } diff --git a/src/ip/v4/packet.rs b/src/ip/v4/packet.rs index 8c40a25..8acc913 100644 --- a/src/ip/v4/packet.rs +++ b/src/ip/v4/packet.rs @@ -12,361 +12,373 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::fmt; use std::io::Cursor; use std::net::Ipv4Addr; -use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; -use crate::ip::Protocol; -use crate::ip::v4::Flags; -use crate::ip::v4::option; use crate::ip::v4::checksum; +use crate::ip::v4::option; +use crate::ip::v4::Flags; +use crate::ip::Protocol; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; /// IPv4 packet parser. #[derive(Copy, Clone)] pub struct Packet { - buffer: B, + buffer: B, } sized!(Packet, - header { - min: 20, - max: 60, - size: p => p.header() as usize * 4, - } - - payload { - min: 0, - max: u16::max_value() as usize - 60, - size: p => (p.length() as usize).saturating_sub(p.header() as usize * 4), - }); +header { + min: 20, + max: 60, + size: p => p.header() as usize * 4, +} + +payload { + min: 0, + max: u16::max_value() as usize - 60, + size: p => (p.length() as usize).saturating_sub(p.header() as usize * 4), +}); impl> fmt::Debug for Packet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct(if self.is_valid() { "ip::v4::Packet" } else { "ip::v4::Packet!" }) - .field("version", &self.version()) - .field("header", &self.header()) - .field("dscp", &self.dscp()) - .field("ecn", &self.ecn()) - .field("length", &self.length()) - .field("id", &self.id()) - .field("flags", &self.flags()) - .field("offset", &self.offset()) - .field("ttl", &self.ttl()) - .field("protocol", &self.protocol()) - .field("checksum", &self.checksum()) - .field("source", &self.source()) - .field("destination", &self.destination()) - .field("payload", &self.payload()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(if self.is_valid() { + "ip::v4::Packet" + } else { + "ip::v4::Packet!" + }) + .field("version", &self.version()) + .field("header", &self.header()) + .field("dscp", &self.dscp()) + .field("ecn", &self.ecn()) + .field("length", &self.length()) + .field("id", &self.id()) + .field("flags", &self.flags()) + .field("offset", &self.offset()) + .field("ttl", &self.ttl()) + .field("protocol", &self.protocol()) + .field("checksum", &self.checksum()) + .field("source", &self.source()) + .field("destination", &self.destination()) + .field("payload", &self.payload()) + .finish() + } } impl> Packet { - /// Create an IPv4 packet without checking the buffer. - pub fn unchecked(buffer: B) -> Packet { - Packet { buffer } - } + /// Create an IPv4 packet without checking the buffer. + pub fn unchecked(buffer: B) -> Packet { + Packet { buffer } + } - /// Parse an IPv4 packet without checking the payload. - pub fn no_payload(buffer: B) -> Result> { - use crate::size::header::Min; + /// Parse an IPv4 packet without checking the payload. + pub fn no_payload(buffer: B) -> Result> { + use crate::size::header::Min; - let packet = Packet::unchecked(buffer); + let packet = Packet::unchecked(buffer); - if packet.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } - if packet.buffer.as_ref()[0] >> 4 != 4 { - Err(Error::InvalidPacket)? - } + if packet.buffer.as_ref()[0] >> 4 != 4 { + Err(Error::InvalidPacket)? + } - if packet.buffer.as_ref().len() < packet.header() as usize * 4 { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < packet.header() as usize * 4 { + Err(Error::SmallBuffer)? + } - Ok(packet) - } + Ok(packet) + } - /// Parse an IPv4 packet, checking the buffer contents are correct. - pub fn new(buffer: B) -> Result> { - let packet = Packet::no_payload(buffer)?; + /// Parse an IPv4 packet, checking the buffer contents are correct. + pub fn new(buffer: B) -> Result> { + let packet = Packet::no_payload(buffer)?; - if packet.buffer.as_ref().len() < packet.length() as usize { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < packet.length() as usize { + Err(Error::SmallBuffer)? + } - Ok(packet) - } + Ok(packet) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - Packet::unchecked(self.buffer.as_ref().to_vec()) - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + Packet::unchecked(self.buffer.as_ref().to_vec()) + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - use crate::size::payload::Size; - - let header = self.header() as usize * 4; - let payload = self.size(); - - let buffer = self.buffer.as_ref(); - let buffer = if buffer.len() < header + payload { - buffer - } - else { - &buffer[.. header + payload] - }; - - buffer.split_at(header) - } + fn split(&self) -> (&[u8], &[u8]) { + use crate::size::payload::Size; + + let header = self.header() as usize * 4; + let payload = self.size(); + + let buffer = self.buffer.as_ref(); + let buffer = if buffer.len() < header + payload { + buffer + } else { + &buffer[..header + payload] + }; + + buffer.split_at(header) + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - use crate::size::payload::Size; - - let header = self.header() as usize * 4; - let payload = self.size(); - - let buffer = self.buffer.as_mut(); - let buffer = if buffer.len() < header + payload { - buffer - } - else { - &mut buffer[.. header + payload] - }; - - buffer.split_at_mut(header) - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + use crate::size::payload::Size; + + let header = self.header() as usize * 4; + let payload = self.size(); + + let buffer = self.buffer.as_mut(); + let buffer = if buffer.len() < header + payload { + buffer + } else { + &mut buffer[..header + payload] + }; + + buffer.split_at_mut(header) + } } impl> Packet { - /// IP protocol version, will always be 4. - pub fn version(&self) -> u8 { - self.buffer.as_ref()[0] >> 4 - } - - /// Length of the IPv4 header in 32 bit words. - pub fn header(&self) -> u8 { - self.buffer.as_ref()[0] & 0b1111 - } - - /// DSCP value. - pub fn dscp(&self) -> u8 { - self.buffer.as_ref()[1] >> 2 - } - - /// ECN value. - pub fn ecn(&self) -> u8 { - self.buffer.as_ref()[1] & 0b11 - } - - /// Total length of the packet in octets. - pub fn length(&self) -> u16 { - (&self.buffer.as_ref()[2 ..]).read_u16::().unwrap() - } - - /// ID of the packet. - pub fn id(&self) -> u16 { - (&self.buffer.as_ref()[4 ..]).read_u16::().unwrap() - } - - /// Flags of the packet. - pub fn flags(&self) -> Flags { - Flags::from_bits((&self.buffer.as_ref()[6 ..]) - .read_u16::().unwrap() >> 13).unwrap() - } - - /// Offset of the packet. - pub fn offset(&self) -> u16 { - (&self.buffer.as_ref()[6 ..]).read_u16::().unwrap() & 0x1fff - } - - /// Time to Live for the packet. - pub fn ttl(&self) -> u8 { - self.buffer.as_ref()[8] - } - - /// Protocol of the inner packet. - pub fn protocol(&self) -> Protocol { - self.buffer.as_ref()[9].into() - } - - /// Checksum of the packet. - pub fn checksum(&self) -> u16 { - (&self.buffer.as_ref()[10 ..]).read_u16::().unwrap() - } - - /// Verify the packet is valid by calculating the checksum. - pub fn is_valid(&self) -> bool { - checksum(P::header(self)) == self.checksum() - } - - /// Source IP address. - pub fn source(&self) -> Ipv4Addr { - Ipv4Addr::new( - self.buffer.as_ref()[12], - self.buffer.as_ref()[13], - self.buffer.as_ref()[14], - self.buffer.as_ref()[15]) - } - - /// Destination IP address. - pub fn destination(&self) -> Ipv4Addr { - Ipv4Addr::new( - self.buffer.as_ref()[16], - self.buffer.as_ref()[17], - self.buffer.as_ref()[18], - self.buffer.as_ref()[19]) - } - - /// IP options for the packet. - pub fn options(&self) -> OptionIter<'_> { - OptionIter { - buffer: &self.buffer.as_ref()[20 .. (self.header() as usize * 4)], - } - } + /// IP protocol version, will always be 4. + pub fn version(&self) -> u8 { + self.buffer.as_ref()[0] >> 4 + } + + /// Length of the IPv4 header in 32 bit words. + pub fn header(&self) -> u8 { + self.buffer.as_ref()[0] & 0b1111 + } + + /// DSCP value. + pub fn dscp(&self) -> u8 { + self.buffer.as_ref()[1] >> 2 + } + + /// ECN value. + pub fn ecn(&self) -> u8 { + self.buffer.as_ref()[1] & 0b11 + } + + /// Total length of the packet in octets. + pub fn length(&self) -> u16 { + (&self.buffer.as_ref()[2..]) + .read_u16::() + .unwrap() + } + + /// ID of the packet. + pub fn id(&self) -> u16 { + (&self.buffer.as_ref()[4..]) + .read_u16::() + .unwrap() + } + + /// Flags of the packet. + pub fn flags(&self) -> Flags { + Flags::from_bits( + (&self.buffer.as_ref()[6..]) + .read_u16::() + .unwrap() + >> 13, + ) + .unwrap() + } + + /// Offset of the packet. + pub fn offset(&self) -> u16 { + (&self.buffer.as_ref()[6..]) + .read_u16::() + .unwrap() + & 0x1fff + } + + /// Time to Live for the packet. + pub fn ttl(&self) -> u8 { + self.buffer.as_ref()[8] + } + + /// Protocol of the inner packet. + pub fn protocol(&self) -> Protocol { + self.buffer.as_ref()[9].into() + } + + /// Checksum of the packet. + pub fn checksum(&self) -> u16 { + (&self.buffer.as_ref()[10..]) + .read_u16::() + .unwrap() + } + + /// Verify the packet is valid by calculating the checksum. + pub fn is_valid(&self) -> bool { + checksum(P::header(self)) == self.checksum() + } + + /// Source IP address. + pub fn source(&self) -> Ipv4Addr { + Ipv4Addr::new( + self.buffer.as_ref()[12], + self.buffer.as_ref()[13], + self.buffer.as_ref()[14], + self.buffer.as_ref()[15], + ) + } + + /// Destination IP address. + pub fn destination(&self) -> Ipv4Addr { + Ipv4Addr::new( + self.buffer.as_ref()[16], + self.buffer.as_ref()[17], + self.buffer.as_ref()[18], + self.buffer.as_ref()[19], + ) + } + + /// IP options for the packet. + pub fn options(&self) -> OptionIter<'_> { + OptionIter { + buffer: &self.buffer.as_ref()[20..(self.header() as usize * 4)], + } + } } impl + AsMut<[u8]>> Packet { - /// Differentiated Services Code Point. - pub fn set_dscp(&mut self, value: u8) -> Result<&mut Self> { - if value > 0b11_1111 { - Err(Error::InvalidValue)? - } - - let old = self.buffer.as_ref()[1]; - self.buffer.as_mut()[1] = (old & 0b11) | value << 2; - - Ok(self) - } - - /// Explicit Congestion Notification. - pub fn set_ecn(&mut self, value: u8) -> Result<&mut Self> { - if value > 0b11 { - Err(Error::InvalidValue)? - } - - let old = self.buffer.as_ref()[1]; - self.buffer.as_mut()[1] = (old & 0b11_1111) | value; - - Ok(self) - } - - /// Packet ID. - pub fn set_id(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.buffer.as_mut()[4 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Packet flags. - pub fn set_flags(&mut self, value: Flags) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[6 ..]) - .write_u16::(value.bits())?; - - Ok(self) - } - - /// Packet fragment offset. - pub fn set_offset(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[6 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Time to Live. - pub fn set_ttl(&mut self, value: u8) -> Result<&mut Self> { - self.header_mut()[8] = value; - - Ok(self) - } - - /// Source address. - pub fn set_source(&mut self, value: Ipv4Addr) -> Result<&mut Self> { - self.header_mut()[12 .. 16].copy_from_slice(&value.octets()); - - Ok(self) - } - - /// Destination address. - pub fn set_destination(&mut self, value: Ipv4Addr) -> Result<&mut Self> { - self.header_mut()[16 .. 20].copy_from_slice(&value.octets()); - - Ok(self) - } - - /// Inner protocol. - pub fn set_protocol(&mut self, value: Protocol) -> Result<&mut Self> { - self.header_mut()[9] = value.into(); - - Ok(self) - } - - /// Create a checksumed setter. - pub fn checked(&mut self) -> Checked<'_, B> { - Checked { - packet: self - } - } - - /// Set the checksum value. - pub fn set_checksum(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[10 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Recalculate and set the checksum value. - pub fn update_checksum(&mut self) -> Result<&mut Self> { - let checksum = checksum(P::header(self)); - self.set_checksum(checksum) - } + /// Differentiated Services Code Point. + pub fn set_dscp(&mut self, value: u8) -> Result<&mut Self> { + if value > 0b11_1111 { + Err(Error::InvalidValue)? + } + + let old = self.buffer.as_ref()[1]; + self.buffer.as_mut()[1] = (old & 0b11) | value << 2; + + Ok(self) + } + + /// Explicit Congestion Notification. + pub fn set_ecn(&mut self, value: u8) -> Result<&mut Self> { + if value > 0b11 { + Err(Error::InvalidValue)? + } + + let old = self.buffer.as_ref()[1]; + self.buffer.as_mut()[1] = (old & 0b11_1111) | value; + + Ok(self) + } + + /// Packet ID. + pub fn set_id(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.buffer.as_mut()[4..]).write_u16::(value)?; + + Ok(self) + } + + /// Packet flags. + pub fn set_flags(&mut self, value: Flags) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[6..]).write_u16::(value.bits())?; + + Ok(self) + } + + /// Packet fragment offset. + pub fn set_offset(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[6..]).write_u16::(value)?; + + Ok(self) + } + + /// Time to Live. + pub fn set_ttl(&mut self, value: u8) -> Result<&mut Self> { + self.header_mut()[8] = value; + + Ok(self) + } + + /// Source address. + pub fn set_source(&mut self, value: Ipv4Addr) -> Result<&mut Self> { + self.header_mut()[12..16].copy_from_slice(&value.octets()); + + Ok(self) + } + + /// Destination address. + pub fn set_destination(&mut self, value: Ipv4Addr) -> Result<&mut Self> { + self.header_mut()[16..20].copy_from_slice(&value.octets()); + + Ok(self) + } + + /// Inner protocol. + pub fn set_protocol(&mut self, value: Protocol) -> Result<&mut Self> { + self.header_mut()[9] = value.into(); + + Ok(self) + } + + /// Create a checksumed setter. + pub fn checked(&mut self) -> Checked<'_, B> { + Checked { packet: self } + } + + /// Set the checksum value. + pub fn set_checksum(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[10..]).write_u16::(value)?; + + Ok(self) + } + + /// Recalculate and set the checksum value. + pub fn update_checksum(&mut self) -> Result<&mut Self> { + let checksum = checksum(P::header(self)); + self.set_checksum(checksum) + } } /// Checked wrapper for IPv4 packets. @@ -375,164 +387,178 @@ impl + AsMut<[u8]>> Packet { /// /// The checksum recalculation happens on `Drop`, so don't leak it. pub struct Checked<'a, B: AsRef<[u8]> + AsMut<[u8]>> { - packet: &'a mut Packet + packet: &'a mut Packet, } impl<'a, B: AsRef<[u8]> + AsMut<[u8]> + 'a> Checked<'a, B> { - /// Differentiated Services Code Point. - pub fn set_dscp(&mut self, value: u8) -> Result<&mut Self> { - self.packet.set_dscp(value)?; - Ok(self) - } - - /// Explicit Congestion Notification. - pub fn set_ecn(&mut self, value: u8) -> Result<&mut Self> { - self.packet.set_ecn(value)?; - Ok(self) - } - - /// Packet ID. - pub fn set_id(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_id(value)?; - Ok(self) - } - - /// Packet flags. - pub fn set_flags(&mut self, value: Flags) -> Result<&mut Self> { - self.packet.set_flags(value)?; - Ok(self) - } - - /// Packet fragment offset. - pub fn set_offset(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_offset(value)?; - Ok(self) - } - - /// Time to Live. - pub fn set_ttl(&mut self, value: u8) -> Result<&mut Self> { - self.packet.set_ttl(value)?; - Ok(self) - } - - /// Source address. - pub fn set_source(&mut self, value: Ipv4Addr) -> Result<&mut Self> { - self.packet.set_source(value)?; - Ok(self) - } - - /// Destination address. - pub fn set_destination(&mut self, value: Ipv4Addr) -> Result<&mut Self> { - self.packet.set_destination(value)?; - Ok(self) - } - - /// Inner protocol. - pub fn set_protocol(&mut self, value: Protocol) -> Result<&mut Self> { - self.packet.set_protocol(value)?; - Ok(self) - } + /// Differentiated Services Code Point. + pub fn set_dscp(&mut self, value: u8) -> Result<&mut Self> { + self.packet.set_dscp(value)?; + Ok(self) + } + + /// Explicit Congestion Notification. + pub fn set_ecn(&mut self, value: u8) -> Result<&mut Self> { + self.packet.set_ecn(value)?; + Ok(self) + } + + /// Packet ID. + pub fn set_id(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_id(value)?; + Ok(self) + } + + /// Packet flags. + pub fn set_flags(&mut self, value: Flags) -> Result<&mut Self> { + self.packet.set_flags(value)?; + Ok(self) + } + + /// Packet fragment offset. + pub fn set_offset(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_offset(value)?; + Ok(self) + } + + /// Time to Live. + pub fn set_ttl(&mut self, value: u8) -> Result<&mut Self> { + self.packet.set_ttl(value)?; + Ok(self) + } + + /// Source address. + pub fn set_source(&mut self, value: Ipv4Addr) -> Result<&mut Self> { + self.packet.set_source(value)?; + Ok(self) + } + + /// Destination address. + pub fn set_destination(&mut self, value: Ipv4Addr) -> Result<&mut Self> { + self.packet.set_destination(value)?; + Ok(self) + } + + /// Inner protocol. + pub fn set_protocol(&mut self, value: Protocol) -> Result<&mut Self> { + self.packet.set_protocol(value)?; + Ok(self) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> Drop for Checked<'a, B> { - fn drop(&mut self) { - self.packet.update_checksum().unwrap(); - } + fn drop(&mut self) { + self.packet.update_checksum().unwrap(); + } } /// Iterator over IP packet options. pub struct OptionIter<'a> { - buffer: &'a [u8], + buffer: &'a [u8], } impl<'a> Iterator for OptionIter<'a> { - type Item = Result>; + type Item = Result>; - fn next(&mut self) -> Option { - use crate::size::Size; + fn next(&mut self) -> Option { + use crate::size::Size; - if self.buffer.is_empty() { - return None; - } + if self.buffer.is_empty() { + return None; + } - match option::Option::new(self.buffer) { - Ok(option) => { - if option.number() == option::Number::End { - return None; - } + match option::Option::new(self.buffer) { + Ok(option) => { + if option.number() == option::Number::End { + return None; + } - self.buffer = &self.buffer[option.size() ..]; - Some(Ok(option)) - } + self.buffer = &self.buffer[option.size()..]; + Some(Ok(option)) + } - Err(error) => - Some(Err(error)) - } - } + Err(error) => Some(Err(error)), + } + } } #[cfg(test)] mod test { - use std::net::Ipv4Addr; - use crate::ip; - - #[test] - fn short_packet() { - assert!(ip::v4::Packet::no_payload(&[64; 10][..]).is_err()); - assert!(ip::v4::Packet::no_payload(&[64; 19][..]).is_err()); - assert!(ip::v4::Packet::no_payload(&[64; 20][..]).is_ok()); - } - - #[test] - fn values() { - let raw = [0x45u8, 0x00, 0x00, 0x34, 0x2d, 0x87, 0x00, 0x00, 0x2c, 0x06, 0x5c, 0x74, 0x42, 0x66, 0x01, 0x6c, 0xc0, 0xa8, 0x00, 0x4f]; - let ip = ip::v4::Packet::no_payload(&raw[..]).unwrap(); - - assert_eq!(ip.header(), 5); - assert_eq!(ip.length(), 52); - assert_eq!(ip.id(), 0x2d87); - assert!(ip.flags().is_empty()); - assert_eq!(ip.protocol(), ip::Protocol::Tcp); - assert_eq!(ip.checksum(), 0x5c74); - assert!(ip.is_valid()); - assert_eq!(ip.source(), "66.102.1.108".parse::().unwrap()); - assert_eq!(ip.destination(), "192.168.0.79".parse::().unwrap()); - } - - #[test] - fn owned() { - let raw: Vec = vec![0x45, 0x00, 0x00, 0x34, 0x2d, 0x87, 0x00, 0x00, 0x2c, 0x06, 0x5c, 0x74, 0x42, 0x66, 0x01, 0x6c, 0xc0, 0xa8, 0x00, 0x4f]; - let ip = ip::v4::Packet::no_payload(raw).unwrap(); - - assert_eq!(ip.checksum(), 0x5c74); - assert!(ip.is_valid()); - } - - #[test] - fn mutable() { - let mut raw = [0x45u8, 0x00, 0x00, 0x34, 0x2d, 0x87, 0x00, 0x00, 0x2c, 0x06, 0x5c, 0x74, 0x42, 0x66, 0x01, 0x6c, 0xc0, 0xa8, 0x00, 0x4f]; - let mut ip = ip::v4::Packet::no_payload(&mut raw[..]).unwrap(); - - assert_eq!(ip.id(), 0x2d87); - assert!(ip.is_valid()); - - ip.set_id(0x4242).unwrap(); - assert_eq!(ip.id(), 0x4242); - assert!(!ip.is_valid()); - - ip.update_checksum().unwrap(); - assert!(ip.is_valid()); - } - - #[test] - fn mutable_checked() { - let mut raw = [0x45u8, 0x00, 0x00, 0x34, 0x2d, 0x87, 0x00, 0x00, 0x2c, 0x06, 0x5c, 0x74, 0x42, 0x66, 0x01, 0x6c, 0xc0, 0xa8, 0x00, 0x4f]; - let mut ip = ip::v4::Packet::no_payload(&mut raw[..]).unwrap(); - - assert_eq!(ip.id(), 0x2d87); - assert!(ip.is_valid()); - - ip.checked().set_id(0x4242).unwrap(); - assert!(ip.is_valid()); - } + use crate::ip; + use std::net::Ipv4Addr; + + #[test] + fn short_packet() { + assert!(ip::v4::Packet::no_payload(&[64; 10][..]).is_err()); + assert!(ip::v4::Packet::no_payload(&[64; 19][..]).is_err()); + assert!(ip::v4::Packet::no_payload(&[64; 20][..]).is_ok()); + } + + #[test] + fn values() { + let raw = [ + 0x45u8, 0x00, 0x00, 0x34, 0x2d, 0x87, 0x00, 0x00, 0x2c, 0x06, 0x5c, 0x74, 0x42, 0x66, + 0x01, 0x6c, 0xc0, 0xa8, 0x00, 0x4f, + ]; + let ip = ip::v4::Packet::no_payload(&raw[..]).unwrap(); + + assert_eq!(ip.header(), 5); + assert_eq!(ip.length(), 52); + assert_eq!(ip.id(), 0x2d87); + assert!(ip.flags().is_empty()); + assert_eq!(ip.protocol(), ip::Protocol::Tcp); + assert_eq!(ip.checksum(), 0x5c74); + assert!(ip.is_valid()); + assert_eq!(ip.source(), "66.102.1.108".parse::().unwrap()); + assert_eq!( + ip.destination(), + "192.168.0.79".parse::().unwrap() + ); + } + + #[test] + fn owned() { + let raw: Vec = vec![ + 0x45, 0x00, 0x00, 0x34, 0x2d, 0x87, 0x00, 0x00, 0x2c, 0x06, 0x5c, 0x74, 0x42, 0x66, + 0x01, 0x6c, 0xc0, 0xa8, 0x00, 0x4f, + ]; + let ip = ip::v4::Packet::no_payload(raw).unwrap(); + + assert_eq!(ip.checksum(), 0x5c74); + assert!(ip.is_valid()); + } + + #[test] + fn mutable() { + let mut raw = [ + 0x45u8, 0x00, 0x00, 0x34, 0x2d, 0x87, 0x00, 0x00, 0x2c, 0x06, 0x5c, 0x74, 0x42, 0x66, + 0x01, 0x6c, 0xc0, 0xa8, 0x00, 0x4f, + ]; + let mut ip = ip::v4::Packet::no_payload(&mut raw[..]).unwrap(); + + assert_eq!(ip.id(), 0x2d87); + assert!(ip.is_valid()); + + ip.set_id(0x4242).unwrap(); + assert_eq!(ip.id(), 0x4242); + assert!(!ip.is_valid()); + + ip.update_checksum().unwrap(); + assert!(ip.is_valid()); + } + + #[test] + fn mutable_checked() { + let mut raw = [ + 0x45u8, 0x00, 0x00, 0x34, 0x2d, 0x87, 0x00, 0x00, 0x2c, 0x06, 0x5c, 0x74, 0x42, 0x66, + 0x01, 0x6c, 0xc0, 0xa8, 0x00, 0x4f, + ]; + let mut ip = ip::v4::Packet::no_payload(&mut raw[..]).unwrap(); + + assert_eq!(ip.id(), 0x2d87); + assert!(ip.is_valid()); + + ip.checked().set_id(0x4242).unwrap(); + assert!(ip.is_valid()); + } } diff --git a/src/ip/v6/builder.rs b/src/ip/v6/builder.rs index 4fbb708..d6f6d6d 100644 --- a/src/ip/v6/builder.rs +++ b/src/ip/v6/builder.rs @@ -12,38 +12,36 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. - - - -use crate::error::*; use crate::buffer::{self, Buffer}; use crate::builder::{Builder as Build, Finalization}; +use crate::error::*; /// IPv6 packet builder. +#[allow(dead_code)] pub struct Builder { - buffer: B, - finalizer: Finalization, + buffer: B, + finalizer: Finalization, } impl Build for Builder { - fn with(buffer: B) -> Result { - Ok(Builder { - buffer: buffer, - finalizer: Default::default(), - }) - } - - fn finalizer(&mut self) -> &mut Finalization { - &mut self.finalizer - } - - fn build(self) -> Result { - Err(Error::InvalidPacket) - } + fn with(buffer: B) -> Result { + Ok(Builder { + buffer, + finalizer: Default::default(), + }) + } + + fn finalizer(&mut self) -> &mut Finalization { + &mut self.finalizer + } + + fn build(self) -> Result { + Err(Error::InvalidPacket) + } } impl Default for Builder { - fn default() -> Self { - Builder::with(buffer::Dynamic::default()).unwrap() - } + fn default() -> Self { + Builder::with(buffer::Dynamic::default()).unwrap() + } } diff --git a/src/ip/v6/packet.rs b/src/ip/v6/packet.rs index 2a252de..5bf5079 100644 --- a/src/ip/v6/packet.rs +++ b/src/ip/v6/packet.rs @@ -12,109 +12,108 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. -use std::fmt; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; +use std::fmt; /// IPv6 packet parser. #[derive(Clone)] pub struct Packet { - buffer: B, + buffer: B, } sized!(Packet, - header { - min: 0, - max: 0, - size: 0, - } - - payload { - min: 0, - max: 0, - size: 0, - }); +header { + min: 0, + max: 0, + size: 0, +} + +payload { + min: 0, + max: 0, + size: 0, +}); impl> fmt::Debug for Packet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ip::v6::Packet") - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ip::v6::Packet").finish() + } } impl> Packet { - /// Create an IPv6 packet without checking the buffer. - pub fn unchecked(buffer: B) -> Packet { - Packet { buffer } - } + /// Create an IPv6 packet without checking the buffer. + pub fn unchecked(buffer: B) -> Packet { + Packet { buffer } + } - /// Parse an IPv6 packet without checking the payload. - pub fn no_payload(buffer: B) -> Result> { - use crate::size::header::Min; + /// Parse an IPv6 packet without checking the payload. + pub fn no_payload(buffer: B) -> Result> { + use crate::size::header::Min; - let packet = Packet::unchecked(buffer); + let packet = Packet::unchecked(buffer); - if packet.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } - if packet.buffer.as_ref()[0] >> 4 != 6 { - Err(Error::InvalidPacket)? - } + if packet.buffer.as_ref()[0] >> 4 != 6 { + Err(Error::InvalidPacket)? + } - Ok(packet) - } + Ok(packet) + } - /// Parse an IPv6 packet, checking the buffer contents are correct. - pub fn new(buffer: B) -> Result> { - Packet::no_payload(buffer) - } + /// Parse an IPv6 packet, checking the buffer contents are correct. + pub fn new(buffer: B) -> Result> { + Packet::no_payload(buffer) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - Packet::unchecked(self.buffer.as_ref().to_vec()) - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + Packet::unchecked(self.buffer.as_ref().to_vec()) + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - &[] - } + fn as_ref(&self) -> &[u8] { + &[] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - &mut [] - } + fn as_mut(&mut self) -> &mut [u8] { + &mut [] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - (&[], &[]) - } + fn split(&self) -> (&[u8], &[u8]) { + (&[], &[]) + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - (&mut [], &mut []) - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + (&mut [], &mut []) + } } diff --git a/src/lib.rs b/src/lib.rs index c4f286a..fb0a393 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ pub mod size; pub use crate::size::Size; mod packet; -pub use crate::packet::{Packet, PacketMut, AsPacket, AsPacketMut}; +pub use crate::packet::{AsPacket, AsPacketMut, Packet, PacketMut}; /// Buffer abstractions, dynamic buffers and static buffers. pub mod buffer; diff --git a/src/packet.rs b/src/packet.rs index b88e0ea..e524b70 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -16,34 +16,34 @@ use crate::error::*; /// A network packet. pub trait Packet { - /// Return a slice to the packet header. - fn header(&self) -> &[u8] { - self.split().0 - } + /// Return a slice to the packet header. + fn header(&self) -> &[u8] { + self.split().0 + } - /// Return a slice to the packet payload. - fn payload(&self) -> &[u8] { - self.split().1 - } + /// Return a slice to the packet payload. + fn payload(&self) -> &[u8] { + self.split().1 + } - /// Return both slices. - fn split(&self) -> (&[u8], &[u8]); + /// Return both slices. + fn split(&self) -> (&[u8], &[u8]); } /// A mutable network packet. pub trait PacketMut { - /// Returns a slice to the packet header. - fn header_mut(&mut self) -> &mut [u8] { - self.split_mut().0 - } + /// Returns a slice to the packet header. + fn header_mut(&mut self) -> &mut [u8] { + self.split_mut().0 + } - /// Returns a slice to the packet payload. - fn payload_mut(&mut self) -> &mut [u8] { - self.split_mut().1 - } + /// Returns a slice to the packet payload. + fn payload_mut(&mut self) -> &mut [u8] { + self.split_mut().1 + } - /// Return both mutable slices. - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]); + /// Return both mutable slices. + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]); } /// A type convertible to a `Packet`. @@ -60,8 +60,8 @@ pub trait PacketMut { /// assert_eq!(packet.destination(), "00:23:69:63:59:be".parse().unwrap()); /// ``` pub trait AsPacket<'a, P: Packet + 'a> { - /// Try converting to a packet. - fn as_packet(&'a self) -> Result

; + /// Try converting to a packet. + fn as_packet(&'a self) -> Result

; } /// A type convertible to a `Packet`. @@ -80,6 +80,6 @@ pub trait AsPacket<'a, P: Packet + 'a> { /// assert_eq!(packet.destination(), "00:23:42:63:00:be".parse().unwrap()); /// ``` pub trait AsPacketMut<'a, P: PacketMut + 'a> { - /// Try converting to a packet. - fn as_packet_mut(&'a mut self) -> Result

; + /// Try converting to a packet. + fn as_packet_mut(&'a mut self) -> Result

; } diff --git a/src/size.rs b/src/size.rs index 10f7e61..281bbc8 100644 --- a/src/size.rs +++ b/src/size.rs @@ -14,80 +14,80 @@ /// Sizes for the header part of a packet. pub mod header { - /// Minimum size of a packet header. - pub trait Min { - /// Get the minimum size. - fn min() -> usize; - } - - /// Maximum size of a packet header. - pub trait Max { - /// Get the maximum size. - fn max() -> usize; - } - - /// Actual size of the packet header. - pub trait Size { - /// Get the actual size. - fn size(&self) -> usize; - } + /// Minimum size of a packet header. + pub trait Min { + /// Get the minimum size. + fn min() -> usize; + } + + /// Maximum size of a packet header. + pub trait Max { + /// Get the maximum size. + fn max() -> usize; + } + + /// Actual size of the packet header. + pub trait Size { + /// Get the actual size. + fn size(&self) -> usize; + } } /// Sizes for the payload part of a packet. pub mod payload { - /// Minimum size of a packet payload. - pub trait Min { - /// Get the minimum size. - fn min() -> usize; - } - - /// Maximum size of a packet payload. - pub trait Max { - /// Get the maximum size. - fn max() -> usize; - } - - /// Actual size of the packet payload. - pub trait Size { - /// Get the actual size. - fn size(&self) -> usize; - } + /// Minimum size of a packet payload. + pub trait Min { + /// Get the minimum size. + fn min() -> usize; + } + + /// Maximum size of a packet payload. + pub trait Max { + /// Get the maximum size. + fn max() -> usize; + } + + /// Actual size of the packet payload. + pub trait Size { + /// Get the actual size. + fn size(&self) -> usize; + } } /// Minimum size of a packet. pub trait Min { - /// Get the minimum size. - fn min() -> usize; + /// Get the minimum size. + fn min() -> usize; } /// Maximum size of a packet. pub trait Max { - /// Get the maximum size. - fn max() -> usize; + /// Get the maximum size. + fn max() -> usize; } /// Actual size of the packet. pub trait Size { - /// Get the actual size. - fn size(&self) -> usize; + /// Get the actual size. + fn size(&self) -> usize; } impl Min for T { - fn min() -> usize { - ::min() + ::min() - } + fn min() -> usize { + ::min() + ::min() + } } impl Max for T { - fn max() -> usize { - ::max() + ::max() - } + fn max() -> usize { + ::max() + ::max() + } } impl Size for T { - fn size(&self) -> usize { - ::size(self) + ::size(self) - } + fn size(&self) -> usize { + ::size(self) + ::size(self) + } } macro_rules! sized { diff --git a/src/tcp/builder.rs b/src/tcp/builder.rs index 7372beb..6c6feb8 100644 --- a/src/tcp/builder.rs +++ b/src/tcp/builder.rs @@ -12,208 +12,221 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, WriteBytesExt}; use std::io::Cursor; -use byteorder::{WriteBytesExt, BigEndian}; -use crate::error::*; use crate::buffer::{self, Buffer}; use crate::builder::{Builder as Build, Finalization}; -use crate::packet::{AsPacket, AsPacketMut}; +use crate::error::*; use crate::ip; -use crate::tcp::Packet; -use crate::tcp::Flags; +use crate::packet::{AsPacket, AsPacketMut}; use crate::tcp::checksum; +use crate::tcp::Flags; +use crate::tcp::Packet; /// TCP packet builder. #[derive(Debug)] +#[allow(dead_code)] pub struct Builder { - buffer: B, - finalizer: Finalization, + buffer: B, + finalizer: Finalization, - ip: (usize, usize), - options: bool, - payload: bool, - payload_length: usize, + ip: (usize, usize), + options: bool, + payload: bool, + payload_length: usize, } impl Build for Builder { - fn with(mut buffer: B) -> Result { - let ip = (buffer.offset(), buffer.length()); - - use crate::size::header::Min; - buffer.next(Packet::<()>::min())?; - - // Set data offset to the minimum. - // - // XXX: This is needed for shit to work. The builder uses setters on the - // `tcp::Packet` which expect the data offset to be set. - buffer.data_mut()[12] = ((Packet::<()>::min() / 4) as u8) << 4; - - Ok(Builder { - buffer: buffer, - finalizer: Default::default(), - - ip: ip, - options: false, - payload: false, - payload_length: 0, - }) - } - - fn finalizer(&mut self) -> &mut Finalization { - &mut self.finalizer - } - - fn build(mut self) -> Result { - self.prepare(); - - let mut buffer = self.buffer.into_inner(); - self.finalizer.finalize(buffer.as_mut())?; - Ok(buffer) - } + fn with(mut buffer: B) -> Result { + let ip = (buffer.offset(), buffer.length()); + + use crate::size::header::Min; + buffer.next(Packet::<()>::min())?; + + // Set data offset to the minimum. + // + // XXX: This is needed for shit to work. The builder uses setters on the + // `tcp::Packet` which expect the data offset to be set. + buffer.data_mut()[12] = ((Packet::<()>::min() / 4) as u8) << 4; + + Ok(Builder { + buffer, + finalizer: Default::default(), + + ip, + options: false, + payload: false, + payload_length: 0, + }) + } + + fn finalizer(&mut self) -> &mut Finalization { + &mut self.finalizer + } + + fn build(mut self) -> Result { + self.prepare(); + + let mut buffer = self.buffer.into_inner(); + self.finalizer.finalize(buffer.as_mut())?; + Ok(buffer) + } } impl Default for Builder { - fn default() -> Self { - Builder::with(buffer::Dynamic::default()).unwrap() - } + fn default() -> Self { + Builder::with(buffer::Dynamic::default()).unwrap() + } } impl<'a, B: Buffer> AsPacket<'a, Packet<&'a [u8]>> for Builder { - fn as_packet(&self) -> Result> { - Packet::new(self.buffer.data()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.buffer.data()) + } } impl<'a, B: Buffer> AsPacketMut<'a, Packet<&'a mut [u8]>> for Builder { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.buffer.data_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.buffer.data_mut()) + } } impl Builder { - /// Source port. - pub fn source(mut self, value: u16) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_source(value)?; - Ok(self) - } - - /// Destination port. - pub fn destination(mut self, value: u16) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_destination(value)?; - Ok(self) - } - - /// Packet sequence. - pub fn sequence(mut self, value: u32) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_sequence(value)?; - Ok(self) - } - - /// Optional acknowledgment. - pub fn acknowledgment(mut self, value: u32) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_acknowledgment(value)?; - Ok(self) - } - - /// Packet flags. - pub fn flags(mut self, value: Flags) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_flags(value)?; - Ok(self) - } - - /// Packet window. - pub fn window(mut self, value: u16) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_window(value)?; - Ok(self) - } - - /// Urgent pointer. - pub fn pointer(mut self, value: u16) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_pointer(value)?; - Ok(self) - } - - /// Payload for the packet. - pub fn payload<'a, T: IntoIterator>(mut self, value: T) -> Result { - if self.payload { - Err(Error::AlreadyDefined)? - } - - self.payload = true; - - for byte in value { - self.buffer.more(1)?; - self.payload_length += 1; - *self.buffer.data_mut().last_mut().unwrap() = *byte; - } - - Ok(self) - } - - fn prepare(&mut self) { - let ip = self.ip; - let length = self.buffer.length(); - let payload_length = self.payload_length; - - self.finalizer.add(move |out| { - // Split the buffer into IP and TCP parts. - let (before, after) = out.split_at_mut(ip.0 + ip.1); - let ip = &mut before[ip.0 ..]; - let tcp = &mut after[.. length]; - - // Set the TCP data offset. - let flags = tcp[12] & 0b1111; - - let offset = ((length - payload_length) / 4) as u8; - tcp[12] = offset << 4 | flags; - - // Calculate the checksum by parsing back the IP packet and set it. - let checksum = checksum(&ip::Packet::no_payload(&ip)?, tcp); - Cursor::new(&mut tcp[16 ..]) - .write_u16::(checksum)?; - - Ok(()) - }); - } + /// Source port. + pub fn source(mut self, value: u16) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_source(value)?; + Ok(self) + } + + /// Destination port. + pub fn destination(mut self, value: u16) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_destination(value)?; + Ok(self) + } + + /// Packet sequence. + pub fn sequence(mut self, value: u32) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_sequence(value)?; + Ok(self) + } + + /// Optional acknowledgment. + pub fn acknowledgment(mut self, value: u32) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_acknowledgment(value)?; + Ok(self) + } + + /// Packet flags. + pub fn flags(mut self, value: Flags) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_flags(value)?; + Ok(self) + } + + /// Packet window. + pub fn window(mut self, value: u16) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_window(value)?; + Ok(self) + } + + /// Urgent pointer. + pub fn pointer(mut self, value: u16) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_pointer(value)?; + Ok(self) + } + + /// Payload for the packet. + pub fn payload<'a, T: IntoIterator>(mut self, value: T) -> Result { + if self.payload { + Err(Error::AlreadyDefined)? + } + + self.payload = true; + + for byte in value { + self.buffer.more(1)?; + self.payload_length += 1; + *self.buffer.data_mut().last_mut().unwrap() = *byte; + } + + Ok(self) + } + + fn prepare(&mut self) { + let ip = self.ip; + let length = self.buffer.length(); + let payload_length = self.payload_length; + + self.finalizer.add(move |out| { + // Split the buffer into IP and TCP parts. + let (before, after) = out.split_at_mut(ip.0 + ip.1); + let ip = &mut before[ip.0..]; + let tcp = &mut after[..length]; + + // Set the TCP data offset. + let flags = tcp[12] & 0b1111; + + let offset = ((length - payload_length) / 4) as u8; + tcp[12] = offset << 4 | flags; + + // Calculate the checksum by parsing back the IP packet and set it. + let checksum = checksum(&ip::Packet::no_payload(&ip)?, tcp); + Cursor::new(&mut tcp[16..]).write_u16::(checksum)?; + + Ok(()) + }); + } } #[cfg(test)] mod test { - use std::net::Ipv4Addr; - use crate::builder::Builder; - use crate::packet::Packet; - use crate::ip; - use crate::tcp; - - #[test] - fn simple() { - let packet = ip::v4::Builder::default() - .id(0x2d87).unwrap() - .ttl(64).unwrap() - .source("66.102.1.108".parse().unwrap()).unwrap() - .destination("192.168.0.79".parse().unwrap()).unwrap() - .tcp().unwrap() - .source(1337).unwrap() - .destination(9001).unwrap() - .flags(tcp::flag::SYN).unwrap() - .payload(b"lol").unwrap() - .build().unwrap(); - - let ip = ip::v4::Packet::new(packet).unwrap(); - assert_eq!(ip.id(), 0x2d87); - assert!(ip.flags().is_empty()); - assert_eq!(ip.length(), 43); - assert_eq!(ip.ttl(), 64); - assert_eq!(ip.protocol(), ip::Protocol::Tcp); - assert_eq!(ip.source(), "66.102.1.108".parse::().unwrap()); - assert_eq!(ip.destination(), "192.168.0.79".parse::().unwrap()); - assert!(ip.is_valid()); - - let tcp = tcp::Packet::new(ip.payload()).unwrap(); - assert_eq!(tcp.source(), 1337); - assert_eq!(tcp.destination(), 9001); - assert_eq!(tcp.flags(), tcp::flag::SYN); - assert!(tcp.is_valid(&ip::Packet::from(&ip))); - } + use crate::builder::Builder; + use crate::ip; + use crate::packet::Packet; + use crate::tcp; + use std::net::Ipv4Addr; + + #[test] + fn simple() { + let packet = ip::v4::Builder::default() + .id(0x2d87) + .unwrap() + .ttl(64) + .unwrap() + .source("66.102.1.108".parse().unwrap()) + .unwrap() + .destination("192.168.0.79".parse().unwrap()) + .unwrap() + .tcp() + .unwrap() + .source(1337) + .unwrap() + .destination(9001) + .unwrap() + .flags(tcp::flag::SYN) + .unwrap() + .payload(b"lol") + .unwrap() + .build() + .unwrap(); + + let ip = ip::v4::Packet::new(packet).unwrap(); + assert_eq!(ip.id(), 0x2d87); + assert!(ip.flags().is_empty()); + assert_eq!(ip.length(), 43); + assert_eq!(ip.ttl(), 64); + assert_eq!(ip.protocol(), ip::Protocol::Tcp); + assert_eq!(ip.source(), "66.102.1.108".parse::().unwrap()); + assert_eq!( + ip.destination(), + "192.168.0.79".parse::().unwrap() + ); + assert!(ip.is_valid()); + + let tcp = tcp::Packet::new(ip.payload()).unwrap(); + assert_eq!(tcp.source(), 1337); + assert_eq!(tcp.destination(), 9001); + assert_eq!(tcp.flags(), tcp::flag::SYN); + assert!(tcp.is_valid(&ip::Packet::from(&ip))); + } } diff --git a/src/tcp/flag.rs b/src/tcp/flag.rs index db6054e..03d2c6d 100644 --- a/src/tcp/flag.rs +++ b/src/tcp/flag.rs @@ -15,35 +15,36 @@ use bitflags::bitflags; bitflags! { - /// TCP flags. - pub struct Flags: u16 { - /// - const FIN = 0b0_0000_0001; + /// TCP flags. + #[derive(Debug, PartialEq, Eq)] + pub struct Flags: u16 { + /// + const FIN = 0b0_0000_0001; - /// - const SYN = 0b0_0000_0010; + /// + const SYN = 0b0_0000_0010; - /// - const RST = 0b0_0000_0100; + /// + const RST = 0b0_0000_0100; - /// - const PSH = 0b0_0000_1000; + /// + const PSH = 0b0_0000_1000; - /// - const ACK = 0b0_0001_0000; + /// + const ACK = 0b0_0001_0000; - /// - const URG = 0b0_0010_0000; + /// + const URG = 0b0_0010_0000; - /// - const ECE = 0b0_0100_0000; + /// + const ECE = 0b0_0100_0000; - /// - const CWR = 0b0_1000_0000; + /// + const CWR = 0b0_1000_0000; - /// - const NS = 0b1_0000_0000; - } + /// + const NS = 0b1_0000_0000; + } } pub const FIN: Flags = Flags::FIN; @@ -54,4 +55,4 @@ pub const ACK: Flags = Flags::ACK; pub const URG: Flags = Flags::URG; pub const ECE: Flags = Flags::ECE; pub const CWR: Flags = Flags::CWR; -pub const NS: Flags = Flags::NS; +pub const NS: Flags = Flags::NS; diff --git a/src/tcp/mod.rs b/src/tcp/mod.rs index 77c62d1..77a0b1e 100644 --- a/src/tcp/mod.rs +++ b/src/tcp/mod.rs @@ -29,7 +29,6 @@ pub use self::builder::Builder; use crate::ip; use crate::ip::Protocol; - /// Calculate the checksum for a TCP packet. /// /// # Note @@ -37,8 +36,8 @@ use crate::ip::Protocol; /// Since the checksum for UDP packets includes a pseudo-header based on the /// enclosing IP packet, one has to be given. pub fn checksum>(ip: &ip::Packet, buffer: &[u8]) -> u16 { + use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::Cursor; - use byteorder::{WriteBytesExt, ReadBytesExt, BigEndian}; let buffer_length = buffer.len(); let mut prefix = [0u8; 40]; @@ -49,7 +48,8 @@ pub fn checksum>(ip: &ip::Packet, buffer: &[u8]) -> u16 { prefix[9] = Protocol::Tcp.into(); Cursor::new(&mut prefix[10..]) - .write_u16::(buffer.len() as u16).unwrap(); + .write_u16::(buffer.len() as u16) + .unwrap(); } ip::Packet::V6(ref _packet) => { @@ -60,11 +60,9 @@ pub fn checksum>(ip: &ip::Packet, buffer: &[u8]) -> u16 { let mut result = 0u32; let mut buffer = Cursor::new(buffer); let mut prefix = match *ip { - ip::Packet::V4(_) => - Cursor::new(&prefix[0..12]), + ip::Packet::V4(_) => Cursor::new(&prefix[0..12]), - ip::Packet::V6(_) => - Cursor::new(&prefix[0..40]), + ip::Packet::V6(_) => Cursor::new(&prefix[0..40]), }; while let Ok(value) = prefix.read_u16::() { @@ -101,8 +99,8 @@ pub fn checksum>(ip: &ip::Packet, buffer: &[u8]) -> u16 { #[cfg(test)] mod test { - use crate::{Builder, Packet, tcp}; use super::*; + use crate::{tcp, Builder, Packet}; #[test] fn test_tcp_checksum_on_odd_length() { @@ -140,7 +138,9 @@ mod test { .unwrap(); let fake_ip_header = ip::Packet::unchecked(&fake_ip_header); - tcp_parse.update_checksum(&fake_ip_header).expect("checksum update failed"); + tcp_parse + .update_checksum(&fake_ip_header) + .expect("checksum update failed"); let checksum = tcp_parse.checksum(); assert_eq!(checksum_orig, checksum); } diff --git a/src/tcp/option.rs b/src/tcp/option.rs index 4a01fd0..7812958 100644 --- a/src/tcp/option.rs +++ b/src/tcp/option.rs @@ -15,192 +15,183 @@ use std::fmt; use crate::error::*; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; use crate::size; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; /// TCP option parser. pub struct Option { - buffer: B, + buffer: B, } sized!(Option, - header { - min: 1, - max: 2, - size: p => match p.length() { - 1 => 1, - _ => 2, - }, - } - - payload { - min: 0, - max: 32, - size: p => match p.length() { - 1 => 0, - n => n as usize - 2, - }, - }); +header { + min: 1, + max: 2, + size: p => match p.length() { + 1 => 1, + _ => 2, + }, +} + +payload { + min: 0, + max: 32, + size: p => match p.length() { + 1 => 0, + n => n as usize - 2, + }, +}); /// TCP option number. #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum Number { - /// - End, + /// + End, - /// - NoOperation, + /// + NoOperation, - /// - MaximumSegmentSize, + /// + MaximumSegmentSize, - /// - WindowScale, + /// + WindowScale, - /// - SelectiveAcknowledgmentPermitted, + /// + SelectiveAcknowledgmentPermitted, - /// - SelectiveAcknowledgment, + /// + SelectiveAcknowledgment, - /// - Timestamp, + /// + Timestamp, - /// - Unknown(u8), + /// + Unknown(u8), } impl> fmt::Debug for Option { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("tcp::Option") - .field("number", &self.number()) - .field("length", &self.length()) - .field("payload", &self.payload()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("tcp::Option") + .field("number", &self.number()) + .field("length", &self.length()) + .field("payload", &self.payload()) + .finish() + } } impl> Option { - /// Parse a TCP option, checking the buffer contents are correct. - pub fn new(buffer: B) -> Result> { - let option = Option { - buffer: buffer, - }; - - if option.buffer.as_ref().len() < ::min() { - Err(Error::SmallBuffer)? - } - - if option.buffer.as_ref().len() < option.length() as usize { - Err(Error::SmallBuffer)? - } - - Ok(option) - } + /// Parse a TCP option, checking the buffer contents are correct. + pub fn new(buffer: B) -> Result> { + let option = Option { buffer }; + + if option.buffer.as_ref().len() < ::min() { + Err(Error::SmallBuffer)? + } + + if option.buffer.as_ref().len() < option.length() as usize { + Err(Error::SmallBuffer)? + } + + Ok(option) + } } impl> AsRef<[u8]> for Option { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Option { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Option<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Option::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Option::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Option<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Option::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Option::new(self.as_mut()) + } } impl> P for Option { - fn split(&self) -> (&[u8], &[u8]) { - match self.length() { - 1 => - self.buffer.as_ref().split_at(1), - - length => - self.buffer.as_ref()[.. length as usize].split_at(2), - } - } + fn split(&self) -> (&[u8], &[u8]) { + match self.length() { + 1 => self.buffer.as_ref().split_at(1), + + length => self.buffer.as_ref()[..length as usize].split_at(2), + } + } } impl + AsMut<[u8]>> PM for Option { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - match self.length() { - 1 => - self.buffer.as_mut().split_at_mut(1), - - length => - self.buffer.as_mut()[.. length as usize].split_at_mut(2), - } - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + match self.length() { + 1 => self.buffer.as_mut().split_at_mut(1), + + length => self.buffer.as_mut()[..length as usize].split_at_mut(2), + } + } } impl> Option { - /// Option number. - pub fn number(&self) -> Number { - self.buffer.as_ref()[0].into() - } - - /// Option length. - pub fn length(&self) -> u8 { - match self.number() { - Number::End | - Number::NoOperation => - 1, - - _ => - self.buffer.as_ref()[1] - } - } + /// Option number. + pub fn number(&self) -> Number { + self.buffer.as_ref()[0].into() + } + + /// Option length. + pub fn length(&self) -> u8 { + match self.number() { + Number::End | Number::NoOperation => 1, + + _ => self.buffer.as_ref()[1], + } + } } impl From for Number { - fn from(value: u8) -> Self { - use self::Number::*; - - match value { - 0 => End, - 1 => NoOperation, - 2 => MaximumSegmentSize, - 3 => WindowScale, - 4 => SelectiveAcknowledgmentPermitted, - 5 => SelectiveAcknowledgment, - 8 => Timestamp, - n => Unknown(n), - } - } + fn from(value: u8) -> Self { + use self::Number::*; + + match value { + 0 => End, + 1 => NoOperation, + 2 => MaximumSegmentSize, + 3 => WindowScale, + 4 => SelectiveAcknowledgmentPermitted, + 5 => SelectiveAcknowledgment, + 8 => Timestamp, + n => Unknown(n), + } + } } -impl Into for Number { - fn into(self) -> u8 { - use self::Number::*; - - match self { - End => 0, - NoOperation => 1, - MaximumSegmentSize => 2, - WindowScale => 3, - SelectiveAcknowledgmentPermitted => 4, - SelectiveAcknowledgment => 5, - Timestamp => 8, - Unknown(n) => n, - } - } +impl From for u8 { + fn from(value: Number) -> Self { + use self::Number::*; + + match value { + End => 0, + NoOperation => 1, + MaximumSegmentSize => 2, + WindowScale => 3, + SelectiveAcknowledgmentPermitted => 4, + SelectiveAcknowledgment => 5, + Timestamp => 8, + Unknown(n) => n, + } + } } diff --git a/src/tcp/packet.rs b/src/tcp/packet.rs index 4b52033..aec22a1 100644 --- a/src/tcp/packet.rs +++ b/src/tcp/packet.rs @@ -12,271 +12,283 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::fmt; use std::io::Cursor; -use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; use crate::ip; -use crate::tcp::Flags; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; use crate::tcp::checksum; use crate::tcp::option; +use crate::tcp::Flags; /// TCP packet parser. pub struct Packet { - buffer: B, + buffer: B, } sized!(Packet, - header { - min: 20, - max: 60, - size: p => p.offset() as usize * 4, - } - - payload { - min: 0, - max: u16::max_value() as usize - 60, - size: p => p.buffer.as_ref().len() - (p.offset() as usize * 4), - }); +header { + min: 20, + max: 60, + size: p => p.offset() as usize * 4, +} + +payload { + min: 0, + max: u16::max_value() as usize - 60, + size: p => p.buffer.as_ref().len() - (p.offset() as usize * 4), +}); impl> fmt::Debug for Packet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("tcp::Packet") - .field("source", &self.source()) - .field("destination", &self.destination()) - .field("sequence", &self.sequence()) - .field("acknowledgment", &self.acknowledgment()) - .field("offset", &self.offset()) - .field("flags", &self.flags()) - .field("window", &self.window()) - .field("checksum", &self.checksum()) - .field("pointer", &self.pointer()) - .field("payload", &self.payload()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("tcp::Packet") + .field("source", &self.source()) + .field("destination", &self.destination()) + .field("sequence", &self.sequence()) + .field("acknowledgment", &self.acknowledgment()) + .field("offset", &self.offset()) + .field("flags", &self.flags()) + .field("window", &self.window()) + .field("checksum", &self.checksum()) + .field("pointer", &self.pointer()) + .field("payload", &self.payload()) + .finish() + } } impl> Packet { - /// Create a TCP packet without checking the buffer. - pub fn unchecked(buffer: B) -> Packet { - Packet { buffer } - } + /// Create a TCP packet without checking the buffer. + pub fn unchecked(buffer: B) -> Packet { + Packet { buffer } + } - /// Parse a TCP packet, checking the buffer contents are correct. - pub fn new(buffer: B) -> Result> { - use crate::size::header::Min; + /// Parse a TCP packet, checking the buffer contents are correct. + pub fn new(buffer: B) -> Result> { + use crate::size::header::Min; - let packet = Packet::unchecked(buffer); + let packet = Packet::unchecked(buffer); - if packet.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } - if packet.buffer.as_ref().len() < packet.offset() as usize * 4 { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < packet.offset() as usize * 4 { + Err(Error::SmallBuffer)? + } - Ok(packet) - } + Ok(packet) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - Packet::unchecked(self.buffer.as_ref().to_vec()) - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + Packet::unchecked(self.buffer.as_ref().to_vec()) + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - let offset = self.offset() as usize; - self.buffer.as_ref().split_at(offset * 4) - } + fn split(&self) -> (&[u8], &[u8]) { + let offset = self.offset() as usize; + self.buffer.as_ref().split_at(offset * 4) + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - let offset = self.offset() as usize; - self.buffer.as_mut().split_at_mut(offset * 4) - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + let offset = self.offset() as usize; + self.buffer.as_mut().split_at_mut(offset * 4) + } } impl> Packet { - /// Source port. - pub fn source(&self) -> u16 { - (&self.buffer.as_ref()[0 ..]).read_u16::().unwrap() - } - - /// Destination port. - pub fn destination(&self) -> u16 { - (&self.buffer.as_ref()[2 ..]).read_u16::().unwrap() - } - - /// Packet sequence. - pub fn sequence(&self) -> u32 { - (&self.buffer.as_ref()[4 ..]).read_u32::().unwrap() - } - - /// Optional acknowledgment. - pub fn acknowledgment(&self) -> u32 { - (&self.buffer.as_ref()[8 ..]).read_u32::().unwrap() - } - - /// Data offset. - pub fn offset(&self) -> u8 { - self.buffer.as_ref()[12] >> 4 - } - - /// Packet flags. - pub fn flags(&self) -> Flags { - Flags::from_bits((&self.buffer.as_ref()[12 ..]) - .read_u16::().unwrap() & 0b1_1111_1111).unwrap() - } - - /// Packet window. - pub fn window(&self) -> u16 { - (&self.buffer.as_ref()[14 ..]).read_u16::().unwrap() - } - - /// Packet checksum. - pub fn checksum(&self) -> u16 { - (&self.buffer.as_ref()[16 ..]).read_u16::().unwrap() - } - - /// Verify the packet is valid by calculating the checksum. - pub fn is_valid>(&self, ip: &ip::Packet) -> bool { - checksum(ip, self.buffer.as_ref()) == self.checksum() - } - - /// Urgent pointer. - pub fn pointer(&self) -> u16 { - (&self.buffer.as_ref()[18 ..]).read_u16::().unwrap() - } - - /// TCP options for the packet. - pub fn options(&self) -> OptionIter<'_> { - OptionIter { - buffer: &self.buffer.as_ref()[20 .. (self.offset() as usize * 4)], - } - } + /// Source port. + pub fn source(&self) -> u16 { + (&self.buffer.as_ref()[0..]) + .read_u16::() + .unwrap() + } + + /// Destination port. + pub fn destination(&self) -> u16 { + (&self.buffer.as_ref()[2..]) + .read_u16::() + .unwrap() + } + + /// Packet sequence. + pub fn sequence(&self) -> u32 { + (&self.buffer.as_ref()[4..]) + .read_u32::() + .unwrap() + } + + /// Optional acknowledgment. + pub fn acknowledgment(&self) -> u32 { + (&self.buffer.as_ref()[8..]) + .read_u32::() + .unwrap() + } + + /// Data offset. + pub fn offset(&self) -> u8 { + self.buffer.as_ref()[12] >> 4 + } + + /// Packet flags. + pub fn flags(&self) -> Flags { + Flags::from_bits( + (&self.buffer.as_ref()[12..]) + .read_u16::() + .unwrap() + & 0b1_1111_1111, + ) + .unwrap() + } + + /// Packet window. + pub fn window(&self) -> u16 { + (&self.buffer.as_ref()[14..]) + .read_u16::() + .unwrap() + } + + /// Packet checksum. + pub fn checksum(&self) -> u16 { + (&self.buffer.as_ref()[16..]) + .read_u16::() + .unwrap() + } + + /// Verify the packet is valid by calculating the checksum. + pub fn is_valid>(&self, ip: &ip::Packet) -> bool { + checksum(ip, self.buffer.as_ref()) == self.checksum() + } + + /// Urgent pointer. + pub fn pointer(&self) -> u16 { + (&self.buffer.as_ref()[18..]) + .read_u16::() + .unwrap() + } + + /// TCP options for the packet. + pub fn options(&self) -> OptionIter<'_> { + OptionIter { + buffer: &self.buffer.as_ref()[20..(self.offset() as usize * 4)], + } + } } impl + AsMut<[u8]>> Packet { - /// Source port. - pub fn set_source(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[0 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Destination port. - pub fn set_destination(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[2 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Packet sequence. - pub fn set_sequence(&mut self, value: u32) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[4 ..]) - .write_u32::(value)?; - - Ok(self) - } - - /// Optional acknowledgment. - pub fn set_acknowledgment(&mut self, value: u32) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[8 ..]) - .write_u32::(value)?; - - Ok(self) - } - - /// Packet flags. - pub fn set_flags(&mut self, value: Flags) -> Result<&mut Self> { - let old = self.header()[12] & 0b1111_0000; - - Cursor::new(&mut self.header_mut()[12 ..]) - .write_u16::((u16::from(old)) << 12 | value.bits())?; - - Ok(self) - } - - /// Packet window. - pub fn set_window(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[14 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Urgent pointer. - pub fn set_pointer(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[18 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Create a checksumed setter. - pub fn checked<'a, 'b, BI: AsRef<[u8]> + 'b>(&'a mut self, ip: &'b ip::Packet) -> Checked<'a, 'b, B, BI> { - Checked { - packet: self, - ip: ip, - } - } - - /// Set the checksum value. - pub fn set_checksum(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[16 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Recalculate and set the checksum value. - pub fn update_checksum>(&mut self, ip: &ip::Packet) -> Result<&mut Self> { - let checksum = checksum(ip, self.buffer.as_ref()); - self.set_checksum(checksum) - } + /// Source port. + pub fn set_source(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[0..]).write_u16::(value)?; + + Ok(self) + } + + /// Destination port. + pub fn set_destination(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[2..]).write_u16::(value)?; + + Ok(self) + } + + /// Packet sequence. + pub fn set_sequence(&mut self, value: u32) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[4..]).write_u32::(value)?; + + Ok(self) + } + + /// Optional acknowledgment. + pub fn set_acknowledgment(&mut self, value: u32) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[8..]).write_u32::(value)?; + + Ok(self) + } + + /// Packet flags. + pub fn set_flags(&mut self, value: Flags) -> Result<&mut Self> { + let old = self.header()[12] & 0b1111_0000; + + Cursor::new(&mut self.header_mut()[12..]) + .write_u16::((u16::from(old)) << 12 | value.bits())?; + + Ok(self) + } + + /// Packet window. + pub fn set_window(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[14..]).write_u16::(value)?; + + Ok(self) + } + + /// Urgent pointer. + pub fn set_pointer(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[18..]).write_u16::(value)?; + + Ok(self) + } + + /// Create a checksumed setter. + pub fn checked<'a, 'b, BI: AsRef<[u8]> + 'b>( + &'a mut self, + ip: &'b ip::Packet, + ) -> Checked<'a, 'b, B, BI> { + Checked { packet: self, ip } + } + + /// Set the checksum value. + pub fn set_checksum(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[16..]).write_u16::(value)?; + + Ok(self) + } + + /// Recalculate and set the checksum value. + pub fn update_checksum>(&mut self, ip: &ip::Packet) -> Result<&mut Self> { + let checksum = checksum(ip, self.buffer.as_ref()); + self.set_checksum(checksum) + } } /// Checked wrapper for UDP packets. @@ -285,154 +297,174 @@ impl + AsMut<[u8]>> Packet { /// /// The checksum recalculation happens on `Drop`, so don't leak it. pub struct Checked<'a, 'b, BP, BI> - where BP: AsRef<[u8]> + AsMut<[u8]> + 'a, - BI: AsRef<[u8]> + 'b +where + BP: AsRef<[u8]> + AsMut<[u8]> + 'a, + BI: AsRef<[u8]> + 'b, { - packet: &'a mut Packet, - ip: &'b ip::Packet, + packet: &'a mut Packet, + ip: &'b ip::Packet, } impl<'a, 'b, BP, BI> Checked<'a, 'b, BP, BI> - where BP: AsRef<[u8]> + AsMut<[u8]> + 'a, - BI: AsRef<[u8]> + 'b +where + BP: AsRef<[u8]> + AsMut<[u8]> + 'a, + BI: AsRef<[u8]> + 'b, { - /// Source port. - pub fn set_source(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_source(value)?; - Ok(self) - } - - /// Destination port. - pub fn set_destination(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_destination(value)?; - Ok(self) - } - - /// Packet sequence. - pub fn set_sequence(&mut self, value: u32) -> Result<&mut Self> { - self.packet.set_sequence(value)?; - Ok(self) - } - - /// Optional acknowledgment. - pub fn set_acknowledgment(&mut self, value: u32) -> Result<&mut Self> { - self.packet.set_acknowledgment(value)?; - Ok(self) - } - - /// Packet flags. - pub fn set_flags(&mut self, value: Flags) -> Result<&mut Self> { - self.packet.set_flags(value)?; - Ok(self) - } - - /// Packet window. - pub fn set_window(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_window(value)?; - Ok(self) - } - - /// Urgent pointer. - pub fn set_pointer(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_pointer(value)?; - Ok(self) - } + /// Source port. + pub fn set_source(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_source(value)?; + Ok(self) + } + + /// Destination port. + pub fn set_destination(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_destination(value)?; + Ok(self) + } + + /// Packet sequence. + pub fn set_sequence(&mut self, value: u32) -> Result<&mut Self> { + self.packet.set_sequence(value)?; + Ok(self) + } + + /// Optional acknowledgment. + pub fn set_acknowledgment(&mut self, value: u32) -> Result<&mut Self> { + self.packet.set_acknowledgment(value)?; + Ok(self) + } + + /// Packet flags. + pub fn set_flags(&mut self, value: Flags) -> Result<&mut Self> { + self.packet.set_flags(value)?; + Ok(self) + } + + /// Packet window. + pub fn set_window(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_window(value)?; + Ok(self) + } + + /// Urgent pointer. + pub fn set_pointer(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_pointer(value)?; + Ok(self) + } } impl<'a, 'b, BP, BI> Drop for Checked<'a, 'b, BP, BI> - where BP: AsRef<[u8]> + AsMut<[u8]> + 'a, - BI: AsRef<[u8]> + 'b +where + BP: AsRef<[u8]> + AsMut<[u8]> + 'a, + BI: AsRef<[u8]> + 'b, { - fn drop(&mut self) { - self.packet.update_checksum(self.ip).unwrap(); - } + fn drop(&mut self) { + self.packet.update_checksum(self.ip).unwrap(); + } } /// Iterator over TCP packet options. pub struct OptionIter<'a> { - buffer: &'a [u8], + buffer: &'a [u8], } impl<'a> Iterator for OptionIter<'a> { - type Item = Result>; + type Item = Result>; - fn next(&mut self) -> Option { - use crate::size::Size; + fn next(&mut self) -> Option { + use crate::size::Size; - if self.buffer.is_empty() { - return None; - } + if self.buffer.is_empty() { + return None; + } - match option::Option::new(self.buffer) { - Ok(option) => { - if option.number() == option::Number::End { - return None; - } + match option::Option::new(self.buffer) { + Ok(option) => { + if option.number() == option::Number::End { + return None; + } - self.buffer = &self.buffer[option.size() ..]; - Some(Ok(option)) - } + self.buffer = &self.buffer[option.size()..]; + Some(Ok(option)) + } - Err(error) => - Some(Err(error)) - } - } + Err(error) => Some(Err(error)), + } + } } #[cfg(test)] mod test { - use crate::packet::{Packet, PacketMut}; - use crate::ip; - use crate::tcp; - - #[test] - fn values() { - let raw = [0x45u8, 0x00, 0x00, 0x3c, 0xc8, 0xa5, 0x40, 0x00, 0x40, 0x06, 0x9f, 0xd5, 0xc0, 0xa8, 0x01, 0x89, 0x08, 0x08, 0x08, 0x08, 0x9b, 0x8a, 0x00, 0x50, 0xde, 0x67, 0xc7, 0x4a, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x72, 0x10, 0x3f, 0x5f, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x59, 0x2b, 0x29, 0x97, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07]; - - let ip = ip::v4::Packet::new(&raw[..]).unwrap(); - let tcp = tcp::Packet::new(ip.payload()).unwrap(); - - assert!(ip.is_valid()); - assert!(tcp.is_valid(&ip::Packet::from(&ip))); - - assert_eq!(tcp.flags(), tcp::flag::SYN); - assert_eq!(tcp.destination(), 80); - } - - #[test] - fn mutable() { - let mut raw = [0x45u8, 0x00, 0x00, 0x3c, 0xc8, 0xa5, 0x40, 0x00, 0x40, 0x06, 0x9f, 0xd5, 0xc0, 0xa8, 0x01, 0x89, 0x08, 0x08, 0x08, 0x08, 0x9b, 0x8a, 0x00, 0x50, 0xde, 0x67, 0xc7, 0x4a, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x72, 0x10, 0x3f, 0x5f, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x59, 0x2b, 0x29, 0x97, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07]; - - let mut ip = ip::v4::Packet::new(&mut raw[..]).unwrap(); - let (ip, tcp) = ip.split_mut(); - let ip = ip::Packet::from(ip::v4::Packet::unchecked(ip)); - let mut tcp = tcp::Packet::new(tcp).unwrap(); - - assert!(tcp.is_valid(&ip)); - assert_eq!(tcp.destination(), 80); - - tcp.set_destination(9001).unwrap(); - assert_eq!(tcp.destination(), 9001); - assert!(!tcp.is_valid(&ip)); - - tcp.update_checksum(&ip).unwrap(); - assert!(tcp.is_valid(&ip)); - } - - #[test] - fn mutable_checked() { - let mut raw = [0x45u8, 0x00, 0x00, 0x3c, 0xc8, 0xa5, 0x40, 0x00, 0x40, 0x06, 0x9f, 0xd5, 0xc0, 0xa8, 0x01, 0x89, 0x08, 0x08, 0x08, 0x08, 0x9b, 0x8a, 0x00, 0x50, 0xde, 0x67, 0xc7, 0x4a, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x72, 0x10, 0x3f, 0x5f, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x59, 0x2b, 0x29, 0x97, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07]; - - let mut ip = ip::v4::Packet::new(&mut raw[..]).unwrap(); - let (ip, tcp) = ip.split_mut(); - let ip = ip::Packet::from(ip::v4::Packet::unchecked(ip)); - let mut tcp = tcp::Packet::new(tcp).unwrap(); - - assert!(tcp.is_valid(&ip)); - assert_eq!(tcp.destination(), 80); - - tcp.checked(&ip).set_destination(9001).unwrap(); - assert_eq!(tcp.destination(), 9001); - assert!(tcp.is_valid(&ip)); - } + use crate::ip; + use crate::packet::{Packet, PacketMut}; + use crate::tcp; + + #[test] + fn values() { + let raw = [ + 0x45u8, 0x00, 0x00, 0x3c, 0xc8, 0xa5, 0x40, 0x00, 0x40, 0x06, 0x9f, 0xd5, 0xc0, 0xa8, + 0x01, 0x89, 0x08, 0x08, 0x08, 0x08, 0x9b, 0x8a, 0x00, 0x50, 0xde, 0x67, 0xc7, 0x4a, + 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x72, 0x10, 0x3f, 0x5f, 0x00, 0x00, 0x02, 0x04, + 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x59, 0x2b, 0x29, 0x97, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x03, 0x03, 0x07, + ]; + + let ip = ip::v4::Packet::new(&raw[..]).unwrap(); + let tcp = tcp::Packet::new(ip.payload()).unwrap(); + + assert!(ip.is_valid()); + assert!(tcp.is_valid(&ip::Packet::from(&ip))); + + assert_eq!(tcp.flags(), tcp::flag::SYN); + assert_eq!(tcp.destination(), 80); + } + + #[test] + fn mutable() { + let mut raw = [ + 0x45u8, 0x00, 0x00, 0x3c, 0xc8, 0xa5, 0x40, 0x00, 0x40, 0x06, 0x9f, 0xd5, 0xc0, 0xa8, + 0x01, 0x89, 0x08, 0x08, 0x08, 0x08, 0x9b, 0x8a, 0x00, 0x50, 0xde, 0x67, 0xc7, 0x4a, + 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x72, 0x10, 0x3f, 0x5f, 0x00, 0x00, 0x02, 0x04, + 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x59, 0x2b, 0x29, 0x97, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x03, 0x03, 0x07, + ]; + + let mut ip = ip::v4::Packet::new(&mut raw[..]).unwrap(); + let (ip, tcp) = ip.split_mut(); + let ip = ip::Packet::from(ip::v4::Packet::unchecked(ip)); + let mut tcp = tcp::Packet::new(tcp).unwrap(); + + assert!(tcp.is_valid(&ip)); + assert_eq!(tcp.destination(), 80); + + tcp.set_destination(9001).unwrap(); + assert_eq!(tcp.destination(), 9001); + assert!(!tcp.is_valid(&ip)); + + tcp.update_checksum(&ip).unwrap(); + assert!(tcp.is_valid(&ip)); + } + + #[test] + fn mutable_checked() { + let mut raw = [ + 0x45u8, 0x00, 0x00, 0x3c, 0xc8, 0xa5, 0x40, 0x00, 0x40, 0x06, 0x9f, 0xd5, 0xc0, 0xa8, + 0x01, 0x89, 0x08, 0x08, 0x08, 0x08, 0x9b, 0x8a, 0x00, 0x50, 0xde, 0x67, 0xc7, 0x4a, + 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x72, 0x10, 0x3f, 0x5f, 0x00, 0x00, 0x02, 0x04, + 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x59, 0x2b, 0x29, 0x97, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x03, 0x03, 0x07, + ]; + + let mut ip = ip::v4::Packet::new(&mut raw[..]).unwrap(); + let (ip, tcp) = ip.split_mut(); + let ip = ip::Packet::from(ip::v4::Packet::unchecked(ip)); + let mut tcp = tcp::Packet::new(tcp).unwrap(); + + assert!(tcp.is_valid(&ip)); + assert_eq!(tcp.destination(), 80); + + tcp.checked(&ip).set_destination(9001).unwrap(); + assert_eq!(tcp.destination(), 9001); + assert!(tcp.is_valid(&ip)); + } } diff --git a/src/udp/builder.rs b/src/udp/builder.rs index 09188bf..0f5cf44 100644 --- a/src/udp/builder.rs +++ b/src/udp/builder.rs @@ -12,166 +12,173 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, WriteBytesExt}; use std::io::Cursor; -use byteorder::{WriteBytesExt, BigEndian}; -use crate::error::*; use crate::buffer::{self, Buffer}; use crate::builder::{Builder as Build, Finalization}; -use crate::packet::{AsPacket, AsPacketMut}; +use crate::error::*; use crate::ip; -use crate::udp::Packet; +use crate::packet::{AsPacket, AsPacketMut}; use crate::udp::checksum; +use crate::udp::Packet; /// UDP packet builder. #[derive(Debug)] pub struct Builder { - buffer: B, - finalizer: Finalization, + buffer: B, + finalizer: Finalization, - ip: (usize, usize), - payload: bool, + ip: (usize, usize), + payload: bool, } impl Build for Builder { - fn with(mut buffer: B) -> Result { - let ip = (buffer.offset(), buffer.length()); + fn with(mut buffer: B) -> Result { + let ip = (buffer.offset(), buffer.length()); - use crate::size::header::Min; - buffer.next(Packet::<()>::min())?; + use crate::size::header::Min; + buffer.next(Packet::<()>::min())?; - Ok(Builder { - buffer: buffer, - finalizer: Default::default(), + Ok(Builder { + buffer, + finalizer: Default::default(), - ip: ip, - payload: false, - }) - } + ip, + payload: false, + }) + } - fn finalizer(&mut self) -> &mut Finalization { - &mut self.finalizer - } + fn finalizer(&mut self) -> &mut Finalization { + &mut self.finalizer + } - fn build(mut self) -> Result { - self.prepare(); + fn build(mut self) -> Result { + self.prepare(); - let mut buffer = self.buffer.into_inner(); - self.finalizer.finalize(buffer.as_mut())?; - Ok(buffer) - } + let mut buffer = self.buffer.into_inner(); + self.finalizer.finalize(buffer.as_mut())?; + Ok(buffer) + } } impl Default for Builder { - fn default() -> Self { - Builder::with(buffer::Dynamic::default()).unwrap() - } + fn default() -> Self { + Builder::with(buffer::Dynamic::default()).unwrap() + } } impl<'a, B: Buffer> AsPacket<'a, Packet<&'a [u8]>> for Builder { - fn as_packet(&self) -> Result> { - Packet::new(self.buffer.data()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.buffer.data()) + } } impl<'a, B: Buffer> AsPacketMut<'a, Packet<&'a mut [u8]>> for Builder { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.buffer.data_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.buffer.data_mut()) + } } impl Builder { - /// Source port. - pub fn source(mut self, value: u16) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_source(value)?; - Ok(self) - } - - /// Destination port. - pub fn destination(mut self, value: u16) -> Result { - Packet::unchecked(self.buffer.data_mut()).set_destination(value)?; - Ok(self) - } - - /// Payload for the packet. - pub fn payload<'a, T: IntoIterator>(mut self, value: T) -> Result { - if self.payload { - Err(Error::AlreadyDefined)? - } - - self.payload = true; - - for byte in value { - self.buffer.more(1)?; - *self.buffer.data_mut().last_mut().unwrap() = *byte; - } - - Ok(self) - } - - fn prepare(&mut self) { - let ip = self.ip; - let length = self.buffer.length(); - - self.finalizer.add(move |out| { - let (before, after) = out.split_at_mut(ip.0 + ip.1); - let ip = &mut before[ip.0 ..]; - let udp = &mut after[.. length]; - - Cursor::new(&mut udp[4 ..]) - .write_u16::(length as u16)?; - - let checksum: Result = if let Ok(packet) = ip::v4::Packet::no_payload(&ip) { - Ok(checksum(&ip::Packet::from(packet), udp)) - } - else if let Ok(packet) = ip::v6::Packet::no_payload(&ip) { - Ok(checksum(&ip::Packet::from(packet), udp)) - } - else { - Err(Error::InvalidPacket)? - }; - - Cursor::new(&mut udp[6 ..]) - .write_u16::(checksum?)?; - - Ok(()) - }); - } + /// Source port. + pub fn source(mut self, value: u16) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_source(value)?; + Ok(self) + } + + /// Destination port. + pub fn destination(mut self, value: u16) -> Result { + Packet::unchecked(self.buffer.data_mut()).set_destination(value)?; + Ok(self) + } + + /// Payload for the packet. + pub fn payload<'a, T: IntoIterator>(mut self, value: T) -> Result { + if self.payload { + Err(Error::AlreadyDefined)? + } + + self.payload = true; + + for byte in value { + self.buffer.more(1)?; + *self.buffer.data_mut().last_mut().unwrap() = *byte; + } + + Ok(self) + } + + fn prepare(&mut self) { + let ip = self.ip; + let length = self.buffer.length(); + + self.finalizer.add(move |out| { + let (before, after) = out.split_at_mut(ip.0 + ip.1); + let ip = &mut before[ip.0..]; + let udp = &mut after[..length]; + + Cursor::new(&mut udp[4..]).write_u16::(length as u16)?; + + let checksum: Result = if let Ok(packet) = ip::v4::Packet::no_payload(&ip) { + Ok(checksum(&ip::Packet::from(packet), udp)) + } else if let Ok(packet) = ip::v6::Packet::no_payload(&ip) { + Ok(checksum(&ip::Packet::from(packet), udp)) + } else { + Err(Error::InvalidPacket)? + }; + + Cursor::new(&mut udp[6..]).write_u16::(checksum?)?; + + Ok(()) + }); + } } #[cfg(test)] mod test { - use std::net::Ipv4Addr; - use crate::builder::Builder; - use crate::packet::Packet; - use crate::ip; - use crate::udp; - - #[test] - fn simple() { - let packet = ip::v4::Builder::default() - .id(0x2d87).unwrap() - .ttl(64).unwrap() - .source("66.102.1.108".parse().unwrap()).unwrap() - .destination("192.168.0.79".parse().unwrap()).unwrap() - .udp().unwrap() - .source(1337).unwrap() - .destination(9001).unwrap() - .build().unwrap(); - - let ip = ip::v4::Packet::new(packet).unwrap(); - assert_eq!(ip.id(), 0x2d87); - assert!(ip.flags().is_empty()); - assert_eq!(ip.length(), 28); - assert_eq!(ip.ttl(), 64); - assert_eq!(ip.protocol(), ip::Protocol::Udp); - assert_eq!(ip.source(), "66.102.1.108".parse::().unwrap()); - assert_eq!(ip.destination(), "192.168.0.79".parse::().unwrap()); - assert!(ip.is_valid()); - - let udp = udp::Packet::new(ip.payload()).unwrap(); - assert_eq!(udp.source(), 1337); - assert_eq!(udp.destination(), 9001); - assert!(udp.is_valid(&ip::Packet::from(&ip))); - } + use crate::builder::Builder; + use crate::ip; + use crate::packet::Packet; + use crate::udp; + use std::net::Ipv4Addr; + + #[test] + fn simple() { + let packet = ip::v4::Builder::default() + .id(0x2d87) + .unwrap() + .ttl(64) + .unwrap() + .source("66.102.1.108".parse().unwrap()) + .unwrap() + .destination("192.168.0.79".parse().unwrap()) + .unwrap() + .udp() + .unwrap() + .source(1337) + .unwrap() + .destination(9001) + .unwrap() + .build() + .unwrap(); + + let ip = ip::v4::Packet::new(packet).unwrap(); + assert_eq!(ip.id(), 0x2d87); + assert!(ip.flags().is_empty()); + assert_eq!(ip.length(), 28); + assert_eq!(ip.ttl(), 64); + assert_eq!(ip.protocol(), ip::Protocol::Udp); + assert_eq!(ip.source(), "66.102.1.108".parse::().unwrap()); + assert_eq!( + ip.destination(), + "192.168.0.79".parse::().unwrap() + ); + assert!(ip.is_valid()); + + let udp = udp::Packet::new(ip.payload()).unwrap(); + assert_eq!(udp.source(), 1337); + assert_eq!(udp.destination(), 9001); + assert!(udp.is_valid(&ip::Packet::from(&ip))); + } } diff --git a/src/udp/mod.rs b/src/udp/mod.rs index fccb01f..8caa2a2 100644 --- a/src/udp/mod.rs +++ b/src/udp/mod.rs @@ -28,92 +28,89 @@ use crate::ip::Protocol; /// Since the checksum for UDP packets includes a pseudo-header based on the /// enclosing IP packet, one has to be given. pub fn checksum>(ip: &ip::Packet, buffer: &[u8]) -> u16 { - use std::io::Cursor; - use byteorder::{WriteBytesExt, ReadBytesExt, BigEndian}; - - let mut prefix = [0u8; 40]; - match *ip { - ip::Packet::V4(ref packet) => { - prefix[0 .. 4].copy_from_slice(&packet.source().octets()); - prefix[4 .. 8].copy_from_slice(&packet.destination().octets()); - - prefix[9] = Protocol::Udp.into(); - Cursor::new(&mut prefix[10 ..]) - .write_u16::(buffer.len() as u16).unwrap(); - } - - ip::Packet::V6(ref _packet) => { - unimplemented!(); - } - }; - - let mut result = 0x0000u32; - let mut buffer = Cursor::new(buffer); - let mut prefix = match *ip { - ip::Packet::V4(_) => - Cursor::new(&prefix[0 .. 12]), - - ip::Packet::V6(_) => - Cursor::new(&prefix[0 .. 40]), - }; - - while let Ok(value) = prefix.read_u16::() { - result += u32::from(value); - - if result > 0xffff { - result -= 0xffff; - } - } - - while let Ok(value) = buffer.read_u16::() { - // Skip checksum field. - if buffer.position() == 8 { - continue; - } - - result += u32::from(value); - - if result > 0xffff { - result -= 0xffff; - } - } - - if let Ok(value) = buffer.read_u8() { - // if we have a trailing byte, make a padded 16-bit value. - let value = (value as u16) << 8; - - result += u32::from(value); - - if result > 0xffff { - result -= 0xffff; - } - } - - !result as u16 + use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; + use std::io::Cursor; + + let mut prefix = [0u8; 40]; + match *ip { + ip::Packet::V4(ref packet) => { + prefix[0..4].copy_from_slice(&packet.source().octets()); + prefix[4..8].copy_from_slice(&packet.destination().octets()); + + prefix[9] = Protocol::Udp.into(); + Cursor::new(&mut prefix[10..]) + .write_u16::(buffer.len() as u16) + .unwrap(); + } + + ip::Packet::V6(ref _packet) => { + unimplemented!(); + } + }; + + let mut result = 0x0000u32; + let mut buffer = Cursor::new(buffer); + let mut prefix = match *ip { + ip::Packet::V4(_) => Cursor::new(&prefix[0..12]), + + ip::Packet::V6(_) => Cursor::new(&prefix[0..40]), + }; + + while let Ok(value) = prefix.read_u16::() { + result += u32::from(value); + + if result > 0xffff { + result -= 0xffff; + } + } + + while let Ok(value) = buffer.read_u16::() { + // Skip checksum field. + if buffer.position() == 8 { + continue; + } + + result += u32::from(value); + + if result > 0xffff { + result -= 0xffff; + } + } + + if let Ok(value) = buffer.read_u8() { + // if we have a trailing byte, make a padded 16-bit value. + let value = (value as u16) << 8; + + result += u32::from(value); + + if result > 0xffff { + result -= 0xffff; + } + } + + !result as u16 } #[cfg(test)] mod tests { - use crate::{udp, ip, Packet}; - use crate::udp::checksum; - - #[test] - fn test_checksum() { - let raw = [ - // IPv4 - 0x45, 0x00, 0x00, 0x44, 0xad, 0x0b, 0x00, 0x00, 0x40, 0x11, 0x72, 0x72, 0xac, 0x14, - 0x02, 0xfd, 0xac, 0x14, 0x00, 0x06, - // UDP - 0xe5, 0x87, 0x00, 0x35, 0x00, 0x30, 0xe3, 0x20, - // data - 0xab, 0xc9, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x6d, - 0x63, 0x63, 0x6c, 0x65, 0x6c, 0x6c, 0x61, 0x6e, 0x02, 0x63, 0x73, 0x05, 0x6d, 0x69, - 0x61, 0x6d, 0x69, 0x03, 0x65, 0x64, 0x75, 0x00, 0x00, 0x01, 0x00, 0x01, - ]; - - let ip = ip::v4::Packet::new(&raw[..]).unwrap(); - let udp = udp::Packet::new(ip.payload()).unwrap(); - - assert_eq!(checksum(&ip::Packet::V4(ip), ip.payload()), udp.checksum()); - } + use crate::udp::checksum; + use crate::{ip, udp, Packet}; + + #[test] + fn test_checksum() { + let raw = [ + // IPv4 + 0x45, 0x00, 0x00, 0x44, 0xad, 0x0b, 0x00, 0x00, 0x40, 0x11, 0x72, 0x72, 0xac, 0x14, + 0x02, 0xfd, 0xac, 0x14, 0x00, 0x06, // UDP + 0xe5, 0x87, 0x00, 0x35, 0x00, 0x30, 0xe3, 0x20, // data + 0xab, 0xc9, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x6d, + 0x63, 0x63, 0x6c, 0x65, 0x6c, 0x6c, 0x61, 0x6e, 0x02, 0x63, 0x73, 0x05, 0x6d, 0x69, + 0x61, 0x6d, 0x69, 0x03, 0x65, 0x64, 0x75, 0x00, 0x00, 0x01, 0x00, 0x01, + ]; + + let ip = ip::v4::Packet::new(&raw[..]).unwrap(); + let udp = udp::Packet::new(ip.payload()).unwrap(); + + assert_eq!(checksum(&ip::Packet::V4(ip), ip.payload()), udp.checksum()); + } } diff --git a/src/udp/packet.rs b/src/udp/packet.rs index ec6bacb..8602bda 100644 --- a/src/udp/packet.rs +++ b/src/udp/packet.rs @@ -12,222 +12,225 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::fmt; use std::io::Cursor; -use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; use crate::error::*; -use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut}; use crate::ip; +use crate::packet::{AsPacket, AsPacketMut, Packet as P, PacketMut as PM}; use crate::udp::checksum; /// UDP packet parser. pub struct Packet { - buffer: B, + buffer: B, } sized!(Packet, - header { - min: 8, - max: 8, - size: 8, - } - - payload { - min: 0, - max: u16::max_value() as usize - 8, - size: p => (p.length() as usize).saturating_sub(8), - }); +header { + min: 8, + max: 8, + size: 8, +} + +payload { + min: 0, + max: u16::max_value() as usize - 8, + size: p => (p.length() as usize).saturating_sub(8), +}); impl> fmt::Debug for Packet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("udp::Packet") - .field("source", &self.source()) - .field("destination", &self.destination()) - .field("checksum", &self.length()) - .field("checksum", &self.checksum()) - .field("payload", &self.payload()) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("udp::Packet") + .field("source", &self.source()) + .field("destination", &self.destination()) + .field("checksum", &self.length()) + .field("checksum", &self.checksum()) + .field("payload", &self.payload()) + .finish() + } } impl> Packet { - /// Create a UDP packet without checking. - pub fn unchecked(buffer: B) -> Packet { - Packet { buffer } - } + /// Create a UDP packet without checking. + pub fn unchecked(buffer: B) -> Packet { + Packet { buffer } + } - /// Parse a UDP packet without checking the payload. - pub fn no_payload(buffer: B) -> Result> { - use crate::size::header::Min; + /// Parse a UDP packet without checking the payload. + pub fn no_payload(buffer: B) -> Result> { + use crate::size::header::Min; - let packet = Packet::unchecked(buffer); + let packet = Packet::unchecked(buffer); - if packet.buffer.as_ref().len() < Self::min() { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < Self::min() { + Err(Error::SmallBuffer)? + } - Ok(packet) - } + Ok(packet) + } - /// Parse a UDP packet, checking the buffer contents are correct. - pub fn new(buffer: B) -> Result> { - let packet = Packet::no_payload(buffer)?; + /// Parse a UDP packet, checking the buffer contents are correct. + pub fn new(buffer: B) -> Result> { + let packet = Packet::no_payload(buffer)?; - if packet.buffer.as_ref().len() < packet.length() as usize { - Err(Error::SmallBuffer)? - } + if packet.buffer.as_ref().len() < packet.length() as usize { + Err(Error::SmallBuffer)? + } - Ok(packet) - } + Ok(packet) + } } impl> Packet { - /// Convert the packet to its owned version. - /// - /// # Notes - /// - /// It would be nice if `ToOwned` could be implemented, but `Packet` already - /// implements `Clone` and the impl would conflict. - pub fn to_owned(&self) -> Packet> { - Packet { - buffer: self.buffer.as_ref().to_vec(), - } - } + /// Convert the packet to its owned version. + /// + /// # Notes + /// + /// It would be nice if `ToOwned` could be implemented, but `Packet` already + /// implements `Clone` and the impl would conflict. + pub fn to_owned(&self) -> Packet> { + Packet { + buffer: self.buffer.as_ref().to_vec(), + } + } } impl> AsRef<[u8]> for Packet { - fn as_ref(&self) -> &[u8] { - use crate::size::Size; + fn as_ref(&self) -> &[u8] { + use crate::size::Size; - &self.buffer.as_ref()[.. self.size()] - } + &self.buffer.as_ref()[..self.size()] + } } impl + AsMut<[u8]>> AsMut<[u8]> for Packet { - fn as_mut(&mut self) -> &mut [u8] { - use crate::size::Size; + fn as_mut(&mut self) -> &mut [u8] { + use crate::size::Size; - let size = self.size(); - &mut self.buffer.as_mut()[.. size] - } + let size = self.size(); + &mut self.buffer.as_mut()[..size] + } } impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B { - fn as_packet(&self) -> Result> { - Packet::new(self.as_ref()) - } + fn as_packet(&self) -> Result> { + Packet::new(self.as_ref()) + } } impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B { - fn as_packet_mut(&mut self) -> Result> { - Packet::new(self.as_mut()) - } + fn as_packet_mut(&mut self) -> Result> { + Packet::new(self.as_mut()) + } } impl> P for Packet { - fn split(&self) -> (&[u8], &[u8]) { - use crate::size::payload::Size; - - let header = 8; - let payload = self.size(); - - let buffer = self.buffer.as_ref(); - let buffer = if buffer.len() < header + payload { - buffer - } - else { - &buffer[.. header + payload] - }; - - buffer.split_at(header) - } + fn split(&self) -> (&[u8], &[u8]) { + use crate::size::payload::Size; + + let header = 8; + let payload = self.size(); + + let buffer = self.buffer.as_ref(); + let buffer = if buffer.len() < header + payload { + buffer + } else { + &buffer[..header + payload] + }; + + buffer.split_at(header) + } } impl + AsMut<[u8]>> PM for Packet { - fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { - use crate::size::payload::Size; - - let header = 8; - let payload = self.size(); - - let buffer = self.buffer.as_mut(); - let buffer = if buffer.len() < header + payload { - buffer - } - else { - &mut buffer[.. header + payload] - }; - - buffer.split_at_mut(header) - } + fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) { + use crate::size::payload::Size; + + let header = 8; + let payload = self.size(); + + let buffer = self.buffer.as_mut(); + let buffer = if buffer.len() < header + payload { + buffer + } else { + &mut buffer[..header + payload] + }; + + buffer.split_at_mut(header) + } } impl> Packet { - /// Source port. - pub fn source(&self) -> u16 { - (&self.buffer.as_ref()[0 ..]).read_u16::().unwrap() - } - - /// Destination port. - pub fn destination(&self) -> u16 { - (&self.buffer.as_ref()[2 ..]).read_u16::().unwrap() - } - - /// Total length of the packet. - pub fn length(&self) -> u16 { - (&self.buffer.as_ref()[4 ..]).read_u16::().unwrap() - } - - /// Checksum of the packet. - pub fn checksum(&self) -> u16 { - (&self.buffer.as_ref()[6 ..]).read_u16::().unwrap() - } - - /// Verify the packet is valid by calculating the checksum. - pub fn is_valid>(&self, ip: &ip::Packet) -> bool { - checksum(ip, self.buffer.as_ref()) == self.checksum() - } + /// Source port. + pub fn source(&self) -> u16 { + (&self.buffer.as_ref()[0..]) + .read_u16::() + .unwrap() + } + + /// Destination port. + pub fn destination(&self) -> u16 { + (&self.buffer.as_ref()[2..]) + .read_u16::() + .unwrap() + } + + /// Total length of the packet. + pub fn length(&self) -> u16 { + (&self.buffer.as_ref()[4..]) + .read_u16::() + .unwrap() + } + + /// Checksum of the packet. + pub fn checksum(&self) -> u16 { + (&self.buffer.as_ref()[6..]) + .read_u16::() + .unwrap() + } + + /// Verify the packet is valid by calculating the checksum. + pub fn is_valid>(&self, ip: &ip::Packet) -> bool { + checksum(ip, self.buffer.as_ref()) == self.checksum() + } } impl + AsMut<[u8]>> Packet { - /// Source port. - pub fn set_source(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[0 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Destination port. - pub fn set_destination(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[2 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Create a checksumed setter. - pub fn checked<'a, 'b, BI: AsRef<[u8]> + 'b>(&'a mut self, ip: &'b ip::Packet) -> Checked<'a, 'b, B, BI> { - Checked { - packet: self, - ip: ip, - } - } - - /// Set the checksum value. - pub fn set_checksum(&mut self, value: u16) -> Result<&mut Self> { - Cursor::new(&mut self.header_mut()[6 ..]) - .write_u16::(value)?; - - Ok(self) - } - - /// Recalculate and set the checksum value. - pub fn update_checksum>(&mut self, ip: &ip::Packet) -> Result<&mut Self> { - let checksum = checksum(ip, self.buffer.as_ref()); - self.set_checksum(checksum) - } + /// Source port. + pub fn set_source(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[0..]).write_u16::(value)?; + + Ok(self) + } + + /// Destination port. + pub fn set_destination(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[2..]).write_u16::(value)?; + + Ok(self) + } + + /// Create a checksumed setter. + pub fn checked<'a, 'b, BI: AsRef<[u8]> + 'b>( + &'a mut self, + ip: &'b ip::Packet, + ) -> Checked<'a, 'b, B, BI> { + Checked { packet: self, ip } + } + + /// Set the checksum value. + pub fn set_checksum(&mut self, value: u16) -> Result<&mut Self> { + Cursor::new(&mut self.header_mut()[6..]).write_u16::(value)?; + + Ok(self) + } + + /// Recalculate and set the checksum value. + pub fn update_checksum>(&mut self, ip: &ip::Packet) -> Result<&mut Self> { + let checksum = checksum(ip, self.buffer.as_ref()); + self.set_checksum(checksum) + } } /// Checked wrapper for UDP packets. @@ -236,92 +239,113 @@ impl + AsMut<[u8]>> Packet { /// /// The checksum recalculation happens on `Drop`, so don't leak it. pub struct Checked<'a, 'b, BP, BI> - where BP: AsRef<[u8]> + AsMut<[u8]> + 'a, - BI: AsRef<[u8]> + 'b +where + BP: AsRef<[u8]> + AsMut<[u8]> + 'a, + BI: AsRef<[u8]> + 'b, { - packet: &'a mut Packet, - ip: &'b ip::Packet, + packet: &'a mut Packet, + ip: &'b ip::Packet, } impl<'a, 'b, BP, BI> Checked<'a, 'b, BP, BI> - where BP: AsRef<[u8]> + AsMut<[u8]> + 'a, - BI: AsRef<[u8]> + 'b +where + BP: AsRef<[u8]> + AsMut<[u8]> + 'a, + BI: AsRef<[u8]> + 'b, { - /// Source port. - pub fn set_source(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_source(value)?; - Ok(self) - } - - /// Destination port. - pub fn set_destination(&mut self, value: u16) -> Result<&mut Self> { - self.packet.set_destination(value)?; - Ok(self) - } + /// Source port. + pub fn set_source(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_source(value)?; + Ok(self) + } + + /// Destination port. + pub fn set_destination(&mut self, value: u16) -> Result<&mut Self> { + self.packet.set_destination(value)?; + Ok(self) + } } impl<'a, 'b, BP, BI> Drop for Checked<'a, 'b, BP, BI> - where BP: AsRef<[u8]> + AsMut<[u8]> + 'a, - BI: AsRef<[u8]> + 'b +where + BP: AsRef<[u8]> + AsMut<[u8]> + 'a, + BI: AsRef<[u8]> + 'b, { - fn drop(&mut self) { - self.packet.update_checksum(self.ip).unwrap(); - } + fn drop(&mut self) { + self.packet.update_checksum(self.ip).unwrap(); + } } #[cfg(test)] mod test { - use crate::packet::{Packet, PacketMut}; - use crate::ip; - use crate::udp; - - #[test] - fn values() { - let raw = [0x45u8, 0x00, 0x00, 0x42, 0x47, 0x07, 0x40, 0x00, 0x40, 0x11, 0x6e, 0xcc, 0xc0, 0xa8, 0x01, 0x89, 0xc0, 0xa8, 0x01, 0xfe, 0xba, 0x2f, 0x00, 0x35, 0x00, 0x2e, 0x1d, 0xf8, 0xbc, 0x81, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x70, 0x69, 0x0c, 0x73, 0x74, 0x65, 0x61, 0x6d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x65, 0x64, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01]; - - let ip = ip::v4::Packet::new(&raw[..]).unwrap(); - let udp = udp::Packet::new(ip.payload()).unwrap(); - - assert!(ip.is_valid()); - assert!(udp.is_valid(&ip::Packet::from(&ip))); - - assert_eq!(udp.destination(), 53); - } - - #[test] - fn mutable() { - let mut raw = [0x45u8, 0x00, 0x00, 0x42, 0x47, 0x07, 0x40, 0x00, 0x40, 0x11, 0x6e, 0xcc, 0xc0, 0xa8, 0x01, 0x89, 0xc0, 0xa8, 0x01, 0xfe, 0xba, 0x2f, 0x00, 0x35, 0x00, 0x2e, 0x1d, 0xf8, 0xbc, 0x81, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x70, 0x69, 0x0c, 0x73, 0x74, 0x65, 0x61, 0x6d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x65, 0x64, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01]; - - let mut ip = ip::v4::Packet::new(&mut raw[..]).unwrap(); - let (ip, udp) = ip.split_mut(); - let ip = ip::Packet::from(ip::v4::Packet::unchecked(ip)); - let mut udp = udp::Packet::new(udp).unwrap(); - - assert!(udp.is_valid(&ip)); - assert_eq!(udp.destination(), 53); - - udp.set_destination(9001).unwrap(); - assert_eq!(udp.destination(), 9001); - assert!(!udp.is_valid(&ip)); - - udp.update_checksum(&ip).unwrap(); - assert!(udp.is_valid(&ip)); - } - - #[test] - fn mutable_checked() { - let mut raw = [0x45u8, 0x00, 0x00, 0x42, 0x47, 0x07, 0x40, 0x00, 0x40, 0x11, 0x6e, 0xcc, 0xc0, 0xa8, 0x01, 0x89, 0xc0, 0xa8, 0x01, 0xfe, 0xba, 0x2f, 0x00, 0x35, 0x00, 0x2e, 0x1d, 0xf8, 0xbc, 0x81, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x70, 0x69, 0x0c, 0x73, 0x74, 0x65, 0x61, 0x6d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x65, 0x64, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01]; - - let mut ip = ip::v4::Packet::new(&mut raw[..]).unwrap(); - let (ip, udp) = ip.split_mut(); - let ip = ip::Packet::from(ip::v4::Packet::unchecked(ip)); - let mut udp = udp::Packet::new(udp).unwrap(); - - assert!(udp.is_valid(&ip)); - assert_eq!(udp.destination(), 53); - - udp.checked(&ip).set_destination(9001).unwrap(); - assert_eq!(udp.destination(), 9001); - assert!(udp.is_valid(&ip)); - } + use crate::ip; + use crate::packet::{Packet, PacketMut}; + use crate::udp; + + #[test] + fn values() { + let raw = [ + 0x45u8, 0x00, 0x00, 0x42, 0x47, 0x07, 0x40, 0x00, 0x40, 0x11, 0x6e, 0xcc, 0xc0, 0xa8, + 0x01, 0x89, 0xc0, 0xa8, 0x01, 0xfe, 0xba, 0x2f, 0x00, 0x35, 0x00, 0x2e, 0x1d, 0xf8, + 0xbc, 0x81, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, + 0x70, 0x69, 0x0c, 0x73, 0x74, 0x65, 0x61, 0x6d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x65, + 0x64, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, + ]; + + let ip = ip::v4::Packet::new(&raw[..]).unwrap(); + let udp = udp::Packet::new(ip.payload()).unwrap(); + + assert!(ip.is_valid()); + assert!(udp.is_valid(&ip::Packet::from(&ip))); + + assert_eq!(udp.destination(), 53); + } + + #[test] + fn mutable() { + let mut raw = [ + 0x45u8, 0x00, 0x00, 0x42, 0x47, 0x07, 0x40, 0x00, 0x40, 0x11, 0x6e, 0xcc, 0xc0, 0xa8, + 0x01, 0x89, 0xc0, 0xa8, 0x01, 0xfe, 0xba, 0x2f, 0x00, 0x35, 0x00, 0x2e, 0x1d, 0xf8, + 0xbc, 0x81, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, + 0x70, 0x69, 0x0c, 0x73, 0x74, 0x65, 0x61, 0x6d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x65, + 0x64, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, + ]; + + let mut ip = ip::v4::Packet::new(&mut raw[..]).unwrap(); + let (ip, udp) = ip.split_mut(); + let ip = ip::Packet::from(ip::v4::Packet::unchecked(ip)); + let mut udp = udp::Packet::new(udp).unwrap(); + + assert!(udp.is_valid(&ip)); + assert_eq!(udp.destination(), 53); + + udp.set_destination(9001).unwrap(); + assert_eq!(udp.destination(), 9001); + assert!(!udp.is_valid(&ip)); + + udp.update_checksum(&ip).unwrap(); + assert!(udp.is_valid(&ip)); + } + + #[test] + fn mutable_checked() { + let mut raw = [ + 0x45u8, 0x00, 0x00, 0x42, 0x47, 0x07, 0x40, 0x00, 0x40, 0x11, 0x6e, 0xcc, 0xc0, 0xa8, + 0x01, 0x89, 0xc0, 0xa8, 0x01, 0xfe, 0xba, 0x2f, 0x00, 0x35, 0x00, 0x2e, 0x1d, 0xf8, + 0xbc, 0x81, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, + 0x70, 0x69, 0x0c, 0x73, 0x74, 0x65, 0x61, 0x6d, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x65, + 0x64, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, + ]; + + let mut ip = ip::v4::Packet::new(&mut raw[..]).unwrap(); + let (ip, udp) = ip.split_mut(); + let ip = ip::Packet::from(ip::v4::Packet::unchecked(ip)); + let mut udp = udp::Packet::new(udp).unwrap(); + + assert!(udp.is_valid(&ip)); + assert_eq!(udp.destination(), 53); + + udp.checked(&ip).set_destination(9001).unwrap(); + assert_eq!(udp.destination(), 9001); + assert!(udp.is_valid(&ip)); + } }