diff options
| author | chenzizhan <[email protected]> | 2023-09-11 16:21:29 +0800 |
|---|---|---|
| committer | chenzizhan <[email protected]> | 2023-09-11 16:21:29 +0800 |
| commit | 098361978603494f701a299a2afacba50fff536e (patch) | |
| tree | ede687a233141bbd4ea65f214a3b4a453ba0dae1 | |
| parent | d65fee6f87e7814381e58ae383b6389cbc5fc896 (diff) | |
max packet size
| -rw-r--r-- | src/session/tcp_reassembly.rs | 50 |
1 files changed, 32 insertions, 18 deletions
diff --git a/src/session/tcp_reassembly.rs b/src/session/tcp_reassembly.rs index 5dd6ee9..c18b766 100644 --- a/src/session/tcp_reassembly.rs +++ b/src/session/tcp_reassembly.rs @@ -18,6 +18,8 @@ use crate::packet::packet::Packet as RawPacket; const DEFAULT_TIMEOUT: Duration = Duration{secs:7200, micros:0}; // 120 min timeout, currently do not support option 28 parse // todo: const TCP_OPTION_TIMESTAMPS: u8 = 28; https://datatracker.ietf.org/doc/rfc5482/ +const DEFAULT_MAX_PACKETS: usize = 2048; + // todo: 装的packet太多怎么办 @@ -29,10 +31,9 @@ pub enum TcpSessionErr { ExpiredSession, /// the seq number is wrong in the 2nd or 3rd handshake. HandshakeFailed, - /// ack number is even higher than the next expected seq number - DiscardedSegment, // todo /// new a connection failed, because the packet is not a SYN packet, but the packet is valid NewConnectionFailed, + /// ack number is even higher than the next expected seq number UnexpectedAckNumber, /// The packet itself is valid, but the window size is not enough to hold the packet. Tcp state machine will change as usual, while the packet payload is discarded. SidePeerWindowFull, @@ -44,6 +45,9 @@ pub mod TcpSessionOk { // use as enum pub const CLOSING: u32 = 0x02; pub const CLOSED: u32 = 0x04; pub const ACK_SEGMENT: u32 = 0x08; + pub const PACKET_IN_PAST: u32 = 0x10; + pub const TOO_MANY_PACKET_WARNING: u32 = 0x20; + pub const TOO_MANY_PACKETS: u32 = 0x40; pub const OTHER: u32 = 0x0; } @@ -344,8 +348,10 @@ pub struct TcpConnection { packets_sent_by_client: Vec<Vec<CopiedRawPacket>>, packets_sent_by_server: Vec<Vec<CopiedRawPacket>>, + max_packets: usize, + max_warning_packets: usize, - pub timeout: Duration, // todo: 这个现在没有接口来设置和读取 + pub timeout: Duration, // todo: 当前使用默认值 } impl TcpPeer { @@ -724,7 +730,6 @@ fn queue_segment(peer: &mut TcpPeer, segment: TcpSegment) { } fn send_peer_segments(peer: &mut TcpPeer, rel_ack: Wrapping<u32>) -> Result<Option<Vec<TcpSegment>>, TcpSessionErr> { - // todo: window println!( "Trying to send segments for {}:{} up to {} (last ack: {})", peer.addr, @@ -761,11 +766,8 @@ fn send_peer_segments(peer: &mut TcpPeer, rel_ack: Wrapping<u32>) -> Result<Opti let mut segment = peer.segments.pop_front().unwrap(); if rel_ack < segment.rel_seq + Wrapping(segment.payload.len() as u32) { - // println!("ACK lower then seq + segment size - SACK?"); println!("ACK for part of buffer"); // split data and insert new dummy segment - println!("rel_ack {} segment.rel_seq {}", rel_ack, segment.rel_seq); - println!("segment data len {}", segment.payload.len()); let acked_len = (rel_ack - segment.rel_seq).0 as usize; let new_segment = segment.split_off(acked_len); println!( @@ -790,7 +792,8 @@ fn send_peer_segments(peer: &mut TcpPeer, rel_ack: Wrapping<u32>) -> Result<Opti "TCP ACKed unseen segment next_seq {} != ack {} (Missed segments?)", peer.next_rel_seq, rel_ack ); - // TODO notify upper layer for missing data + // TODO 这个正确吗?如果因为这个,把整个老segment 都删了肯定不对,具体怎么处理错误看需求吧 + // return Err(TcpSessionErr::UnexpectedAckNumber); } peer.last_rel_ack = rel_ack; @@ -892,6 +895,8 @@ impl TcpConnection { packets_sent_by_client: Vec::new(), packets_sent_by_server: Vec::new(), timeout: DEFAULT_TIMEOUT, + max_packets: DEFAULT_MAX_PACKETS, + max_warning_packets: DEFAULT_MAX_PACKETS >> 1, }; if !packet.has_flag(TcpFlags::SYN) { @@ -911,11 +916,13 @@ impl TcpConnection { let client_status_before = stream.client.status.clone(); let server_status_before = stream.server.status.clone(); + let mut ok_ret = TcpSessionOk::OTHER; // check time delay with previous packet before updating let packet_ts = tcp.get_timestamp(); if stream.last_seen_ts > packet_ts { println!("packet received in past"); + ok_ret |= TcpSessionOk::PACKET_IN_PAST; } else if packet_ts - stream.last_seen_ts > self.timeout { println!("TCP stream received packet after timeout"); stream.expire(); @@ -946,7 +953,6 @@ impl TcpConnection { TcpStatus::Established => { // check for close request if tcp.has_flag(TcpFlags::FIN) || tcp.has_flag(TcpFlags::RST) { - println!("Requesting end of connection"); stream.handle_closing_connection(tcp, to_server) } else { stream.handle_established_connection(tcp, to_server) @@ -955,14 +961,21 @@ impl TcpConnection { _ => stream.handle_closing_connection(tcp, to_server), }?; - let mut ok_ret = TcpSessionOk::OTHER; if let Some(sent_packet) = sent_packet { - if !to_server { // ack packet, so the previous packet if from the other side. Like a ack packet from server, so the sent packets are from client - self.packets_sent_by_client.push(sent_packet.into_iter().map(|s| s.raw_packet).collect()); + ok_ret = ok_ret | TcpSessionOk::ACK_SEGMENT; + let send_queue = if to_server { // ack packet, so the previous packet if from the other side. + &mut self.packets_sent_by_server } else { - self.packets_sent_by_server.push(sent_packet.into_iter().map(|s| s.raw_packet).collect()); + &mut self.packets_sent_by_client + }; + if send_queue.len() >= self.max_packets { + ok_ret |= TcpSessionOk::TOO_MANY_PACKETS; + } else { + if send_queue.len() >= self.max_warning_packets { + ok_ret |= TcpSessionOk::TOO_MANY_PACKET_WARNING; + } + send_queue.push(sent_packet.into_iter().map(|s| s.raw_packet).collect()); } - ok_ret = ok_ret | TcpSessionOk::ACK_SEGMENT; } if client_status_before != stream.client.status || server_status_before != stream.server.status { @@ -970,13 +983,10 @@ impl TcpConnection { client_status_before, stream.client.status, server_status_before, stream.server.status ); if stream.client.status == TcpStatus::Established { - println!("handshake completed"); ok_ret = ok_ret | TcpSessionOk::ESTABLISHED; } else if stream.client.status == TcpStatus::Closed || stream.server.status == TcpStatus::Closed { - println!("connection closed"); ok_ret |= TcpSessionOk::CLOSED; } else if client_status_before == TcpStatus::Established { - println!("connection closed"); ok_ret = TcpSessionOk::CLOSING; } } @@ -1322,7 +1332,11 @@ mod tests { } // #[test] - + // todo: expired session + + // todo: many error flag + // todo: window full + // todo: many packet in queue(warning and discard) }
\ No newline at end of file |
