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
use crate::Error;
use byteorder::{BigEndian as BE, WriteBytesExt};
use log::*;
use nom::{ErrorKind as NomErrorKind, *};
use std::mem::size_of;
use std::io::{Cursor, Write};

const MINIMUM_HEADER_BYTES: usize = 20; //5 32bit words
const MAXIMUM_HEADER_BYTES: usize = 60; //15 32bit words

#[derive(Clone, Copy, Debug)]
pub struct HeaderLengthAndFlags {
    pub inner: u16,
    pub header_length: usize,
    pub flags: u16,
}

#[derive(Clone, Copy, Debug)]
pub struct Tcp<'a> {
    pub src_port: u16,
    pub dst_port: u16,
    pub sequence_number: u32,
    pub acknowledgement_number: u32,
    pub header_length_and_flags: HeaderLengthAndFlags,
    pub window: u16,
    pub check: u16,
    pub urgent: u16,
    pub options: &'a [u8],
    pub payload: &'a [u8],
}

impl<'a> Tcp<'a> {
    pub fn as_bytes(&self) -> Vec<u8> {
        let inner = Vec::with_capacity(
            size_of::<u16>() * 6
            + size_of::<u32>() * 2
            + self.options.len()
            + self.payload.len()
        );
        let mut writer = Cursor::new(inner);
        writer.write_u16::<BE>(self.src_port).unwrap();
        writer.write_u16::<BE>(self.dst_port).unwrap();
        writer.write_u32::<BE>(self.sequence_number).unwrap();
        writer.write_u32::<BE>(self.acknowledgement_number).unwrap();
        writer.write_u16::<BE>(self.header_length_and_flags.inner).unwrap();
        writer.write_u16::<BE>(self.window).unwrap();
        writer.write_u16::<BE>(self.check).unwrap();
        writer.write_u16::<BE>(self.urgent).unwrap();
        writer.write(self.options).unwrap();
        writer.write(self.payload).unwrap();
        writer.into_inner()
    }

    pub fn extract_length(value: u16) -> usize {
        let words = value >> 12;
        (words * 4) as usize
    }

    pub fn parse<'b>(input: &'b [u8]) -> Result<(&'b [u8], Tcp<'b>), Error> {
        trace!("Available={}", input.len());

        do_parse!(
            input,
            src_port: be_u16
                >> dst_port: be_u16
                >> sequence_number: be_u32
                >> acknowledgement_number: be_u32
                >> header_length_and_flags: map_res!(be_u16, |v| {
                    let hl = Tcp::extract_length(v);
                    trace!("Header Length={}", hl);
                    if hl >= MINIMUM_HEADER_BYTES && hl <= MAXIMUM_HEADER_BYTES {
                        let flags = v & 0x01FF; //take lower 9 bits
                        let h = HeaderLengthAndFlags {
                            inner: v,
                            header_length: hl,
                            flags: flags,
                        };
                        Ok(h)
                    } else {
                        Err(error_position!(input, NomErrorKind::CondReduce::<u32>))
                    }
                })
                >> window: be_u16
                >> check: be_u16
                >> urgent: be_u16
                >> options: take!(header_length_and_flags.header_length - MINIMUM_HEADER_BYTES)
                >> payload: rest
                >> (Tcp {
                    src_port: src_port,
                    dst_port: dst_port,
                    sequence_number: sequence_number,
                    acknowledgement_number: acknowledgement_number,
                    header_length_and_flags: header_length_and_flags,
                    window: window,
                    check: check,
                    urgent: urgent,
                    options: options,
                    payload: payload.into()
                })
        ).map_err(Error::from)
    }
}

#[cfg(test)]
pub mod tests {
    use hex_slice::AsHex;

    use super::*;

    pub const RAW_DATA: &'static [u8] = &[
        0xC6u8, 0xB7u8, //src port, 50871
        0x00u8, 0x50u8, //dst port, 80
        0x00u8, 0x00u8, 0x00u8, 0x01u8, //sequence number, 1
        0x00u8, 0x00u8, 0x00u8, 0x02u8, //acknowledgement number, 2
        0x50u8, 0x00u8, //header and flags, 0
        0x00u8, 0x00u8, //window
        0x00u8, 0x00u8, //check
        0x00u8, 0x00u8, //urgent
        //no options
        //payload
        0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
        0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
        0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0xfcu8, 0xfdu8, 0xfeu8,
        0xffu8, //payload, 8 words
    ];

    #[test]
    fn convert_length() {
        assert_eq!(Tcp::extract_length(0x0000u16), 0); //0 words, 0 bytes
        assert_eq!(Tcp::extract_length(0x3000u16), 12); //3 words, 12 bytes
    }

    #[test]
    fn parse_tcp() {
        let _ = env_logger::try_init();

        let (rem, l4) = Tcp::parse(RAW_DATA).expect("Unable to parse");

        assert!(rem.is_empty());

        assert_eq!(l4.dst_port, 80);
        assert_eq!(l4.src_port, 50871);
        assert_eq!(
            l4.payload,
            [
                0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
                0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
                0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0xfcu8, 0xfdu8,
                0xfeu8, 0xffu8
            ],
            "Payload Mismatch: {:x}",
            l4.payload.as_hex()
        );

        assert_eq!(l4.as_bytes().as_slice(), RAW_DATA);
    }
}