Skip to main content

stackforge_core/layer/tcp/
builder.rs

1//! TCP packet builder.
2//!
3//! Provides a fluent API for constructing TCP packets with automatic
4//! field calculation (checksum, data offset).
5//!
6//! # Example
7//!
8//! ```rust
9//! use stackforge_core::layer::tcp::{TcpBuilder, TcpFlags};
10//! use std::net::Ipv4Addr;
11//!
12//! // Build a SYN packet
13//! let packet = TcpBuilder::new()
14//!     .src_port(12345)
15//!     .dst_port(80)
16//!     .seq(1000)
17//!     .syn()
18//!     .window(65535)
19//!     .mss(1460)
20//!     .wscale(7)
21//!     .sack_ok()
22//!     .build();
23//! ```
24
25use std::net::{Ipv4Addr, Ipv6Addr};
26
27use super::checksum::{tcp_checksum_ipv4, tcp_checksum_ipv6};
28use super::flags::TcpFlags;
29use super::header::{TCP_MIN_HEADER_LEN, TcpLayer, offsets};
30use super::options::{TcpAoValue, TcpOption, TcpOptions, TcpOptionsBuilder, TcpSackBlock};
31use crate::layer::field::FieldError;
32
33/// Builder for TCP packets.
34#[derive(Debug, Clone)]
35pub struct TcpBuilder {
36    // Header fields
37    src_port: u16,
38    dst_port: u16,
39    seq: u32,
40    ack: u32,
41    data_offset: Option<u8>,
42    reserved: u8,
43    flags: TcpFlags,
44    window: u16,
45    checksum: Option<u16>,
46    urgent_ptr: u16,
47
48    // Options
49    options: TcpOptions,
50
51    // Payload
52    payload: Vec<u8>,
53
54    // Build options
55    auto_checksum: bool,
56    auto_data_offset: bool,
57
58    // IP addresses for checksum calculation
59    src_ip: Option<IpAddr>,
60    dst_ip: Option<IpAddr>,
61
62    // Tracks whether flags were explicitly set by the user.
63    // When true, the default SYN flag has already been cleared.
64    flags_explicitly_set: bool,
65}
66
67/// IP address enum for checksum calculation.
68#[derive(Debug, Clone, Copy)]
69pub enum IpAddr {
70    V4(Ipv4Addr),
71    V6(Ipv6Addr),
72}
73
74impl From<Ipv4Addr> for IpAddr {
75    fn from(addr: Ipv4Addr) -> Self {
76        IpAddr::V4(addr)
77    }
78}
79
80impl From<Ipv6Addr> for IpAddr {
81    fn from(addr: Ipv6Addr) -> Self {
82        IpAddr::V6(addr)
83    }
84}
85
86impl Default for TcpBuilder {
87    fn default() -> Self {
88        Self {
89            src_port: 20,
90            dst_port: 80,
91            seq: 0,
92            ack: 0,
93            data_offset: None,
94            reserved: 0,
95            flags: TcpFlags::from_u16(0x02), // SYN
96            window: 8192,
97            checksum: None,
98            urgent_ptr: 0,
99            options: TcpOptions::new(),
100            payload: Vec::new(),
101            auto_checksum: true,
102            auto_data_offset: true,
103            src_ip: None,
104            dst_ip: None,
105            flags_explicitly_set: false,
106        }
107    }
108}
109
110impl TcpBuilder {
111    /// Create a new TCP builder with default values.
112    pub fn new() -> Self {
113        Self::default()
114    }
115
116    /// Create a builder initialized from an existing packet.
117    pub fn from_bytes(data: &[u8]) -> Result<Self, FieldError> {
118        let layer = TcpLayer::at_offset_dynamic(data, 0)?;
119
120        let mut builder = Self::new();
121        builder.src_port = layer.src_port(data)?;
122        builder.dst_port = layer.dst_port(data)?;
123        builder.seq = layer.seq(data)?;
124        builder.ack = layer.ack(data)?;
125        builder.data_offset = Some(layer.data_offset(data)?);
126        builder.reserved = layer.reserved(data)?;
127        builder.flags = layer.flags(data)?;
128        builder.window = layer.window(data)?;
129        builder.checksum = Some(layer.checksum(data)?);
130        builder.urgent_ptr = layer.urgent_ptr(data)?;
131
132        // Parse options if present
133        if layer.options_len(data) > 0 {
134            builder.options = layer.options(data)?;
135        }
136
137        // Copy payload
138        let header_len = layer.calculate_header_len(data);
139        if data.len() > header_len {
140            builder.payload = data[header_len..].to_vec();
141        }
142
143        // Disable auto-calculation since we're copying exact values
144        builder.auto_checksum = false;
145        builder.auto_data_offset = false;
146
147        Ok(builder)
148    }
149
150    // ========== Header Field Setters ==========
151
152    /// Set the source port.
153    pub fn src_port(mut self, port: u16) -> Self {
154        self.src_port = port;
155        self
156    }
157
158    /// Alias for src_port (Scapy compatibility).
159    pub fn sport(self, port: u16) -> Self {
160        self.src_port(port)
161    }
162
163    /// Set the destination port.
164    pub fn dst_port(mut self, port: u16) -> Self {
165        self.dst_port = port;
166        self
167    }
168
169    /// Alias for dst_port (Scapy compatibility).
170    pub fn dport(self, port: u16) -> Self {
171        self.dst_port(port)
172    }
173
174    /// Set the sequence number.
175    pub fn seq(mut self, seq: u32) -> Self {
176        self.seq = seq;
177        self
178    }
179
180    /// Set the acknowledgment number.
181    pub fn ack_num(mut self, ack: u32) -> Self {
182        self.ack = ack;
183        self
184    }
185
186    /// Set the data offset (in 32-bit words).
187    pub fn data_offset(mut self, offset: u8) -> Self {
188        self.data_offset = Some(offset);
189        self.auto_data_offset = false;
190        self
191    }
192
193    /// Alias for data_offset (Scapy compatibility).
194    pub fn dataofs(self, offset: u8) -> Self {
195        self.data_offset(offset)
196    }
197
198    /// Set the reserved bits.
199    pub fn reserved(mut self, reserved: u8) -> Self {
200        self.reserved = reserved & 0x07;
201        self
202    }
203
204    /// Set the flags.
205    pub fn flags(mut self, flags: TcpFlags) -> Self {
206        self.flags = flags;
207        self.flags_explicitly_set = true;
208        self
209    }
210
211    /// Set flags from a string like "S", "SA", "FA", etc.
212    pub fn flags_str(mut self, s: &str) -> Self {
213        self.flags = TcpFlags::from_str(s);
214        self.flags_explicitly_set = true;
215        self
216    }
217
218    /// Clear default flags on first explicit flag call.
219    /// The default has SYN set (matching Scapy's TCP() default), but when
220    /// the user explicitly sets flags via individual methods, the default
221    /// should be cleared first so e.g. `.fin()` produces only FIN, not SYN|FIN.
222    fn clear_defaults_if_needed(&mut self) {
223        if !self.flags_explicitly_set {
224            self.flags = TcpFlags::from_u16(0);
225            self.flags_explicitly_set = true;
226        }
227    }
228
229    /// Set the SYN flag.
230    pub fn syn(mut self) -> Self {
231        self.clear_defaults_if_needed();
232        self.flags.syn = true;
233        self
234    }
235
236    /// Set the ACK flag.
237    pub fn ack(mut self) -> Self {
238        self.clear_defaults_if_needed();
239        self.flags.ack = true;
240        self
241    }
242
243    /// Set the FIN flag.
244    pub fn fin(mut self) -> Self {
245        self.clear_defaults_if_needed();
246        self.flags.fin = true;
247        self
248    }
249
250    /// Set the RST flag.
251    pub fn rst(mut self) -> Self {
252        self.clear_defaults_if_needed();
253        self.flags.rst = true;
254        self
255    }
256
257    /// Set the PSH flag.
258    pub fn psh(mut self) -> Self {
259        self.clear_defaults_if_needed();
260        self.flags.psh = true;
261        self
262    }
263
264    /// Set the URG flag.
265    pub fn urg(mut self) -> Self {
266        self.clear_defaults_if_needed();
267        self.flags.urg = true;
268        self
269    }
270
271    /// Set the ECE flag.
272    pub fn ece(mut self) -> Self {
273        self.clear_defaults_if_needed();
274        self.flags.ece = true;
275        self
276    }
277
278    /// Set the CWR flag.
279    pub fn cwr(mut self) -> Self {
280        self.clear_defaults_if_needed();
281        self.flags.cwr = true;
282        self
283    }
284
285    /// Set the NS flag.
286    pub fn ns(mut self) -> Self {
287        self.clear_defaults_if_needed();
288        self.flags.ns = true;
289        self
290    }
291
292    /// Set SYN+ACK flags.
293    pub fn syn_ack(mut self) -> Self {
294        self.clear_defaults_if_needed();
295        self.flags.syn = true;
296        self.flags.ack = true;
297        self
298    }
299
300    /// Set FIN+ACK flags.
301    pub fn fin_ack(mut self) -> Self {
302        self.clear_defaults_if_needed();
303        self.flags.fin = true;
304        self.flags.ack = true;
305        self
306    }
307
308    /// Set PSH+ACK flags.
309    pub fn psh_ack(mut self) -> Self {
310        self.clear_defaults_if_needed();
311        self.flags.psh = true;
312        self.flags.ack = true;
313        self
314    }
315
316    /// Set the window size.
317    pub fn window(mut self, window: u16) -> Self {
318        self.window = window;
319        self
320    }
321
322    /// Set the checksum manually.
323    pub fn checksum(mut self, checksum: u16) -> Self {
324        self.checksum = Some(checksum);
325        self.auto_checksum = false;
326        self
327    }
328
329    /// Alias for checksum (Scapy compatibility).
330    pub fn chksum(self, checksum: u16) -> Self {
331        self.checksum(checksum)
332    }
333
334    /// Set the urgent pointer.
335    pub fn urgent_ptr(mut self, urgptr: u16) -> Self {
336        self.urgent_ptr = urgptr;
337        self
338    }
339
340    /// Alias for urgent_ptr (Scapy compatibility).
341    pub fn urgptr(self, urgptr: u16) -> Self {
342        self.urgent_ptr(urgptr)
343    }
344
345    // ========== IP Address Setters (for checksum) ==========
346
347    /// Set the source IP address (for checksum calculation).
348    pub fn src_ip<T: Into<IpAddr>>(mut self, ip: T) -> Self {
349        self.src_ip = Some(ip.into());
350        self
351    }
352
353    /// Set the destination IP address (for checksum calculation).
354    pub fn dst_ip<T: Into<IpAddr>>(mut self, ip: T) -> Self {
355        self.dst_ip = Some(ip.into());
356        self
357    }
358
359    /// Set both source and destination IPv4 addresses.
360    pub fn ipv4_addrs(mut self, src: Ipv4Addr, dst: Ipv4Addr) -> Self {
361        self.src_ip = Some(IpAddr::V4(src));
362        self.dst_ip = Some(IpAddr::V4(dst));
363        self
364    }
365
366    /// Set both source and destination IPv6 addresses.
367    pub fn ipv6_addrs(mut self, src: Ipv6Addr, dst: Ipv6Addr) -> Self {
368        self.src_ip = Some(IpAddr::V6(src));
369        self.dst_ip = Some(IpAddr::V6(dst));
370        self
371    }
372
373    // ========== Options ==========
374
375    /// Set the options.
376    pub fn options(mut self, options: TcpOptions) -> Self {
377        self.options = options;
378        self
379    }
380
381    /// Add a single option.
382    pub fn option(mut self, option: TcpOption) -> Self {
383        self.options.push(option);
384        self
385    }
386
387    /// Add options using a builder function.
388    pub fn with_options<F>(mut self, f: F) -> Self
389    where
390        F: FnOnce(TcpOptionsBuilder) -> TcpOptionsBuilder,
391    {
392        self.options = f(TcpOptionsBuilder::new()).build();
393        self
394    }
395
396    /// Add an MSS (Maximum Segment Size) option.
397    pub fn mss(mut self, mss: u16) -> Self {
398        self.options.push(TcpOption::Mss(mss));
399        self
400    }
401
402    /// Add a Window Scale option.
403    pub fn wscale(mut self, scale: u8) -> Self {
404        self.options.push(TcpOption::WScale(scale));
405        self
406    }
407
408    /// Add SACK Permitted option.
409    pub fn sack_ok(mut self) -> Self {
410        self.options.push(TcpOption::SackOk);
411        self
412    }
413
414    /// Add a SACK option with blocks.
415    pub fn sack(mut self, blocks: Vec<TcpSackBlock>) -> Self {
416        self.options.push(TcpOption::Sack(blocks));
417        self
418    }
419
420    /// Add a Timestamp option.
421    pub fn timestamp(mut self, ts_val: u32, ts_ecr: u32) -> Self {
422        self.options.push(TcpOption::timestamp(ts_val, ts_ecr));
423        self
424    }
425
426    /// Add a NOP (padding) option.
427    pub fn nop(mut self) -> Self {
428        self.options.push(TcpOption::Nop);
429        self
430    }
431
432    /// Add an EOL (End of Options) option.
433    pub fn eol(mut self) -> Self {
434        self.options.push(TcpOption::Eol);
435        self
436    }
437
438    /// Add a TFO (TCP Fast Open) option.
439    pub fn tfo(mut self, cookie: Option<Vec<u8>>) -> Self {
440        self.options.push(TcpOption::Tfo { cookie });
441        self
442    }
443
444    /// Add an MD5 signature option.
445    pub fn md5(mut self, signature: [u8; 16]) -> Self {
446        self.options.push(TcpOption::Md5(signature));
447        self
448    }
449
450    /// Add an Authentication Option (TCP-AO).
451    pub fn ao(mut self, key_id: u8, rnext_key_id: u8, mac: Vec<u8>) -> Self {
452        self.options
453            .push(TcpOption::Ao(TcpAoValue::new(key_id, rnext_key_id, mac)));
454        self
455    }
456
457    // ========== Payload ==========
458
459    /// Set the payload data.
460    pub fn payload(mut self, payload: impl Into<Vec<u8>>) -> Self {
461        self.payload = payload.into();
462        self
463    }
464
465    /// Append data to the payload.
466    pub fn append_payload(mut self, data: &[u8]) -> Self {
467        self.payload.extend_from_slice(data);
468        self
469    }
470
471    // ========== Build Options ==========
472
473    /// Enable or disable automatic checksum calculation.
474    pub fn auto_checksum(mut self, enabled: bool) -> Self {
475        self.auto_checksum = enabled;
476        self
477    }
478
479    /// Enable or disable automatic data offset calculation.
480    pub fn auto_data_offset(mut self, enabled: bool) -> Self {
481        self.auto_data_offset = enabled;
482        self
483    }
484
485    // ========== Build Methods ==========
486
487    /// Calculate the header size (including options, with padding).
488    pub fn header_size(&self) -> usize {
489        if let Some(doff) = self.data_offset {
490            (doff as usize) * 4
491        } else {
492            let opts_len = self.options.padded_len();
493            TCP_MIN_HEADER_LEN + opts_len
494        }
495    }
496
497    /// Calculate the total packet size.
498    pub fn packet_size(&self) -> usize {
499        self.header_size() + self.payload.len()
500    }
501
502    /// Build the TCP packet.
503    pub fn build(&self) -> Vec<u8> {
504        let total_size = self.packet_size();
505        let mut buf = vec![0u8; total_size];
506        self.build_into(&mut buf)
507            .expect("buffer is correctly sized");
508        buf
509    }
510
511    /// Build the TCP packet into an existing buffer.
512    pub fn build_into(&self, buf: &mut [u8]) -> Result<usize, FieldError> {
513        let header_size = self.header_size();
514        let total_size = self.packet_size();
515
516        if buf.len() < total_size {
517            return Err(FieldError::BufferTooShort {
518                offset: 0,
519                need: total_size,
520                have: buf.len(),
521            });
522        }
523
524        // Calculate data offset
525        let data_offset = if self.auto_data_offset {
526            (header_size / 4) as u8
527        } else {
528            self.data_offset.unwrap_or(5)
529        };
530
531        // Source Port
532        buf[offsets::SRC_PORT] = (self.src_port >> 8) as u8;
533        buf[offsets::SRC_PORT + 1] = (self.src_port & 0xFF) as u8;
534
535        // Destination Port
536        buf[offsets::DST_PORT] = (self.dst_port >> 8) as u8;
537        buf[offsets::DST_PORT + 1] = (self.dst_port & 0xFF) as u8;
538
539        // Sequence Number
540        buf[offsets::SEQ..offsets::SEQ + 4].copy_from_slice(&self.seq.to_be_bytes());
541
542        // Acknowledgment Number
543        buf[offsets::ACK..offsets::ACK + 4].copy_from_slice(&self.ack.to_be_bytes());
544
545        // Data Offset + Reserved + NS flag
546        buf[offsets::DATA_OFFSET] =
547            ((data_offset & 0x0F) << 4) | ((self.reserved & 0x07) << 1) | self.flags.ns_bit();
548
549        // Flags (without NS)
550        buf[offsets::FLAGS] = self.flags.to_byte();
551
552        // Window
553        buf[offsets::WINDOW] = (self.window >> 8) as u8;
554        buf[offsets::WINDOW + 1] = (self.window & 0xFF) as u8;
555
556        // Checksum (initially 0)
557        buf[offsets::CHECKSUM] = 0;
558        buf[offsets::CHECKSUM + 1] = 0;
559
560        // Urgent Pointer
561        buf[offsets::URG_PTR] = (self.urgent_ptr >> 8) as u8;
562        buf[offsets::URG_PTR + 1] = (self.urgent_ptr & 0xFF) as u8;
563
564        // Options
565        if !self.options.is_empty() {
566            let opts_bytes = self.options.to_bytes();
567            let opts_end = offsets::OPTIONS + opts_bytes.len();
568            if opts_end <= header_size {
569                buf[offsets::OPTIONS..opts_end].copy_from_slice(&opts_bytes);
570            }
571        }
572
573        // Payload
574        if !self.payload.is_empty() {
575            buf[header_size..header_size + self.payload.len()].copy_from_slice(&self.payload);
576        }
577
578        // Checksum (computed last if we have IP addresses)
579        let checksum = if self.auto_checksum {
580            match (self.src_ip, self.dst_ip) {
581                (Some(IpAddr::V4(src)), Some(IpAddr::V4(dst))) => {
582                    tcp_checksum_ipv4(src, dst, &buf[..total_size])
583                }
584                (Some(IpAddr::V6(src)), Some(IpAddr::V6(dst))) => {
585                    tcp_checksum_ipv6(src, dst, &buf[..total_size])
586                }
587                _ => 0, // Can't compute checksum without IP addresses
588            }
589        } else {
590            self.checksum.unwrap_or(0)
591        };
592        buf[offsets::CHECKSUM] = (checksum >> 8) as u8;
593        buf[offsets::CHECKSUM + 1] = (checksum & 0xFF) as u8;
594
595        Ok(total_size)
596    }
597
598    /// Build only the header (no payload).
599    pub fn build_header(&self) -> Vec<u8> {
600        let header_size = self.header_size();
601        let mut buf = vec![0u8; header_size];
602
603        // Create a copy without payload
604        let builder = Self {
605            payload: Vec::new(),
606            ..self.clone()
607        };
608        builder
609            .build_into(&mut buf)
610            .expect("buffer is correctly sized");
611
612        buf
613    }
614}
615
616// ========== Convenience Constructors ==========
617
618impl TcpBuilder {
619    /// Create a SYN packet builder.
620    pub fn syn_packet() -> Self {
621        Self::new().syn().ack_num(0)
622    }
623
624    /// Create a SYN-ACK packet builder.
625    pub fn syn_ack_packet() -> Self {
626        Self::new().syn_ack()
627    }
628
629    /// Create an ACK packet builder.
630    pub fn ack_packet() -> Self {
631        Self::new().flags(TcpFlags::A)
632    }
633
634    /// Create a FIN-ACK packet builder.
635    pub fn fin_ack_packet() -> Self {
636        Self::new().fin_ack()
637    }
638
639    /// Create a RST packet builder.
640    pub fn rst_packet() -> Self {
641        Self::new().flags(TcpFlags::R)
642    }
643
644    /// Create a RST-ACK packet builder.
645    pub fn rst_ack_packet() -> Self {
646        Self::new().flags(TcpFlags::RA)
647    }
648
649    /// Create a PSH-ACK packet builder (for data).
650    pub fn data_packet() -> Self {
651        Self::new().psh_ack()
652    }
653}
654
655// ========== Random Values ==========
656
657#[cfg(feature = "rand")]
658impl TcpBuilder {
659    /// Set a random sequence number.
660    pub fn random_seq(mut self) -> Self {
661        use rand::Rng;
662        self.seq = rand::rng().random();
663        self
664    }
665
666    /// Set a random source port (dynamic range: 49152-65535).
667    pub fn random_sport(mut self) -> Self {
668        use rand::Rng;
669        self.src_port = rand::rng().random_range(49152..=65535);
670        self
671    }
672}
673
674#[cfg(test)]
675mod tests {
676    use super::*;
677
678    #[test]
679    fn test_basic_build() {
680        let pkt = TcpBuilder::new()
681            .src_port(12345)
682            .dst_port(80)
683            .seq(1000)
684            .syn()
685            .window(65535)
686            .build();
687
688        assert_eq!(pkt.len(), 20); // Minimum header, no options
689
690        let layer = TcpLayer::at_offset(0);
691        assert_eq!(layer.src_port(&pkt).unwrap(), 12345);
692        assert_eq!(layer.dst_port(&pkt).unwrap(), 80);
693        assert_eq!(layer.seq(&pkt).unwrap(), 1000);
694        assert_eq!(layer.window(&pkt).unwrap(), 65535);
695
696        let flags = layer.flags(&pkt).unwrap();
697        assert!(flags.syn);
698        assert!(!flags.ack);
699    }
700
701    #[test]
702    fn test_with_options() {
703        let pkt = TcpBuilder::new()
704            .src_port(12345)
705            .dst_port(80)
706            .syn()
707            .mss(1460)
708            .wscale(7)
709            .sack_ok()
710            .nop()
711            .build();
712
713        let layer = TcpLayer::at_offset(0);
714        let opts = layer.options(&pkt).unwrap();
715
716        assert_eq!(opts.mss(), Some(1460));
717        assert_eq!(opts.wscale(), Some(7));
718        assert!(opts.sack_permitted());
719    }
720
721    #[test]
722    fn test_with_payload() {
723        let payload = b"Hello, TCP!";
724        let pkt = TcpBuilder::new()
725            .src_port(12345)
726            .dst_port(80)
727            .psh_ack()
728            .payload(payload.to_vec())
729            .build();
730
731        assert_eq!(pkt.len(), 20 + payload.len());
732
733        let layer = TcpLayer::at_offset(0);
734        let pkt_payload = layer.payload(&pkt);
735        assert_eq!(pkt_payload, payload);
736    }
737
738    #[test]
739    fn test_with_checksum() {
740        let src_ip = Ipv4Addr::new(192, 168, 1, 1);
741        let dst_ip = Ipv4Addr::new(192, 168, 1, 2);
742
743        let pkt = TcpBuilder::new()
744            .src_port(12345)
745            .dst_port(80)
746            .syn()
747            .ipv4_addrs(src_ip, dst_ip)
748            .build();
749
750        let layer = TcpLayer::at_offset(0);
751        let checksum = layer.checksum(&pkt).unwrap();
752        assert_ne!(checksum, 0);
753    }
754
755    #[test]
756    fn test_flags() {
757        let pkt = TcpBuilder::new().syn_ack().build();
758
759        let layer = TcpLayer::at_offset(0);
760        let flags = layer.flags(&pkt).unwrap();
761        assert!(flags.syn);
762        assert!(flags.ack);
763
764        let pkt = TcpBuilder::new().fin_ack().build();
765        let flags = layer.flags(&pkt).unwrap();
766        assert!(flags.fin);
767        assert!(flags.ack);
768    }
769
770    #[test]
771    fn test_from_bytes() {
772        let original = TcpBuilder::new()
773            .src_port(12345)
774            .dst_port(443)
775            .seq(0xDEADBEEF)
776            .ack_num(0xCAFEBABE)
777            .syn_ack()
778            .window(32768)
779            .mss(1460)
780            .build();
781
782        let rebuilt = TcpBuilder::from_bytes(&original)
783            .unwrap()
784            .auto_checksum(false)
785            .build();
786
787        assert_eq!(original.len(), rebuilt.len());
788
789        let layer = TcpLayer::at_offset(0);
790        assert_eq!(
791            layer.src_port(&original).unwrap(),
792            layer.src_port(&rebuilt).unwrap()
793        );
794        assert_eq!(
795            layer.dst_port(&original).unwrap(),
796            layer.dst_port(&rebuilt).unwrap()
797        );
798        assert_eq!(layer.seq(&original).unwrap(), layer.seq(&rebuilt).unwrap());
799        assert_eq!(layer.ack(&original).unwrap(), layer.ack(&rebuilt).unwrap());
800    }
801
802    #[test]
803    fn test_convenience_constructors() {
804        let syn = TcpBuilder::syn_packet().build();
805        let layer = TcpLayer::at_offset(0);
806        let flags = layer.flags(&syn).unwrap();
807        assert!(flags.syn);
808        assert!(!flags.ack);
809
810        let syn_ack = TcpBuilder::syn_ack_packet().build();
811        let flags = layer.flags(&syn_ack).unwrap();
812        assert!(flags.syn);
813        assert!(flags.ack);
814
815        let rst = TcpBuilder::rst_packet().build();
816        let flags = layer.flags(&rst).unwrap();
817        assert!(flags.rst);
818    }
819
820    #[test]
821    fn test_timestamp_option() {
822        let pkt = TcpBuilder::new()
823            .syn()
824            .mss(1460)
825            .timestamp(12345, 0)
826            .build();
827
828        let layer = TcpLayer::at_offset(0);
829        let opts = layer.options(&pkt).unwrap();
830
831        let ts = opts.timestamp().unwrap();
832        assert_eq!(ts.ts_val, 12345);
833        assert_eq!(ts.ts_ecr, 0);
834    }
835
836    #[test]
837    fn test_tfo_option() {
838        let cookie = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
839        let pkt = TcpBuilder::new().syn().tfo(Some(cookie.clone())).build();
840
841        let layer = TcpLayer::at_offset(0);
842        let opts = layer.options(&pkt).unwrap();
843
844        assert_eq!(opts.tfo_cookie(), Some(cookie.as_slice()));
845    }
846
847    #[test]
848    fn test_flags_str() {
849        let pkt = TcpBuilder::new().flags_str("SA").build();
850
851        let layer = TcpLayer::at_offset(0);
852        let flags = layer.flags(&pkt).unwrap();
853        assert!(flags.syn);
854        assert!(flags.ack);
855
856        let pkt = TcpBuilder::new().flags_str("FA").build();
857        let flags = layer.flags(&pkt).unwrap();
858        assert!(flags.fin);
859        assert!(flags.ack);
860    }
861}