Skip to main content

packet_strata/packet/
tcp.rs

1//! TCP (Transmission Control Protocol) packet parser
2//!
3//! This module implements parsing for TCP segments as defined in RFC 793.
4//! TCP provides reliable, ordered, and error-checked delivery of data
5//! between applications.
6//!
7//! # TCP Header Format
8//!
9//! ```text
10//!  0                   1                   2                   3
11//!  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
12//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13//! |          Source Port          |       Destination Port        |
14//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15//! |                        Sequence Number                        |
16//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17//! |                    Acknowledgment Number                      |
18//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19//! |  Data |       |C|E|U|A|P|R|S|F|                               |
20//! | Offset| Rsrvd |W|C|R|C|S|S|Y|I|            Window             |
21//! |       |       |R|E|G|K|H|T|N|N|                               |
22//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23//! |           Checksum            |         Urgent Pointer        |
24//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25//! |                    Options (if Data Offset > 5)               |
26//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27//! ```
28//!
29//! # Key characteristics
30//!
31//! - Minimum header size: 20 bytes (Data Offset = 5)
32//! - Maximum header size: 60 bytes (Data Offset = 15)
33//! - Flags: CWR, ECE, URG, ACK, PSH, RST, SYN, FIN
34//!
35//! # Examples
36//!
37//! ## Basic TCP parsing
38//!
39//! ```
40//! use packet_strata::packet::tcp::TcpHeader;
41//! use packet_strata::packet::HeaderParser;
42//!
43//! // TCP SYN packet
44//! let packet = vec![
45//!     0x1F, 0x90,              // Source port: 8080
46//!     0x00, 0x50,              // Destination port: 80
47//!     0x00, 0x00, 0x00, 0x01,  // Sequence number: 1
48//!     0x00, 0x00, 0x00, 0x00,  // Acknowledgment number: 0
49//!     0x50, 0x02,              // Data offset=5, Flags=SYN
50//!     0xFF, 0xFF,              // Window size: 65535
51//!     0x00, 0x00,              // Checksum
52//!     0x00, 0x00,              // Urgent pointer
53//!     // Payload follows...
54//! ];
55//!
56//! let (header, payload) = TcpHeader::from_bytes(&packet).unwrap();
57//! assert_eq!(header.src_port(), 8080);
58//! assert_eq!(header.dst_port(), 80);
59//! assert!(header.has_syn());
60//! assert!(!header.has_ack());
61//! assert_eq!(header.window_size(), 65535);
62//! ```
63//!
64//! ## TCP with options (SYN-ACK)
65//!
66//! ```
67//! use packet_strata::packet::tcp::TcpHeader;
68//! use packet_strata::packet::HeaderParser;
69//!
70//! // TCP SYN-ACK packet with MSS option
71//! let packet = vec![
72//!     0x00, 0x50,              // Source port: 80
73//!     0x1F, 0x90,              // Destination port: 8080
74//!     0x00, 0x00, 0x00, 0x01,  // Sequence number: 1
75//!     0x00, 0x00, 0x00, 0x02,  // Acknowledgment number: 2
76//!     0x60, 0x12,              // Data offset=6, Flags=SYN+ACK
77//!     0x72, 0x10,              // Window size: 29200
78//!     0x00, 0x00,              // Checksum
79//!     0x00, 0x00,              // Urgent pointer
80//!     0x02, 0x04, 0x05, 0xB4,  // MSS option: 1460
81//!     // Payload follows...
82//! ];
83//!
84//! let (header, payload) = TcpHeader::from_bytes(&packet).unwrap();
85//! assert!(header.has_syn());
86//! assert!(header.has_ack());
87//! assert_eq!(header.data_offset(), 6);
88//! assert_eq!(header.data_offset() as usize * 4, 24);  // Header length in bytes
89//! ```
90
91pub mod opt;
92
93use std::fmt::{self, Formatter};
94use std::ops::Deref;
95
96use smol_str::{SmolStr, SmolStrBuilder};
97use zerocopy::byteorder::{BigEndian, U16, U32};
98use zerocopy::{FromBytes, IntoBytes, Unaligned};
99
100use crate::packet::tcp::opt::TcpOptionsIter;
101use crate::packet::{HeaderParser, PacketHeader};
102
103/// TCP Header structure as defined in RFC 793
104///
105/// The fixed portion of the TCP header is 20 bytes. Additional options
106/// may be present if Data Offset > 5.
107#[repr(C, packed)]
108#[derive(
109    FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, zerocopy::KnownLayout, zerocopy::Immutable,
110)]
111pub struct TcpHeader {
112    src_port: U16<BigEndian>,
113    dst_port: U16<BigEndian>,
114    sequence_number: U32<BigEndian>,
115    acknowledgment_number: U32<BigEndian>,
116    data_offset_flags: U16<BigEndian>,
117    window_size: U16<BigEndian>,
118    checksum: U16<BigEndian>,
119    urgent_pointer: U16<BigEndian>,
120}
121
122impl TcpHeader {
123    // TCP Flags
124    pub const FLAG_FIN: u8 = 0x01;
125    pub const FLAG_SYN: u8 = 0x02;
126    pub const FLAG_RST: u8 = 0x04;
127    pub const FLAG_PSH: u8 = 0x08;
128    pub const FLAG_ACK: u8 = 0x10;
129    pub const FLAG_URG: u8 = 0x20;
130    pub const FLAG_ECE: u8 = 0x40;
131    pub const FLAG_CWR: u8 = 0x80;
132
133    #[allow(unused)]
134    const NAME: &'static str = "TcpHeader";
135
136    /// Returns the data offset (header length) in 32-bit words
137    #[inline]
138    pub fn data_offset(&self) -> u8 {
139        (self.data_offset_flags.get() >> 12) as u8
140    }
141
142    /// Returns the TCP flags byte
143    #[inline]
144    pub fn flags(&self) -> u8 {
145        (self.data_offset_flags.get() & 0x00FF) as u8
146    }
147
148    /// Check if FIN flag is set
149    #[inline]
150    pub fn has_fin(&self) -> bool {
151        self.flags() & Self::FLAG_FIN != 0
152    }
153
154    /// Check if SYN flag is set
155    #[inline]
156    pub fn has_syn(&self) -> bool {
157        self.flags() & Self::FLAG_SYN != 0
158    }
159
160    /// Check if RST flag is set
161    #[inline]
162    pub fn has_rst(&self) -> bool {
163        self.flags() & Self::FLAG_RST != 0
164    }
165
166    /// Check if PSH flag is set
167    #[inline]
168    pub fn has_psh(&self) -> bool {
169        self.flags() & Self::FLAG_PSH != 0
170    }
171
172    /// Check if ACK flag is set
173    #[inline]
174    pub fn has_ack(&self) -> bool {
175        self.flags() & Self::FLAG_ACK != 0
176    }
177
178    /// Check if URG flag is set
179    #[inline]
180    pub fn has_urg(&self) -> bool {
181        self.flags() & Self::FLAG_URG != 0
182    }
183
184    /// Check if ECE flag is set
185    #[inline]
186    pub fn has_ece(&self) -> bool {
187        self.flags() & Self::FLAG_ECE != 0
188    }
189
190    /// Check if CWR flag is set
191    #[inline]
192    pub fn has_cwr(&self) -> bool {
193        self.flags() & Self::FLAG_CWR != 0
194    }
195
196    /// Returns the source port number
197    #[inline]
198    pub fn src_port(&self) -> u16 {
199        self.src_port.get()
200    }
201
202    /// Returns the destination port number
203    #[inline]
204    pub fn dst_port(&self) -> u16 {
205        self.dst_port.get()
206    }
207
208    /// Returns the sequence number
209    #[inline]
210    pub fn sequence_number(&self) -> u32 {
211        self.sequence_number.get()
212    }
213
214    /// Validates the TCP header
215    #[inline]
216    fn is_valid(&self) -> bool {
217        // Data offset must be at least 5 (20 bytes minimum)
218        // and at most 15 (60 bytes maximum)
219        let offset = self.data_offset();
220        (5..=15).contains(&offset)
221    }
222
223    /// Returns the acknowledgment number
224    #[inline]
225    pub fn acknowledgment_number(&self) -> u32 {
226        self.acknowledgment_number.get()
227    }
228
229    /// Returns the window size
230    #[inline]
231    pub fn window_size(&self) -> u16 {
232        self.window_size.get()
233    }
234
235    /// Returns the urgent pointer
236    #[inline]
237    pub fn urgent_pointer(&self) -> u16 {
238        self.urgent_pointer.get()
239    }
240
241    /// Returns a string representation of active flags
242    pub fn flags_string(&self) -> SmolStr {
243        let mut result = SmolStrBuilder::new();
244        if self.has_fin() {
245            result.push('F');
246        }
247        if self.has_syn() {
248            result.push('S');
249        }
250        if self.has_rst() {
251            result.push('R');
252        }
253        if self.has_psh() {
254            result.push('P');
255        }
256        if self.has_ack() {
257            result.push('A');
258        }
259        if self.has_urg() {
260            result.push('U');
261        }
262        if self.has_ece() {
263            result.push('E');
264        }
265        if self.has_cwr() {
266            result.push('C');
267        }
268        result.finish()
269    }
270}
271
272#[derive(Debug, Clone)]
273pub struct TcpHeaderOpt<'a> {
274    pub header: &'a TcpHeader,
275    pub raw_options: &'a [u8],
276}
277
278impl<'a> TcpHeaderOpt<'a> {
279    /// Get TCP options slice
280    pub fn options(&'a self) -> TcpOptionsIter<'a> {
281        TcpOptionsIter::new(self.raw_options)
282    }
283}
284
285impl Deref for TcpHeaderOpt<'_> {
286    type Target = TcpHeader;
287
288    #[inline]
289    fn deref(&self) -> &Self::Target {
290        self.header
291    }
292}
293
294impl PacketHeader for TcpHeader {
295    const NAME: &'static str = "TcpHeader";
296    type InnerType = ();
297
298    #[inline]
299    fn inner_type(&self) -> Self::InnerType {}
300
301    /// Returns the header length in bytes
302    #[inline]
303    fn total_len(&self, _buf: &[u8]) -> usize {
304        (self.data_offset() as usize) * 4
305    }
306
307    /// Validates the TCP header
308    #[inline]
309    fn is_valid(&self) -> bool {
310        self.is_valid()
311    }
312}
313
314impl HeaderParser for TcpHeader {
315    type Output<'a> = TcpHeaderOpt<'a>;
316
317    #[inline]
318    fn into_view<'a>(header: &'a Self, raw_options: &'a [u8]) -> Self::Output<'a> {
319        TcpHeaderOpt {
320            header,
321            raw_options,
322        }
323    }
324}
325
326impl fmt::Display for TcpHeader {
327    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
328        write!(
329            f,
330            "TCP {} -> {} [{}] seq={} ack={} win={}",
331            self.src_port(),
332            self.dst_port(),
333            self.flags_string(),
334            self.sequence_number(),
335            self.acknowledgment_number(),
336            self.window_size()
337        )?;
338
339        if self.data_offset() > 5 {
340            write!(f, " +opts")?;
341        }
342
343        Ok(())
344    }
345}
346
347impl fmt::Display for TcpHeaderOpt<'_> {
348    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
349        write!(f, "{}", self.header)?;
350
351        if !self.raw_options.is_empty() {
352            write!(f, " opts=[")?;
353            let mut first = true;
354            for opt in self.options().flatten() {
355                if !first {
356                    write!(f, ",")?;
357                }
358                first = false;
359                write!(f, "{}", opt)?;
360            }
361            write!(f, "]")?;
362        }
363
364        Ok(())
365    }
366}
367
368#[cfg(test)]
369mod tests {
370    use super::*;
371
372    #[test]
373    fn test_tcp_flags() {
374        let header = TcpHeader {
375            src_port: U16::new(80),
376            dst_port: U16::new(12345),
377            sequence_number: U32::new(0),
378            acknowledgment_number: U32::new(0),
379            data_offset_flags: U16::new((5 << 12) | TcpHeader::FLAG_SYN as u16),
380            window_size: U16::new(65535),
381            checksum: U16::new(0),
382            urgent_pointer: U16::new(0),
383        };
384
385        // Create a minimal buffer for total_len() call
386        let buf = [0u8; 20];
387
388        assert_eq!(header.data_offset(), 5);
389        assert_eq!(header.total_len(&buf), 20);
390        assert!(header.has_syn());
391        assert!(!header.has_ack());
392        assert!(header.is_valid());
393    }
394
395    #[test]
396    fn test_tcp_header_validation() {
397        let mut header = TcpHeader {
398            src_port: U16::new(80),
399            dst_port: U16::new(12345),
400            sequence_number: U32::new(0),
401            acknowledgment_number: U32::new(0),
402            data_offset_flags: U16::new(4 << 12), // Invalid: too small
403            window_size: U16::new(65535),
404            checksum: U16::new(0),
405            urgent_pointer: U16::new(0),
406        };
407
408        assert!(!header.is_valid());
409
410        header.data_offset_flags = U16::new(5 << 12);
411        assert!(header.is_valid());
412    }
413
414    #[test]
415    fn test_tcp_header_size() {
416        assert_eq!(std::mem::size_of::<TcpHeader>(), 20);
417        assert_eq!(TcpHeader::FIXED_LEN, 20);
418    }
419
420    #[test]
421    fn test_tcp_all_flags() {
422        let mut header = create_test_header();
423
424        // Test each flag individually
425        header.data_offset_flags = U16::new((5 << 12) | TcpHeader::FLAG_FIN as u16);
426        assert!(header.has_fin());
427        assert!(!header.has_syn());
428
429        header.data_offset_flags = U16::new((5 << 12) | TcpHeader::FLAG_SYN as u16);
430        assert!(header.has_syn());
431        assert!(!header.has_fin());
432
433        header.data_offset_flags = U16::new((5 << 12) | TcpHeader::FLAG_RST as u16);
434        assert!(header.has_rst());
435
436        header.data_offset_flags = U16::new((5 << 12) | TcpHeader::FLAG_PSH as u16);
437        assert!(header.has_psh());
438
439        header.data_offset_flags = U16::new((5 << 12) | TcpHeader::FLAG_ACK as u16);
440        assert!(header.has_ack());
441
442        header.data_offset_flags = U16::new((5 << 12) | TcpHeader::FLAG_URG as u16);
443        assert!(header.has_urg());
444
445        header.data_offset_flags = U16::new((5 << 12) | TcpHeader::FLAG_ECE as u16);
446        assert!(header.has_ece());
447
448        header.data_offset_flags = U16::new((5 << 12) | TcpHeader::FLAG_CWR as u16);
449        assert!(header.has_cwr());
450
451        // Test multiple flags
452        header.data_offset_flags =
453            U16::new((5 << 12) | (TcpHeader::FLAG_SYN | TcpHeader::FLAG_ACK) as u16);
454        assert!(header.has_syn());
455        assert!(header.has_ack());
456        assert_eq!(header.flags_string(), "SA");
457    }
458
459    #[test]
460    fn test_tcp_parsing_basic() {
461        let packet = create_test_packet();
462
463        let result = TcpHeader::from_bytes(&packet);
464        assert!(result.is_ok());
465
466        let (header, payload) = result.unwrap();
467        assert_eq!(header.src_port(), 54321);
468        assert_eq!(header.dst_port(), 80);
469        assert_eq!(header.data_offset(), 5);
470        assert!(header.has_syn());
471        assert!(header.is_valid());
472        assert_eq!(payload.len(), 0); // No payload in test packet
473    }
474
475    #[test]
476    fn test_tcp_parsing_too_small() {
477        let packet = vec![0u8; 19]; // Only 19 bytes, need 20
478
479        let result = TcpHeader::from_bytes(&packet);
480        assert!(result.is_err());
481    }
482
483    #[test]
484    fn test_tcp_total_len_no_options() {
485        let packet = create_test_packet();
486        let (header, _) = TcpHeader::from_bytes(&packet).unwrap();
487
488        // No options, should return 20 bytes
489        assert_eq!(header.total_len(&packet), 20);
490        assert_eq!(header.data_offset(), 5);
491    }
492
493    #[test]
494    fn test_tcp_with_mss_option() {
495        let mut packet = create_test_packet();
496
497        // Change data offset to 6 (6 * 4 = 24 bytes header with 4 bytes of options)
498        packet[12] = 0x60; // Data offset 6, no flags set initially
499        packet[13] = 0x02; // SYN flag
500
501        // Add MSS option (Kind 2, Length 4, MSS value 1460)
502        packet.push(0x02); // Kind: MSS
503        packet.push(0x04); // Length: 4 bytes
504        packet.extend_from_slice(&1460u16.to_be_bytes()); // MSS value
505
506        let (header, _) = TcpHeader::from_bytes(&packet).unwrap();
507
508        // Verify header length includes options
509        assert_eq!(header.data_offset(), 6);
510        assert_eq!(header.total_len(&packet), 24); // 6 * 4 = 24 bytes
511        assert!(header.is_valid());
512
513        // Get the raw options slice
514        let options_len = (header.data_offset() as usize * 4) - TcpHeader::FIXED_LEN;
515        let options_start = TcpHeader::FIXED_LEN;
516        let raw_options = &packet[options_start..options_start + options_len];
517
518        assert_eq!(raw_options.len(), 4);
519        assert_eq!(raw_options[0], 0x02); // MSS kind
520        assert_eq!(raw_options[1], 0x04); // Length
521    }
522
523    #[test]
524    fn test_tcp_with_window_scale_option() {
525        let mut packet = create_test_packet();
526
527        // Change data offset to 6 (24 bytes with 4 bytes of options)
528        packet[12] = 0x60;
529        packet[13] = 0x02; // SYN flag
530
531        // Add Window Scale option (Kind 3, Length 3, Shift count 7) + NOP for padding
532        packet.push(0x03); // Kind: Window Scale
533        packet.push(0x03); // Length: 3 bytes
534        packet.push(0x07); // Shift count: 7
535        packet.push(0x01); // NOP for padding to 4 bytes
536
537        let (header, _) = TcpHeader::from_bytes(&packet).unwrap();
538
539        assert_eq!(header.data_offset(), 6);
540        assert_eq!(header.total_len(&packet), 24);
541
542        let options_len = (header.data_offset() as usize * 4) - TcpHeader::FIXED_LEN;
543        let options_start = TcpHeader::FIXED_LEN;
544        let raw_options = &packet[options_start..options_start + options_len];
545
546        assert_eq!(raw_options.len(), 4);
547        assert_eq!(raw_options[0], 0x03); // Window Scale kind
548        assert_eq!(raw_options[2], 0x07); // Shift count
549    }
550
551    #[test]
552    fn test_tcp_with_timestamp_option() {
553        let mut packet = create_test_packet();
554
555        // Change data offset to 8 (8 * 4 = 32 bytes with 12 bytes of options)
556        packet[12] = 0x80;
557        packet[13] = 0x02; // SYN flag
558
559        // Add Timestamp option (Kind 8, Length 10, TSval, TSecr)
560        packet.push(0x08); // Kind: Timestamp
561        packet.push(0x0A); // Length: 10 bytes
562        packet.extend_from_slice(&12345678u32.to_be_bytes()); // TSval
563        packet.extend_from_slice(&87654321u32.to_be_bytes()); // TSecr
564
565        // Add 2 NOPs for padding to reach 12 bytes
566        packet.push(0x01); // NOP
567        packet.push(0x01); // NOP
568
569        let (header, _) = TcpHeader::from_bytes(&packet).unwrap();
570
571        assert_eq!(header.data_offset(), 8);
572        assert_eq!(header.total_len(&packet), 32);
573
574        let options_len = (header.data_offset() as usize * 4) - TcpHeader::FIXED_LEN;
575        let options_start = TcpHeader::FIXED_LEN;
576        let raw_options = &packet[options_start..options_start + options_len];
577
578        assert_eq!(raw_options.len(), 12);
579        assert_eq!(raw_options[0], 0x08); // Timestamp kind
580        assert_eq!(raw_options[1], 0x0A); // Length
581    }
582
583    #[test]
584    fn test_tcp_with_sack_permitted_option() {
585        let mut packet = create_test_packet();
586
587        // Change data offset to 6 (24 bytes with 4 bytes of options)
588        packet[12] = 0x60;
589        packet[13] = 0x02; // SYN flag
590
591        // Add SACK Permitted option (Kind 4, Length 2) + 2 NOPs for padding
592        packet.push(0x04); // Kind: SACK Permitted
593        packet.push(0x02); // Length: 2 bytes
594        packet.push(0x01); // NOP
595        packet.push(0x01); // NOP
596
597        let (header, _) = TcpHeader::from_bytes(&packet).unwrap();
598
599        assert_eq!(header.data_offset(), 6);
600        assert_eq!(header.total_len(&packet), 24);
601
602        let options_len = (header.data_offset() as usize * 4) - TcpHeader::FIXED_LEN;
603        let options_start = TcpHeader::FIXED_LEN;
604        let raw_options = &packet[options_start..options_start + options_len];
605
606        assert_eq!(raw_options[0], 0x04); // SACK Permitted kind
607    }
608
609    #[test]
610    fn test_tcp_with_multiple_options() {
611        let mut packet = create_test_packet();
612
613        // Change data offset to 10 (10 * 4 = 40 bytes with 20 bytes of options)
614        packet[12] = 0xA0;
615        packet[13] = 0x02; // SYN flag
616
617        // Add multiple options: MSS + SACK Permitted + Timestamp + Window Scale
618        // MSS (4 bytes)
619        packet.push(0x02); // Kind: MSS
620        packet.push(0x04); // Length
621        packet.extend_from_slice(&1460u16.to_be_bytes());
622
623        // SACK Permitted (2 bytes)
624        packet.push(0x04); // Kind: SACK Permitted
625        packet.push(0x02); // Length
626
627        // Timestamp (10 bytes)
628        packet.push(0x08); // Kind: Timestamp
629        packet.push(0x0A); // Length
630        packet.extend_from_slice(&12345u32.to_be_bytes()); // TSval
631        packet.extend_from_slice(&0u32.to_be_bytes()); // TSecr
632
633        // Window Scale (3 bytes) + NOP for padding
634        packet.push(0x03); // Kind: Window Scale
635        packet.push(0x03); // Length
636        packet.push(0x07); // Shift count
637        packet.push(0x01); // NOP
638
639        let (header, _) = TcpHeader::from_bytes(&packet).unwrap();
640
641        assert_eq!(header.data_offset(), 10);
642        assert_eq!(header.total_len(&packet), 40);
643
644        let options_len = (header.data_offset() as usize * 4) - TcpHeader::FIXED_LEN;
645        let options_start = TcpHeader::FIXED_LEN;
646        let raw_options = &packet[options_start..options_start + options_len];
647
648        assert_eq!(raw_options.len(), 20);
649        assert_eq!(raw_options[0], 0x02); // MSS
650        assert_eq!(raw_options[4], 0x04); // SACK Permitted
651        assert_eq!(raw_options[6], 0x08); // Timestamp
652        assert_eq!(raw_options[16], 0x03); // Window Scale
653    }
654
655    #[test]
656    fn test_tcp_from_bytes_with_options_and_payload() {
657        let mut packet = create_test_packet();
658
659        // Change data offset to 7 (7 * 4 = 28 bytes header with 8 bytes of options)
660        packet[12] = 0x70;
661        packet[13] = 0x18; // PSH + ACK flags
662
663        // Add 8 bytes of options (MSS + padding)
664        packet.push(0x02); // MSS kind
665        packet.push(0x04); // Length
666        packet.extend_from_slice(&1460u16.to_be_bytes());
667        packet.extend_from_slice(&[0x01, 0x01, 0x01, 0x01]); // 4 NOPs
668
669        // Add some payload data
670        let payload_data = b"HTTP/1.1 200 OK\r\n";
671        packet.extend_from_slice(payload_data);
672
673        let result = TcpHeader::from_bytes(&packet);
674        assert!(result.is_ok());
675
676        let (header, payload) = result.unwrap();
677
678        // Verify the payload starts after ALL of the header (base + options)
679        // Should skip 28 bytes (7 * 4)
680        assert_eq!(payload.len(), payload_data.len());
681        assert_eq!(payload, payload_data);
682
683        // Verify header info
684        assert_eq!(header.data_offset(), 7);
685        assert_eq!(header.total_len(&packet), 28);
686        assert!(header.has_psh());
687        assert!(header.has_ack());
688    }
689
690    #[test]
691    fn test_tcp_total_len_includes_options() {
692        // Test that total_len() correctly includes TCP options
693        let mut packet = create_test_packet();
694
695        // Test 1: No options - should return 20
696        let (header, _) = TcpHeader::from_bytes(&packet).unwrap();
697        assert_eq!(header.total_len(&packet), 20);
698        assert_eq!(header.data_offset(), 5);
699
700        // Test 2: With 4 bytes of options (data offset = 6)
701        packet = create_test_packet();
702        packet[12] = 0x60; // Data offset 6
703        packet.extend_from_slice(&[0x01, 0x01, 0x01, 0x01]); // 4 NOPs
704        let (header, _) = TcpHeader::from_bytes(&packet).unwrap();
705        assert_eq!(header.total_len(&packet), 24); // 6 * 4
706        assert_eq!(header.data_offset(), 6);
707
708        // Test 3: With 8 bytes of options (data offset = 7)
709        packet = create_test_packet();
710        packet[12] = 0x70;
711        packet.extend_from_slice(&[0x01; 8]); // 8 NOPs
712        let (header, _) = TcpHeader::from_bytes(&packet).unwrap();
713        assert_eq!(header.total_len(&packet), 28); // 7 * 4
714        assert_eq!(header.data_offset(), 7);
715
716        // Test 4: Maximum header size with options (data offset = 15)
717        packet = create_test_packet();
718        packet[12] = 0xF0; // Data offset 15
719        packet.extend_from_slice(&[0x01; 40]); // 40 bytes of NOPs
720        let (header, _) = TcpHeader::from_bytes(&packet).unwrap();
721        assert_eq!(header.total_len(&packet), 60); // 15 * 4
722        assert_eq!(header.data_offset(), 15);
723    }
724
725    #[test]
726    fn test_tcp_options_extraction() {
727        let mut packet = create_test_packet();
728
729        // No options case
730        let (header, _) = TcpHeader::from_bytes(&packet).unwrap();
731        let options_len = (header.data_offset() as usize * 4) - TcpHeader::FIXED_LEN;
732        assert_eq!(options_len, 0);
733
734        // With options
735        packet = create_test_packet();
736        packet[12] = 0x60;
737        packet.extend_from_slice(&[0x02, 0x04, 0x05, 0xb4]); // MSS option
738        let (header, _) = TcpHeader::from_bytes(&packet).unwrap();
739        let options_len = (header.data_offset() as usize * 4) - TcpHeader::FIXED_LEN;
740        let options_start = TcpHeader::FIXED_LEN;
741        let raw_options = &packet[options_start..options_start + options_len];
742        assert_eq!(raw_options.len(), 4);
743    }
744
745    #[test]
746    fn test_tcp_flags_string() {
747        let mut header = create_test_header();
748
749        header.data_offset_flags = U16::new(5 << 12);
750        assert_eq!(header.flags_string(), "");
751
752        header.data_offset_flags = U16::new((5 << 12) | TcpHeader::FLAG_SYN as u16);
753        assert_eq!(header.flags_string(), "S");
754
755        header.data_offset_flags =
756            U16::new((5 << 12) | (TcpHeader::FLAG_SYN | TcpHeader::FLAG_ACK) as u16);
757        assert_eq!(header.flags_string(), "SA");
758
759        header.data_offset_flags = U16::new(
760            (5 << 12) | (TcpHeader::FLAG_FIN | TcpHeader::FLAG_PSH | TcpHeader::FLAG_ACK) as u16,
761        );
762        assert_eq!(header.flags_string(), "FPA");
763
764        // All flags
765        header.data_offset_flags = U16::new((5 << 12) | 0xFF);
766        assert_eq!(header.flags_string(), "FSRPAUEC");
767    }
768
769    #[test]
770    fn test_tcp_sequence_and_ack_numbers() {
771        let mut header = create_test_header();
772
773        header.sequence_number = U32::new(1000);
774        header.acknowledgment_number = U32::new(2000);
775
776        assert_eq!(header.sequence_number(), 1000);
777        assert_eq!(header.acknowledgment_number(), 2000);
778    }
779
780    #[test]
781    fn test_tcp_window_and_urgent() {
782        let mut header = create_test_header();
783
784        header.window_size = U16::new(65535);
785        header.urgent_pointer = U16::new(100);
786
787        assert_eq!(header.window_size(), 65535);
788        assert_eq!(header.urgent_pointer(), 100);
789    }
790
791    // Helper function to create a test header
792    fn create_test_header() -> TcpHeader {
793        TcpHeader {
794            src_port: U16::new(80),
795            dst_port: U16::new(12345),
796            sequence_number: U32::new(0),
797            acknowledgment_number: U32::new(0),
798            data_offset_flags: U16::new(5 << 12), // Data offset 5, no flags
799            window_size: U16::new(65535),
800            checksum: U16::new(0),
801            urgent_pointer: U16::new(0),
802        }
803    }
804
805    // Helper function to create a test TCP packet
806    fn create_test_packet() -> Vec<u8> {
807        let mut packet = Vec::new();
808
809        // Source port: 54321
810        packet.extend_from_slice(&54321u16.to_be_bytes());
811
812        // Destination port: 80
813        packet.extend_from_slice(&80u16.to_be_bytes());
814
815        // Sequence number: 1000
816        packet.extend_from_slice(&1000u32.to_be_bytes());
817
818        // Acknowledgment number: 0
819        packet.extend_from_slice(&0u32.to_be_bytes());
820
821        // Data offset (5) + Flags (SYN)
822        packet.extend_from_slice(&0x5002u16.to_be_bytes()); // 5 << 12 | SYN
823
824        // Window size: 65535
825        packet.extend_from_slice(&65535u16.to_be_bytes());
826
827        // Checksum: 0
828        packet.extend_from_slice(&0u16.to_be_bytes());
829
830        // Urgent pointer: 0
831        packet.extend_from_slice(&0u16.to_be_bytes());
832
833        packet
834    }
835}