diff options
| author | chenzizhan <[email protected]> | 2023-09-08 16:18:25 +0800 |
|---|---|---|
| committer | chenzizhan <[email protected]> | 2023-09-08 16:18:25 +0800 |
| commit | 86383d3727299e2cfd1f17c25184e8b881237644 (patch) | |
| tree | 73caeadf00f3549b67e5c1cb52f7c2ae8870d4a2 | |
| parent | 0a97b72612cb04347822d323d7aa234db5f288bd (diff) | |
test 3 common tcp session cases
| -rw-r--r-- | src/session/tcp_reassembly.rs | 384 |
1 files changed, 344 insertions, 40 deletions
diff --git a/src/session/tcp_reassembly.rs b/src/session/tcp_reassembly.rs index fc6ee69..e613b8e 100644 --- a/src/session/tcp_reassembly.rs +++ b/src/session/tcp_reassembly.rs @@ -1,7 +1,8 @@ use std::collections::VecDeque; use std::fmt; -use std::net::{IpAddr, Ipv4Addr}; +use std::net::{Ipv4Addr}; use std::num::Wrapping; +use std::vec::IntoIter; use super::duration::Duration; use crate::protocol::ipv4::IPv4Header; use crate::protocol::ipv6::IPv6Header; @@ -17,25 +18,16 @@ const DEFAULT_TIMEOUT: Duration = Duration{secs:7200, micros:0}; // 120 min time // todo: const TCP_OPTION_TIMESTAMPS: u8 = 28; https://datatracker.ietf.org/doc/rfc5482/ #[derive(Debug, Eq, PartialEq)] -pub enum TcpStreamError { - Anomaly, - /// Connection is OK, but sides are inverted - Inverted, - /// Packet received but connection has expired - Expired, - HandshakeFailed, -} - pub enum TcpConnectionErr { PacketNotV4Tcp, - WrongFlags, // todo返回当前的会话状态,以及期望的flag - // todo: TCP header to flag:u16 + WrongFlags, // todo返回当前的会话状态,以及期望的flag, 为此: + // todo: TCP header to flag:u16 ExpiredSession, /// the seq number is wrong in the 2nd or 3rd handshake HandshakeFailed, } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Clone)] #[allow(dead_code)] pub enum TcpStatus { Closed = 0, @@ -66,6 +58,84 @@ enum TcpFlags { URG = 0x20, } +pub struct TcpIterator<'a> { + segments: IntoIter<&'a TcpSegment>, +} + +impl<'a> Iterator for TcpIterator<'a> { + type Item = RawPacket<'a>; + + fn next(&mut self) -> Option<Self::Item> { + while let Some(segment) = self.segments.next() { + let mut ret_encap = Vec::new(); + for encap in &segment.raw_packet.encapsulation { + match encap { + CopiedEncapsulation::L2_ETH(l2, seg) => { + ret_encap.push(Encapsulation::L2_ETH(l2.clone(), seg.as_slice())); + } + CopiedEncapsulation::L3_IP4(ipv4, seg) => { + ret_encap.push(Encapsulation::L3_IP4(ipv4.clone(), seg.as_slice())); + } + CopiedEncapsulation::L3_IP6(ipv6, seg) => { + ret_encap.push(Encapsulation::L3_IP6(ipv6.clone(), seg.as_slice())); + } + CopiedEncapsulation::L4_TCP(tcp, seg) => { + ret_encap.push(Encapsulation::L4_TCP(tcp.clone(), seg.as_slice())); + } + CopiedEncapsulation::L4_UDP(udp, seg) => { + ret_encap.push(Encapsulation::L4_UDP(udp.clone(), seg.as_slice())); + } + CopiedEncapsulation::L7_DNS(dns, seg) => { + ret_encap.push(Encapsulation::L7_DNS(dns.clone(), seg.as_slice())); + } + CopiedEncapsulation::L7_HTTP(http, seg) => { + ret_encap.push(Encapsulation::L7_HTTP(http.clone(), seg.as_slice())); + } + CopiedEncapsulation::Unsupported(seg) => { + ret_encap.push(Encapsulation::Unsupported(seg.as_slice())); + } + } + } + + return Some(RawPacket { + encapsulation: ret_encap, + orig_data: segment.raw_packet.orig_data.as_slice(), + orig_len: segment.raw_packet.orig_len, + }); + } + None + } +} + +impl<'a> IntoIterator for &'a TcpPeer { + type Item = RawPacket<'a>; + type IntoIter = TcpIterator<'a>; + + fn into_iter(self) -> Self::IntoIter { + TcpIterator { + segments: self.segments + .iter().collect::<Vec<_>>() + .into_iter(), + } + } +} + +impl TcpConnection { + fn into_iter_for_client(&self, is_sent_packet: bool) -> TcpIterator { + if !is_sent_packet { + (&self.stream.client).into_iter() + } else { + // todo: 记录发送的东西 + TcpIterator { + segments: Vec::new().into_iter(), + } + } + } + fn into_iter_for_server(&self) -> TcpIterator { + (&self.stream.server).into_iter() + } +} + // since the pub encapsulation has many reference of the original packet buffer, we have to copy them first #[allow(non_camel_case_types)] #[derive(Debug, Clone)] @@ -113,7 +183,7 @@ impl From<&RawPacket<'_>> for CopiedRawPacket { } } -#[derive(Debug)] +#[derive(Debug, Clone)] struct TcpPacket { payload : Vec<u8>, src_ip: Ipv4Addr, @@ -138,22 +208,21 @@ impl TcpPacket { TcpFlags::RST => self.tcp_header.flag_rst, TcpFlags::SYN => self.tcp_header.flag_syn, TcpFlags::FIN => self.tcp_header.flag_fin, - _ => false, } } fn payload(&self) -> &[u8] { self.payload.as_slice() } fn get_timestamp(&self) -> Duration { // todo: 感觉这个duration没什么用,改成u32 吧,单位是秒 - let mut timeVal:u32 = 0; + let mut time_val:u32 = 0; if let Some(options) = &self.tcp_header.options { for option in options { - if let TcpOption::TIMESTAMPS{length, ts_value, ts_reply} = option { - timeVal = *ts_value; + if let TcpOption::TIMESTAMPS{length:_, ts_value, ts_reply:_} = option { + time_val = *ts_value; } } } - Duration::new(timeVal, 0) + Duration::new(time_val, 0) } } @@ -259,6 +328,7 @@ impl TcpPeer { } } +#[derive(Debug)] struct TcpStream { pub client: TcpPeer, pub server: TcpPeer, @@ -268,9 +338,14 @@ struct TcpStream { pub last_seen_ts: Duration, } + + +#[derive(Debug)] pub struct TcpConnection { stream: TcpStream, + // todo: 接受发送的重排结果 + pub timeout: Duration, } @@ -289,10 +364,6 @@ impl TcpPeer { } } -fn tmp_take_ownership(t: TcpHeader) { - -} - impl TcpStream { pub fn new(packet: &TcpPacket) -> Self { TcpStream { @@ -311,7 +382,7 @@ impl TcpStream { let seq = Wrapping(tcp.get_sequence()); let ack = Wrapping(tcp.get_acknowledgement()); - let (mut src, mut dst) = if to_server { + let (src, dst) = if to_server { (&mut self.client, &mut self.server) } else { (&mut self.server, &mut self.client) @@ -499,7 +570,6 @@ impl TcpStream { }; queue_segment(origin, segment); - // if there is a ACK, check & send segments on the *other* side let ret = if has_ack { send_peer_segments(destination, rel_ack) @@ -521,7 +591,7 @@ impl TcpStream { tcp: TcpPacket, to_server: bool, ) -> Result<Option<Vec<TcpSegment>>, TcpConnectionErr> { - let (mut origin, destination) = if to_server { + let (origin, destination) = if to_server { (&mut self.client, &mut self.server) } else { (&mut self.server, &mut self.client) @@ -654,8 +724,7 @@ impl TcpStream { } // TcpStream fn queue_segment(peer: &mut TcpPeer, segment: TcpSegment) { - // only store segments with data, except FIN - if segment.payload.is_empty() && !segment.tcp_header.flag_fin { + if segment.payload.is_empty() { return; } // // println @@ -681,6 +750,7 @@ fn queue_segment(peer: &mut TcpPeer, segment: TcpSegment) { } fn send_peer_segments(peer: &mut TcpPeer, rel_ack: Wrapping<u32>) -> Option<Vec<TcpSegment>> { + // todo: window println!( "Trying to send segments for {}:{} up to {} (last ack: {})", peer.addr, @@ -834,28 +904,30 @@ fn adjust_seq_numbers(origin: &mut TcpPeer, segment: &TcpSegment) { impl TcpConnection { pub(crate) fn try_new(packet: &RawPacket) -> Result<Self, TcpConnectionErr> { let simple_packet = raw_packet_convert_to_my_packet(packet)?; + Self::_try_new(simple_packet) + } - let mut stream = TcpStream::new(&simple_packet); + pub(crate) fn update(&mut self, packet: &RawPacket) -> Result<Option<Vec<TcpSegment>>, TcpConnectionErr> { + let simple_packet = raw_packet_convert_to_my_packet(packet)?; + self._update(simple_packet) + } + + fn _try_new(packet: TcpPacket) -> Result<Self, TcpConnectionErr> { let mut connection = TcpConnection { - stream, + stream: TcpStream::new(&packet), timeout: DEFAULT_TIMEOUT, }; - if !simple_packet.has_flag(TcpFlags::SYN) { + if !packet.has_flag(TcpFlags::SYN) { return Err(TcpConnectionErr::WrongFlags); } - connection._update(simple_packet)?; + connection._update(packet)?; Ok(connection) } - pub(crate) fn update(&mut self, packet: &RawPacket) -> Result<Option<Vec<TcpSegment>>, TcpConnectionErr> { - let simple_packet = raw_packet_convert_to_my_packet(packet)?; - self._update(simple_packet) - } - fn _update(&mut self, tcp: TcpPacket) -> Result<Option<Vec<TcpSegment>>, TcpConnectionErr> { - let mut stream = &mut self.stream; + let stream = &mut self.stream; println!("stream state: {:?}", stream.status); // check time delay with previous packet before updating @@ -870,8 +942,8 @@ impl TcpConnection { stream.last_seen_ts = packet_ts; // get origin and destination - let to_server = tcp.src_ip == stream.server.addr && - tcp.tcp_header.source_port == stream.server.port; + let to_server = tcp.dst_ip == stream.server.addr && + tcp.tcp_header.dest_port == stream.server.port; println!("to_server: {}", to_server); let (origin, _destination) = if to_server { (&stream.client, &stream.server) @@ -924,3 +996,235 @@ impl fmt::Debug for TcpPeer { Ok(()) } } + + +#[cfg(test)] +mod tests { + use super::*; + + #[derive(Debug, Clone)] + enum PeerRole { + Client, + Server, + } + #[derive(Debug, Clone)] + struct PeerInTest { + addr: Ipv4Addr, + /// println: port + port: u16, + role: PeerRole, + } + + #[derive(Debug, Clone)] + struct SendPacket { + from: PeerInTest, + to: PeerInTest, + packet: TcpPacket, + } + + impl Default for CopiedRawPacket { + fn default() -> Self { + CopiedRawPacket { + encapsulation: Vec::new(), + + orig_data: Vec::new(), + orig_len: 0, + } + } + } + + impl SendPacket { + fn new(from: &PeerInTest, to: &PeerInTest, seq_num: u32, ack_num: u32, has_ack: bool, has_syn: bool, has_rst: bool, has_fin: bool, segment: &[u8]) -> Self { + let src_ip = from.addr; + let dst_ip = to.addr; + let header = TcpHeader { + source_port: from.port, + dest_port: to.port, + seq_num, + ack_num, + data_offset: 0, + reserved: 0, + flag_urg: false, + flag_ack: has_ack, + flag_psh: false, + flag_rst: has_rst, + flag_syn: has_syn, + flag_fin: has_fin, + window: 0, + checksum: 0, + urgent_ptr: 0, + options: None, + }; + SendPacket { + from: from.clone(), + to: to.clone(), + packet: TcpPacket { + src_ip, + dst_ip, + tcp_header: header, + payload: segment.to_vec(), + raw_packet: CopiedRawPacket::default(), + }, + } + } + } + + #[test] + fn a_very_normal_connection() { + let client = PeerInTest { + addr: Ipv4Addr::new(192, 168, 1, 1), + port: 1234, + role: PeerRole::Client, + }; + let server = PeerInTest { + addr: Ipv4Addr::new(192, 168, 1, 2), + port: 80, + role: PeerRole::Server, + }; + let packet_handshake1: SendPacket = SendPacket::new(&client, &server, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::_try_new(packet_handshake1.packet).unwrap(); + assert!(connection.stream.client.status == TcpStatus::SynSent); + assert!(connection.stream.server.status == TcpStatus::Listen); + + let packet_handshake2: SendPacket = SendPacket::new(&server, &client, 0, 1, true, true, false, false, &[]); + let segments = connection._update(packet_handshake2.packet).unwrap(); + assert!(connection.stream.client.status == TcpStatus::SynSent); + assert!(connection.stream.server.status == TcpStatus::SynRcv); + assert!(segments.is_none()); + + let packet_handshake3: SendPacket = SendPacket::new(&client, &server, 1, 1, true, false, false, false, &[]); + let segments = connection._update(packet_handshake3.packet).unwrap(); + assert!(connection.stream.client.status == TcpStatus::Established); + assert!(connection.stream.server.status == TcpStatus::Established); + assert!(segments.is_none()); + + let packet_established_from_client: SendPacket = SendPacket::new(&client, &server, 1, 1, true, false, false, false, &[1, 2, 3]); + let segments = connection._update(packet_established_from_client.packet).unwrap(); + assert!(segments.is_none()); + assert!(connection.stream.client.segments.len() == 1); + + let packet_established_server_responce: SendPacket = SendPacket::new(&server, &client, 1, 4, true, false, false, false, &[]); + let segments = connection._update(packet_established_server_responce.packet).unwrap(); + assert!(connection.stream.client.segments.len() == 0); + assert!(segments.as_ref().unwrap().len() == 1); + assert!(segments.as_ref().unwrap()[0].payload.as_slice() == &[1, 2, 3]); + + let packet_established_from_server: SendPacket = SendPacket::new(&server, &client, 1, 4, true, false, false, false, &[4]); + let segments = connection._update(packet_established_from_server.packet).unwrap(); + assert!(connection.stream.server.segments.len() == 1); + assert!(segments.is_none()); + + let packet_established_client_responce: SendPacket = SendPacket::new(&client, &server, 4, 2, true, false, false, false, &[]); + let segments = connection._update(packet_established_client_responce.packet).unwrap(); + assert!(connection.stream.server.segments.len() == 0); + assert!(segments.as_ref().unwrap().len() == 1); + assert!(segments.as_ref().unwrap()[0].payload.as_slice() == &[4]); + + assert!(connection.stream.client.status == TcpStatus::Established); + assert!(connection.stream.server.status == TcpStatus::Established); + let packet_close_by_client: SendPacket = SendPacket::new(&client, &server, 4, 2, true, false, false, true, &[]); + let segments = connection._update(packet_close_by_client.packet).unwrap(); + assert!(connection.stream.client.status == TcpStatus::FinWait1); + assert!(connection.stream.server.status == TcpStatus::CloseWait); + assert!(segments.is_none()); + + let packet_close_response_by_server: SendPacket = SendPacket::new(&server, &client, 2, 5, true, false, false, false, &[]); + let segments = connection._update(packet_close_response_by_server.packet).unwrap(); + assert!(connection.stream.client.status == TcpStatus::FinWait2); + assert!(connection.stream.server.status == TcpStatus::CloseWait); + assert!(segments.is_none()); + + let packet_close_by_server: SendPacket = SendPacket::new(&server, &client, 2, 5, true, false, false, true, &[]); + let segments = connection._update(packet_close_by_server.packet).unwrap(); + assert!(connection.stream.client.status == TcpStatus::TimeWait); + assert!(connection.stream.server.status == TcpStatus::LastAck); + assert!(segments.is_none()); + + let packet_close_response_by_client: SendPacket = SendPacket::new(&client, &server, 5, 3, true, false, false, false, &[]); + let segments = connection._update(packet_close_response_by_client.packet).unwrap(); + assert!(connection.stream.client.status == TcpStatus::Closed); + assert!(connection.stream.server.status == TcpStatus::Closed); + assert!(segments.is_none()); + + } + + #[test] + fn several_ordered_segments_in_one_ack() { + let client = PeerInTest { + addr: Ipv4Addr::new(192, 168, 1, 1), + port: 1234, + role: PeerRole::Client, + }; + let server = PeerInTest { + addr: Ipv4Addr::new(192, 168, 1, 2), + port: 80, + role: PeerRole::Server, + }; + + // standard handshake + let packet_handshake1: SendPacket = SendPacket::new(&client, &server, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::_try_new(packet_handshake1.packet).unwrap(); + let packet_handshake2: SendPacket = SendPacket::new(&server, &client, 0, 1, true, true, false, false, &[]); + connection._update(packet_handshake2.packet).unwrap(); + let packet_handshake3: SendPacket = SendPacket::new(&client, &server, 1, 1, true, false, false, false, &[]); + connection._update(packet_handshake3.packet).unwrap(); + + // send 3 segments from client + let packet_established_from_client1: SendPacket = SendPacket::new(&client, &server, 1, 1, true, false, false, false, &[1, 2, 3]); + let segments = connection._update(packet_established_from_client1.packet).unwrap(); + assert!(segments.is_none()); + let packet_established_from_client2 = SendPacket::new(&client, &server, 4, 1, true, false, false, false, &[4, 5, 6]); + let segments = connection._update(packet_established_from_client2.packet).unwrap(); + assert!(segments.is_none()); + let packet_established_from_client3 = SendPacket::new(&client, &server, 7, 1, true, false, false, false, &[7, 8, 9]); + let segments = connection._update(packet_established_from_client3.packet).unwrap(); + assert!(segments.is_none()); + + // server ack + let packet_established_server_responce: SendPacket = SendPacket::new(&server, &client, 1, 10, true, false, false, false, &[]); + let segments = connection._update(packet_established_server_responce.packet).unwrap(); + assert!(segments.as_ref().unwrap().len() == 3); + assert!(segments.as_ref().unwrap()[0].payload.as_slice() == &[1, 2, 3]); + assert!(segments.as_ref().unwrap()[1].payload.as_slice() == &[4, 5, 6]); + assert!(segments.as_ref().unwrap()[2].payload.as_slice() == &[7, 8, 9]); + } + + #[test] + fn several_unordered_segments_in_one_ack() { + let client = PeerInTest { + addr: Ipv4Addr::new(192, 168, 1, 1), + port: 1234, + role: PeerRole::Client, + }; + let server = PeerInTest { + addr: Ipv4Addr::new(192, 168, 1, 2), + port: 80, + role: PeerRole::Server, + }; + + // standard handshake + let packet_handshake1: SendPacket = SendPacket::new(&client, &server, 0, 0, false, true, false, false, &[]); + let mut connection = TcpConnection::_try_new(packet_handshake1.packet).unwrap(); + let packet_handshake2: SendPacket = SendPacket::new(&server, &client, 0, 1, true, true, false, false, &[]); + connection._update(packet_handshake2.packet).unwrap(); + let packet_handshake3: SendPacket = SendPacket::new(&client, &server, 1, 1, true, false, false, false, &[]); + connection._update(packet_handshake3.packet).unwrap(); + + // send 3 segments from client + let packet_established_from_client1: SendPacket = SendPacket::new(&client, &server, 1, 1, true, false, false, false, &[1, 2, 3]); + let packet_established_from_client2 = SendPacket::new(&client, &server, 4, 1, true, false, false, false, &[4, 5, 6]); + let packet_established_from_client3 = SendPacket::new(&client, &server, 7, 1, true, false, false, false, &[7, 8, 9]); + connection._update(packet_established_from_client3.packet).unwrap(); + connection._update(packet_established_from_client1.packet).unwrap(); + connection._update(packet_established_from_client2.packet).unwrap(); + + // server ack + let packet_established_server_responce: SendPacket = SendPacket::new(&server, &client, 1, 10, true, false, false, false, &[]); + let segments = connection._update(packet_established_server_responce.packet).unwrap(); + assert!(segments.as_ref().unwrap().len() == 3); + assert!(segments.as_ref().unwrap()[0].payload.as_slice() == &[1, 2, 3]); + assert!(segments.as_ref().unwrap()[1].payload.as_slice() == &[4, 5, 6]); + assert!(segments.as_ref().unwrap()[2].payload.as_slice() == &[7, 8, 9]); + } + +}
\ No newline at end of file |
