Add ICMP
This commit is contained in:
parent
4a5ff43d60
commit
32a254a4ce
121
src/packet/protocols/icmp.rs
Normal file
121
src/packet/protocols/icmp.rs
Normal file
@ -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 icmpv6;
|
||||||
pub mod tcp;
|
pub mod tcp;
|
||||||
pub mod udp;
|
pub mod udp;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user