packet_builder/
tcp.rs

1use pnet::packet::tcp::{MutableTcpPacket};
2use pnet::packet::tcp::ipv4_checksum as ipv4_tcp_checksum;
3use std::net::Ipv4Addr;
4use pnet::packet::tcp::{TcpOption, TcpOptionPacket};
5use L4Checksum;
6
7impl <'p>L4Checksum for MutableTcpPacket<'p> {
8  fn checksum_ipv4(&mut self, source: &Ipv4Addr, destination: &Ipv4Addr) -> () {
9    self.set_checksum(ipv4_tcp_checksum(&self.to_immutable(), source, destination));
10  }
11}
12
13/// Calculate the length (in double words) of an array of TcpOption structs 
14pub fn get_options_len(vals: &[TcpOption]) -> u8 {
15  let mut len = 0;
16  for opt in vals.iter() {
17    len += TcpOptionPacket::packet_size(&opt);
18  }
19
20  match len {
21    0 => 0,
22    _ => {
23      let mut ret = len  / 4;
24      ret += 1;
25      ret as u8
26    }
27  }
28}
29
30#[macro_export]
31macro_rules! extract_options_len {
32  (set_options, $value:expr) => {{
33    tcp::get_options_len($value)
34  }};
35  ($func:ident, $value:expr) => {{
36    println!("Unexpected case matched in extract_set_options: {} {}", stringify!($func), stringify!($value));
37    0
38  }};
39}
40
41
42#[macro_export]
43macro_rules! tcp {
44   ({$($func:ident => $value:expr), *}, $payload_pkt:expr, $protocol:expr, $buf:expr) => {{
45      const TCP_HEADER_LEN: usize = 20;
46      // We need to calculate the length of the options before we create the MutableTcpPacket
47      let mut opts_len = 0;
48      $(
49        match stringify!($func) {
50          "set_options" => {
51            opts_len = extract_options_len!($func, $value);
52          }
53          _ => (),
54        }
55      )*
56
57      let total_len = TCP_HEADER_LEN + $payload_pkt.packet().len() + (opts_len as usize * 4);
58      let buf_len = $buf.len();
59      let mut pkt = pnet::packet::tcp::MutableTcpPacket::new(&mut $buf[buf_len - total_len..]).unwrap();
60      pkt.set_data_offset(5 + opts_len);
61      pkt.set_flags(pnet::packet::tcp::TcpFlags::SYN);
62      pkt.set_sequence(0);
63      pkt.set_acknowledgement(0);
64      pkt.set_urgent_ptr(0);
65      pkt.set_window(65535);
66      $(
67        pkt.$func($value);
68      )*
69      (pkt, pnet::packet::ip::IpNextHeaderProtocols::Tcp)
70   }};
71}
72
73#[cfg(test)]
74mod tests {
75   use pnet::packet::Packet;
76   use ::payload;
77   use payload::PayloadData;
78   use tcp;
79   use pnet::packet::tcp::TcpOption;
80
81   #[test]
82   fn macro_tcp_basic() {
83      let mut buf = [0; 33];
84      let (pkt, proto) = tcp!({set_source => 53, set_destination => 5353, set_options => &vec!(TcpOption::mss(1200), TcpOption::wscale(2))},
85        payload!({"hello".to_string().into_bytes()}, buf).0, None, buf);
86      assert_eq!(proto, pnet::packet::ip::IpNextHeaderProtocols::Tcp);
87
88      let buf_expected = vec![0; 33];
89      let mut pkt_expected = pnet::packet::tcp::MutableTcpPacket::owned(buf_expected).unwrap();
90      pkt_expected.set_destination(5353); 
91      pkt_expected.set_source(53); 
92      pkt_expected.set_data_offset(7);
93      pkt_expected.set_payload(&"hello".to_string().into_bytes()); 
94      pkt_expected.set_options(&vec!(TcpOption::mss(1200), TcpOption::wscale(2))); 
95      pkt_expected.set_flags(pnet::packet::tcp::TcpFlags::SYN);
96      pkt_expected.set_sequence(0);
97      pkt_expected.set_acknowledgement(0);
98      pkt_expected.set_urgent_ptr(0);
99      pkt_expected.set_window(65535);
100      assert_eq!(pkt_expected.packet(), pkt.packet());
101   }
102}
103