1use crate::Error;
2use byteorder::{BigEndian as BE, WriteBytesExt};
3use log::*;
4use nom::{ErrorKind as NomErrorKind, *};
5use std::mem::size_of;
6use std::io::{Cursor, Write};
7
8const MINIMUM_HEADER_BYTES: usize = 20; const MAXIMUM_HEADER_BYTES: usize = 60; #[derive(Clone, Copy, Debug)]
12pub struct HeaderLengthAndFlags {
13 pub inner: u16,
14 pub header_length: usize,
15 pub flags: u16,
16}
17
18#[derive(Clone, Copy, Debug)]
19pub struct Tcp<'a> {
20 pub src_port: u16,
21 pub dst_port: u16,
22 pub sequence_number: u32,
23 pub acknowledgement_number: u32,
24 pub header_length_and_flags: HeaderLengthAndFlags,
25 pub window: u16,
26 pub check: u16,
27 pub urgent: u16,
28 pub options: &'a [u8],
29 pub payload: &'a [u8],
30}
31
32impl<'a> Tcp<'a> {
33 pub fn as_bytes(&self) -> Vec<u8> {
34 let inner = Vec::with_capacity(
35 size_of::<u16>() * 6
36 + size_of::<u32>() * 2
37 + self.options.len()
38 + self.payload.len()
39 );
40 let mut writer = Cursor::new(inner);
41 writer.write_u16::<BE>(self.src_port).unwrap();
42 writer.write_u16::<BE>(self.dst_port).unwrap();
43 writer.write_u32::<BE>(self.sequence_number).unwrap();
44 writer.write_u32::<BE>(self.acknowledgement_number).unwrap();
45 writer.write_u16::<BE>(self.header_length_and_flags.inner).unwrap();
46 writer.write_u16::<BE>(self.window).unwrap();
47 writer.write_u16::<BE>(self.check).unwrap();
48 writer.write_u16::<BE>(self.urgent).unwrap();
49 writer.write(self.options).unwrap();
50 writer.write(self.payload).unwrap();
51 writer.into_inner()
52 }
53
54 pub fn extract_length(value: u16) -> usize {
55 let words = value >> 12;
56 (words * 4) as usize
57 }
58
59 pub fn parse<'b>(input: &'b [u8]) -> Result<(&'b [u8], Tcp<'b>), Error> {
60 trace!("Available={}", input.len());
61
62 do_parse!(
63 input,
64 src_port: be_u16
65 >> dst_port: be_u16
66 >> sequence_number: be_u32
67 >> acknowledgement_number: be_u32
68 >> header_length_and_flags: map_res!(be_u16, |v| {
69 let hl = Tcp::extract_length(v);
70 trace!("Header Length={}", hl);
71 if hl >= MINIMUM_HEADER_BYTES && hl <= MAXIMUM_HEADER_BYTES {
72 let flags = v & 0x01FF; let h = HeaderLengthAndFlags {
74 inner: v,
75 header_length: hl,
76 flags: flags,
77 };
78 Ok(h)
79 } else {
80 Err(error_position!(input, NomErrorKind::CondReduce::<u32>))
81 }
82 })
83 >> window: be_u16
84 >> check: be_u16
85 >> urgent: be_u16
86 >> options: take!(header_length_and_flags.header_length - MINIMUM_HEADER_BYTES)
87 >> payload: rest
88 >> (Tcp {
89 src_port: src_port,
90 dst_port: dst_port,
91 sequence_number: sequence_number,
92 acknowledgement_number: acknowledgement_number,
93 header_length_and_flags: header_length_and_flags,
94 window: window,
95 check: check,
96 urgent: urgent,
97 options: options,
98 payload: payload.into()
99 })
100 ).map_err(Error::from)
101 }
102}
103
104#[cfg(test)]
105pub mod tests {
106 use hex_slice::AsHex;
107
108 use super::*;
109
110 pub const RAW_DATA: &'static [u8] = &[
111 0xC6u8, 0xB7u8, 0x00u8, 0x50u8, 0x00u8, 0x00u8, 0x00u8, 0x01u8, 0x00u8, 0x00u8, 0x00u8, 0x02u8, 0x50u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
122 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
123 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0xfcu8, 0xfdu8, 0xfeu8,
124 0xffu8, ];
126
127 #[test]
128 fn convert_length() {
129 assert_eq!(Tcp::extract_length(0x0000u16), 0); assert_eq!(Tcp::extract_length(0x3000u16), 12); }
132
133 #[test]
134 fn parse_tcp() {
135 let _ = env_logger::try_init();
136
137 let (rem, l4) = Tcp::parse(RAW_DATA).expect("Unable to parse");
138
139 assert!(rem.is_empty());
140
141 assert_eq!(l4.dst_port, 80);
142 assert_eq!(l4.src_port, 50871);
143 assert_eq!(
144 l4.payload,
145 [
146 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
147 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
148 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0xfcu8, 0xfdu8,
149 0xfeu8, 0xffu8
150 ],
151 "Payload Mismatch: {:x}",
152 l4.payload.as_hex()
153 );
154
155 assert_eq!(l4.as_bytes().as_slice(), RAW_DATA);
156 }
157}