use super::LayerKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TcpFlagsView {
pub syn: bool,
pub ack: bool,
pub fin: bool,
pub rst: bool,
pub psh: bool,
pub urg: bool,
pub ece: bool,
pub cwr: bool,
pub ns: bool,
}
impl TcpFlagsView {
pub(crate) fn from_bytes(flags_hi: u8, flags_lo: u8) -> Self {
Self {
ns: flags_hi & 0x01 != 0,
fin: flags_lo & 0x01 != 0,
syn: flags_lo & 0x02 != 0,
rst: flags_lo & 0x04 != 0,
psh: flags_lo & 0x08 != 0,
ack: flags_lo & 0x10 != 0,
urg: flags_lo & 0x20 != 0,
ece: flags_lo & 0x40 != 0,
cwr: flags_lo & 0x80 != 0,
}
}
}
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub enum TcpOption<'a> {
EndOfList,
Nop,
Mss(u16),
WindowScale(u8),
SackPermitted,
Sack(&'a [u8]),
Timestamp { tsval: u32, tsecr: u32 },
Unknown { kind: u8, data: &'a [u8] },
}
#[derive(Debug, Clone, Copy)]
pub struct TcpSlice<'a> {
raw: &'a [u8],
header_len: usize,
}
impl<'a> TcpSlice<'a> {
pub(crate) fn new(raw: &'a [u8], header_len: usize) -> Self {
Self { raw, header_len }
}
pub fn src_port(&self) -> u16 {
u16::from_be_bytes([self.raw[0], self.raw[1]])
}
pub fn dst_port(&self) -> u16 {
u16::from_be_bytes([self.raw[2], self.raw[3]])
}
pub fn seq(&self) -> u32 {
u32::from_be_bytes([self.raw[4], self.raw[5], self.raw[6], self.raw[7]])
}
pub fn ack(&self) -> u32 {
u32::from_be_bytes([self.raw[8], self.raw[9], self.raw[10], self.raw[11]])
}
pub fn data_offset(&self) -> u8 {
(self.raw[12] >> 4) & 0x0F
}
pub fn flags(&self) -> TcpFlagsView {
TcpFlagsView::from_bytes(self.raw[12], self.raw[13])
}
pub fn window(&self) -> u16 {
u16::from_be_bytes([self.raw[14], self.raw[15]])
}
pub fn checksum(&self) -> u16 {
u16::from_be_bytes([self.raw[16], self.raw[17]])
}
pub fn urgent_pointer(&self) -> u16 {
u16::from_be_bytes([self.raw[18], self.raw[19]])
}
pub fn header(&self) -> &'a [u8] {
&self.raw[..self.header_len]
}
pub fn payload(&self) -> &'a [u8] {
&self.raw[self.header_len..]
}
pub fn options(&self) -> TcpOptionsIter<'a> {
let raw = if self.header_len > 20 {
&self.raw[20..self.header_len]
} else {
&[][..]
};
TcpOptionsIter { raw }
}
pub fn bytes(&self) -> &'a [u8] {
self.raw
}
pub fn kind(&self) -> LayerKind {
LayerKind::Tcp
}
}
#[derive(Debug, Clone)]
pub struct TcpOptionsIter<'a> {
raw: &'a [u8],
}
impl<'a> Iterator for TcpOptionsIter<'a> {
type Item = TcpOption<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.raw.is_empty() {
return None;
}
let kind = self.raw[0];
match kind {
0 => {
self.raw = &[];
Some(TcpOption::EndOfList)
}
1 => {
self.raw = &self.raw[1..];
Some(TcpOption::Nop)
}
_ => {
if self.raw.len() < 2 {
self.raw = &[];
return None;
}
let len = self.raw[1] as usize;
if len < 2 || len > self.raw.len() {
self.raw = &[];
return None;
}
let data = &self.raw[2..len];
let opt = match (kind, data.len()) {
(2, 2) => TcpOption::Mss(u16::from_be_bytes([data[0], data[1]])),
(3, 1) => TcpOption::WindowScale(data[0]),
(4, 0) => TcpOption::SackPermitted,
(5, _) => TcpOption::Sack(data),
(8, 8) => TcpOption::Timestamp {
tsval: u32::from_be_bytes([data[0], data[1], data[2], data[3]]),
tsecr: u32::from_be_bytes([data[4], data[5], data[6], data[7]]),
},
_ => TcpOption::Unknown { kind, data },
};
self.raw = &self.raw[len..];
Some(opt)
}
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct UdpSlice<'a> {
raw: &'a [u8],
}
impl<'a> UdpSlice<'a> {
pub(crate) fn new(raw: &'a [u8]) -> Self {
Self { raw }
}
pub fn src_port(&self) -> u16 {
u16::from_be_bytes([self.raw[0], self.raw[1]])
}
pub fn dst_port(&self) -> u16 {
u16::from_be_bytes([self.raw[2], self.raw[3]])
}
pub fn length(&self) -> u16 {
u16::from_be_bytes([self.raw[4], self.raw[5]])
}
pub fn checksum(&self) -> u16 {
u16::from_be_bytes([self.raw[6], self.raw[7]])
}
pub fn header(&self) -> &'a [u8] {
&self.raw[..8]
}
pub fn payload(&self) -> &'a [u8] {
&self.raw[8..]
}
pub fn bytes(&self) -> &'a [u8] {
self.raw
}
pub fn kind(&self) -> LayerKind {
LayerKind::Udp
}
}
#[derive(Debug, Clone, Copy)]
pub struct Icmpv4Slice<'a> {
raw: &'a [u8],
}
impl<'a> Icmpv4Slice<'a> {
pub(crate) fn new(raw: &'a [u8]) -> Self {
Self { raw }
}
pub fn icmp_type(&self) -> u8 {
self.raw[0]
}
pub fn code(&self) -> u8 {
self.raw[1]
}
pub fn checksum(&self) -> u16 {
u16::from_be_bytes([self.raw[2], self.raw[3]])
}
pub fn payload(&self) -> &'a [u8] {
&self.raw[4..]
}
pub fn header(&self) -> &'a [u8] {
&self.raw[..4.min(self.raw.len())]
}
pub fn bytes(&self) -> &'a [u8] {
self.raw
}
pub fn kind(&self) -> LayerKind {
LayerKind::Icmpv4
}
}
#[derive(Debug, Clone, Copy)]
pub struct Icmpv6Slice<'a> {
raw: &'a [u8],
}
impl<'a> Icmpv6Slice<'a> {
pub(crate) fn new(raw: &'a [u8]) -> Self {
Self { raw }
}
pub fn icmp_type(&self) -> u8 {
self.raw[0]
}
pub fn code(&self) -> u8 {
self.raw[1]
}
pub fn checksum(&self) -> u16 {
u16::from_be_bytes([self.raw[2], self.raw[3]])
}
pub fn payload(&self) -> &'a [u8] {
&self.raw[4..]
}
pub fn header(&self) -> &'a [u8] {
&self.raw[..4.min(self.raw.len())]
}
pub fn bytes(&self) -> &'a [u8] {
self.raw
}
pub fn kind(&self) -> LayerKind {
LayerKind::Icmpv6
}
}