1#[cfg(test)]
2mod chunk_test;
3
4use std::fmt;
5use std::net::{IpAddr, SocketAddr};
6use std::ops::{BitAnd, BitOr};
7use std::str::FromStr;
8use std::sync::atomic::Ordering;
9use std::time::SystemTime;
10
11use portable_atomic::AtomicU64;
12
13use super::net::*;
14use crate::error::Result;
15
16lazy_static! {
17 static ref TAG_CTR: AtomicU64 = AtomicU64::new(0);
18}
19
20pub fn base36(value: impl Into<u64>) -> String {
22 let mut digits: Vec<u8> = vec![];
23
24 let mut value = value.into();
25 while value > 0 {
26 let digit = (value % 36) as usize;
27 value /= 36;
28
29 digits.push(b"0123456789abcdefghijklmnopqrstuvwxyz"[digit]);
30 }
31
32 digits.reverse();
33 format!("{:0>8}", String::from_utf8(digits).unwrap())
34}
35
36fn assign_chunk_tag() -> String {
39 let n = TAG_CTR.fetch_add(1, Ordering::SeqCst);
40 base36(n)
41}
42
43#[derive(Copy, Clone, PartialEq, Debug)]
44pub(crate) struct TcpFlag(pub(crate) u8);
45
46pub(crate) const TCP_FLAG_ZERO: TcpFlag = TcpFlag(0x00);
47pub(crate) const TCP_FLAG_FIN: TcpFlag = TcpFlag(0x01);
48pub(crate) const TCP_FLAG_SYN: TcpFlag = TcpFlag(0x02);
49pub(crate) const TCP_FLAG_RST: TcpFlag = TcpFlag(0x04);
50pub(crate) const TCP_FLAG_PSH: TcpFlag = TcpFlag(0x08);
51pub(crate) const TCP_FLAG_ACK: TcpFlag = TcpFlag(0x10);
52
53impl BitOr for TcpFlag {
54 type Output = Self;
55
56 fn bitor(self, rhs: Self) -> Self::Output {
58 Self(self.0 | rhs.0)
59 }
60}
61
62impl BitAnd for TcpFlag {
63 type Output = Self;
64
65 fn bitand(self, rhs: Self) -> Self::Output {
67 Self(self.0 & rhs.0)
68 }
69}
70
71impl fmt::Display for TcpFlag {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 let mut sa = vec![];
74 if *self & TCP_FLAG_FIN != TCP_FLAG_ZERO {
75 sa.push("FIN");
76 }
77 if *self & TCP_FLAG_SYN != TCP_FLAG_ZERO {
78 sa.push("SYN");
79 }
80 if *self & TCP_FLAG_RST != TCP_FLAG_ZERO {
81 sa.push("RST");
82 }
83 if *self & TCP_FLAG_PSH != TCP_FLAG_ZERO {
84 sa.push("PSH");
85 }
86 if *self & TCP_FLAG_ACK != TCP_FLAG_ZERO {
87 sa.push("ACK");
88 }
89
90 write!(f, "{}", sa.join("-"))
91 }
92}
93
94pub trait Chunk: fmt::Display + fmt::Debug {
96 fn set_timestamp(&mut self) -> SystemTime; fn get_timestamp(&self) -> SystemTime; fn get_source_ip(&self) -> IpAddr; fn get_destination_ip(&self) -> IpAddr; fn set_source_addr(&mut self, address: &str) -> Result<()>; fn set_destination_addr(&mut self, address: &str) -> Result<()>; fn source_addr(&self) -> SocketAddr;
104 fn destination_addr(&self) -> SocketAddr;
105 fn user_data(&self) -> Vec<u8>;
106 fn tag(&self) -> String;
107 fn network(&self) -> String; fn clone_to(&self) -> Box<dyn Chunk + Send + Sync>;
109}
110
111#[derive(PartialEq, Debug)]
112pub(crate) struct ChunkIp {
113 pub(crate) timestamp: SystemTime,
114 pub(crate) source_ip: IpAddr,
115 pub(crate) destination_ip: IpAddr,
116 pub(crate) tag: String,
117}
118
119impl ChunkIp {
120 fn set_timestamp(&mut self) -> SystemTime {
121 self.timestamp = SystemTime::now();
122 self.timestamp
123 }
124
125 fn get_timestamp(&self) -> SystemTime {
126 self.timestamp
127 }
128
129 fn get_destination_ip(&self) -> IpAddr {
130 self.destination_ip
131 }
132
133 fn get_source_ip(&self) -> IpAddr {
134 self.source_ip
135 }
136
137 fn tag(&self) -> String {
138 self.tag.clone()
139 }
140}
141
142#[derive(PartialEq, Debug)]
143pub(crate) struct ChunkUdp {
144 pub(crate) chunk_ip: ChunkIp,
145 pub(crate) source_port: u16,
146 pub(crate) destination_port: u16,
147 pub(crate) user_data: Vec<u8>,
148}
149
150impl fmt::Display for ChunkUdp {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 write!(
153 f,
154 "{} chunk {} {} => {}",
155 self.network(),
156 self.tag(),
157 self.source_addr(),
158 self.destination_addr(),
159 )
160 }
161}
162
163impl Chunk for ChunkUdp {
164 fn set_timestamp(&mut self) -> SystemTime {
165 self.chunk_ip.set_timestamp()
166 }
167
168 fn get_timestamp(&self) -> SystemTime {
169 self.chunk_ip.get_timestamp()
170 }
171
172 fn get_destination_ip(&self) -> IpAddr {
173 self.chunk_ip.get_destination_ip()
174 }
175
176 fn get_source_ip(&self) -> IpAddr {
177 self.chunk_ip.get_source_ip()
178 }
179
180 fn tag(&self) -> String {
181 self.chunk_ip.tag()
182 }
183
184 fn source_addr(&self) -> SocketAddr {
185 SocketAddr::new(self.chunk_ip.source_ip, self.source_port)
186 }
187
188 fn destination_addr(&self) -> SocketAddr {
189 SocketAddr::new(self.chunk_ip.destination_ip, self.destination_port)
190 }
191
192 fn user_data(&self) -> Vec<u8> {
193 self.user_data.clone()
194 }
195
196 fn clone_to(&self) -> Box<dyn Chunk + Send + Sync> {
197 Box::new(ChunkUdp {
198 chunk_ip: ChunkIp {
199 timestamp: self.chunk_ip.timestamp,
200 source_ip: self.chunk_ip.source_ip,
201 destination_ip: self.chunk_ip.destination_ip,
202 tag: self.chunk_ip.tag.clone(),
203 },
204 source_port: self.source_port,
205 destination_port: self.destination_port,
206 user_data: self.user_data.clone(),
207 })
208 }
209
210 fn network(&self) -> String {
211 UDP_STR.to_owned()
212 }
213
214 fn set_source_addr(&mut self, address: &str) -> Result<()> {
215 let addr = SocketAddr::from_str(address)?;
216 self.chunk_ip.source_ip = addr.ip();
217 self.source_port = addr.port();
218 Ok(())
219 }
220
221 fn set_destination_addr(&mut self, address: &str) -> Result<()> {
222 let addr = SocketAddr::from_str(address)?;
223 self.chunk_ip.destination_ip = addr.ip();
224 self.destination_port = addr.port();
225 Ok(())
226 }
227}
228
229impl ChunkUdp {
230 pub(crate) fn new(src_addr: SocketAddr, dst_addr: SocketAddr) -> Self {
231 ChunkUdp {
232 chunk_ip: ChunkIp {
233 timestamp: SystemTime::now(),
234 source_ip: src_addr.ip(),
235 destination_ip: dst_addr.ip(),
236 tag: assign_chunk_tag(),
237 },
238 source_port: src_addr.port(),
239 destination_port: dst_addr.port(),
240 user_data: vec![],
241 }
242 }
243}
244
245#[derive(PartialEq, Debug)]
246pub(crate) struct ChunkTcp {
247 chunk_ip: ChunkIp,
248 source_port: u16,
249 destination_port: u16,
250 flags: TcpFlag, user_data: Vec<u8>, }
255
256impl fmt::Display for ChunkTcp {
257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258 write!(
259 f,
260 "{} {} chunk {} {} => {}",
261 self.network(),
262 self.flags,
263 self.chunk_ip.tag,
264 self.source_addr(),
265 self.destination_addr(),
266 )
267 }
268}
269
270impl Chunk for ChunkTcp {
271 fn set_timestamp(&mut self) -> SystemTime {
272 self.chunk_ip.set_timestamp()
273 }
274
275 fn get_timestamp(&self) -> SystemTime {
276 self.chunk_ip.get_timestamp()
277 }
278
279 fn get_destination_ip(&self) -> IpAddr {
280 self.chunk_ip.get_destination_ip()
281 }
282
283 fn get_source_ip(&self) -> IpAddr {
284 self.chunk_ip.get_source_ip()
285 }
286
287 fn tag(&self) -> String {
288 self.chunk_ip.tag()
289 }
290
291 fn source_addr(&self) -> SocketAddr {
292 SocketAddr::new(self.chunk_ip.source_ip, self.source_port)
293 }
294
295 fn destination_addr(&self) -> SocketAddr {
296 SocketAddr::new(self.chunk_ip.destination_ip, self.destination_port)
297 }
298
299 fn user_data(&self) -> Vec<u8> {
300 self.user_data.clone()
301 }
302
303 fn clone_to(&self) -> Box<dyn Chunk + Send + Sync> {
304 Box::new(ChunkTcp {
305 chunk_ip: ChunkIp {
306 timestamp: self.chunk_ip.timestamp,
307 source_ip: self.chunk_ip.source_ip,
308 destination_ip: self.chunk_ip.destination_ip,
309 tag: self.chunk_ip.tag.clone(),
310 },
311 source_port: self.source_port,
312 destination_port: self.destination_port,
313 flags: self.flags,
314 user_data: self.user_data.clone(),
315 })
316 }
317
318 fn network(&self) -> String {
319 "tcp".to_owned()
320 }
321
322 fn set_source_addr(&mut self, address: &str) -> Result<()> {
323 let addr = SocketAddr::from_str(address)?;
324 self.chunk_ip.source_ip = addr.ip();
325 self.source_port = addr.port();
326 Ok(())
327 }
328
329 fn set_destination_addr(&mut self, address: &str) -> Result<()> {
330 let addr = SocketAddr::from_str(address)?;
331 self.chunk_ip.destination_ip = addr.ip();
332 self.destination_port = addr.port();
333 Ok(())
334 }
335}
336
337impl ChunkTcp {
338 pub(crate) fn new(src_addr: SocketAddr, dst_addr: SocketAddr, flags: TcpFlag) -> Self {
339 ChunkTcp {
340 chunk_ip: ChunkIp {
341 timestamp: SystemTime::now(),
342 source_ip: src_addr.ip(),
343 destination_ip: dst_addr.ip(),
344 tag: assign_chunk_tag(),
345 },
346 source_port: src_addr.port(),
347 destination_port: dst_addr.port(),
348 flags,
349 user_data: vec![],
350 }
351 }
352}