#[cfg(test)] mod chunk_test; use super::net::*; use crate::error::Result; use std::fmt; use std::net::{IpAddr, SocketAddr}; use std::ops::{BitAnd, BitOr}; use std::str::FromStr; use std::sync::atomic::{AtomicU64, Ordering}; use std::time::SystemTime; lazy_static! { static ref TAG_CTR: AtomicU64 = AtomicU64::new(0); } /// Encodes a u64 value to a lowercase base 36 string. pub fn base36(value: impl Into) -> String { let mut digits: Vec = vec![]; let mut value = value.into(); while value > 0 { let digit = (value % 36) as usize; value /= 36; digits.push(b"0123456789abcdefghijklmnopqrstuvwxyz"[digit]); } digits.reverse(); format!("{:0>8}", String::from_utf8(digits).unwrap()) } // Generate a base36-encoded unique tag // See: https://play.golang.org/p/0ZaAID1q-HN fn assign_chunk_tag() -> String { let n = TAG_CTR.fetch_add(1, Ordering::SeqCst); base36(n) } #[derive(Copy, Clone, PartialEq, Debug)] pub(crate) struct TcpFlag(pub(crate) u8); pub(crate) const TCP_FLAG_ZERO: TcpFlag = TcpFlag(0x00); pub(crate) const TCP_FLAG_FIN: TcpFlag = TcpFlag(0x01); pub(crate) const TCP_FLAG_SYN: TcpFlag = TcpFlag(0x02); pub(crate) const TCP_FLAG_RST: TcpFlag = TcpFlag(0x04); pub(crate) const TCP_FLAG_PSH: TcpFlag = TcpFlag(0x08); pub(crate) const TCP_FLAG_ACK: TcpFlag = TcpFlag(0x10); impl BitOr for TcpFlag { type Output = Self; // rhs is the "right-hand side" of the expression `a | b` fn bitor(self, rhs: Self) -> Self::Output { Self(self.0 | rhs.0) } } impl BitAnd for TcpFlag { type Output = Self; // rhs is the "right-hand side" of the expression `a & b` fn bitand(self, rhs: Self) -> Self::Output { Self(self.0 & rhs.0) } } impl fmt::Display for TcpFlag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut sa = vec![]; if *self & TCP_FLAG_FIN != TCP_FLAG_ZERO { sa.push("FIN"); } if *self & TCP_FLAG_SYN != TCP_FLAG_ZERO { sa.push("SYN"); } if *self & TCP_FLAG_RST != TCP_FLAG_ZERO { sa.push("RST"); } if *self & TCP_FLAG_PSH != TCP_FLAG_ZERO { sa.push("PSH"); } if *self & TCP_FLAG_ACK != TCP_FLAG_ZERO { sa.push("ACK"); } write!(f, "{}", sa.join("-")) } } // Chunk represents a packet passed around in the vnet pub trait Chunk: fmt::Display + fmt::Debug { fn set_timestamp(&mut self) -> SystemTime; // used by router fn get_timestamp(&self) -> SystemTime; // used by router fn get_source_ip(&self) -> IpAddr; // used by routee fn get_destination_ip(&self) -> IpAddr; // used by router fn set_source_addr(&mut self, address: &str) -> Result<()>; // used by nat fn set_destination_addr(&mut self, address: &str) -> Result<()>; // used by nat fn source_addr(&self) -> SocketAddr; fn destination_addr(&self) -> SocketAddr; fn user_data(&self) -> Vec; fn tag(&self) -> String; fn network(&self) -> String; // returns "udp" or "tcp" fn clone_to(&self) -> Box; } #[derive(PartialEq, Debug)] pub(crate) struct ChunkIp { pub(crate) timestamp: SystemTime, pub(crate) source_ip: IpAddr, pub(crate) destination_ip: IpAddr, pub(crate) tag: String, } impl ChunkIp { fn set_timestamp(&mut self) -> SystemTime { self.timestamp = SystemTime::now(); self.timestamp } fn get_timestamp(&self) -> SystemTime { self.timestamp } fn get_destination_ip(&self) -> IpAddr { self.destination_ip } fn get_source_ip(&self) -> IpAddr { self.source_ip } fn tag(&self) -> String { self.tag.clone() } } #[derive(PartialEq, Debug)] pub(crate) struct ChunkUdp { pub(crate) chunk_ip: ChunkIp, pub(crate) source_port: u16, pub(crate) destination_port: u16, pub(crate) user_data: Vec, } impl fmt::Display for ChunkUdp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{} chunk {} {} => {}", self.network(), self.tag(), self.source_addr(), self.destination_addr(), ) } } impl Chunk for ChunkUdp { fn set_timestamp(&mut self) -> SystemTime { self.chunk_ip.set_timestamp() } fn get_timestamp(&self) -> SystemTime { self.chunk_ip.get_timestamp() } fn get_destination_ip(&self) -> IpAddr { self.chunk_ip.get_destination_ip() } fn get_source_ip(&self) -> IpAddr { self.chunk_ip.get_source_ip() } fn tag(&self) -> String { self.chunk_ip.tag() } fn source_addr(&self) -> SocketAddr { SocketAddr::new(self.chunk_ip.source_ip, self.source_port) } fn destination_addr(&self) -> SocketAddr { SocketAddr::new(self.chunk_ip.destination_ip, self.destination_port) } fn user_data(&self) -> Vec { self.user_data.clone() } fn clone_to(&self) -> Box { Box::new(ChunkUdp { chunk_ip: ChunkIp { timestamp: self.chunk_ip.timestamp, source_ip: self.chunk_ip.source_ip, destination_ip: self.chunk_ip.destination_ip, tag: self.chunk_ip.tag.clone(), }, source_port: self.source_port, destination_port: self.destination_port, user_data: self.user_data.clone(), }) } fn network(&self) -> String { UDP_STR.to_owned() } fn set_source_addr(&mut self, address: &str) -> Result<()> { let addr = SocketAddr::from_str(address)?; self.chunk_ip.source_ip = addr.ip(); self.source_port = addr.port(); Ok(()) } fn set_destination_addr(&mut self, address: &str) -> Result<()> { let addr = SocketAddr::from_str(address)?; self.chunk_ip.destination_ip = addr.ip(); self.destination_port = addr.port(); Ok(()) } } impl ChunkUdp { pub(crate) fn new(src_addr: SocketAddr, dst_addr: SocketAddr) -> Self { ChunkUdp { chunk_ip: ChunkIp { timestamp: SystemTime::now(), source_ip: src_addr.ip(), destination_ip: dst_addr.ip(), tag: assign_chunk_tag(), }, source_port: src_addr.port(), destination_port: dst_addr.port(), user_data: vec![], } } } #[derive(PartialEq, Debug)] pub(crate) struct ChunkTcp { chunk_ip: ChunkIp, source_port: u16, destination_port: u16, flags: TcpFlag, // control bits user_data: Vec, // only with PSH flag // seq :u32, // always starts with 0 // ack :u32, // always starts with 0 } impl fmt::Display for ChunkTcp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{} {} chunk {} {} => {}", self.network(), self.flags, self.chunk_ip.tag, self.source_addr(), self.destination_addr(), ) } } impl Chunk for ChunkTcp { fn set_timestamp(&mut self) -> SystemTime { self.chunk_ip.set_timestamp() } fn get_timestamp(&self) -> SystemTime { self.chunk_ip.get_timestamp() } fn get_destination_ip(&self) -> IpAddr { self.chunk_ip.get_destination_ip() } fn get_source_ip(&self) -> IpAddr { self.chunk_ip.get_source_ip() } fn tag(&self) -> String { self.chunk_ip.tag() } fn source_addr(&self) -> SocketAddr { SocketAddr::new(self.chunk_ip.source_ip, self.source_port) } fn destination_addr(&self) -> SocketAddr { SocketAddr::new(self.chunk_ip.destination_ip, self.destination_port) } fn user_data(&self) -> Vec { self.user_data.clone() } fn clone_to(&self) -> Box { Box::new(ChunkTcp { chunk_ip: ChunkIp { timestamp: self.chunk_ip.timestamp, source_ip: self.chunk_ip.source_ip, destination_ip: self.chunk_ip.destination_ip, tag: self.chunk_ip.tag.clone(), }, source_port: self.source_port, destination_port: self.destination_port, flags: self.flags, user_data: self.user_data.clone(), }) } fn network(&self) -> String { "tcp".to_owned() } fn set_source_addr(&mut self, address: &str) -> Result<()> { let addr = SocketAddr::from_str(address)?; self.chunk_ip.source_ip = addr.ip(); self.source_port = addr.port(); Ok(()) } fn set_destination_addr(&mut self, address: &str) -> Result<()> { let addr = SocketAddr::from_str(address)?; self.chunk_ip.destination_ip = addr.ip(); self.destination_port = addr.port(); Ok(()) } } impl ChunkTcp { pub(crate) fn new(src_addr: SocketAddr, dst_addr: SocketAddr, flags: TcpFlag) -> Self { ChunkTcp { chunk_ip: ChunkIp { timestamp: SystemTime::now(), source_ip: src_addr.ip(), destination_ip: dst_addr.ip(), tag: assign_chunk_tag(), }, source_port: src_addr.port(), destination_port: dst_addr.port(), flags, user_data: vec![], } } }