1
This commit is contained in:
Evan Pratten 2023-07-18 14:02:18 -04:00
parent 4a5ff43d60
commit 32a254a4ce
2 changed files with 122 additions and 0 deletions
src/packet/protocols

@ -0,0 +1,121 @@
use pnet_packet::{
icmp::{IcmpCode, IcmpType},
Packet,
};
use crate::packet::error::PacketError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct IcmpPacket<T> {
pub icmp_type: IcmpType,
pub icmp_code: IcmpCode,
pub payload: T,
}
impl<T> IcmpPacket<T> {
/// Construct a new ICMPv6 packet
pub fn new(icmp_type: IcmpType, icmp_code: IcmpCode, payload: T) -> Self {
Self {
icmp_type,
icmp_code,
payload,
}
}
}
impl<T> IcmpPacket<T>
where
T: From<Vec<u8>>,
{
/// Construct a new ICMPv6 packet from raw bytes
pub fn new_from_bytes(bytes: &[u8]) -> Result<Self, PacketError> {
// Parse the packet
let packet =
pnet_packet::icmp::IcmpPacket::new(bytes).ok_or(PacketError::TooShort(bytes.len()))?;
// Return the packet
Ok(Self {
icmp_type: packet.get_icmp_type(),
icmp_code: packet.get_icmp_code(),
payload: packet.payload().to_vec().into(),
})
}
}
impl IcmpPacket<Vec<u8>> {
/// Construct a new ICMPv6 packet with a raw payload from raw bytes
pub fn new_from_bytes_raw_payload(bytes: &[u8]) -> Result<Self, PacketError> {
// Parse the packet
let packet =
pnet_packet::icmp::IcmpPacket::new(bytes).ok_or(PacketError::TooShort(bytes.len()))?;
// Return the packet
Ok(Self {
icmp_type: packet.get_icmp_type(),
icmp_code: packet.get_icmp_code(),
payload: packet.payload().to_vec(),
})
}
}
impl<T> Into<Vec<u8>> for IcmpPacket<T>
where
T: Into<Vec<u8>>,
{
fn into(self) -> Vec<u8> {
// Convert the payload into raw bytes
let payload: Vec<u8> = self.payload.into();
// Allocate a mutable packet to write into
let total_length =
pnet_packet::icmp::MutableIcmpPacket::minimum_packet_size() + payload.len();
let mut output =
pnet_packet::icmp::MutableIcmpPacket::owned(vec![0u8; total_length]).unwrap();
// Write the type and code
output.set_icmp_type(self.icmp_type);
output.set_icmp_code(self.icmp_code);
// Write the payload
output.set_payload(&payload);
// Calculate the checksum
output.set_checksum(0);
output.set_checksum(pnet_packet::icmp::checksum(&output.to_immutable()));
// Return the raw bytes
output.packet().to_vec()
}
}
#[cfg(test)]
mod tests {
use pnet_packet::icmp::IcmpTypes;
use super::*;
// Test packet construction
#[test]
#[rustfmt::skip]
fn test_packet_construction() {
// Make a new packet
let packet = IcmpPacket::new(
IcmpTypes::EchoRequest,
IcmpCode(0),
"Hello, world!".as_bytes().to_vec(),
);
// Convert to raw bytes
let packet_bytes: Vec<u8> = packet.into();
// Check the contents
assert!(packet_bytes.len() >= 4 + 13);
assert_eq!(packet_bytes[0], IcmpTypes::EchoRequest.0);
assert_eq!(packet_bytes[1], 0);
assert_eq!(u16::from_be_bytes([packet_bytes[2], packet_bytes[3]]), 0xb6b3);
assert_eq!(
&packet_bytes[4..],
"Hello, world!".as_bytes().to_vec().as_slice()
);
}
}

@ -1,3 +1,4 @@
pub mod icmp;
pub mod icmpv6;
pub mod tcp;
pub mod udp;