use bytes::{Bytes, BytesMut};
use smallvec::SmallVec;
use crate::error::{PacketError, Result};
use crate::layer::{
DnsLayer, HttpLayer, IcmpLayer, Icmpv6Layer, Ipv6Layer, LayerEnum, LayerIndex, LayerKind,
RawLayer, SshLayer, TcpLayer, TlsLayer, UdpLayer,
arp::ArpLayer,
dhcp::{DHCP_CLIENT_PORT, DHCP_SERVER_PORT, is_dhcp_payload},
ethernet::{Dot3Layer, ETHERNET_HEADER_LEN, EthernetLayer},
ethertype,
ftp::{FTP_CONTROL_PORT, is_ftp_payload},
http,
http2::{Http2Layer, is_http2_payload},
icmp,
imap::{IMAP_PORT, is_imap_payload},
ip_protocol,
ipv4::Ipv4Layer,
pop3::{POP3_PORT, is_pop3_payload},
smtp::{SMTP_PORT, SMTP_SUBMISSION_PORT, SMTPS_PORT, is_smtp_payload},
ssh::{SSH_PORT, is_ssh_payload},
tftp::{TFTP_PORT, is_tftp_payload},
tls::is_tls_payload,
};
const INLINE_LAYER_CAPACITY: usize = 4;
#[derive(Debug, Clone)]
pub struct Packet {
data: Bytes,
layers: SmallVec<[LayerIndex; INLINE_LAYER_CAPACITY]>,
is_dirty: bool,
}
impl Packet {
#[inline]
#[must_use]
pub fn empty() -> Self {
Self {
data: Bytes::new(),
layers: SmallVec::new(),
is_dirty: false,
}
}
#[inline]
pub fn from_bytes(data: impl Into<Bytes>) -> Self {
Self {
data: data.into(),
layers: SmallVec::new(),
is_dirty: false,
}
}
#[inline]
#[must_use]
pub fn from_slice(data: &[u8]) -> Self {
Self {
data: Bytes::copy_from_slice(data),
layers: SmallVec::new(),
is_dirty: false,
}
}
#[inline]
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
data: Bytes::from(BytesMut::with_capacity(capacity)),
layers: SmallVec::new(),
is_dirty: false,
}
}
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[inline]
pub fn is_dirty(&self) -> bool {
self.is_dirty
}
#[inline]
pub fn layer_count(&self) -> usize {
self.layers.len()
}
#[inline]
pub fn is_parsed(&self) -> bool {
!self.layers.is_empty()
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.data
}
#[inline]
pub fn bytes(&self) -> Bytes {
self.data.clone()
}
#[inline]
pub fn into_bytes(self) -> Bytes {
self.data
}
#[inline]
pub fn layers(&self) -> &[LayerIndex] {
&self.layers
}
#[inline]
pub fn get_layer(&self, kind: LayerKind) -> Option<&LayerIndex> {
self.layers.iter().find(|l| l.kind == kind)
}
pub fn layer_bytes(&self, kind: LayerKind) -> Result<&[u8]> {
self.get_layer(kind)
.map(|idx| &self.data[idx.range()])
.ok_or(PacketError::LayerNotFound(kind))
}
#[inline]
pub fn payload(&self) -> &[u8] {
self.layers
.last()
.map_or(&self.data, |l| &self.data[l.end..])
}
pub fn ethernet(&self) -> Option<EthernetLayer> {
self.get_layer(LayerKind::Ethernet)
.map(|idx| EthernetLayer::new(idx.start, idx.end))
}
pub fn ipv4(&self) -> Option<Ipv4Layer> {
self.get_layer(LayerKind::Ipv4)
.map(|idx| Ipv4Layer::new(idx.start, idx.end))
}
pub fn arp(&self) -> Option<ArpLayer> {
self.get_layer(LayerKind::Arp)
.map(|idx| ArpLayer::new(idx.start, idx.end))
}
pub fn icmp(&self) -> Option<IcmpLayer> {
self.get_layer(LayerKind::Icmp)
.map(|idx| IcmpLayer { index: *idx })
}
pub fn tcp(&self) -> Option<TcpLayer> {
self.get_layer(LayerKind::Tcp)
.map(|idx| TcpLayer::new(idx.start, idx.end))
}
pub fn udp(&self) -> Option<UdpLayer> {
self.get_layer(LayerKind::Udp)
.map(|idx| UdpLayer { index: *idx })
}
pub fn dns(&self) -> Option<DnsLayer> {
self.get_layer(LayerKind::Dns)
.map(|idx| DnsLayer { index: *idx })
}
pub fn tls(&self) -> Option<TlsLayer> {
self.get_layer(LayerKind::Tls)
.map(|idx| TlsLayer { index: *idx })
}
pub fn mqtt(&self) -> Option<crate::layer::mqtt::MqttLayer> {
self.get_layer(LayerKind::Mqtt)
.map(|idx| crate::layer::mqtt::MqttLayer::new(*idx))
}
pub fn mqttsn(&self) -> Option<crate::layer::mqttsn::MqttSnLayer> {
self.get_layer(LayerKind::MqttSn)
.map(|idx| crate::layer::mqttsn::MqttSnLayer::new(*idx))
}
pub fn modbus(&self) -> Option<crate::layer::modbus::ModbusLayer> {
self.get_layer(LayerKind::Modbus)
.map(|idx| crate::layer::modbus::ModbusLayer::new(*idx))
}
pub fn zwave(&self) -> Option<crate::layer::zwave::ZWaveLayer> {
self.get_layer(LayerKind::ZWave)
.map(|idx| crate::layer::zwave::ZWaveLayer::new(*idx))
}
pub fn ftp(&self) -> Option<crate::layer::ftp::FtpLayer> {
self.get_layer(LayerKind::Ftp)
.map(|idx| crate::layer::ftp::FtpLayer::new(*idx))
}
pub fn tftp(&self) -> Option<crate::layer::tftp::TftpLayer> {
self.get_layer(LayerKind::Tftp)
.map(|idx| crate::layer::tftp::TftpLayer::new(*idx))
}
pub fn smtp(&self) -> Option<crate::layer::smtp::SmtpLayer> {
self.get_layer(LayerKind::Smtp)
.map(|idx| crate::layer::smtp::SmtpLayer::new(*idx))
}
pub fn pop3(&self) -> Option<crate::layer::pop3::Pop3Layer> {
self.get_layer(LayerKind::Pop3)
.map(|idx| crate::layer::pop3::Pop3Layer::new(*idx))
}
pub fn imap(&self) -> Option<crate::layer::imap::ImapLayer> {
self.get_layer(LayerKind::Imap)
.map(|idx| crate::layer::imap::ImapLayer::new(*idx))
}
pub fn layer_enum(&self, idx: &LayerIndex) -> LayerEnum {
match idx.kind {
LayerKind::Ethernet => LayerEnum::Ethernet(EthernetLayer::new(idx.start, idx.end)),
LayerKind::Dot3 => LayerEnum::Dot3(Dot3Layer::new(idx.start, idx.end)),
LayerKind::Arp => LayerEnum::Arp(ArpLayer::new(idx.start, idx.end)),
LayerKind::Ipv4 => LayerEnum::Ipv4(Ipv4Layer::new(idx.start, idx.end)),
LayerKind::Ipv6 => LayerEnum::Ipv6(Ipv6Layer { index: *idx }),
LayerKind::Icmp => LayerEnum::Icmp(IcmpLayer { index: *idx }),
LayerKind::Icmpv6 => LayerEnum::Icmpv6(Icmpv6Layer { index: *idx }),
LayerKind::Tcp => LayerEnum::Tcp(TcpLayer::new(idx.start, idx.end)),
LayerKind::Udp => LayerEnum::Udp(UdpLayer { index: *idx }),
LayerKind::Dns => LayerEnum::Dns(DnsLayer { index: *idx }),
LayerKind::Ssh => LayerEnum::Ssh(SshLayer { index: *idx }),
LayerKind::Tls => LayerEnum::Tls(TlsLayer { index: *idx }),
LayerKind::Dot15d4 => {
LayerEnum::Dot15d4(crate::layer::dot15d4::Dot15d4Layer::new(idx.start, idx.end))
},
LayerKind::Dot15d4Fcs => LayerEnum::Dot15d4Fcs(
crate::layer::dot15d4::Dot15d4FcsLayer::new(idx.start, idx.end),
),
LayerKind::Dot11 => {
LayerEnum::Dot11(crate::layer::dot11::Dot11Layer::new(idx.start, idx.end))
},
LayerKind::Http => LayerEnum::Http(HttpLayer { index: *idx }),
LayerKind::Http2 => LayerEnum::Http2(Http2Layer::new(idx.start, idx.end, false)),
LayerKind::Quic => LayerEnum::Quic(crate::layer::quic::QuicLayer::from_index(*idx)),
LayerKind::L2tp => LayerEnum::L2tp(crate::layer::l2tp::L2tpLayer::new(*idx)),
LayerKind::Mqtt => LayerEnum::Mqtt(crate::layer::mqtt::MqttLayer::new(*idx)),
LayerKind::MqttSn => LayerEnum::MqttSn(crate::layer::mqttsn::MqttSnLayer::new(*idx)),
LayerKind::Modbus => LayerEnum::Modbus(crate::layer::modbus::ModbusLayer::new(*idx)),
LayerKind::ZWave => LayerEnum::ZWave(crate::layer::zwave::ZWaveLayer::new(*idx)),
LayerKind::Ftp => LayerEnum::Ftp(crate::layer::ftp::FtpLayer::new(*idx)),
LayerKind::Tftp => LayerEnum::Tftp(crate::layer::tftp::TftpLayer::new(*idx)),
LayerKind::Smtp => LayerEnum::Smtp(crate::layer::smtp::SmtpLayer::new(*idx)),
LayerKind::Pop3 => LayerEnum::Pop3(crate::layer::pop3::Pop3Layer::new(*idx)),
LayerKind::Imap => LayerEnum::Imap(crate::layer::imap::ImapLayer::new(*idx)),
LayerKind::Dhcp => LayerEnum::Dhcp(crate::layer::dhcp::DhcpLayer::new(*idx)),
LayerKind::Raw
| LayerKind::Dot1Q
| LayerKind::Dot1AD
| LayerKind::Dot1AH
| LayerKind::LLC
| LayerKind::SNAP
| LayerKind::Generic => LayerEnum::Raw(RawLayer { index: *idx }),
}
}
pub fn layer_enums(&self) -> Vec<LayerEnum> {
self.layers.iter().map(|idx| self.layer_enum(idx)).collect()
}
pub fn parse(&mut self) -> Result<()> {
self.layers.clear();
if self.data.len() < ETHERNET_HEADER_LEN {
return Ok(());
}
let eth_end = ETHERNET_HEADER_LEN;
self.layers
.push(LayerIndex::new(LayerKind::Ethernet, 0, eth_end));
let etype = u16::from_be_bytes([self.data[12], self.data[13]]);
match etype {
ethertype::IPV4 => self.parse_ipv4(eth_end)?,
ethertype::IPV6 => self.parse_ipv6(eth_end)?,
ethertype::ARP => self.parse_arp(eth_end)?,
_ => {
if eth_end < self.data.len() {
self.layers
.push(LayerIndex::new(LayerKind::Raw, eth_end, self.data.len()));
}
},
}
Ok(())
}
fn parse_ipv4(&mut self, offset: usize) -> Result<()> {
let min_size = 20;
if offset + min_size > self.data.len() {
return Err(PacketError::BufferTooShort {
expected: offset + min_size,
actual: self.data.len(),
});
}
let ihl = (self.data[offset] & 0x0F) as usize;
let header_len = ihl * 4;
if header_len < min_size {
return Err(PacketError::ParseError {
offset,
message: format!("invalid IHL: {ihl}"),
});
}
let ip_end = offset + header_len;
if ip_end > self.data.len() {
return Err(PacketError::BufferTooShort {
expected: ip_end,
actual: self.data.len(),
});
}
self.layers
.push(LayerIndex::new(LayerKind::Ipv4, offset, ip_end));
let protocol = self.data[offset + 9];
match protocol {
ip_protocol::TCP => self.parse_tcp(ip_end)?,
ip_protocol::UDP => self.parse_udp(ip_end)?,
ip_protocol::ICMP => self.parse_icmp(ip_end)?,
_ => {
if ip_end < self.data.len() {
self.layers
.push(LayerIndex::new(LayerKind::Raw, ip_end, self.data.len()));
}
},
}
Ok(())
}
fn parse_ipv6(&mut self, offset: usize) -> Result<()> {
let min_size = 40;
if offset + min_size > self.data.len() {
return Err(PacketError::BufferTooShort {
expected: offset + min_size,
actual: self.data.len(),
});
}
let ip_end = offset + min_size;
self.layers
.push(LayerIndex::new(LayerKind::Ipv6, offset, ip_end));
let next_header = self.data[offset + 6];
match next_header {
ip_protocol::TCP => self.parse_tcp(ip_end)?,
ip_protocol::UDP => self.parse_udp(ip_end)?,
ip_protocol::ICMPV6 => self.parse_icmpv6(ip_end)?,
_ => {
if ip_end < self.data.len() {
self.layers
.push(LayerIndex::new(LayerKind::Raw, ip_end, self.data.len()));
}
},
}
Ok(())
}
fn parse_arp(&mut self, offset: usize) -> Result<()> {
if offset + 6 > self.data.len() {
return Err(PacketError::BufferTooShort {
expected: offset + 6,
actual: self.data.len(),
});
}
let hwlen = self.data[offset + 4] as usize;
let plen = self.data[offset + 5] as usize;
let total_len = 8 + 2 * hwlen + 2 * plen;
if offset + total_len > self.data.len() {
return Err(PacketError::BufferTooShort {
expected: offset + total_len,
actual: self.data.len(),
});
}
let arp_end = offset + total_len;
self.layers
.push(LayerIndex::new(LayerKind::Arp, offset, arp_end));
if arp_end < self.data.len() {
self.layers
.push(LayerIndex::new(LayerKind::Raw, arp_end, self.data.len()));
}
Ok(())
}
fn parse_tcp(&mut self, offset: usize) -> Result<()> {
let min_size = 20;
if offset + min_size > self.data.len() {
return Err(PacketError::BufferTooShort {
expected: offset + min_size,
actual: self.data.len(),
});
}
let data_offset = ((self.data[offset + 12] >> 4) & 0x0F) as usize;
let header_len = data_offset * 4;
let tcp_end = (offset + header_len).min(self.data.len());
self.layers
.push(LayerIndex::new(LayerKind::Tcp, offset, tcp_end));
if tcp_end < self.data.len() {
let src_port = u16::from_be_bytes([self.data[offset], self.data[offset + 1]]);
let dst_port = u16::from_be_bytes([self.data[offset + 2], self.data[offset + 3]]);
let payload = &self.data[tcp_end..];
if (src_port == SSH_PORT || dst_port == SSH_PORT) && is_ssh_payload(payload) {
self.parse_ssh(tcp_end)?;
} else if (src_port == 502 || dst_port == 502)
&& crate::layer::modbus::is_modbus_tcp_payload(payload)
{
self.layers
.push(LayerIndex::new(LayerKind::Modbus, tcp_end, self.data.len()));
} else if (src_port == 1883 || dst_port == 1883)
&& crate::layer::mqtt::is_mqtt_payload(payload)
{
self.layers
.push(LayerIndex::new(LayerKind::Mqtt, tcp_end, self.data.len()));
} else if (src_port == FTP_CONTROL_PORT || dst_port == FTP_CONTROL_PORT)
&& is_ftp_payload(payload)
{
self.layers
.push(LayerIndex::new(LayerKind::Ftp, tcp_end, self.data.len()));
} else if (src_port == SMTP_PORT
|| dst_port == SMTP_PORT
|| src_port == SMTP_SUBMISSION_PORT
|| dst_port == SMTP_SUBMISSION_PORT
|| src_port == SMTPS_PORT
|| dst_port == SMTPS_PORT)
&& is_smtp_payload(payload)
{
self.layers
.push(LayerIndex::new(LayerKind::Smtp, tcp_end, self.data.len()));
} else if (src_port == POP3_PORT || dst_port == POP3_PORT) && is_pop3_payload(payload) {
self.layers
.push(LayerIndex::new(LayerKind::Pop3, tcp_end, self.data.len()));
} else if (src_port == IMAP_PORT || dst_port == IMAP_PORT) && is_imap_payload(payload) {
self.layers
.push(LayerIndex::new(LayerKind::Imap, tcp_end, self.data.len()));
} else if is_tls_payload(payload) {
self.parse_tls(tcp_end)?;
} else if is_http2_payload(payload) {
self.layers
.push(LayerIndex::new(LayerKind::Http2, tcp_end, self.data.len()));
} else if http::detection::is_http(payload) {
self.layers
.push(LayerIndex::new(LayerKind::Http, tcp_end, self.data.len()));
} else {
self.layers
.push(LayerIndex::new(LayerKind::Raw, tcp_end, self.data.len()));
}
}
Ok(())
}
fn parse_udp(&mut self, offset: usize) -> Result<()> {
let min_size = 8;
if offset + min_size > self.data.len() {
return Err(PacketError::BufferTooShort {
expected: offset + min_size,
actual: self.data.len(),
});
}
let udp_end = offset + min_size;
self.layers
.push(LayerIndex::new(LayerKind::Udp, offset, udp_end));
let dst_port = u16::from_be_bytes([self.data[offset + 2], self.data[offset + 3]]);
let src_port = u16::from_be_bytes([self.data[offset], self.data[offset + 1]]);
if (dst_port == 53 || src_port == 53 || dst_port == 5353 || src_port == 5353)
&& udp_end + 12 <= self.data.len()
{
self.layers
.push(LayerIndex::new(LayerKind::Dns, udp_end, self.data.len()));
} else if (dst_port == 443 || src_port == 443 || dst_port == 4433 || src_port == 4433)
&& udp_end < self.data.len()
&& is_quic_payload(&self.data[udp_end..])
{
self.layers
.push(LayerIndex::new(LayerKind::Quic, udp_end, self.data.len()));
} else if (dst_port == 1701 || src_port == 1701)
&& udp_end + 2 <= self.data.len()
&& (self.data[udp_end + 1] & 0x0F) == 2
{
self.layers
.push(LayerIndex::new(LayerKind::L2tp, udp_end, self.data.len()));
} else if (dst_port == 1883 || src_port == 1883)
&& udp_end < self.data.len()
&& crate::layer::mqttsn::is_mqttsn_payload(&self.data[udp_end..])
{
self.layers
.push(LayerIndex::new(LayerKind::MqttSn, udp_end, self.data.len()));
} else if (dst_port == TFTP_PORT || src_port == TFTP_PORT)
&& udp_end < self.data.len()
&& is_tftp_payload(&self.data[udp_end..])
{
self.layers
.push(LayerIndex::new(LayerKind::Tftp, udp_end, self.data.len()));
} else if (dst_port == DHCP_SERVER_PORT
|| src_port == DHCP_SERVER_PORT
|| dst_port == DHCP_CLIENT_PORT
|| src_port == DHCP_CLIENT_PORT)
&& udp_end < self.data.len()
&& is_dhcp_payload(&self.data[udp_end..])
{
self.layers
.push(LayerIndex::new(LayerKind::Dhcp, udp_end, self.data.len()));
} else if udp_end < self.data.len() {
self.layers
.push(LayerIndex::new(LayerKind::Raw, udp_end, self.data.len()));
}
Ok(())
}
fn parse_icmp(&mut self, offset: usize) -> Result<()> {
if offset + 8 > self.data.len() {
return Err(PacketError::BufferTooShort {
expected: offset + 8,
actual: self.data.len(),
});
}
self.layers
.push(LayerIndex::new(LayerKind::Icmp, offset, self.data.len()));
if offset < self.data.len() {
let icmp_type = self.data[offset];
if icmp::is_error_type(icmp_type) {
let embedded_offset = offset + 8;
if embedded_offset < self.data.len() {
let _ = self.parse_ipv4(embedded_offset);
}
}
}
Ok(())
}
fn parse_icmpv6(&mut self, offset: usize) -> Result<()> {
if offset + 8 > self.data.len() {
return Err(PacketError::BufferTooShort {
expected: offset + 8,
actual: self.data.len(),
});
}
self.layers
.push(LayerIndex::new(LayerKind::Icmpv6, offset, self.data.len()));
Ok(())
}
fn parse_ssh(&mut self, offset: usize) -> Result<()> {
let remaining = &self.data[offset..];
if remaining.len() >= 4 && &remaining[..4] == b"SSH-" {
let end = remaining
.windows(2)
.position(|w| w == b"\r\n")
.map_or(self.data.len(), |p| offset + p + 2);
self.layers
.push(LayerIndex::new(LayerKind::Ssh, offset, end));
if end < self.data.len() {
self.layers
.push(LayerIndex::new(LayerKind::Raw, end, self.data.len()));
}
} else if remaining.len() >= 5 {
let pkt_len =
u32::from_be_bytes([remaining[0], remaining[1], remaining[2], remaining[3]])
as usize;
let end = (offset + 4 + pkt_len).min(self.data.len());
self.layers
.push(LayerIndex::new(LayerKind::Ssh, offset, end));
if end < self.data.len() {
self.layers
.push(LayerIndex::new(LayerKind::Raw, end, self.data.len()));
}
} else {
self.layers
.push(LayerIndex::new(LayerKind::Raw, offset, self.data.len()));
}
Ok(())
}
fn parse_tls(&mut self, offset: usize) -> Result<()> {
use crate::layer::tls::TLS_RECORD_HEADER_LEN;
let remaining = self.data.len() - offset;
if remaining < TLS_RECORD_HEADER_LEN {
self.layers
.push(LayerIndex::new(LayerKind::Raw, offset, self.data.len()));
return Ok(());
}
let frag_len = u16::from_be_bytes([self.data[offset + 3], self.data[offset + 4]]) as usize;
let record_end = (offset + TLS_RECORD_HEADER_LEN + frag_len).min(self.data.len());
self.layers
.push(LayerIndex::new(LayerKind::Tls, offset, record_end));
if record_end < self.data.len() {
self.layers
.push(LayerIndex::new(LayerKind::Raw, record_end, self.data.len()));
}
Ok(())
}
pub fn with_data_mut<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let bytes = std::mem::take(&mut self.data);
let mut bytes_mut = bytes
.try_into_mut()
.unwrap_or_else(|b| BytesMut::from(b.as_ref()));
let result = f(&mut bytes_mut);
self.data = bytes_mut.freeze();
self.is_dirty = true;
result
}
pub fn set_byte(&mut self, offset: usize, value: u8) {
self.with_data_mut(|data| data[offset] = value);
}
pub fn set_bytes(&mut self, offset: usize, values: &[u8]) {
self.with_data_mut(|data| data[offset..offset + values.len()].copy_from_slice(values));
}
#[inline]
pub fn mark_dirty(&mut self) {
self.is_dirty = true;
}
#[inline]
pub fn mark_clean(&mut self) {
self.is_dirty = false;
}
pub fn add_layer(&mut self, index: LayerIndex) {
self.layers.push(index);
}
pub fn set_data(&mut self, data: BytesMut) {
self.data = data.freeze();
self.is_dirty = true;
}
}
impl Default for Packet {
fn default() -> Self {
Self::empty()
}
}
impl From<Vec<u8>> for Packet {
fn from(data: Vec<u8>) -> Self {
Self::from_bytes(data)
}
}
impl From<&[u8]> for Packet {
fn from(data: &[u8]) -> Self {
Self::from_slice(data)
}
}
impl AsRef<[u8]> for Packet {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
fn is_quic_payload(buf: &[u8]) -> bool {
!buf.is_empty() && (buf[0] & 0x40) != 0
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ARP_HEADER_LEN;
use crate::layer::field::MacAddress;
fn sample_arp_packet() -> Vec<u8> {
vec![
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xc0, 0xa8, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x01, 0x02, ]
}
#[test]
fn test_packet_parse_arp() {
let data = sample_arp_packet();
let mut packet = Packet::from_bytes(data);
packet.parse().unwrap();
assert_eq!(packet.layer_count(), 2);
let eth = packet.ethernet().unwrap();
assert!(eth.is_broadcast(packet.as_bytes()));
assert_eq!(eth.ethertype(packet.as_bytes()).unwrap(), ethertype::ARP);
let arp = packet.arp().unwrap();
assert!(arp.is_request(packet.as_bytes()));
}
#[test]
fn test_packet_layer_access() {
let data = sample_arp_packet();
let mut packet = Packet::from_bytes(data);
packet.parse().unwrap();
let eth_bytes = packet.layer_bytes(LayerKind::Ethernet).unwrap();
assert_eq!(eth_bytes.len(), ETHERNET_HEADER_LEN);
let arp_bytes = packet.layer_bytes(LayerKind::Arp).unwrap();
assert_eq!(arp_bytes.len(), ARP_HEADER_LEN);
}
#[test]
fn test_packet_modify_through_layer() {
let data = sample_arp_packet();
let mut packet = Packet::from_bytes(data);
packet.parse().unwrap();
let eth = packet.ethernet().unwrap();
packet.with_data_mut(|buf| {
eth.set_src(buf, MacAddress::new([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]))
.unwrap();
});
assert!(packet.is_dirty());
let eth = packet.ethernet().unwrap();
assert_eq!(
eth.src(packet.as_bytes()).unwrap(),
MacAddress::new([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff])
);
}
#[test]
fn test_icmp_error_packet_parsing() {
let data = vec![
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x08, 0x00, 0x45, 0x00, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 192, 168, 1, 1, 192, 168, 1, 100, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x1c, 0xab, 0xcd, 0x00, 0x00, 0x40, 0x11, 0x00, 0x00, 192, 168, 1, 100, 8, 8, 8, 8, 0x04, 0xd2, 0x00, 0x35, 0x00, 0x14, 0x00, 0x00, ];
let mut packet = Packet::from_bytes(data);
packet.parse().unwrap();
assert_eq!(packet.layer_count(), 5);
assert!(packet.ethernet().is_some());
assert!(packet.ipv4().is_some());
assert!(packet.icmp().is_some());
let icmp = packet.icmp().unwrap();
let icmp_type = icmp.icmp_type(packet.as_bytes()).unwrap();
assert_eq!(icmp_type, 3);
let layers = packet.layers();
let _embedded_ip_idx = layers
.iter()
.rposition(|idx| idx.kind == LayerKind::Ipv4)
.unwrap();
assert!(packet.udp().is_some());
}
#[test]
fn test_icmp_time_exceeded_with_tcp() {
let data = vec![
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
0x45, 0x00, 0x00, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 10, 0, 0, 1, 192, 168, 1, 100, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x28, 0x12, 0x34, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 192, 168, 1, 100, 93, 184, 216, 34, 0x04, 0xd2, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, ];
let mut packet = Packet::from_bytes(data);
packet.parse().unwrap();
assert_eq!(packet.layer_count(), 5);
assert!(packet.icmp().is_some());
assert!(packet.tcp().is_some());
let icmp = packet.icmp().unwrap();
assert_eq!(icmp.icmp_type(packet.as_bytes()).unwrap(), 11);
}
#[test]
fn test_icmp_with_extensions() {
let data = vec![
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x08, 0x00, 0x45, 0x00, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0x64, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x3c, 0x12, 0x34, 0x40, 0x00, 0x01, 0x11, 0x00, 0x00, 0xc0, 0xa8, 0x01, 0x64, 0x08, 0x08, 0x08, 0x08, 0x04, 0xd2, 0x00, 0x35, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x19, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xa8, 0x01, 0x01, ];
let mut packet = Packet::from_bytes(data.clone());
packet.parse().unwrap();
assert!(packet.icmp().is_some());
let icmp = packet.icmp().unwrap();
assert_eq!(
icmp.icmp_type(packet.as_bytes()).unwrap(),
crate::layer::icmp::types::types::TIME_EXCEEDED
);
use crate::layer::icmp;
let icmp_offset = packet.layers()[1].end; let icmp_payload = &data[icmp_offset + 8..];
assert!(icmp::has_extensions(
crate::layer::icmp::types::types::TIME_EXCEEDED,
icmp_payload.len()
));
let ext_offset = icmp_offset + 8 + 128; if let Some((version, _checksum)) = icmp::parse_extension_header(&data, ext_offset) {
assert_eq!(version, 2);
let obj_offset = ext_offset + 4;
if let Some((len, classnum, _classtype, data_offset)) =
icmp::parse_extension_object(&data, obj_offset)
{
assert_eq!(len, 16);
assert_eq!(
classnum,
icmp::extensions::class_nums::INTERFACE_INFORMATION
);
let data_len = (len as usize) - 4; if let Some(info) = icmp::parse_interface_information(&data, data_offset, data_len)
{
assert!(info.flags.has_ifindex);
assert!(info.flags.has_ipaddr);
assert_eq!(info.ifindex, Some(2));
if let Some(icmp::IpAddr::V4(ip)) = info.ip_addr {
assert_eq!(ip.to_string(), "192.168.1.1");
} else {
panic!("Expected IPv4 address");
}
}
}
}
}
}