Skip to main content

stackforge_core/layer/tcp/
flags.rs

1//! TCP flags implementation.
2//!
3//! TCP flags are a 9-bit field in the TCP header (including NS, CWR, ECE).
4//! This module provides a structured representation matching Scapy's FlagsField.
5
6use std::fmt;
7
8/// TCP flags structure (9 bits).
9///
10/// Bit layout (from MSB to LSB in the 16-bit flags/reserved field):
11/// - NS (Nonce Sum) - ECN nonce concealment
12/// - CWR (Congestion Window Reduced)
13/// - ECE (ECN-Echo)
14/// - URG (Urgent)
15/// - ACK (Acknowledgment)
16/// - PSH (Push)
17/// - RST (Reset)
18/// - SYN (Synchronize)
19/// - FIN (Finish)
20///
21/// Scapy uses the string "FSRPAUECN" for flags (reversed order).
22#[derive(Clone, Copy, PartialEq, Eq, Default, Hash)]
23pub struct TcpFlags {
24    /// FIN - No more data from sender
25    pub fin: bool,
26    /// SYN - Synchronize sequence numbers
27    pub syn: bool,
28    /// RST - Reset the connection
29    pub rst: bool,
30    /// PSH - Push function
31    pub psh: bool,
32    /// ACK - Acknowledgment field significant
33    pub ack: bool,
34    /// URG - Urgent pointer field significant
35    pub urg: bool,
36    /// ECE - ECN-Echo (RFC 3168)
37    pub ece: bool,
38    /// CWR - Congestion Window Reduced (RFC 3168)
39    pub cwr: bool,
40    /// NS - ECN-nonce concealment protection (RFC 3540)
41    pub ns: bool,
42}
43
44impl TcpFlags {
45    /// No flags set
46    pub const NONE: Self = Self {
47        fin: false,
48        syn: false,
49        rst: false,
50        psh: false,
51        ack: false,
52        urg: false,
53        ece: false,
54        cwr: false,
55        ns: false,
56    };
57
58    /// SYN flag only (connection initiation)
59    pub const S: Self = Self {
60        fin: false,
61        syn: true,
62        rst: false,
63        psh: false,
64        ack: false,
65        urg: false,
66        ece: false,
67        cwr: false,
68        ns: false,
69    };
70
71    /// SYN+ACK flags (connection acknowledgment)
72    pub const SA: Self = Self {
73        fin: false,
74        syn: true,
75        rst: false,
76        psh: false,
77        ack: true,
78        urg: false,
79        ece: false,
80        cwr: false,
81        ns: false,
82    };
83
84    /// ACK flag only
85    pub const A: Self = Self {
86        fin: false,
87        syn: false,
88        rst: false,
89        psh: false,
90        ack: true,
91        urg: false,
92        ece: false,
93        cwr: false,
94        ns: false,
95    };
96
97    /// FIN+ACK flags (connection termination)
98    pub const FA: Self = Self {
99        fin: true,
100        syn: false,
101        rst: false,
102        psh: false,
103        ack: true,
104        urg: false,
105        ece: false,
106        cwr: false,
107        ns: false,
108    };
109
110    /// RST flag only (connection reset)
111    pub const R: Self = Self {
112        fin: false,
113        syn: false,
114        rst: true,
115        psh: false,
116        ack: false,
117        urg: false,
118        ece: false,
119        cwr: false,
120        ns: false,
121    };
122
123    /// RST+ACK flags
124    pub const RA: Self = Self {
125        fin: false,
126        syn: false,
127        rst: true,
128        psh: false,
129        ack: true,
130        urg: false,
131        ece: false,
132        cwr: false,
133        ns: false,
134    };
135
136    /// PSH+ACK flags (data push)
137    pub const PA: Self = Self {
138        fin: false,
139        syn: false,
140        rst: false,
141        psh: true,
142        ack: true,
143        urg: false,
144        ece: false,
145        cwr: false,
146        ns: false,
147    };
148
149    /// Flag bit positions (in the 9-bit flags field)
150    pub const FIN_BIT: u16 = 0x001;
151    pub const SYN_BIT: u16 = 0x002;
152    pub const RST_BIT: u16 = 0x004;
153    pub const PSH_BIT: u16 = 0x008;
154    pub const ACK_BIT: u16 = 0x010;
155    pub const URG_BIT: u16 = 0x020;
156    pub const ECE_BIT: u16 = 0x040;
157    pub const CWR_BIT: u16 = 0x080;
158    pub const NS_BIT: u16 = 0x100;
159
160    /// Create flags from a raw 16-bit value (data offset + reserved + flags).
161    ///
162    /// The flags are in the lower 9 bits (with NS in bit 8 of the high byte).
163    #[inline]
164    pub fn from_u16(value: u16) -> Self {
165        Self {
166            fin: (value & Self::FIN_BIT) != 0,
167            syn: (value & Self::SYN_BIT) != 0,
168            rst: (value & Self::RST_BIT) != 0,
169            psh: (value & Self::PSH_BIT) != 0,
170            ack: (value & Self::ACK_BIT) != 0,
171            urg: (value & Self::URG_BIT) != 0,
172            ece: (value & Self::ECE_BIT) != 0,
173            cwr: (value & Self::CWR_BIT) != 0,
174            ns: (value & Self::NS_BIT) != 0,
175        }
176    }
177
178    /// Create flags from just the flags byte (lower 8 bits).
179    #[inline]
180    pub fn from_byte(byte: u8) -> Self {
181        Self::from_u16(byte as u16)
182    }
183
184    /// Create flags from two bytes (data_offset_reserved + flags).
185    #[inline]
186    pub fn from_bytes(hi: u8, lo: u8) -> Self {
187        let ns = (hi & 0x01) != 0;
188        let mut flags = Self::from_byte(lo);
189        flags.ns = ns;
190        flags
191    }
192
193    /// Convert to a raw 9-bit value.
194    #[inline]
195    pub fn to_u16(self) -> u16 {
196        let mut value = 0u16;
197        if self.fin {
198            value |= Self::FIN_BIT;
199        }
200        if self.syn {
201            value |= Self::SYN_BIT;
202        }
203        if self.rst {
204            value |= Self::RST_BIT;
205        }
206        if self.psh {
207            value |= Self::PSH_BIT;
208        }
209        if self.ack {
210            value |= Self::ACK_BIT;
211        }
212        if self.urg {
213            value |= Self::URG_BIT;
214        }
215        if self.ece {
216            value |= Self::ECE_BIT;
217        }
218        if self.cwr {
219            value |= Self::CWR_BIT;
220        }
221        if self.ns {
222            value |= Self::NS_BIT;
223        }
224        value
225    }
226
227    /// Convert to the lower flags byte (without NS).
228    #[inline]
229    pub fn to_byte(self) -> u8 {
230        (self.to_u16() & 0xFF) as u8
231    }
232
233    /// Get the NS bit for the high byte.
234    #[inline]
235    pub fn ns_bit(self) -> u8 {
236        if self.ns { 0x01 } else { 0x00 }
237    }
238
239    /// Create flags from a string like "S", "SA", "FA", "PA", "R", etc.
240    /// Uses Scapy's "FSRPAUECN" convention.
241    pub fn from_str(s: &str) -> Self {
242        let mut flags = Self::NONE;
243        for c in s.chars() {
244            match c {
245                'F' | 'f' => flags.fin = true,
246                'S' | 's' => flags.syn = true,
247                'R' | 'r' => flags.rst = true,
248                'P' | 'p' => flags.psh = true,
249                'A' | 'a' => flags.ack = true,
250                'U' | 'u' => flags.urg = true,
251                'E' | 'e' => flags.ece = true,
252                'C' | 'c' => flags.cwr = true,
253                'N' | 'n' => flags.ns = true,
254                _ => {}, // Ignore unknown characters
255            }
256        }
257        flags
258    }
259
260    /// Check if this is a SYN packet (SYN set, ACK not set).
261    #[inline]
262    pub fn is_syn(&self) -> bool {
263        self.syn && !self.ack
264    }
265
266    /// Check if this is a SYN-ACK packet.
267    #[inline]
268    pub fn is_syn_ack(&self) -> bool {
269        self.syn && self.ack
270    }
271
272    /// Check if this is a pure ACK packet.
273    #[inline]
274    pub fn is_ack(&self) -> bool {
275        self.ack && !self.syn && !self.fin && !self.rst
276    }
277
278    /// Check if this is a FIN packet.
279    #[inline]
280    pub fn is_fin(&self) -> bool {
281        self.fin
282    }
283
284    /// Check if this is a RST packet.
285    #[inline]
286    pub fn is_rst(&self) -> bool {
287        self.rst
288    }
289
290    /// Check if ECN is enabled (ECE or CWR set).
291    #[inline]
292    pub fn has_ecn(&self) -> bool {
293        self.ece || self.cwr
294    }
295
296    /// Check if any flag is set.
297    #[inline]
298    pub fn is_empty(&self) -> bool {
299        !self.fin
300            && !self.syn
301            && !self.rst
302            && !self.psh
303            && !self.ack
304            && !self.urg
305            && !self.ece
306            && !self.cwr
307            && !self.ns
308    }
309
310    /// Count how many flags are set.
311    #[inline]
312    pub fn count(&self) -> u8 {
313        let mut count = 0;
314        if self.fin {
315            count += 1;
316        }
317        if self.syn {
318            count += 1;
319        }
320        if self.rst {
321            count += 1;
322        }
323        if self.psh {
324            count += 1;
325        }
326        if self.ack {
327            count += 1;
328        }
329        if self.urg {
330            count += 1;
331        }
332        if self.ece {
333            count += 1;
334        }
335        if self.cwr {
336            count += 1;
337        }
338        if self.ns {
339            count += 1;
340        }
341        count
342    }
343}
344
345impl fmt::Display for TcpFlags {
346    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347        // Scapy order: FSRPAUECN
348        let mut s = String::with_capacity(9);
349        if self.fin {
350            s.push('F');
351        }
352        if self.syn {
353            s.push('S');
354        }
355        if self.rst {
356            s.push('R');
357        }
358        if self.psh {
359            s.push('P');
360        }
361        if self.ack {
362            s.push('A');
363        }
364        if self.urg {
365            s.push('U');
366        }
367        if self.ece {
368            s.push('E');
369        }
370        if self.cwr {
371            s.push('C');
372        }
373        if self.ns {
374            s.push('N');
375        }
376
377        if s.is_empty() {
378            write!(f, "-")
379        } else {
380            write!(f, "{}", s)
381        }
382    }
383}
384
385impl fmt::Debug for TcpFlags {
386    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387        write!(f, "TcpFlags({})", self)
388    }
389}
390
391impl From<u16> for TcpFlags {
392    fn from(value: u16) -> Self {
393        Self::from_u16(value)
394    }
395}
396
397impl From<u8> for TcpFlags {
398    fn from(value: u8) -> Self {
399        Self::from_byte(value)
400    }
401}
402
403impl From<TcpFlags> for u16 {
404    fn from(flags: TcpFlags) -> Self {
405        flags.to_u16()
406    }
407}
408
409impl From<TcpFlags> for u8 {
410    fn from(flags: TcpFlags) -> Self {
411        flags.to_byte()
412    }
413}
414
415impl From<&str> for TcpFlags {
416    fn from(s: &str) -> Self {
417        Self::from_str(s)
418    }
419}
420
421impl std::ops::BitOr for TcpFlags {
422    type Output = Self;
423
424    fn bitor(self, rhs: Self) -> Self::Output {
425        Self {
426            fin: self.fin || rhs.fin,
427            syn: self.syn || rhs.syn,
428            rst: self.rst || rhs.rst,
429            psh: self.psh || rhs.psh,
430            ack: self.ack || rhs.ack,
431            urg: self.urg || rhs.urg,
432            ece: self.ece || rhs.ece,
433            cwr: self.cwr || rhs.cwr,
434            ns: self.ns || rhs.ns,
435        }
436    }
437}
438
439impl std::ops::BitAnd for TcpFlags {
440    type Output = Self;
441
442    fn bitand(self, rhs: Self) -> Self::Output {
443        Self {
444            fin: self.fin && rhs.fin,
445            syn: self.syn && rhs.syn,
446            rst: self.rst && rhs.rst,
447            psh: self.psh && rhs.psh,
448            ack: self.ack && rhs.ack,
449            urg: self.urg && rhs.urg,
450            ece: self.ece && rhs.ece,
451            cwr: self.cwr && rhs.cwr,
452            ns: self.ns && rhs.ns,
453        }
454    }
455}
456
457impl std::ops::BitOrAssign for TcpFlags {
458    fn bitor_assign(&mut self, rhs: Self) {
459        *self = *self | rhs;
460    }
461}
462
463impl std::ops::BitAndAssign for TcpFlags {
464    fn bitand_assign(&mut self, rhs: Self) {
465        *self = *self & rhs;
466    }
467}
468
469#[cfg(test)]
470mod tests {
471    use super::*;
472
473    #[test]
474    fn test_from_u16() {
475        let flags = TcpFlags::from_u16(0x02); // SYN
476        assert!(flags.syn);
477        assert!(!flags.ack);
478        assert!(!flags.fin);
479
480        let flags = TcpFlags::from_u16(0x12); // SYN+ACK
481        assert!(flags.syn);
482        assert!(flags.ack);
483
484        let flags = TcpFlags::from_u16(0x10); // ACK
485        assert!(!flags.syn);
486        assert!(flags.ack);
487
488        let flags = TcpFlags::from_u16(0x11); // FIN+ACK
489        assert!(flags.fin);
490        assert!(flags.ack);
491
492        let flags = TcpFlags::from_u16(0x04); // RST
493        assert!(flags.rst);
494
495        let flags = TcpFlags::from_u16(0x100); // NS
496        assert!(flags.ns);
497    }
498
499    #[test]
500    fn test_to_u16() {
501        assert_eq!(TcpFlags::S.to_u16(), 0x02);
502        assert_eq!(TcpFlags::SA.to_u16(), 0x12);
503        assert_eq!(TcpFlags::A.to_u16(), 0x10);
504        assert_eq!(TcpFlags::FA.to_u16(), 0x11);
505        assert_eq!(TcpFlags::R.to_u16(), 0x04);
506    }
507
508    #[test]
509    fn test_from_str() {
510        let flags = TcpFlags::from_str("S");
511        assert!(flags.syn);
512        assert!(!flags.ack);
513
514        let flags = TcpFlags::from_str("SA");
515        assert!(flags.syn);
516        assert!(flags.ack);
517
518        let flags = TcpFlags::from_str("FSRPAUECN");
519        assert!(flags.fin);
520        assert!(flags.syn);
521        assert!(flags.rst);
522        assert!(flags.psh);
523        assert!(flags.ack);
524        assert!(flags.urg);
525        assert!(flags.ece);
526        assert!(flags.cwr);
527        assert!(flags.ns);
528    }
529
530    #[test]
531    fn test_display() {
532        assert_eq!(TcpFlags::S.to_string(), "S");
533        assert_eq!(TcpFlags::SA.to_string(), "SA");
534        assert_eq!(TcpFlags::FA.to_string(), "FA");
535        assert_eq!(TcpFlags::PA.to_string(), "PA");
536        assert_eq!(TcpFlags::NONE.to_string(), "-");
537    }
538
539    #[test]
540    fn test_is_methods() {
541        assert!(TcpFlags::S.is_syn());
542        assert!(!TcpFlags::SA.is_syn()); // SYN-ACK is not "just SYN"
543        assert!(TcpFlags::SA.is_syn_ack());
544        assert!(TcpFlags::A.is_ack());
545        assert!(TcpFlags::FA.is_fin());
546        assert!(TcpFlags::R.is_rst());
547    }
548
549    #[test]
550    fn test_bit_ops() {
551        let flags = TcpFlags::S | TcpFlags::A;
552        assert!(flags.syn);
553        assert!(flags.ack);
554
555        let flags = TcpFlags::SA & TcpFlags::S;
556        assert!(flags.syn);
557        assert!(!flags.ack);
558    }
559
560    #[test]
561    fn test_from_bytes() {
562        // Data offset (5) + reserved (000) + NS (0) + flags (0x12 = SYN+ACK)
563        // Byte 12: 0101_0000 = 0x50 (data offset 5, NS=0)
564        // Byte 13: 0001_0010 = 0x12 (SYN+ACK)
565        let flags = TcpFlags::from_bytes(0x50, 0x12);
566        assert!(flags.syn);
567        assert!(flags.ack);
568        assert!(!flags.ns);
569
570        // With NS bit set (bit 0 of byte 12)
571        let flags = TcpFlags::from_bytes(0x51, 0x12);
572        assert!(flags.syn);
573        assert!(flags.ack);
574        assert!(flags.ns);
575    }
576
577    #[test]
578    fn test_constants() {
579        assert_eq!(TcpFlags::NONE.to_u16(), 0);
580        assert_eq!(TcpFlags::S.to_u16(), 0x002);
581        assert_eq!(TcpFlags::SA.to_u16(), 0x012);
582        assert_eq!(TcpFlags::A.to_u16(), 0x010);
583        assert_eq!(TcpFlags::FA.to_u16(), 0x011);
584        assert_eq!(TcpFlags::R.to_u16(), 0x004);
585        assert_eq!(TcpFlags::RA.to_u16(), 0x014);
586        assert_eq!(TcpFlags::PA.to_u16(), 0x018);
587    }
588}