Bläddra i källkod

Add `ipsec_ah` packet

thegreathir 1 år sedan
förälder
incheckning
d0b5f76a1f
2 ändrade filer med 123 tillägg och 0 borttagningar
  1. 120 0
      src/wire/ipsec_ah.rs
  2. 3 0
      src/wire/mod.rs

+ 120 - 0
src/wire/ipsec_ah.rs

@@ -0,0 +1,120 @@
+use byteorder::{ByteOrder, NetworkEndian};
+
+use super::{Error, IpProtocol, Result};
+
+/// A read/write wrapper around an IPSec Authentication Header packet buffer.
+#[derive(Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct Packet<T: AsRef<[u8]>> {
+    buffer: T,
+}
+
+mod field {
+    use crate::wire::field::Field;
+
+    pub const NEXT_HEADER: usize = 0;
+    pub const PAYLOAD_LEN: usize = 1;
+    pub const RESERVED: Field = 2..4;
+    pub const SPI: Field = 4..8;
+    pub const SEQUENCE_NUMBER: Field = 8..16;
+}
+
+impl<T: AsRef<[u8]>> Packet<T> {
+    /// Imbue a raw octet buffer with IPsec Authentication Header packet structure.
+    pub const fn new_unchecked(buffer: T) -> Packet<T> {
+        Packet { buffer }
+    }
+
+    /// Shorthand for a combination of [new_unchecked] and [check_len].
+    ///
+    /// [new_unchecked]: #method.new_unchecked
+    /// [check_len]: #method.check_len
+    pub fn new_checked(buffer: T) -> Result<Packet<T>> {
+        let packet = Self::new_unchecked(buffer);
+        packet.check_len()?;
+        Ok(packet)
+    }
+
+    /// Ensure that no accessor method will panic if called.
+    /// Returns `Err(Error)` if the buffer is too short.
+    /// Returns `Err(Error)` if the buffer is shorter than payload length
+    ///
+    /// The result of this check is invalidated by calling [set_payload_len].
+    ///
+    /// [set_payload_len]: #method.set_payload_len
+    #[allow(clippy::if_same_then_else)]
+    pub fn check_len(&self) -> Result<()> {
+        let len = self.buffer.as_ref().len();
+        if len < field::SEQUENCE_NUMBER.end {
+            Err(Error)
+        } else if len < self.header_len() {
+            Err(Error)
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Consume the packet, returning the underlying buffer.
+    pub fn into_inner(self) -> T {
+        self.buffer
+    }
+
+    /// Return length of Authentication Header in octets
+    pub fn header_len(&self) -> usize {
+        (self.payload_len() as usize + 2) * 4
+    }
+
+    /// Return next header protocol type
+    /// The value is taken from the list of IP protocol numbers.
+    pub fn next_header(&self) -> IpProtocol {
+        let data = self.buffer.as_ref();
+        IpProtocol::from(data[field::NEXT_HEADER])
+    }
+
+    /// Return the length of this Authentication Header in 4-octet units, minus 2
+    pub fn payload_len(&self) -> u8 {
+        let data = self.buffer.as_ref();
+        data[field::PAYLOAD_LEN]
+    }
+
+    /// Return the security parameters index
+    pub fn security_parameters_index(&self) -> u32 {
+        let field = &self.buffer.as_ref()[field::SPI];
+        NetworkEndian::read_u32(field)
+    }
+
+    /// Return sequence number
+    pub fn sequence_number(&self) -> u32 {
+        let field = &self.buffer.as_ref()[field::SEQUENCE_NUMBER];
+        NetworkEndian::read_u32(field)
+    }
+}
+
+impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
+    /// Return a pointer to the integrity check value
+    #[inline]
+    pub fn integrity_check_value(&self) -> &'a [u8] {
+        let range = field::SEQUENCE_NUMBER.end as usize..self.header_len();
+        let data = self.buffer.as_ref();
+        &data[range]
+    }
+}
+
+
+impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
+    fn as_ref(&self) -> &[u8] {
+        self.buffer.as_ref()
+    }
+}
+
+impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
+    fn set_next_header(&mut self, value: IpProtocol) {
+        let data = self.buffer.as_mut();
+        data[field::NEXT_HEADER] = value.into()
+    }
+
+    fn set_payload_len(&mut self, value: u8) {
+        let data = self.buffer.as_mut();
+        data[field::PAYLOAD_LEN] = value
+    }
+}

+ 3 - 0
src/wire/mod.rs

@@ -127,6 +127,9 @@ mod sixlowpan;
 mod tcp;
 mod udp;
 
+#[cfg(feature = "proto-ipsec-ah")]
+mod ipsec_ah;
+
 use core::fmt;
 
 use crate::phy::Medium;