#![doc = include_str!("../README.md")]
#![no_std]
extern crate alloc;
pub mod geneve;
use alloc::{borrow::ToOwned, string::String, vec::Vec};
use core::{
fmt::{self, LowerHex, UpperHex},
net::IpAddr,
ops::{Index, IndexMut},
slice::{Iter, IterMut, SliceIndex},
};
use bytes::{Buf, BufMut, Bytes, BytesMut, buf::UninitSlice};
use ts_hexdump::{AsHexExt, Case, hex_fmt};
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct Packet {
contents: Bytes,
}
impl Packet {
pub const EMPTY: Packet = Packet {
contents: Bytes::from_static(&[]),
};
pub fn is_empty(&self) -> bool {
self.contents.is_empty()
}
pub fn iter(&'_ self) -> Iter<'_, u8> {
self.contents.iter()
}
pub fn len(&self) -> usize {
self.contents.len()
}
}
impl fmt::Debug for Packet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:X}")
}
}
impl AsRef<[u8]> for Packet {
fn as_ref(&self) -> &[u8] {
self.contents.as_ref()
}
}
impl Buf for Packet {
fn remaining(&self) -> usize {
self.contents.remaining()
}
fn chunk(&self) -> &[u8] {
&self.contents
}
fn advance(&mut self, cnt: usize) {
self.contents.advance(cnt);
}
}
impl From<&[u8]> for Packet {
fn from(value: &[u8]) -> Self {
Self {
contents: Bytes::from(value.to_owned()),
}
}
}
impl From<Bytes> for Packet {
fn from(value: Bytes) -> Self {
Self { contents: value }
}
}
impl From<BytesMut> for Packet {
fn from(value: BytesMut) -> Self {
Self {
contents: value.freeze(),
}
}
}
impl From<PacketMut> for Packet {
fn from(value: PacketMut) -> Self {
value.freeze()
}
}
impl From<Vec<u8>> for Packet {
fn from(value: Vec<u8>) -> Self {
Self {
contents: value.into(),
}
}
}
impl<T> Index<T> for Packet
where
[u8]: Index<T>,
{
type Output = <[u8] as Index<T>>::Output;
#[inline]
fn index(&self, index: T) -> &Self::Output {
self.contents.index(index)
}
}
impl LowerHex for Packet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
self.iter().hex(Case::Lower).flatten().collect::<String>()
)
}
}
impl UpperHex for Packet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
self.iter().hex(Case::Upper).flatten().collect::<String>()
)
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct PacketMut {
contents: BytesMut,
}
impl PacketMut {
pub fn new(size: usize) -> Self {
Self {
contents: BytesMut::zeroed(size),
}
}
pub fn with_capacity(size: usize) -> Self {
Self {
contents: BytesMut::with_capacity(size),
}
}
pub fn capacity(&self) -> usize {
self.contents.capacity()
}
pub fn extend_from_slice(&mut self, slice: &[u8]) {
self.contents.extend_from_slice(slice);
}
pub fn grow_front(&mut self, len: usize) {
let existing_len = self.contents.len();
self.contents.resize(existing_len + len, 0);
self.contents.copy_within(..existing_len, len);
self.contents[..len].fill(0);
}
pub fn extend_front_from_slice(&mut self, slice: &[u8]) {
self.grow_front(slice.len());
self.contents[..slice.len()].copy_from_slice(slice);
}
pub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[u8]>>::Output>
where
I: SliceIndex<[u8]>,
{
self.contents.get(index)
}
pub fn get_mut<I>(&mut self, index: I) -> Option<&mut <I as SliceIndex<[u8]>>::Output>
where
I: SliceIndex<[u8]>,
{
self.contents.get_mut(index)
}
pub fn freeze(self) -> Packet {
Packet {
contents: self.contents.freeze(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn iter(&'_ self) -> Iter<'_, u8> {
self.contents.iter()
}
pub fn iter_mut(&'_ mut self) -> IterMut<'_, u8> {
self.contents.iter_mut()
}
pub fn len(&self) -> usize {
self.contents.len()
}
pub fn truncate(&mut self, count: usize) {
self.contents.truncate(count);
}
pub fn truncate_front(&mut self, count: usize) {
self.contents.advance(count);
}
pub fn split_off(&mut self, at: usize) -> PacketMut {
Self {
contents: self.contents.split_off(at),
}
}
pub fn split_to(&mut self, at: usize) -> PacketMut {
Self {
contents: self.contents.split_to(at),
}
}
fn get_ip_family(&self) -> Option<u8> {
match self.get(0)? >> 4 {
4 => Some(4),
6 => Some(6),
_ => None,
}
}
fn ipv4_at(&self, idx: usize) -> Option<IpAddr> {
let octets: [u8; 4] = self.get(idx..idx + 4)?.try_into().unwrap();
Some(IpAddr::from(octets))
}
fn ipv6_at(&self, idx: usize) -> Option<IpAddr> {
let octets: [u8; 16] = self.get(idx..idx + 16)?.try_into().unwrap();
Some(IpAddr::from(octets))
}
pub fn get_src_addr(&self) -> Option<IpAddr> {
match self.get_ip_family() {
Some(4) => self.ipv4_at(12),
Some(6) => self.ipv6_at(8),
_ => None,
}
}
pub fn get_dst_addr(&self) -> Option<IpAddr> {
match self.get_ip_family() {
Some(4) => self.ipv4_at(16),
Some(6) => self.ipv6_at(24),
_ => None,
}
}
}
impl fmt::Debug for PacketMut {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:X}")
}
}
impl AsMut<[u8]> for PacketMut {
fn as_mut(&mut self) -> &mut [u8] {
self.contents.as_mut()
}
}
impl AsRef<[u8]> for PacketMut {
fn as_ref(&self) -> &[u8] {
self.contents.as_ref()
}
}
impl Buf for PacketMut {
fn remaining(&self) -> usize {
self.contents.remaining_mut()
}
fn chunk(&self) -> &[u8] {
&self.contents
}
fn advance(&mut self, cnt: usize) {
self.contents.advance(cnt)
}
}
unsafe impl BufMut for PacketMut {
fn remaining_mut(&self) -> usize {
self.contents.remaining_mut()
}
unsafe fn advance_mut(&mut self, cnt: usize) {
unsafe {
self.contents.advance_mut(cnt);
}
}
fn chunk_mut(&mut self) -> &mut UninitSlice {
self.contents.chunk_mut()
}
}
impl crypto_box::aead::Buffer for PacketMut {
fn extend_from_slice(&mut self, other: &[u8]) -> crypto_box::aead::Result<()> {
self.contents.extend_from_slice(other);
Ok(())
}
fn truncate(&mut self, len: usize) {
self.truncate(len);
}
}
impl From<&[u8]> for PacketMut {
fn from(value: &[u8]) -> Self {
Self {
contents: BytesMut::from(value),
}
}
}
impl<const N: usize> From<&[u8; N]> for PacketMut {
fn from(value: &[u8; N]) -> Self {
Self {
contents: BytesMut::from(value.as_ref()),
}
}
}
impl From<Vec<u8>> for PacketMut {
fn from(value: Vec<u8>) -> Self {
Self {
contents: BytesMut::from(value.as_slice()),
}
}
}
impl From<BytesMut> for PacketMut {
fn from(value: BytesMut) -> Self {
Self { contents: value }
}
}
impl<T> Index<T> for PacketMut
where
[u8]: Index<T>,
{
type Output = <[u8] as Index<T>>::Output;
#[inline]
fn index(&self, index: T) -> &Self::Output {
self.contents.index(index)
}
}
impl<T> IndexMut<T> for PacketMut
where
[u8]: IndexMut<T>,
{
#[inline]
fn index_mut(&mut self, index: T) -> &mut Self::Output {
self.contents.index_mut(index)
}
}
impl LowerHex for PacketMut {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
hex_fmt(self.iter(), Case::Lower, f)
}
}
impl UpperHex for PacketMut {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
hex_fmt(self.iter(), Case::Upper, f)
}
}
#[cfg(test)]
mod tests {
use alloc::string::String;
use core::fmt::Write;
use super::*;
const BYTE_SEQUENCE_1: &[u8] = &[
0x00u8, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
];
const BYTE_SEQUENCE_2: &[u8] = &[0x06, 0x00, 0x00, 0x00, 0x00];
#[test]
fn test_packet_mut_hexdump() {
let pkt = PacketMut::from(BYTE_SEQUENCE_1);
let mut buf = String::new();
write!(
buf,
"{}",
pkt.iter()
.hexdump(Case::Lower)
.flatten()
.collect::<String>()
)
.unwrap();
assert_eq!(
buf,
"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................\n10 aa bb cc dd ee ff .......\n"
);
buf.clear();
write!(
buf,
"{}",
pkt.iter()
.hexdump(Case::Upper)
.flatten()
.collect::<String>()
)
.unwrap();
assert_eq!(
buf,
"00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ................\n10 AA BB CC DD EE FF .......\n"
);
}
#[test]
fn test_packet_mut_iter() {
let pkt = PacketMut::from(BYTE_SEQUENCE_1);
for (idx, byte) in pkt.iter().enumerate() {
assert_eq!(
*byte, BYTE_SEQUENCE_1[idx],
"packet and original bytes should have identical values in same order"
);
}
}
#[test]
fn test_packet_mut_iter_mut() {
let mut pkt1 = PacketMut::from(BYTE_SEQUENCE_1);
let pkt2 = PacketMut::from(BYTE_SEQUENCE_1);
for byte in pkt1.iter_mut() {
*byte = byte.wrapping_sub(0xFF);
}
for (idx, byte) in pkt1.iter().enumerate() {
assert_eq!(
*byte,
BYTE_SEQUENCE_1[idx].wrapping_sub(0xFF),
"pkt1 and original bytes should have values offset by 0xFF"
);
assert_eq!(
pkt2[idx], BYTE_SEQUENCE_1[idx],
"pkt2 and original bytes should have identical values in same order"
);
assert_eq!(
pkt1[idx],
pkt2[idx].wrapping_sub(0xFF),
"pkt1 and pkt2 should have values offset by 0xFF"
);
}
}
#[test]
fn test_packet_mut_prepend() {
let mut pkt = PacketMut::from(BYTE_SEQUENCE_1);
pkt.grow_front(5);
assert_eq!(pkt.len(), BYTE_SEQUENCE_1.len() + 5);
assert_eq!(pkt[..5], [0; 5]);
assert_eq!(&pkt[5..], BYTE_SEQUENCE_1);
let mut pkt = PacketMut::from(BYTE_SEQUENCE_1);
pkt.extend_front_from_slice(BYTE_SEQUENCE_2);
assert_eq!(pkt.len(), BYTE_SEQUENCE_1.len() + BYTE_SEQUENCE_2.len());
assert_eq!(&pkt[..BYTE_SEQUENCE_2.len()], BYTE_SEQUENCE_2);
assert_eq!(&pkt[BYTE_SEQUENCE_2.len()..], BYTE_SEQUENCE_1);
}
}