stackforge_core/flow/
icmp_state.rs1use std::time::Duration;
2
3use crate::Packet;
4
5use super::config::FlowConfig;
6use super::state::ConversationStatus;
7
8#[derive(Debug, Clone)]
13pub struct IcmpFlowState {
14 pub icmp_type: u8,
16 pub icmp_code: u8,
18 pub identifier: Option<u16>,
20 pub request_count: u64,
22 pub reply_count: u64,
24 pub last_seq: Option<u16>,
26 pub status: ConversationStatus,
28}
29
30impl IcmpFlowState {
31 #[must_use]
32 pub fn new(icmp_type: u8, icmp_code: u8) -> Self {
33 Self {
34 icmp_type,
35 icmp_code,
36 identifier: None,
37 request_count: 0,
38 reply_count: 0,
39 last_seq: None,
40 status: ConversationStatus::Active,
41 }
42 }
43
44 pub fn process_packet(&mut self, packet: &Packet, buf: &[u8], icmp_type: u8, icmp_code: u8) {
49 self.icmp_type = icmp_type;
51 self.icmp_code = icmp_code;
52
53 if let Some(icmp_layer) = crate::layer::LayerKind::Icmp
55 .try_into()
56 .ok()
57 .and_then(|kind| packet.get_layer(kind))
58 {
59 let icmp_start = icmp_layer.start;
60
61 if buf.len() >= icmp_start + 6 {
63 self.identifier = Some(u16::from_be_bytes([
64 buf[icmp_start + 4],
65 buf[icmp_start + 5],
66 ]));
67 }
68
69 if buf.len() >= icmp_start + 8 {
71 self.last_seq = Some(u16::from_be_bytes([
72 buf[icmp_start + 6],
73 buf[icmp_start + 7],
74 ]));
75 }
76
77 match icmp_type {
79 8 => {
80 self.request_count += 1;
82 },
83 0 => {
84 self.reply_count += 1;
86 },
87 128 => {
88 self.request_count += 1;
90 },
91 129 => {
92 self.reply_count += 1;
94 },
95 _ => {
96 },
98 }
99 }
100
101 self.status = ConversationStatus::Active;
102 }
103
104 #[must_use]
106 pub fn check_timeout(&self, last_seen: Duration, now: Duration, config: &FlowConfig) -> bool {
107 now.saturating_sub(last_seen) > config.udp_timeout
109 }
110}
111
112impl Default for IcmpFlowState {
113 fn default() -> Self {
114 Self::new(0, 0)
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn test_icmp_state_new() {
124 let state = IcmpFlowState::new(8, 0);
125 assert_eq!(state.icmp_type, 8);
126 assert_eq!(state.icmp_code, 0);
127 assert_eq!(state.request_count, 0);
128 assert_eq!(state.reply_count, 0);
129 assert_eq!(state.identifier, None);
130 assert_eq!(state.last_seq, None);
131 }
132
133 #[test]
134 fn test_icmp_timeout() {
135 let config = FlowConfig::default(); let state = IcmpFlowState::new(8, 0);
137
138 assert!(!state.check_timeout(Duration::from_secs(100), Duration::from_secs(200), &config));
140
141 assert!(state.check_timeout(Duration::from_secs(100), Duration::from_secs(300), &config));
143 }
144}