1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! Transmission Control Protocol related packet processing
use prelude::*;

/// The TCP parser
pub struct TcpParser;

impl Parsable<PathIp> for TcpParser {
    /// Parse a `TcpPacket` from an `&[u8]`
    fn parse<'a>(&mut self,
                 input: &'a [u8],
                 result: Option<&ParserResultVec>,
                 path: Option<&mut PathIp>)
                 -> IResult<&'a [u8], ParserResult> {
        do_parse!(input,
            // Check the IP protocol from the parent parser (IPv4 or IPv6)
            expr_opt!(match result {
                Some(vector) => match vector.last() {
                    // Check the parent node for the correct IP protocol
                    Some(ref any) => match (any.downcast_ref::<Ipv4Packet>(),
                                            any.downcast_ref::<Ipv6Packet>()) {

                        // IPv4
                        (Some(ipv4), _) => if ipv4.protocol == IpProtocol::Tcp {
                            Some(())
                        } else {
                            None
                        },

                        // IPv6
                        (_, Some(ipv6)) => if ipv6.next_header == IpProtocol::Tcp {
                            Some(())
                        } else {
                            None
                        },

                        _ => None,
                    },

                    // Previous result found, but not correct parent
                    _ => None,
                },
                // Parse also if no result is given, for testability
                None => Some(()),
            }) >>

            // Parse the header
            src: be_u16 >>
            dst: be_u16 >>
            seq: be_u32 >>
            ack: be_u32 >>
            data_offset_res_flags : bits!(tuple!(take_bits!(u8, 4),
                                                 take_bits!(u8, 6),
                                                 take_bits!(u8, 6))) >>
            window : be_u16 >>
            checksum : be_u16 >>
            urgent_ptr : be_u16 >>
            options_check: expr_opt!((data_offset_res_flags.0 * 4).checked_sub(20)) >>
            options: take!(options_check) >>

            // Try to track the connection
            path_error: expr_opt!(match track_connection(path, result, src, dst) {
                Err(e) => Some(Some(e.code)),
                Ok(()) => Some(None),
            }) >>

            (Box::new(TcpPacket {
                header: TcpHeader {
                    source_port: src,
                    dest_port: dst,
                    sequence_no: seq,
                    ack_no: ack,
                    data_offset: data_offset_res_flags.0 * 4,
                    reserved: data_offset_res_flags.1,
                    flag_urg: data_offset_res_flags.2 & 0b100000 == 0b100000,
                    flag_ack: data_offset_res_flags.2 & 0b010000 == 0b010000,
                    flag_psh: data_offset_res_flags.2 & 0b001000 == 0b001000,
                    flag_rst: data_offset_res_flags.2 & 0b000100 == 0b000100,
                    flag_syn: data_offset_res_flags.2 & 0b000010 == 0b000010,
                    flag_fin: data_offset_res_flags.2 & 0b000001 == 0b000001,
                    window: window,
                    checksum: checksum,
                    urgent_pointer: urgent_ptr,
                    options: options.to_vec()
                },
                path_error: path_error,
            }))
        )
    }
}

impl fmt::Display for TcpParser {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TCP")
    }
}

#[derive(Debug, Eq, PartialEq)]
/// Representation of an User Datagram Protocol packet
pub struct TcpPacket {
    /// The header of the TCP packet
    pub header: TcpHeader,

    /// Set to some error code if the connection tracking failed
    pub path_error: Option<PathErrorType>,
}

#[derive(Debug, Eq, PartialEq)]
/// Representation of a Transmission Control Protocol packet header
pub struct TcpHeader {
    /// Identifies the sending port
    pub source_port: u16,

    /// Identifies the receiving port
    pub dest_port: u16,

    /// If the SYN flag is set (1), then this is the initial sequence number. The sequence number
    /// of the actual first data byte and the acknowledged number in the corresponding ACK are then
    /// this sequence number plus 1.
    /// If the SYN flag is clear (0), then this is the accumulated sequence number of the first
    /// data byte of this segment for the current session.
    pub sequence_no: u32,

    /// If the ACK flag is set then the value of this field is the next sequence number that the
    /// sender is expecting. This acknowledges receipt of all prior bytes (if any). The first ACK
    /// sent by each end acknowledges the other end's initial sequence number itself, but no data.
    pub ack_no: u32,

    /// Specifies the size of the TCP header in 32-bit words. The minimum size header is 5 words
    /// and the maximum is 15 words thus giving the minimum size of 20 bytes and maximum of 60
    /// bytes, allowing for up to 40 bytes of options in the header. This field gets its name from
    /// the fact that it is also the offset from the start of the TCP segment to the actual data.
    pub data_offset: u8,

    /// Kor future use and should be set to zero
    pub reserved: u8,

    /// Indicates that the Urgent pointer field is significant
    pub flag_urg: bool,

    /// Indicates that the Acknowledgment field is significant. All packets after the initial SYN
    /// packet sent by the client should have this flag set.
    pub flag_ack: bool,

    /// Push function. Asks to push the buffered data to the receiving application.
    pub flag_psh: bool,

    /// Reset the connection
    pub flag_rst: bool,

    /// Synchronize sequence numbers. Only the first packet sent from each end should have this
    /// flag set. Some other flags and fields change meaning based on this flag, and some are only
    /// valid for when it is set, and others when it is clear.
    pub flag_syn: bool,

    /// No more data from sender
    pub flag_fin: bool,

    /// The size of the receive window, which specifies the number of window size units (by
    /// default, bytes) (beyond the segment identified by the sequence number in the acknowledgment
    /// field) that the sender of this segment is currently willing to receive (see Flow control
    /// and Window Scaling)
    pub window: u16,

    /// The 16-bit checksum field is used for error-checking of the header and data
    pub checksum: u16,

    /// If the URG flag is set, then this 16-bit field is an offset from the sequence number
    /// indicating the last urgent data byte
    pub urgent_pointer: u16,

    /// The length of this field is determined by the data offset field.
    pub options: Vec<u8>,
}