use byteorder::{ByteOrder, NetworkEndian}; use core::{cmp, fmt, i32, ops}; use super::{Error, Result}; use crate::phy::ChecksumCapabilities; use crate::wire::ip::checksum; use crate::wire::{IpAddress, IpProtocol}; /// A TCP sequence number. /// /// A sequence number is a monotonically advancing integer modulo 232. /// Sequence numbers do not have a discontiguity when compared pairwise across a signed overflow. #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct SeqNumber(pub i32); impl fmt::Display for SeqNumber { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0 as u32) } } impl ops::Add for SeqNumber { type Output = SeqNumber; fn add(self, rhs: usize) -> SeqNumber { if rhs > i32::MAX as usize { panic!("attempt to add to sequence number with unsigned overflow") } SeqNumber(self.0.wrapping_add(rhs as i32)) } } impl ops::Sub for SeqNumber { type Output = SeqNumber; fn sub(self, rhs: usize) -> SeqNumber { if rhs > i32::MAX as usize { panic!("attempt to subtract to sequence number with unsigned overflow") } SeqNumber(self.0.wrapping_sub(rhs as i32)) } } impl ops::AddAssign for SeqNumber { fn add_assign(&mut self, rhs: usize) { *self = *self + rhs; } } impl ops::Sub for SeqNumber { type Output = usize; fn sub(self, rhs: SeqNumber) -> usize { let result = self.0.wrapping_sub(rhs.0); if result < 0 { panic!("attempt to subtract sequence numbers with underflow") } result as usize } } impl cmp::PartialOrd for SeqNumber { fn partial_cmp(&self, other: &SeqNumber) -> Option { self.0.wrapping_sub(other.0).partial_cmp(&0) } } /// A read/write wrapper around a Transmission Control Protocol packet buffer. #[derive(Debug, PartialEq, Eq, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Packet> { buffer: T, } mod field { #![allow(non_snake_case)] use crate::wire::field::*; pub const SRC_PORT: Field = 0..2; pub const DST_PORT: Field = 2..4; pub const SEQ_NUM: Field = 4..8; pub const ACK_NUM: Field = 8..12; pub const FLAGS: Field = 12..14; pub const WIN_SIZE: Field = 14..16; pub const CHECKSUM: Field = 16..18; pub const URGENT: Field = 18..20; pub const fn OPTIONS(length: u8) -> Field { URGENT.end..(length as usize) } pub const FLG_FIN: u16 = 0x001; pub const FLG_SYN: u16 = 0x002; pub const FLG_RST: u16 = 0x004; pub const FLG_PSH: u16 = 0x008; pub const FLG_ACK: u16 = 0x010; pub const FLG_URG: u16 = 0x020; pub const FLG_ECE: u16 = 0x040; pub const FLG_CWR: u16 = 0x080; pub const FLG_NS: u16 = 0x100; pub const OPT_END: u8 = 0x00; pub const OPT_NOP: u8 = 0x01; pub const OPT_MSS: u8 = 0x02; pub const OPT_WS: u8 = 0x03; pub const OPT_SACKPERM: u8 = 0x04; pub const OPT_SACKRNG: u8 = 0x05; } pub const HEADER_LEN: usize = field::URGENT.end; impl> Packet { /// Imbue a raw octet buffer with TCP packet structure. pub const fn new_unchecked(buffer: T) -> Packet { Packet { buffer } } /// Shorthand for a combination of [new_unchecked] and [check_len]. /// /// [new_unchecked]: #method.new_unchecked /// [check_len]: #method.check_len pub fn new_checked(buffer: T) -> Result> { let packet = Self::new_unchecked(buffer); packet.check_len()?; Ok(packet) } /// Ensure that no accessor method will panic if called. /// Returns `Err(Error)` if the buffer is too short. /// Returns `Err(Error)` if the header length field has a value smaller /// than the minimal header length. /// /// The result of this check is invalidated by calling [set_header_len]. /// /// [set_header_len]: #method.set_header_len pub fn check_len(&self) -> Result<()> { let len = self.buffer.as_ref().len(); if len < field::URGENT.end { Err(Error) } else { let header_len = self.header_len() as usize; if len < header_len || header_len < field::URGENT.end { Err(Error) } else { Ok(()) } } } /// Consume the packet, returning the underlying buffer. pub fn into_inner(self) -> T { self.buffer } /// Return the source port field. #[inline] pub fn src_port(&self) -> u16 { let data = self.buffer.as_ref(); NetworkEndian::read_u16(&data[field::SRC_PORT]) } /// Return the destination port field. #[inline] pub fn dst_port(&self) -> u16 { let data = self.buffer.as_ref(); NetworkEndian::read_u16(&data[field::DST_PORT]) } /// Return the sequence number field. #[inline] pub fn seq_number(&self) -> SeqNumber { let data = self.buffer.as_ref(); SeqNumber(NetworkEndian::read_i32(&data[field::SEQ_NUM])) } /// Return the acknowledgement number field. #[inline] pub fn ack_number(&self) -> SeqNumber { let data = self.buffer.as_ref(); SeqNumber(NetworkEndian::read_i32(&data[field::ACK_NUM])) } /// Return the FIN flag. #[inline] pub fn fin(&self) -> bool { let data = self.buffer.as_ref(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); raw & field::FLG_FIN != 0 } /// Return the SYN flag. #[inline] pub fn syn(&self) -> bool { let data = self.buffer.as_ref(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); raw & field::FLG_SYN != 0 } /// Return the RST flag. #[inline] pub fn rst(&self) -> bool { let data = self.buffer.as_ref(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); raw & field::FLG_RST != 0 } /// Return the PSH flag. #[inline] pub fn psh(&self) -> bool { let data = self.buffer.as_ref(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); raw & field::FLG_PSH != 0 } /// Return the ACK flag. #[inline] pub fn ack(&self) -> bool { let data = self.buffer.as_ref(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); raw & field::FLG_ACK != 0 } /// Return the URG flag. #[inline] pub fn urg(&self) -> bool { let data = self.buffer.as_ref(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); raw & field::FLG_URG != 0 } /// Return the ECE flag. #[inline] pub fn ece(&self) -> bool { let data = self.buffer.as_ref(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); raw & field::FLG_ECE != 0 } /// Return the CWR flag. #[inline] pub fn cwr(&self) -> bool { let data = self.buffer.as_ref(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); raw & field::FLG_CWR != 0 } /// Return the NS flag. #[inline] pub fn ns(&self) -> bool { let data = self.buffer.as_ref(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); raw & field::FLG_NS != 0 } /// Return the header length, in octets. #[inline] pub fn header_len(&self) -> u8 { let data = self.buffer.as_ref(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); ((raw >> 12) * 4) as u8 } /// Return the window size field. #[inline] pub fn window_len(&self) -> u16 { let data = self.buffer.as_ref(); NetworkEndian::read_u16(&data[field::WIN_SIZE]) } /// Return the checksum field. #[inline] pub fn checksum(&self) -> u16 { let data = self.buffer.as_ref(); NetworkEndian::read_u16(&data[field::CHECKSUM]) } /// Return the urgent pointer field. #[inline] pub fn urgent_at(&self) -> u16 { let data = self.buffer.as_ref(); NetworkEndian::read_u16(&data[field::URGENT]) } /// Return the length of the segment, in terms of sequence space. pub fn segment_len(&self) -> usize { let data = self.buffer.as_ref(); let mut length = data.len() - self.header_len() as usize; if self.syn() { length += 1 } if self.fin() { length += 1 } length } /// Returns whether the selective acknowledgement SYN flag is set or not. pub fn selective_ack_permitted(&self) -> Result { let data = self.buffer.as_ref(); let mut options = &data[field::OPTIONS(self.header_len())]; while !options.is_empty() { let (next_options, option) = TcpOption::parse(options)?; if option == TcpOption::SackPermitted { return Ok(true); } options = next_options; } Ok(false) } /// Return the selective acknowledgement ranges, if any. If there are none in the packet, an /// array of ``None`` values will be returned. /// pub fn selective_ack_ranges(&self) -> Result<[Option<(u32, u32)>; 3]> { let data = self.buffer.as_ref(); let mut options = &data[field::OPTIONS(self.header_len())]; while !options.is_empty() { let (next_options, option) = TcpOption::parse(options)?; if let TcpOption::SackRange(slice) = option { return Ok(slice); } options = next_options; } Ok([None, None, None]) } /// Validate the packet checksum. /// /// # Panics /// This function panics unless `src_addr` and `dst_addr` belong to the same family, /// and that family is IPv4 or IPv6. /// /// # Fuzzing /// This function always returns `true` when fuzzing. pub fn verify_checksum(&self, src_addr: &IpAddress, dst_addr: &IpAddress) -> bool { if cfg!(fuzzing) { return true; } let data = self.buffer.as_ref(); checksum::combine(&[ checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Tcp, data.len() as u32), checksum::data(data), ]) == !0 } } impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> { /// Return a pointer to the options. #[inline] pub fn options(&self) -> &'a [u8] { let header_len = self.header_len(); let data = self.buffer.as_ref(); &data[field::OPTIONS(header_len)] } /// Return a pointer to the payload. #[inline] pub fn payload(&self) -> &'a [u8] { let header_len = self.header_len() as usize; let data = self.buffer.as_ref(); &data[header_len..] } } impl + AsMut<[u8]>> Packet { /// Set the source port field. #[inline] pub fn set_src_port(&mut self, value: u16) { let data = self.buffer.as_mut(); NetworkEndian::write_u16(&mut data[field::SRC_PORT], value) } /// Set the destination port field. #[inline] pub fn set_dst_port(&mut self, value: u16) { let data = self.buffer.as_mut(); NetworkEndian::write_u16(&mut data[field::DST_PORT], value) } /// Set the sequence number field. #[inline] pub fn set_seq_number(&mut self, value: SeqNumber) { let data = self.buffer.as_mut(); NetworkEndian::write_i32(&mut data[field::SEQ_NUM], value.0) } /// Set the acknowledgement number field. #[inline] pub fn set_ack_number(&mut self, value: SeqNumber) { let data = self.buffer.as_mut(); NetworkEndian::write_i32(&mut data[field::ACK_NUM], value.0) } /// Clear the entire flags field. #[inline] pub fn clear_flags(&mut self) { let data = self.buffer.as_mut(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); let raw = raw & !0x0fff; NetworkEndian::write_u16(&mut data[field::FLAGS], raw) } /// Set the FIN flag. #[inline] pub fn set_fin(&mut self, value: bool) { let data = self.buffer.as_mut(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); let raw = if value { raw | field::FLG_FIN } else { raw & !field::FLG_FIN }; NetworkEndian::write_u16(&mut data[field::FLAGS], raw) } /// Set the SYN flag. #[inline] pub fn set_syn(&mut self, value: bool) { let data = self.buffer.as_mut(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); let raw = if value { raw | field::FLG_SYN } else { raw & !field::FLG_SYN }; NetworkEndian::write_u16(&mut data[field::FLAGS], raw) } /// Set the RST flag. #[inline] pub fn set_rst(&mut self, value: bool) { let data = self.buffer.as_mut(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); let raw = if value { raw | field::FLG_RST } else { raw & !field::FLG_RST }; NetworkEndian::write_u16(&mut data[field::FLAGS], raw) } /// Set the PSH flag. #[inline] pub fn set_psh(&mut self, value: bool) { let data = self.buffer.as_mut(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); let raw = if value { raw | field::FLG_PSH } else { raw & !field::FLG_PSH }; NetworkEndian::write_u16(&mut data[field::FLAGS], raw) } /// Set the ACK flag. #[inline] pub fn set_ack(&mut self, value: bool) { let data = self.buffer.as_mut(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); let raw = if value { raw | field::FLG_ACK } else { raw & !field::FLG_ACK }; NetworkEndian::write_u16(&mut data[field::FLAGS], raw) } /// Set the URG flag. #[inline] pub fn set_urg(&mut self, value: bool) { let data = self.buffer.as_mut(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); let raw = if value { raw | field::FLG_URG } else { raw & !field::FLG_URG }; NetworkEndian::write_u16(&mut data[field::FLAGS], raw) } /// Set the ECE flag. #[inline] pub fn set_ece(&mut self, value: bool) { let data = self.buffer.as_mut(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); let raw = if value { raw | field::FLG_ECE } else { raw & !field::FLG_ECE }; NetworkEndian::write_u16(&mut data[field::FLAGS], raw) } /// Set the CWR flag. #[inline] pub fn set_cwr(&mut self, value: bool) { let data = self.buffer.as_mut(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); let raw = if value { raw | field::FLG_CWR } else { raw & !field::FLG_CWR }; NetworkEndian::write_u16(&mut data[field::FLAGS], raw) } /// Set the NS flag. #[inline] pub fn set_ns(&mut self, value: bool) { let data = self.buffer.as_mut(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); let raw = if value { raw | field::FLG_NS } else { raw & !field::FLG_NS }; NetworkEndian::write_u16(&mut data[field::FLAGS], raw) } /// Set the header length, in octets. #[inline] pub fn set_header_len(&mut self, value: u8) { let data = self.buffer.as_mut(); let raw = NetworkEndian::read_u16(&data[field::FLAGS]); let raw = (raw & !0xf000) | ((value as u16) / 4) << 12; NetworkEndian::write_u16(&mut data[field::FLAGS], raw) } /// Return the window size field. #[inline] pub fn set_window_len(&mut self, value: u16) { let data = self.buffer.as_mut(); NetworkEndian::write_u16(&mut data[field::WIN_SIZE], value) } /// Set the checksum field. #[inline] pub fn set_checksum(&mut self, value: u16) { let data = self.buffer.as_mut(); NetworkEndian::write_u16(&mut data[field::CHECKSUM], value) } /// Set the urgent pointer field. #[inline] pub fn set_urgent_at(&mut self, value: u16) { let data = self.buffer.as_mut(); NetworkEndian::write_u16(&mut data[field::URGENT], value) } /// Compute and fill in the header checksum. /// /// # Panics /// This function panics unless `src_addr` and `dst_addr` belong to the same family, /// and that family is IPv4 or IPv6. pub fn fill_checksum(&mut self, src_addr: &IpAddress, dst_addr: &IpAddress) { self.set_checksum(0); let checksum = { let data = self.buffer.as_ref(); !checksum::combine(&[ checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Tcp, data.len() as u32), checksum::data(data), ]) }; self.set_checksum(checksum) } /// Return a pointer to the options. #[inline] pub fn options_mut(&mut self) -> &mut [u8] { let header_len = self.header_len(); let data = self.buffer.as_mut(); &mut data[field::OPTIONS(header_len)] } /// Return a mutable pointer to the payload data. #[inline] pub fn payload_mut(&mut self) -> &mut [u8] { let header_len = self.header_len() as usize; let data = self.buffer.as_mut(); &mut data[header_len..] } } impl> AsRef<[u8]> for Packet { fn as_ref(&self) -> &[u8] { self.buffer.as_ref() } } /// A representation of a single TCP option. #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum TcpOption<'a> { EndOfList, NoOperation, MaxSegmentSize(u16), WindowScale(u8), SackPermitted, SackRange([Option<(u32, u32)>; 3]), Unknown { kind: u8, data: &'a [u8] }, } impl<'a> TcpOption<'a> { pub fn parse(buffer: &'a [u8]) -> Result<(&'a [u8], TcpOption<'a>)> { let (length, option); match *buffer.first().ok_or(Error)? { field::OPT_END => { length = 1; option = TcpOption::EndOfList; } field::OPT_NOP => { length = 1; option = TcpOption::NoOperation; } kind => { length = *buffer.get(1).ok_or(Error)? as usize; let data = buffer.get(2..length).ok_or(Error)?; match (kind, length) { (field::OPT_END, _) | (field::OPT_NOP, _) => unreachable!(), (field::OPT_MSS, 4) => { option = TcpOption::MaxSegmentSize(NetworkEndian::read_u16(data)) } (field::OPT_MSS, _) => return Err(Error), (field::OPT_WS, 3) => option = TcpOption::WindowScale(data[0]), (field::OPT_WS, _) => return Err(Error), (field::OPT_SACKPERM, 2) => option = TcpOption::SackPermitted, (field::OPT_SACKPERM, _) => return Err(Error), (field::OPT_SACKRNG, n) => { if n < 10 || (n - 2) % 8 != 0 { return Err(Error); } if n > 26 { // It's possible for a remote to send 4 SACK blocks, but extremely rare. // Better to "lose" that 4th block and save the extra RAM and CPU // cycles in the vastly more common case. // // RFC 2018: SACK option that specifies n blocks will have a length of // 8*n+2 bytes, so the 40 bytes available for TCP options can specify a // maximum of 4 blocks. It is expected that SACK will often be used in // conjunction with the Timestamp option used for RTTM [...] thus a // maximum of 3 SACK blocks will be allowed in this case. net_debug!("sACK with >3 blocks, truncating to 3"); } let mut sack_ranges: [Option<(u32, u32)>; 3] = [None; 3]; // RFC 2018: Each contiguous block of data queued at the data receiver is // defined in the SACK option by two 32-bit unsigned integers in network // byte order[...] sack_ranges.iter_mut().enumerate().for_each(|(i, nmut)| { let left = i * 8; *nmut = if left < data.len() { let mid = left + 4; let right = mid + 4; let range_left = NetworkEndian::read_u32(&data[left..mid]); let range_right = NetworkEndian::read_u32(&data[mid..right]); Some((range_left, range_right)) } else { None }; }); option = TcpOption::SackRange(sack_ranges); } (_, _) => option = TcpOption::Unknown { kind, data }, } } } Ok((&buffer[length..], option)) } pub fn buffer_len(&self) -> usize { match *self { TcpOption::EndOfList => 1, TcpOption::NoOperation => 1, TcpOption::MaxSegmentSize(_) => 4, TcpOption::WindowScale(_) => 3, TcpOption::SackPermitted => 2, TcpOption::SackRange(s) => s.iter().filter(|s| s.is_some()).count() * 8 + 2, TcpOption::Unknown { data, .. } => 2 + data.len(), } } pub fn emit<'b>(&self, buffer: &'b mut [u8]) -> &'b mut [u8] { let length; match *self { TcpOption::EndOfList => { length = 1; // There may be padding space which also should be initialized. for p in buffer.iter_mut() { *p = field::OPT_END; } } TcpOption::NoOperation => { length = 1; buffer[0] = field::OPT_NOP; } _ => { length = self.buffer_len(); buffer[1] = length as u8; match self { &TcpOption::EndOfList | &TcpOption::NoOperation => unreachable!(), &TcpOption::MaxSegmentSize(value) => { buffer[0] = field::OPT_MSS; NetworkEndian::write_u16(&mut buffer[2..], value) } &TcpOption::WindowScale(value) => { buffer[0] = field::OPT_WS; buffer[2] = value; } &TcpOption::SackPermitted => { buffer[0] = field::OPT_SACKPERM; } &TcpOption::SackRange(slice) => { buffer[0] = field::OPT_SACKRNG; slice .iter() .filter(|s| s.is_some()) .enumerate() .for_each(|(i, s)| { let (first, second) = *s.as_ref().unwrap(); let pos = i * 8 + 2; NetworkEndian::write_u32(&mut buffer[pos..], first); NetworkEndian::write_u32(&mut buffer[pos + 4..], second); }); } &TcpOption::Unknown { kind, data: provided, } => { buffer[0] = kind; buffer[2..].copy_from_slice(provided) } } } } &mut buffer[length..] } } /// The possible control flags of a Transmission Control Protocol packet. #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Control { None, Psh, Syn, Fin, Rst, } #[allow(clippy::len_without_is_empty)] impl Control { /// Return the length of a control flag, in terms of sequence space. pub const fn len(self) -> usize { match self { Control::Syn | Control::Fin => 1, _ => 0, } } /// Turn the PSH flag into no flag, and keep the rest as-is. pub const fn quash_psh(self) -> Control { match self { Control::Psh => Control::None, _ => self, } } } /// A high-level representation of a Transmission Control Protocol packet. #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Repr<'a> { pub src_port: u16, pub dst_port: u16, pub control: Control, pub seq_number: SeqNumber, pub ack_number: Option, pub window_len: u16, pub window_scale: Option, pub max_seg_size: Option, pub sack_permitted: bool, pub sack_ranges: [Option<(u32, u32)>; 3], pub payload: &'a [u8], } impl<'a> Repr<'a> { /// Parse a Transmission Control Protocol packet and return a high-level representation. pub fn parse( packet: &Packet<&'a T>, src_addr: &IpAddress, dst_addr: &IpAddress, checksum_caps: &ChecksumCapabilities, ) -> Result> where T: AsRef<[u8]> + ?Sized, { // Source and destination ports must be present. if packet.src_port() == 0 { return Err(Error); } if packet.dst_port() == 0 { return Err(Error); } // Valid checksum is expected. if checksum_caps.tcp.rx() && !packet.verify_checksum(src_addr, dst_addr) { return Err(Error); } let control = match (packet.syn(), packet.fin(), packet.rst(), packet.psh()) { (false, false, false, false) => Control::None, (false, false, false, true) => Control::Psh, (true, false, false, _) => Control::Syn, (false, true, false, _) => Control::Fin, (false, false, true, _) => Control::Rst, _ => return Err(Error), }; let ack_number = match packet.ack() { true => Some(packet.ack_number()), false => None, }; // The PSH flag is ignored. // The URG flag and the urgent field is ignored. This behavior is standards-compliant, // however, most deployed systems (e.g. Linux) are *not* standards-compliant, and would // cut the byte at the urgent pointer from the stream. let mut max_seg_size = None; let mut window_scale = None; let mut options = packet.options(); let mut sack_permitted = false; let mut sack_ranges = [None, None, None]; while !options.is_empty() { let (next_options, option) = TcpOption::parse(options)?; match option { TcpOption::EndOfList => break, TcpOption::NoOperation => (), TcpOption::MaxSegmentSize(value) => max_seg_size = Some(value), TcpOption::WindowScale(value) => { // RFC 1323: Thus, the shift count must be limited to 14 (which allows windows // of 2**30 = 1 Gigabyte). If a Window Scale option is received with a shift.cnt // value exceeding 14, the TCP should log the error but use 14 instead of the // specified value. window_scale = if value > 14 { net_debug!( "{}:{}:{}:{}: parsed window scaling factor >14, setting to 14", src_addr, packet.src_port(), dst_addr, packet.dst_port() ); Some(14) } else { Some(value) }; } TcpOption::SackPermitted => sack_permitted = true, TcpOption::SackRange(slice) => sack_ranges = slice, _ => (), } options = next_options; } Ok(Repr { src_port: packet.src_port(), dst_port: packet.dst_port(), control: control, seq_number: packet.seq_number(), ack_number: ack_number, window_len: packet.window_len(), window_scale: window_scale, max_seg_size: max_seg_size, sack_permitted: sack_permitted, sack_ranges: sack_ranges, payload: packet.payload(), }) } /// Return the length of a header that will be emitted from this high-level representation. /// /// This should be used for buffer space calculations. /// The TCP header length is a multiple of 4. pub fn header_len(&self) -> usize { let mut length = field::URGENT.end; if self.max_seg_size.is_some() { length += 4 } if self.window_scale.is_some() { length += 3 } if self.sack_permitted { length += 2; } let sack_range_len: usize = self .sack_ranges .iter() .map(|o| o.map(|_| 8).unwrap_or(0)) .sum(); if sack_range_len > 0 { length += sack_range_len + 2; } if length % 4 != 0 { length += 4 - length % 4; } length } /// Return the length of a packet that will be emitted from this high-level representation. pub fn buffer_len(&self) -> usize { self.header_len() + self.payload.len() } /// Emit a high-level representation into a Transmission Control Protocol packet. pub fn emit( &self, packet: &mut Packet<&mut T>, src_addr: &IpAddress, dst_addr: &IpAddress, checksum_caps: &ChecksumCapabilities, ) where T: AsRef<[u8]> + AsMut<[u8]> + ?Sized, { packet.set_src_port(self.src_port); packet.set_dst_port(self.dst_port); packet.set_seq_number(self.seq_number); packet.set_ack_number(self.ack_number.unwrap_or(SeqNumber(0))); packet.set_window_len(self.window_len); packet.set_header_len(self.header_len() as u8); packet.clear_flags(); match self.control { Control::None => (), Control::Psh => packet.set_psh(true), Control::Syn => packet.set_syn(true), Control::Fin => packet.set_fin(true), Control::Rst => packet.set_rst(true), } packet.set_ack(self.ack_number.is_some()); { let mut options = packet.options_mut(); if let Some(value) = self.max_seg_size { let tmp = options; options = TcpOption::MaxSegmentSize(value).emit(tmp); } if let Some(value) = self.window_scale { let tmp = options; options = TcpOption::WindowScale(value).emit(tmp); } if self.sack_permitted { let tmp = options; options = TcpOption::SackPermitted.emit(tmp); } else if self.ack_number.is_some() && self.sack_ranges.iter().any(|s| s.is_some()) { let tmp = options; options = TcpOption::SackRange(self.sack_ranges).emit(tmp); } if !options.is_empty() { TcpOption::EndOfList.emit(options); } } packet.set_urgent_at(0); packet.payload_mut()[..self.payload.len()].copy_from_slice(self.payload); if checksum_caps.tcp.tx() { packet.fill_checksum(src_addr, dst_addr) } else { // make sure we get a consistently zeroed checksum, // since implementations might rely on it packet.set_checksum(0); } } /// Return the length of the segment, in terms of sequence space. pub const fn segment_len(&self) -> usize { self.payload.len() + self.control.len() } /// Return whether the segment has no flags set (except PSH) and no data. pub const fn is_empty(&self) -> bool { match self.control { _ if !self.payload.is_empty() => false, Control::Syn | Control::Fin | Control::Rst => false, Control::None | Control::Psh => true, } } } impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Cannot use Repr::parse because we don't have the IP addresses. write!(f, "TCP src={} dst={}", self.src_port(), self.dst_port())?; if self.syn() { write!(f, " syn")? } if self.fin() { write!(f, " fin")? } if self.rst() { write!(f, " rst")? } if self.psh() { write!(f, " psh")? } if self.ece() { write!(f, " ece")? } if self.cwr() { write!(f, " cwr")? } if self.ns() { write!(f, " ns")? } write!(f, " seq={}", self.seq_number())?; if self.ack() { write!(f, " ack={}", self.ack_number())?; } write!(f, " win={}", self.window_len())?; if self.urg() { write!(f, " urg={}", self.urgent_at())?; } write!(f, " len={}", self.payload().len())?; let mut options = self.options(); while !options.is_empty() { let (next_options, option) = match TcpOption::parse(options) { Ok(res) => res, Err(err) => return write!(f, " ({err})"), }; match option { TcpOption::EndOfList => break, TcpOption::NoOperation => (), TcpOption::MaxSegmentSize(value) => write!(f, " mss={value}")?, TcpOption::WindowScale(value) => write!(f, " ws={value}")?, TcpOption::SackPermitted => write!(f, " sACK")?, TcpOption::SackRange(slice) => write!(f, " sACKr{slice:?}")?, // debug print conveniently includes the []s TcpOption::Unknown { kind, .. } => write!(f, " opt({kind})")?, } options = next_options; } Ok(()) } } impl<'a> fmt::Display for Repr<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "TCP src={} dst={}", self.src_port, self.dst_port)?; match self.control { Control::Syn => write!(f, " syn")?, Control::Fin => write!(f, " fin")?, Control::Rst => write!(f, " rst")?, Control::Psh => write!(f, " psh")?, Control::None => (), } write!(f, " seq={}", self.seq_number)?; if let Some(ack_number) = self.ack_number { write!(f, " ack={ack_number}")?; } write!(f, " win={}", self.window_len)?; write!(f, " len={}", self.payload.len())?; if let Some(max_seg_size) = self.max_seg_size { write!(f, " mss={max_seg_size}")?; } Ok(()) } } use crate::wire::pretty_print::{PrettyIndent, PrettyPrint}; impl> PrettyPrint for Packet { fn pretty_print( buffer: &dyn AsRef<[u8]>, f: &mut fmt::Formatter, indent: &mut PrettyIndent, ) -> fmt::Result { match Packet::new_checked(buffer) { Err(err) => write!(f, "{indent}({err})"), Ok(packet) => write!(f, "{indent}{packet}"), } } } #[cfg(test)] mod test { use super::*; #[cfg(feature = "proto-ipv4")] use crate::wire::Ipv4Address; #[cfg(feature = "proto-ipv4")] const SRC_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 1]); #[cfg(feature = "proto-ipv4")] const DST_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 2]); #[cfg(feature = "proto-ipv4")] static PACKET_BYTES: [u8; 28] = [ 0xbf, 0x00, 0x00, 0x50, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x60, 0x35, 0x01, 0x23, 0x01, 0xb6, 0x02, 0x01, 0x03, 0x03, 0x0c, 0x01, 0xaa, 0x00, 0x00, 0xff, ]; #[cfg(feature = "proto-ipv4")] static OPTION_BYTES: [u8; 4] = [0x03, 0x03, 0x0c, 0x01]; #[cfg(feature = "proto-ipv4")] static PAYLOAD_BYTES: [u8; 4] = [0xaa, 0x00, 0x00, 0xff]; #[test] #[cfg(feature = "proto-ipv4")] fn test_deconstruct() { let packet = Packet::new_unchecked(&PACKET_BYTES[..]); assert_eq!(packet.src_port(), 48896); assert_eq!(packet.dst_port(), 80); assert_eq!(packet.seq_number(), SeqNumber(0x01234567)); assert_eq!(packet.ack_number(), SeqNumber(0x89abcdefu32 as i32)); assert_eq!(packet.header_len(), 24); assert!(packet.fin()); assert!(!packet.syn()); assert!(packet.rst()); assert!(!packet.psh()); assert!(packet.ack()); assert!(packet.urg()); assert_eq!(packet.window_len(), 0x0123); assert_eq!(packet.urgent_at(), 0x0201); assert_eq!(packet.checksum(), 0x01b6); assert_eq!(packet.options(), &OPTION_BYTES[..]); assert_eq!(packet.payload(), &PAYLOAD_BYTES[..]); assert!(packet.verify_checksum(&SRC_ADDR.into(), &DST_ADDR.into())); } #[test] #[cfg(feature = "proto-ipv4")] fn test_construct() { let mut bytes = vec![0xa5; PACKET_BYTES.len()]; let mut packet = Packet::new_unchecked(&mut bytes); packet.set_src_port(48896); packet.set_dst_port(80); packet.set_seq_number(SeqNumber(0x01234567)); packet.set_ack_number(SeqNumber(0x89abcdefu32 as i32)); packet.set_header_len(24); packet.clear_flags(); packet.set_fin(true); packet.set_syn(false); packet.set_rst(true); packet.set_psh(false); packet.set_ack(true); packet.set_urg(true); packet.set_window_len(0x0123); packet.set_urgent_at(0x0201); packet.set_checksum(0xEEEE); packet.options_mut().copy_from_slice(&OPTION_BYTES[..]); packet.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]); packet.fill_checksum(&SRC_ADDR.into(), &DST_ADDR.into()); assert_eq!(&*packet.into_inner(), &PACKET_BYTES[..]); } #[test] #[cfg(feature = "proto-ipv4")] fn test_truncated() { let packet = Packet::new_unchecked(&PACKET_BYTES[..23]); assert_eq!(packet.check_len(), Err(Error)); } #[test] fn test_impossible_len() { let mut bytes = vec![0; 20]; let mut packet = Packet::new_unchecked(&mut bytes); packet.set_header_len(10); assert_eq!(packet.check_len(), Err(Error)); } #[cfg(feature = "proto-ipv4")] static SYN_PACKET_BYTES: [u8; 24] = [ 0xbf, 0x00, 0x00, 0x50, 0x01, 0x23, 0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x01, 0x23, 0x7a, 0x8d, 0x00, 0x00, 0xaa, 0x00, 0x00, 0xff, ]; #[cfg(feature = "proto-ipv4")] fn packet_repr() -> Repr<'static> { Repr { src_port: 48896, dst_port: 80, seq_number: SeqNumber(0x01234567), ack_number: None, window_len: 0x0123, window_scale: None, control: Control::Syn, max_seg_size: None, sack_permitted: false, sack_ranges: [None, None, None], payload: &PAYLOAD_BYTES, } } #[test] #[cfg(feature = "proto-ipv4")] fn test_parse() { let packet = Packet::new_unchecked(&SYN_PACKET_BYTES[..]); let repr = Repr::parse( &packet, &SRC_ADDR.into(), &DST_ADDR.into(), &ChecksumCapabilities::default(), ) .unwrap(); assert_eq!(repr, packet_repr()); } #[test] #[cfg(feature = "proto-ipv4")] fn test_emit() { let repr = packet_repr(); let mut bytes = vec![0xa5; repr.buffer_len()]; let mut packet = Packet::new_unchecked(&mut bytes); repr.emit( &mut packet, &SRC_ADDR.into(), &DST_ADDR.into(), &ChecksumCapabilities::default(), ); assert_eq!(&*packet.into_inner(), &SYN_PACKET_BYTES[..]); } #[test] #[cfg(feature = "proto-ipv4")] fn test_header_len_multiple_of_4() { let mut repr = packet_repr(); repr.window_scale = Some(0); // This TCP Option needs 3 bytes. assert_eq!(repr.header_len() % 4, 0); // Should e.g. be 28 instead of 27. } macro_rules! assert_option_parses { ($opt:expr, $data:expr) => {{ assert_eq!(TcpOption::parse($data), Ok((&[][..], $opt))); let buffer = &mut [0; 40][..$opt.buffer_len()]; assert_eq!($opt.emit(buffer), &mut []); assert_eq!(&*buffer, $data); }}; } #[test] fn test_tcp_options() { assert_option_parses!(TcpOption::EndOfList, &[0x00]); assert_option_parses!(TcpOption::NoOperation, &[0x01]); assert_option_parses!(TcpOption::MaxSegmentSize(1500), &[0x02, 0x04, 0x05, 0xdc]); assert_option_parses!(TcpOption::WindowScale(12), &[0x03, 0x03, 0x0c]); assert_option_parses!(TcpOption::SackPermitted, &[0x4, 0x02]); assert_option_parses!( TcpOption::SackRange([Some((500, 1500)), None, None]), &[0x05, 0x0a, 0x00, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x05, 0xdc] ); assert_option_parses!( TcpOption::SackRange([Some((875, 1225)), Some((1500, 2500)), None]), &[ 0x05, 0x12, 0x00, 0x00, 0x03, 0x6b, 0x00, 0x00, 0x04, 0xc9, 0x00, 0x00, 0x05, 0xdc, 0x00, 0x00, 0x09, 0xc4 ] ); assert_option_parses!( TcpOption::SackRange([ Some((875000, 1225000)), Some((1500000, 2500000)), Some((876543210, 876654320)) ]), &[ 0x05, 0x1a, 0x00, 0x0d, 0x59, 0xf8, 0x00, 0x12, 0xb1, 0x28, 0x00, 0x16, 0xe3, 0x60, 0x00, 0x26, 0x25, 0xa0, 0x34, 0x3e, 0xfc, 0xea, 0x34, 0x40, 0xae, 0xf0 ] ); assert_option_parses!( TcpOption::Unknown { kind: 12, data: &[1, 2, 3][..] }, &[0x0c, 0x05, 0x01, 0x02, 0x03] ) } #[test] fn test_malformed_tcp_options() { assert_eq!(TcpOption::parse(&[]), Err(Error)); assert_eq!(TcpOption::parse(&[0xc]), Err(Error)); assert_eq!(TcpOption::parse(&[0xc, 0x05, 0x01, 0x02]), Err(Error)); assert_eq!(TcpOption::parse(&[0xc, 0x01]), Err(Error)); assert_eq!(TcpOption::parse(&[0x2, 0x02]), Err(Error)); assert_eq!(TcpOption::parse(&[0x3, 0x02]), Err(Error)); } }