nex_packet/
tcp.rs

1//! A TCP packet abstraction.
2
3use crate::ip::IpNextLevelProtocol;
4use crate::Packet;
5use crate::PrimitiveValues;
6
7use alloc::{vec, vec::Vec};
8
9use nex_macro::packet;
10use nex_macro_helper::types::*;
11
12use crate::util::{self, Octets};
13use std::net::Ipv4Addr;
14use std::net::Ipv6Addr;
15
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19/// Minimum TCP Header Length
20pub const TCP_HEADER_LEN: usize = MutableTcpPacket::minimum_packet_size();
21/// Minimum TCP Data Offset
22pub const TCP_MIN_DATA_OFFSET: u8 = 5;
23/// Maximum TCP Option Length
24pub const TCP_OPTION_MAX_LEN: usize = 40;
25/// Maximum TCP Header Length (with options)
26pub const TCP_HEADER_MAX_LEN: usize = TCP_HEADER_LEN + TCP_OPTION_MAX_LEN;
27
28/// Represents the TCP option header.
29#[derive(Clone, Debug, PartialEq, Eq)]
30#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
31pub struct TcpOptionHeader {
32    pub kind: TcpOptionKind,
33    pub length: Option<u8>,
34    pub data: Vec<u8>,
35}
36
37impl TcpOptionHeader {
38    /// Get the timestamp of the TCP option
39    pub fn get_timestamp(&self) -> (u32, u32) {
40        if self.kind == TcpOptionKind::TIMESTAMPS && self.data.len() >= 8 {
41            let mut my: [u8; 4] = [0; 4];
42            my.copy_from_slice(&self.data[0..4]);
43            let mut their: [u8; 4] = [0; 4];
44            their.copy_from_slice(&self.data[4..8]);
45            (u32::from_be_bytes(my), u32::from_be_bytes(their))
46        } else {
47            return (0, 0);
48        }
49    }
50    /// Get the MSS of the TCP option
51    pub fn get_mss(&self) -> u16 {
52        if self.kind == TcpOptionKind::MSS && self.data.len() >= 2 {
53            let mut mss: [u8; 2] = [0; 2];
54            mss.copy_from_slice(&self.data[0..2]);
55            u16::from_be_bytes(mss)
56        } else {
57            0
58        }
59    }
60    /// Get the WSCALE of the TCP option
61    pub fn get_wscale(&self) -> u8 {
62        if self.kind == TcpOptionKind::WSCALE && self.data.len() > 0 {
63            self.data[0]
64        } else {
65            0
66        }
67    }
68}
69
70/// Represents the TCP header.
71#[derive(Clone, Debug, PartialEq, Eq)]
72#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
73pub struct TcpHeader {
74    pub source: u16be,
75    pub destination: u16be,
76    pub sequence: u32be,
77    pub acknowledgement: u32be,
78    pub data_offset: u4,
79    pub reserved: u4,
80    pub flags: u8,
81    pub window: u16be,
82    pub checksum: u16be,
83    pub urgent_ptr: u16be,
84    pub options: Vec<TcpOptionHeader>,
85}
86
87impl TcpHeader {
88    /// Construct a TCP header from a byte slice.
89    pub fn from_bytes(packet: &[u8]) -> Result<TcpHeader, String> {
90        if packet.len() < TCP_HEADER_LEN {
91            return Err("Packet is too small for TCP header".to_string());
92        }
93        match TcpPacket::new(packet) {
94            Some(tcp_packet) => Ok(TcpHeader {
95                source: tcp_packet.get_source(),
96                destination: tcp_packet.get_destination(),
97                sequence: tcp_packet.get_sequence(),
98                acknowledgement: tcp_packet.get_acknowledgement(),
99                data_offset: tcp_packet.get_data_offset(),
100                reserved: tcp_packet.get_reserved(),
101                flags: tcp_packet.get_flags(),
102                window: tcp_packet.get_window(),
103                checksum: tcp_packet.get_checksum(),
104                urgent_ptr: tcp_packet.get_urgent_ptr(),
105                options: tcp_packet
106                    .get_options_iter()
107                    .map(|opt| TcpOptionHeader {
108                        kind: opt.get_kind(),
109                        length: opt.get_length_raw().first().cloned(),
110                        data: opt.payload().to_vec(),
111                    })
112                    .collect(),
113            }),
114            None => Err("Failed to parse TCP packet".to_string()),
115        }
116    }
117    /// Construct a TCP header from a TcpPacket.
118    pub(crate) fn from_packet(tcp_packet: &TcpPacket) -> TcpHeader {
119        TcpHeader {
120            source: tcp_packet.get_source(),
121            destination: tcp_packet.get_destination(),
122            sequence: tcp_packet.get_sequence(),
123            acknowledgement: tcp_packet.get_acknowledgement(),
124            data_offset: tcp_packet.get_data_offset(),
125            reserved: tcp_packet.get_reserved(),
126            flags: tcp_packet.get_flags(),
127            window: tcp_packet.get_window(),
128            checksum: tcp_packet.get_checksum(),
129            urgent_ptr: tcp_packet.get_urgent_ptr(),
130            options: tcp_packet
131                .get_options_iter()
132                .map(|opt| TcpOptionHeader {
133                    kind: opt.get_kind(),
134                    length: opt.get_length_raw().first().cloned(),
135                    data: opt.payload().to_vec(),
136                })
137                .collect(),
138        }
139    }
140}
141
142/// Represents the TCP Flags
143/// <https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml#tcp-header-flags>
144#[allow(non_snake_case)]
145#[allow(non_upper_case_globals)]
146pub mod TcpFlags {
147    /// CWR – Congestion Window Reduced (CWR) flag is set by the sending
148    /// host to indicate that it received a TCP segment with the ECE flag set
149    /// and had responded in congestion control mechanism.
150    pub const CWR: u8 = 0b10000000;
151    /// ECE – ECN-Echo has a dual role, depending on the value of the
152    /// SYN flag. It indicates:
153    /// If the SYN flag is set (1), that the TCP peer is ECN capable.
154    /// If the SYN flag is clear (0), that a packet with Congestion Experienced
155    /// flag set (ECN=11) in IP header received during normal transmission.
156    pub const ECE: u8 = 0b01000000;
157    /// URG – indicates that the Urgent pointer field is significant.
158    pub const URG: u8 = 0b00100000;
159    /// ACK – indicates that the Acknowledgment field is significant.
160    /// All packets after the initial SYN packet sent by the client should have this flag set.
161    pub const ACK: u8 = 0b00010000;
162    /// PSH – Push function. Asks to push the buffered data to the receiving application.
163    pub const PSH: u8 = 0b00001000;
164    /// RST – Reset the connection.
165    pub const RST: u8 = 0b00000100;
166    /// SYN – Synchronize sequence numbers. Only the first packet sent from each end
167    /// should have this flag set.
168    pub const SYN: u8 = 0b00000010;
169    /// FIN – No more data from sender.
170    pub const FIN: u8 = 0b00000001;
171}
172
173/// Represents a TCP packet.
174#[packet]
175pub struct Tcp {
176    pub source: u16be,
177    pub destination: u16be,
178    pub sequence: u32be,
179    pub acknowledgement: u32be,
180    pub data_offset: u4,
181    pub reserved: u4,
182    pub flags: u8,
183    pub window: u16be,
184    pub checksum: u16be,
185    pub urgent_ptr: u16be,
186    #[length_fn = "tcp_options_length"]
187    pub options: Vec<TcpOption>,
188    #[payload]
189    pub payload: Vec<u8>,
190}
191
192/// Represents a TCP Option Kind.
193/// <https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml#tcp-parameters-1>
194#[allow(non_camel_case_types)]
195#[repr(u8)]
196#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
197#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
198pub enum TcpOptionKind {
199    EOL = 0,
200    NOP = 1,
201    MSS = 2,
202    WSCALE = 3,
203    SACK_PERMITTED = 4,
204    SACK = 5,
205    ECHO = 6,
206    ECHO_REPLY = 7,
207    TIMESTAMPS = 8,
208    POCP = 9,
209    POSP = 10,
210    CC = 11,
211    CC_NEW = 12,
212    CC_ECHO = 13,
213    ALT_CHECKSUM_REQ = 14,
214    ALT_CHECKSUM_DATA = 15,
215    SKEETER = 16,
216    BUBBA = 17,
217    TRAILER_CHECKSUM = 18,
218    MD5_SIGNATURE = 19,
219    SCPS_CAPABILITIES = 20,
220    SELECTIVE_ACK = 21,
221    RECORD_BOUNDARIES = 22,
222    CORRUPTION_EXPERIENCED = 23,
223    SNAP = 24,
224    UNASSIGNED = 25,
225    TCP_COMPRESSION_FILTER = 26,
226    QUICK_START = 27,
227    USER_TIMEOUT = 28,
228    TCP_AO = 29,
229    MPTCP = 30,
230    RESERVED_31 = 31,
231    RESERVED_32 = 32,
232    RESERVED_33 = 33,
233    FAST_OPEN_COOKIE = 34,
234    TCP_ENO = 69,
235    ACC_ECNO_0 = 172,
236    ACC_ECNO_1 = 174,
237    EXPERIMENT_1 = 253,
238    EXPERIMENT_2 = 254,
239    RESERVED(u8),
240}
241
242impl TcpOptionKind {
243    /// Construct a TCP option kind from a u8.
244    pub fn new(n: u8) -> TcpOptionKind {
245        match n {
246            0 => TcpOptionKind::EOL,
247            1 => TcpOptionKind::NOP,
248            2 => TcpOptionKind::MSS,
249            3 => TcpOptionKind::WSCALE,
250            4 => TcpOptionKind::SACK_PERMITTED,
251            5 => TcpOptionKind::SACK,
252            6 => TcpOptionKind::ECHO,
253            7 => TcpOptionKind::ECHO_REPLY,
254            8 => TcpOptionKind::TIMESTAMPS,
255            9 => TcpOptionKind::POCP,
256            10 => TcpOptionKind::POSP,
257            11 => TcpOptionKind::CC,
258            12 => TcpOptionKind::CC_NEW,
259            13 => TcpOptionKind::CC_ECHO,
260            14 => TcpOptionKind::ALT_CHECKSUM_REQ,
261            15 => TcpOptionKind::ALT_CHECKSUM_DATA,
262            16 => TcpOptionKind::SKEETER,
263            17 => TcpOptionKind::BUBBA,
264            18 => TcpOptionKind::TRAILER_CHECKSUM,
265            19 => TcpOptionKind::MD5_SIGNATURE,
266            20 => TcpOptionKind::SCPS_CAPABILITIES,
267            21 => TcpOptionKind::SELECTIVE_ACK,
268            22 => TcpOptionKind::RECORD_BOUNDARIES,
269            23 => TcpOptionKind::CORRUPTION_EXPERIENCED,
270            24 => TcpOptionKind::SNAP,
271            25 => TcpOptionKind::UNASSIGNED,
272            26 => TcpOptionKind::TCP_COMPRESSION_FILTER,
273            27 => TcpOptionKind::QUICK_START,
274            28 => TcpOptionKind::USER_TIMEOUT,
275            29 => TcpOptionKind::TCP_AO,
276            30 => TcpOptionKind::MPTCP,
277            31 => TcpOptionKind::RESERVED_31,
278            32 => TcpOptionKind::RESERVED_32,
279            33 => TcpOptionKind::RESERVED_33,
280            34 => TcpOptionKind::FAST_OPEN_COOKIE,
281            69 => TcpOptionKind::TCP_ENO,
282            172 => TcpOptionKind::ACC_ECNO_0,
283            174 => TcpOptionKind::ACC_ECNO_1,
284            253 => TcpOptionKind::EXPERIMENT_1,
285            254 => TcpOptionKind::EXPERIMENT_2,
286            _ => TcpOptionKind::RESERVED(n),
287        }
288    }
289    /// Get the name of the TCP option kind.
290    pub fn name(&self) -> String {
291        match *self {
292            TcpOptionKind::EOL => String::from("EOL"),
293            TcpOptionKind::NOP => String::from("NOP"),
294            TcpOptionKind::MSS => String::from("MSS"),
295            TcpOptionKind::WSCALE => String::from("WSCALE"),
296            TcpOptionKind::SACK_PERMITTED => String::from("SACK_PERMITTED"),
297            TcpOptionKind::SACK => String::from("SACK"),
298            TcpOptionKind::ECHO => String::from("ECHO"),
299            TcpOptionKind::ECHO_REPLY => String::from("ECHO_REPLY"),
300            TcpOptionKind::TIMESTAMPS => String::from("TIMESTAMPS"),
301            TcpOptionKind::POCP => String::from("POCP"),
302            TcpOptionKind::POSP => String::from("POSP"),
303            TcpOptionKind::CC => String::from("CC"),
304            TcpOptionKind::CC_NEW => String::from("CC_NEW"),
305            TcpOptionKind::CC_ECHO => String::from("CC_ECHO"),
306            TcpOptionKind::ALT_CHECKSUM_REQ => String::from("ALT_CHECKSUM_REQ"),
307            TcpOptionKind::ALT_CHECKSUM_DATA => String::from("ALT_CHECKSUM_DATA"),
308            TcpOptionKind::SKEETER => String::from("SKEETER"),
309            TcpOptionKind::BUBBA => String::from("BUBBA"),
310            TcpOptionKind::TRAILER_CHECKSUM => String::from("TRAILER_CHECKSUM"),
311            TcpOptionKind::MD5_SIGNATURE => String::from("MD5_SIGNATURE"),
312            TcpOptionKind::SCPS_CAPABILITIES => String::from("SCPS_CAPABILITIES"),
313            TcpOptionKind::SELECTIVE_ACK => String::from("SELECTIVE_ACK"),
314            TcpOptionKind::RECORD_BOUNDARIES => String::from("RECORD_BOUNDARIES"),
315            TcpOptionKind::CORRUPTION_EXPERIENCED => String::from("CORRUPTION_EXPERIENCED"),
316            TcpOptionKind::SNAP => String::from("SNAP"),
317            TcpOptionKind::UNASSIGNED => String::from("UNASSIGNED"),
318            TcpOptionKind::TCP_COMPRESSION_FILTER => String::from("TCP_COMPRESSION_FILTER"),
319            TcpOptionKind::QUICK_START => String::from("QUICK_START"),
320            TcpOptionKind::USER_TIMEOUT => String::from("USER_TIMEOUT"),
321            TcpOptionKind::TCP_AO => String::from("TCP_AO"),
322            TcpOptionKind::MPTCP => String::from("MPTCP"),
323            TcpOptionKind::RESERVED_31 => String::from("RESERVED_31"),
324            TcpOptionKind::RESERVED_32 => String::from("RESERVED_32"),
325            TcpOptionKind::RESERVED_33 => String::from("RESERVED_33"),
326            TcpOptionKind::FAST_OPEN_COOKIE => String::from("FAST_OPEN_COOKIE"),
327            TcpOptionKind::TCP_ENO => String::from("TCP_ENO"),
328            TcpOptionKind::ACC_ECNO_0 => String::from("ACC_ECNO_0"),
329            TcpOptionKind::ACC_ECNO_1 => String::from("ACC_ECNO_1"),
330            TcpOptionKind::EXPERIMENT_1 => String::from("EXPERIMENT_1"),
331            TcpOptionKind::EXPERIMENT_2 => String::from("EXPERIMENT_2"),
332            TcpOptionKind::RESERVED(n) => format!("RESERVED_{}", n),
333        }
334    }
335    /// Get size (bytes) of the TCP option.
336    pub fn size(&self) -> usize {
337        match *self {
338            TcpOptionKind::EOL => 1,
339            TcpOptionKind::NOP => 1,
340            TcpOptionKind::MSS => 4,
341            TcpOptionKind::WSCALE => 3,
342            TcpOptionKind::SACK_PERMITTED => 2,
343            TcpOptionKind::SACK => 10,
344            TcpOptionKind::ECHO => 6,
345            TcpOptionKind::ECHO_REPLY => 6,
346            TcpOptionKind::TIMESTAMPS => 10,
347            TcpOptionKind::POCP => 2,
348            TcpOptionKind::POSP => 3,
349            TcpOptionKind::ALT_CHECKSUM_REQ => 3,
350            TcpOptionKind::ALT_CHECKSUM_DATA => 12,
351            TcpOptionKind::TRAILER_CHECKSUM => 3,
352            TcpOptionKind::MD5_SIGNATURE => 18,
353            TcpOptionKind::QUICK_START => 8,
354            TcpOptionKind::USER_TIMEOUT => 4,
355            _ => 0,
356        }
357    }
358}
359
360impl PrimitiveValues for TcpOptionKind {
361    type T = (u8,);
362    fn to_primitive_values(&self) -> (u8,) {
363        match *self {
364            TcpOptionKind::EOL => (0,),
365            TcpOptionKind::NOP => (1,),
366            TcpOptionKind::MSS => (2,),
367            TcpOptionKind::WSCALE => (3,),
368            TcpOptionKind::SACK_PERMITTED => (4,),
369            TcpOptionKind::SACK => (5,),
370            TcpOptionKind::ECHO => (6,),
371            TcpOptionKind::ECHO_REPLY => (7,),
372            TcpOptionKind::TIMESTAMPS => (8,),
373            TcpOptionKind::POCP => (9,),
374            TcpOptionKind::POSP => (10,),
375            TcpOptionKind::CC => (11,),
376            TcpOptionKind::CC_NEW => (12,),
377            TcpOptionKind::CC_ECHO => (13,),
378            TcpOptionKind::ALT_CHECKSUM_REQ => (14,),
379            TcpOptionKind::ALT_CHECKSUM_DATA => (15,),
380            TcpOptionKind::SKEETER => (16,),
381            TcpOptionKind::BUBBA => (17,),
382            TcpOptionKind::TRAILER_CHECKSUM => (18,),
383            TcpOptionKind::MD5_SIGNATURE => (19,),
384            TcpOptionKind::SCPS_CAPABILITIES => (20,),
385            TcpOptionKind::SELECTIVE_ACK => (21,),
386            TcpOptionKind::RECORD_BOUNDARIES => (22,),
387            TcpOptionKind::CORRUPTION_EXPERIENCED => (23,),
388            TcpOptionKind::SNAP => (24,),
389            TcpOptionKind::UNASSIGNED => (25,),
390            TcpOptionKind::TCP_COMPRESSION_FILTER => (26,),
391            TcpOptionKind::QUICK_START => (27,),
392            TcpOptionKind::USER_TIMEOUT => (28,),
393            TcpOptionKind::TCP_AO => (29,),
394            TcpOptionKind::MPTCP => (30,),
395            TcpOptionKind::RESERVED_31 => (31,),
396            TcpOptionKind::RESERVED_32 => (32,),
397            TcpOptionKind::RESERVED_33 => (33,),
398            TcpOptionKind::FAST_OPEN_COOKIE => (34,),
399            TcpOptionKind::TCP_ENO => (35,),
400            TcpOptionKind::ACC_ECNO_0 => (36,),
401            TcpOptionKind::ACC_ECNO_1 => (37,),
402            TcpOptionKind::EXPERIMENT_1 => (253,),
403            TcpOptionKind::EXPERIMENT_2 => (254,),
404            TcpOptionKind::RESERVED(n) => (n,),
405        }
406    }
407}
408
409/// A TCP option.
410#[packet]
411pub struct TcpOption {
412    #[construct_with(u8)]
413    kind: TcpOptionKind,
414    #[length_fn = "tcp_option_length"]
415    // The length field is an optional field, using a Vec is a way to implement
416    // it
417    length: Vec<u8>,
418    #[length_fn = "tcp_option_payload_length"]
419    #[payload]
420    data: Vec<u8>,
421}
422
423impl TcpOption {
424    /// NOP: This may be used to align option fields on 32-bit boundaries for better performance.
425    pub fn nop() -> Self {
426        TcpOption {
427            kind: TcpOptionKind::NOP,
428            length: vec![],
429            data: vec![],
430        }
431    }
432
433    /// Timestamp: TCP timestamps, defined in RFC 1323, can help TCP determine in which order
434    /// packets were sent. TCP timestamps are not normally aligned to the system clock and
435    /// start at some random value.
436    pub fn timestamp(my: u32, their: u32) -> Self {
437        let mut data = vec![];
438        data.extend_from_slice(&my.octets()[..]);
439        data.extend_from_slice(&their.octets()[..]);
440
441        TcpOption {
442            kind: TcpOptionKind::TIMESTAMPS,
443            length: vec![10],
444            data: data,
445        }
446    }
447
448    /// MSS: The maximum segment size (MSS) is the largest amount of data, specified in bytes,
449    /// that TCP is willing to receive in a single segment.
450    pub fn mss(val: u16) -> Self {
451        let mut data = vec![];
452        data.extend_from_slice(&val.octets()[..]);
453
454        TcpOption {
455            kind: TcpOptionKind::MSS,
456            length: vec![4],
457            data: data,
458        }
459    }
460
461    /// Window scale: The TCP window scale option, as defined in RFC 1323, is an option used to
462    /// increase the maximum window size from 65,535 bytes to 1 gigabyte.
463    pub fn wscale(val: u8) -> Self {
464        TcpOption {
465            kind: TcpOptionKind::WSCALE,
466            length: vec![3],
467            data: vec![val],
468        }
469    }
470
471    /// Selective acknowledgment (SACK) option, defined in RFC 2018 allows the receiver to acknowledge
472    /// discontinuous blocks of packets which were received correctly. This options enables use of
473    /// SACK during negotiation.
474    pub fn sack_perm() -> Self {
475        TcpOption {
476            kind: TcpOptionKind::SACK_PERMITTED,
477            length: vec![2],
478            data: vec![],
479        }
480    }
481
482    /// Selective acknowledgment (SACK) option, defined in RFC 2018 allows the receiver to acknowledge
483    /// discontinuous blocks of packets which were received correctly. The acknowledgement can specify
484    /// a number of SACK blocks, where each SACK block is conveyed by the starting and ending sequence
485    /// numbers of a contiguous range that the receiver correctly received.
486    pub fn selective_ack(acks: &[u32]) -> Self {
487        let mut data = vec![];
488        for ack in acks {
489            data.extend_from_slice(&ack.octets()[..]);
490        }
491        TcpOption {
492            kind: TcpOptionKind::SACK,
493            length: vec![1 /* number */ + 1 /* length */ + data.len() as u8],
494            data: data,
495        }
496    }
497    /// Get the TCP option kind.
498    pub fn kind(&self) -> TcpOptionKind {
499        self.kind
500    }
501    /// Get length of the TCP option.
502    pub fn length(&self) -> u8 {
503        if self.length.is_empty() {
504            0
505        } else {
506            self.length[0]
507        }
508    }
509    /// Get the timestamp of the TCP option
510    pub fn get_timestamp(&self) -> (u32, u32) {
511        if self.kind == TcpOptionKind::TIMESTAMPS && self.data.len() >= 8 {
512            let mut my: [u8; 4] = [0; 4];
513            my.copy_from_slice(&self.data[0..4]);
514            let mut their: [u8; 4] = [0; 4];
515            their.copy_from_slice(&self.data[4..8]);
516            (u32::from_be_bytes(my), u32::from_be_bytes(their))
517        } else {
518            return (0, 0);
519        }
520    }
521    /// Get the MSS of the TCP option
522    pub fn get_mss(&self) -> u16 {
523        if self.kind == TcpOptionKind::MSS && self.data.len() >= 2 {
524            let mut mss: [u8; 2] = [0; 2];
525            mss.copy_from_slice(&self.data[0..2]);
526            u16::from_be_bytes(mss)
527        } else {
528            0
529        }
530    }
531    /// Get the WSCALE of the TCP option
532    pub fn get_wscale(&self) -> u8 {
533        if self.kind == TcpOptionKind::WSCALE && self.data.len() > 0 {
534            self.data[0]
535        } else {
536            0
537        }
538    }
539}
540
541/// This function gets the 'length' of the length field of the IPv4Option packet
542/// Few options (EOL, NOP) are 1 bytes long, and then have a length field equal
543/// to 0.
544#[inline]
545fn tcp_option_length(option: &TcpOptionPacket) -> usize {
546    match option.get_kind() {
547        TcpOptionKind::EOL => 0,
548        TcpOptionKind::NOP => 0,
549        _ => 1,
550    }
551}
552
553fn tcp_option_payload_length(ipv4_option: &TcpOptionPacket) -> usize {
554    match ipv4_option.get_length_raw().first() {
555        Some(len) if *len >= 2 => *len as usize - 2,
556        _ => 0,
557    }
558}
559
560#[inline]
561fn tcp_options_length(tcp: &TcpPacket) -> usize {
562    let data_offset = tcp.get_data_offset();
563
564    if data_offset > 5 {
565        data_offset as usize * 4 - 20
566    } else {
567        0
568    }
569}
570
571/// Calculate a checksum for a packet built on IPv4.
572pub fn ipv4_checksum(packet: &TcpPacket, source: &Ipv4Addr, destination: &Ipv4Addr) -> u16 {
573    ipv4_checksum_adv(packet, &[], source, destination)
574}
575
576/// Calculate the checksum for a packet built on IPv4, Advanced version which
577/// accepts an extra slice of data that will be included in the checksum
578/// as being part of the data portion of the packet.
579///
580/// If `packet` contains an odd number of bytes the last byte will not be
581/// counted as the first byte of a word together with the first byte of
582/// `extra_data`.
583pub fn ipv4_checksum_adv(
584    packet: &TcpPacket,
585    extra_data: &[u8],
586    source: &Ipv4Addr,
587    destination: &Ipv4Addr,
588) -> u16 {
589    util::ipv4_checksum(
590        packet.packet(),
591        8,
592        extra_data,
593        source,
594        destination,
595        IpNextLevelProtocol::Tcp,
596    )
597}
598
599/// Calculate a checksum for a packet built on IPv6.
600pub fn ipv6_checksum(packet: &TcpPacket, source: &Ipv6Addr, destination: &Ipv6Addr) -> u16 {
601    ipv6_checksum_adv(packet, &[], source, destination)
602}
603
604/// Calculate the checksum for a packet built on IPv6, Advanced version which
605/// accepts an extra slice of data that will be included in the checksum
606/// as being part of the data portion of the packet.
607///
608/// If `packet` contains an odd number of bytes the last byte will not be
609/// counted as the first byte of a word together with the first byte of
610/// `extra_data`.
611pub fn ipv6_checksum_adv(
612    packet: &TcpPacket,
613    extra_data: &[u8],
614    source: &Ipv6Addr,
615    destination: &Ipv6Addr,
616) -> u16 {
617    util::ipv6_checksum(
618        packet.packet(),
619        8,
620        extra_data,
621        source,
622        destination,
623        IpNextLevelProtocol::Tcp,
624    )
625}
626
627#[test]
628fn tcp_header_ipv4_test() {
629    use crate::ip::IpNextLevelProtocol;
630    use crate::ipv4::MutableIpv4Packet;
631
632    const IPV4_HEADER_LEN: usize = 20;
633    const TCP_HEADER_LEN: usize = 32;
634    const TEST_DATA_LEN: usize = 4;
635
636    let mut packet = [0u8; IPV4_HEADER_LEN + TCP_HEADER_LEN + TEST_DATA_LEN];
637    let ipv4_source = Ipv4Addr::new(192, 168, 2, 1);
638    let ipv4_destination = Ipv4Addr::new(192, 168, 111, 51);
639    {
640        let mut ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
641        ip_header.set_next_level_protocol(IpNextLevelProtocol::Tcp);
642        ip_header.set_source(ipv4_source);
643        ip_header.set_destination(ipv4_destination);
644    }
645
646    // Set data
647    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN] = 't' as u8;
648    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 1] = 'e' as u8;
649    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 2] = 's' as u8;
650    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 3] = 't' as u8;
651
652    {
653        let mut tcp_header = MutableTcpPacket::new(&mut packet[IPV4_HEADER_LEN..]).unwrap();
654        tcp_header.set_source(49511);
655        assert_eq!(tcp_header.get_source(), 49511);
656
657        tcp_header.set_destination(9000);
658        assert_eq!(tcp_header.get_destination(), 9000);
659
660        tcp_header.set_sequence(0x9037d2b8);
661        assert_eq!(tcp_header.get_sequence(), 0x9037d2b8);
662
663        tcp_header.set_acknowledgement(0x944bb276);
664        assert_eq!(tcp_header.get_acknowledgement(), 0x944bb276);
665
666        tcp_header.set_flags(TcpFlags::PSH | TcpFlags::ACK);
667        assert_eq!(tcp_header.get_flags(), TcpFlags::PSH | TcpFlags::ACK);
668
669        tcp_header.set_window(4015);
670        assert_eq!(tcp_header.get_window(), 4015);
671
672        tcp_header.set_data_offset(8);
673        assert_eq!(tcp_header.get_data_offset(), 8);
674
675        let ts = TcpOption::timestamp(743951781, 44056978);
676        tcp_header.set_options(&vec![TcpOption::nop(), TcpOption::nop(), ts]);
677
678        let checksum = ipv4_checksum(&tcp_header.to_immutable(), &ipv4_source, &ipv4_destination);
679        tcp_header.set_checksum(checksum);
680        assert_eq!(tcp_header.get_checksum(), 0xc031);
681    }
682    let ref_packet = [
683        0xc1, 0x67, /* source */
684        0x23, 0x28, /* destination */
685        0x90, 0x37, 0xd2, 0xb8, /* seq */
686        0x94, 0x4b, 0xb2, 0x76, /* ack */
687        0x80, 0x18, 0x0f, 0xaf, /* length, flags, win */
688        0xc0, 0x31, /* checksum */
689        0x00, 0x00, /* urg ptr */
690        0x01, 0x01, /* options: nop */
691        0x08, 0x0a, 0x2c, 0x57, 0xcd, 0xa5, 0x02, 0xa0, 0x41, 0x92, /* timestamp */
692        0x74, 0x65, 0x73, 0x74, /* "test" */
693    ];
694    assert_eq!(&ref_packet[..], &packet[20..]);
695}
696
697#[test]
698fn tcp_test_options_invalid_offset() {
699    let mut buf = [0; 20]; // no space for options
700    {
701        if let Some(mut tcp) = MutableTcpPacket::new(&mut buf[..]) {
702            tcp.set_data_offset(10); // set invalid offset
703        }
704    }
705
706    if let Some(tcp) = TcpPacket::new(&buf[..]) {
707        let _options = tcp.get_options_iter(); // shouldn't crash here
708    }
709}
710
711#[test]
712fn tcp_test_options_vec_invalid_offset() {
713    let mut buf = [0; 20]; // no space for options
714    {
715        if let Some(mut tcp) = MutableTcpPacket::new(&mut buf[..]) {
716            tcp.set_data_offset(10); // set invalid offset
717        }
718    }
719
720    if let Some(tcp) = TcpPacket::new(&buf[..]) {
721        let _options = tcp.get_options(); // shouldn't crash here
722    }
723}
724
725#[test]
726fn tcp_test_options_slice_invalid_offset() {
727    let mut buf = [0; 20]; // no space for options
728    {
729        if let Some(mut tcp) = MutableTcpPacket::new(&mut buf[..]) {
730            tcp.set_data_offset(10); // set invalid offset
731        }
732    }
733
734    if let Some(tcp) = TcpPacket::new(&buf[..]) {
735        let _options = tcp.get_options_raw(); // shouldn't crash here
736    }
737}
738
739#[test]
740fn tcp_test_option_invalid_len() {
741    use std::println;
742    let mut buf = [0; 24];
743    {
744        if let Some(mut tcp) = MutableTcpPacket::new(&mut buf[..]) {
745            tcp.set_data_offset(6);
746        }
747        buf[20] = 2; // option type
748        buf[21] = 8; // option len, not enough space for it
749    }
750
751    if let Some(tcp) = TcpPacket::new(&buf[..]) {
752        let options = tcp.get_options_iter();
753        for opt in options {
754            println!("{:?}", opt);
755        }
756    }
757}
758
759#[test]
760fn tcp_test_payload_slice_invalid_offset() {
761    let mut buf = [0; 20];
762    {
763        if let Some(mut tcp) = MutableTcpPacket::new(&mut buf[..]) {
764            tcp.set_data_offset(10); // set invalid offset
765        }
766    }
767
768    if let Some(tcp) = TcpPacket::new(&buf[..]) {
769        assert_eq!(tcp.payload().len(), 0);
770    }
771}