use crate::dissect::{Dissect, DissectResult};
use crate::Error;
#[derive(Debug, Clone)]
pub struct Tcp<'a> {
data: &'a [u8],
}
impl<'a> Tcp<'a> {
pub fn new(data: &'a [u8]) -> Result<Self, Error> {
if data.len() < 20 {
return Err(Error::truncated(20, data.len()));
}
Ok(Self { data })
}
pub fn src_port(&self) -> u16 {
u16::from_be_bytes([self.data[0], self.data[1]])
}
pub fn dst_port(&self) -> u16 {
u16::from_be_bytes([self.data[2], self.data[3]])
}
pub fn seq(&self) -> u32 {
u32::from_be_bytes([self.data[4], self.data[5], self.data[6], self.data[7]])
}
pub fn ack(&self) -> u32 {
u32::from_be_bytes([self.data[8], self.data[9], self.data[10], self.data[11]])
}
pub fn data_offset(&self) -> usize {
((self.data[12] >> 4) * 4) as usize
}
pub fn flags(&self) -> u8 {
self.data[13]
}
pub fn fin(&self) -> bool {
(self.flags() & 0x01) != 0
}
pub fn syn(&self) -> bool {
(self.flags() & 0x02) != 0
}
pub fn rst(&self) -> bool {
(self.flags() & 0x04) != 0
}
pub fn psh(&self) -> bool {
(self.flags() & 0x08) != 0
}
pub fn ack_flag(&self) -> bool {
(self.flags() & 0x10) != 0
}
pub fn urg(&self) -> bool {
(self.flags() & 0x20) != 0
}
pub fn window(&self) -> u16 {
u16::from_be_bytes([self.data[14], self.data[15]])
}
pub fn checksum(&self) -> u16 {
u16::from_be_bytes([self.data[16], self.data[17]])
}
pub fn urgent(&self) -> u16 {
u16::from_be_bytes([self.data[18], self.data[19]])
}
pub fn payload(&self) -> &'a [u8] {
let offset = self.data_offset();
if offset >= self.data.len() {
&[]
} else {
&self.data[offset..]
}
}
}
impl<'a> Dissect<'a> for Tcp<'a> {
type Output = &'a [u8];
fn dissect(&self) -> DissectResult<Self::Output> {
Ok(self.payload())
}
fn data(&self) -> &'a [u8] {
self.data
}
fn header_len(&self) -> usize {
self.data_offset()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tcp_new_valid() {
let data = vec![
0x00, 0x50, 0x01, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
let tcp = Tcp::new(&data).unwrap();
assert_eq!(tcp.src_port(), 80);
assert_eq!(tcp.dst_port(), 443);
assert!(tcp.syn());
}
#[test]
fn test_tcp_new_truncated() {
let data = vec![0u8; 10];
let result = Tcp::new(&data);
assert!(result.is_err());
}
#[test]
fn test_tcp_flags() {
let data = vec![
0x00, 0x50, 0x01, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
let tcp = Tcp::new(&data).unwrap();
assert!(tcp.syn());
assert!(tcp.ack_flag());
}
#[test]
fn test_tcp_payload() {
let mut data = vec![
0x00, 0x50, 0x01, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
data.extend_from_slice(&[0xde, 0xad, 0xbe, 0xef]); let tcp = Tcp::new(&data).unwrap();
assert_eq!(tcp.payload(), &[0xde, 0xad, 0xbe, 0xef]);
}
}