From 670226a9565655c8dcbc927582012e48b2c56580 Mon Sep 17 00:00:00 2001 From: SajjadPourali Date: Fri, 19 Jan 2024 17:30:10 -0500 Subject: [PATCH 1/3] UnknownPackets --- examples/tun.rs | 3 +++ src/lib.rs | 35 +++++++++++++++++----------- src/packet.rs | 51 +++++++++++++++++++++++++++------------- src/stream/mod.rs | 20 +++++++++++++++- src/stream/tcp.rs | 4 ++-- src/stream/udp.rs | 11 +++++---- src/stream/unknown.rs | 54 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 141 insertions(+), 37 deletions(-) create mode 100644 src/stream/unknown.rs diff --git a/examples/tun.rs b/examples/tun.rs index bfafc9e..be5b6a0 100644 --- a/examples/tun.rs +++ b/examples/tun.rs @@ -109,6 +109,9 @@ async fn main() -> Result<(), Box> { println!("==== end UDP connection ===="); }); } + _ => { + continue; + } }; } } diff --git a/src/lib.rs b/src/lib.rs index d48e103..b001faf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ use tracing::{error, trace}; use crate::{ packet::IpStackPacketProtocol, - stream::{IpStackTcpStream, IpStackUdpStream}, + stream::{IpStackTcpStream, IpStackUdpStream, IpStackUnknownTransport}, }; mod error; mod packet; @@ -99,26 +99,32 @@ impl IpStack { select! { Ok(n) = device.read(&mut buffer) => { let offset = if config.packet_information && cfg!(unix) {4} else {0}; - // dbg!(&buffer[offset..n]); let Ok(packet) = NetworkPacket::parse(&buffer[offset..n]) else { - #[cfg(feature = "log")] - trace!("parse error"); + accept_sender.send(IpStackStream::UnknownNetwork(buffer[offset..n].to_vec()))?; continue; }; + if let IpStackPacketProtocol::Unknown = packet.transport_protocol() { + accept_sender.send(IpStackStream::UnknownTransport(IpStackUnknownTransport::new(packet.src_addr().ip(),packet.dst_addr().ip(),packet.payload,packet.ip,pkt_sender.clone())))?; + continue; + } + match streams.entry(packet.network_tuple()){ Occupied(entry) =>{ - let t = packet.transport_protocol(); + // let t = packet.transport_protocol(); if let Err(_x) = entry.get().send(packet){ #[cfg(feature = "log")] trace!("{}", _x); - match t{ - IpStackPacketProtocol::Tcp(_t) => { - // dbg!(t.flags()); - } - IpStackPacketProtocol::Udp => { - // dbg!("udp"); - } - } + // match t{ + // IpStackPacketProtocol::Tcp(_t) => { + // // dbg!(t.flags()); + // } + // IpStackPacketProtocol::Udp => { + // // dbg!("udp"); + // } + // IpStackPacketProtocol::Unknown => { + // // dbg!("unknown"); + // } + // } } } @@ -141,6 +147,9 @@ impl IpStack { entry.insert(stream.stream_sender()); accept_sender.send(IpStackStream::Udp(stream))?; } + IpStackPacketProtocol::Unknown => { + unreachable!() + } } } } diff --git a/src/packet.rs b/src/packet.rs index f4e3fe7..c54cd29 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,6 +1,6 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; -use etherparse::{IpHeader, PacketHeaders, TcpHeader, TransportHeader}; +use etherparse::{IpHeader, PacketHeaders, TcpHeader, UdpHeader, WriteError}; use crate::error::IpStackError; @@ -23,24 +23,33 @@ pub mod tcp_flags { pub(crate) enum IpStackPacketProtocol { Tcp(TcpPacket), + Unknown, Udp, } + +pub(crate) enum TransportHeader { + Tcp(TcpHeader), + Udp(UdpHeader), + Unknown, +} + pub struct NetworkPacket { - pub ip: IpHeader, - pub transport: TransportHeader, - pub payload: Vec, + pub(crate) ip: IpHeader, + pub(crate) transport: TransportHeader, + pub(crate) payload: Vec, } impl NetworkPacket { pub fn parse(buf: &[u8]) -> Result { let p = PacketHeaders::from_ip_slice(buf).map_err(|_| IpStackError::InvalidPacket)?; let ip = p.ip.ok_or(IpStackError::InvalidPacket)?; - let transport = p - .transport - .filter(|t| { - (matches!(t, TransportHeader::Tcp(_)) || matches!(t, TransportHeader::Udp(_))) - }) - .ok_or(IpStackError::UnsupportedTransportProtocol)?; + // p.payload; + let transport = match p.transport { + Some(etherparse::TransportHeader::Tcp(h)) => TransportHeader::Tcp(h), + Some(etherparse::TransportHeader::Udp(u)) => TransportHeader::Udp(u), + _ => TransportHeader::Unknown, + }; + let payload = p.payload.to_vec(); Ok(NetworkPacket { ip, @@ -52,14 +61,14 @@ impl NetworkPacket { match self.transport { TransportHeader::Udp(_) => IpStackPacketProtocol::Udp, TransportHeader::Tcp(ref h) => IpStackPacketProtocol::Tcp(h.into()), - _ => unreachable!(), + _ => IpStackPacketProtocol::Unknown, } } pub fn src_addr(&self) -> SocketAddr { let port = match &self.transport { TransportHeader::Udp(udp) => udp.source_port, TransportHeader::Tcp(tcp) => tcp.source_port, - _ => unreachable!(), + _ => 0, }; match &self.ip { IpHeader::Version4(ip, _) => { @@ -74,7 +83,7 @@ impl NetworkPacket { let port = match &self.transport { TransportHeader::Udp(udp) => udp.destination_port, TransportHeader::Tcp(tcp) => tcp.destination_port, - _ => unreachable!(), + _ => 0, }; match &self.ip { IpHeader::Version4(ip, _) => { @@ -104,9 +113,19 @@ impl NetworkPacket { self.ip .write(&mut buf) .map_err(IpStackError::PacketWriteError)?; - self.transport - .write(&mut buf) - .map_err(IpStackError::PacketWriteError)?; + match self.transport { + TransportHeader::Tcp(ref h) => h + .write(&mut buf) + .map_err(WriteError::from) + .map_err(IpStackError::PacketWriteError)?, + TransportHeader::Udp(ref h) => { + h.write(&mut buf).map_err(IpStackError::PacketWriteError)? + } + _ => {} + }; + // self.transport + // .write(&mut buf) + // .map_err(IpStackError::PacketWriteError)?; buf.extend_from_slice(&self.payload); Ok(buf) } diff --git a/src/stream/mod.rs b/src/stream/mod.rs index 4a134bb..4f41e26 100644 --- a/src/stream/mod.rs +++ b/src/stream/mod.rs @@ -1,15 +1,19 @@ -use std::net::SocketAddr; +use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; pub use self::tcp::IpStackTcpStream; pub use self::udp::IpStackUdpStream; +pub use self::unknown::IpStackUnknownTransport; mod tcb; mod tcp; mod udp; +mod unknown; pub enum IpStackStream { Tcp(IpStackTcpStream), Udp(IpStackUdpStream), + UnknownTransport(IpStackUnknownTransport), // todo: fix lint error + UnknownNetwork(Vec), // todo: fix lint errorP } impl IpStackStream { @@ -17,12 +21,26 @@ impl IpStackStream { match self { IpStackStream::Tcp(tcp) => tcp.local_addr(), IpStackStream::Udp(udp) => udp.local_addr(), + IpStackStream::UnknownNetwork(_) => { + SocketAddr::V4(SocketAddrV4::new(std::net::Ipv4Addr::new(0, 0, 0, 0), 0)) + } + IpStackStream::UnknownTransport(unknown) => match unknown.src_addr() { + std::net::IpAddr::V4(addr) => SocketAddr::V4(SocketAddrV4::new(addr, 0)), + std::net::IpAddr::V6(addr) => SocketAddr::V6(SocketAddrV6::new(addr, 0, 0, 0)), + }, } } pub fn peer_addr(&self) -> SocketAddr { match self { IpStackStream::Tcp(tcp) => tcp.peer_addr(), IpStackStream::Udp(udp) => udp.peer_addr(), + IpStackStream::UnknownNetwork(_) => { + SocketAddr::V4(SocketAddrV4::new(std::net::Ipv4Addr::new(0, 0, 0, 0), 0)) + } + IpStackStream::UnknownTransport(unknown) => match unknown.dst_addr() { + std::net::IpAddr::V4(addr) => SocketAddr::V4(SocketAddrV4::new(addr, 0)), + std::net::IpAddr::V6(addr) => SocketAddr::V6(SocketAddrV6::new(addr, 0, 0, 0)), + }, } } } diff --git a/src/stream/tcp.rs b/src/stream/tcp.rs index c3d6fd0..9c739ca 100644 --- a/src/stream/tcp.rs +++ b/src/stream/tcp.rs @@ -1,10 +1,10 @@ use crate::{ error::IpStackError, - packet::{tcp_flags, IpStackPacketProtocol, TcpPacket}, + packet::{tcp_flags, IpStackPacketProtocol, TcpPacket, TransportHeader}, stream::tcb::{Tcb, TcpState}, DROP_TTL, TTL, }; -use etherparse::{Ipv4Extensions, Ipv4Header, Ipv6Extensions, TransportHeader}; +use etherparse::{Ipv4Extensions, Ipv4Header, Ipv6Extensions}; use std::{ cmp, future::Future, diff --git a/src/stream/udp.rs b/src/stream/udp.rs index c5c4983..bf7a14d 100644 --- a/src/stream/udp.rs +++ b/src/stream/udp.rs @@ -8,16 +8,17 @@ use std::{ time::Duration, }; -use etherparse::{ - Ipv4Extensions, Ipv4Header, Ipv6Extensions, Ipv6Header, TransportHeader, UdpHeader, -}; +use etherparse::{Ipv4Extensions, Ipv4Header, Ipv6Extensions, Ipv6Header, UdpHeader}; use tokio::{ io::{AsyncRead, AsyncWrite}, sync::mpsc::{self, UnboundedReceiver, UnboundedSender}, time::Sleep, }; - -use crate::{packet::NetworkPacket, TTL}; +// use crate::packet::TransportHeader; +use crate::{ + packet::{NetworkPacket, TransportHeader}, + TTL, +}; pub struct IpStackUdpStream { src_addr: SocketAddr, diff --git a/src/stream/unknown.rs b/src/stream/unknown.rs new file mode 100644 index 0000000..bf3e66a --- /dev/null +++ b/src/stream/unknown.rs @@ -0,0 +1,54 @@ +use std::net::IpAddr; + +use etherparse::IpHeader; +use tokio::sync::mpsc::UnboundedSender; + +use crate::packet::NetworkPacket; + +pub struct IpStackUnknownTransport { + src_addr: IpAddr, + dst_addr: IpAddr, + payload: Vec, + ip: IpHeader, + // packet_sender: UnboundedSender, +} + +impl IpStackUnknownTransport { + pub fn new( + src_addr: IpAddr, + dst_addr: IpAddr, + payload: Vec, + ip: IpHeader, + _packet_sender: UnboundedSender, + ) -> Self { + IpStackUnknownTransport { + src_addr, + dst_addr, + payload, + ip, + // packet_sender, + } + } + pub fn src_addr(&self) -> IpAddr { + self.src_addr + } + pub fn dst_addr(&self) -> IpAddr { + self.dst_addr + } + pub fn payload(&self) -> &[u8] { + &self.payload + } + pub fn ip_protocol(&self) -> u8 { + match &self.ip { + IpHeader::Version4(ip, _) => ip.protocol, + IpHeader::Version6(ip, _) => ip.next_header, + } + } + // pub fn send(&self, payload: Vec) { + // let packet = NetworkPacket::new(self.ip.clone(), payload); + // self.packet_sender.send(packet).unwrap(); + // // } + // pub fn create_rev_packet(&self, mut payload: Vec)-> Result{ + + // } +} From 5bbd543b613cdbd16f91439ddaf0f82101290d63 Mon Sep 17 00:00:00 2001 From: SajjadPourali Date: Sat, 20 Jan 2024 18:42:33 -0500 Subject: [PATCH 2/3] Fix lint error --- src/lib.rs | 2 +- src/stream/mod.rs | 4 ++-- src/stream/unknown.rs | 15 ++++++++------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b001faf..c1d4468 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,7 +104,7 @@ impl IpStack { continue; }; if let IpStackPacketProtocol::Unknown = packet.transport_protocol() { - accept_sender.send(IpStackStream::UnknownTransport(IpStackUnknownTransport::new(packet.src_addr().ip(),packet.dst_addr().ip(),packet.payload,packet.ip,pkt_sender.clone())))?; + accept_sender.send(IpStackStream::UnknownTransport(IpStackUnknownTransport::new(packet.src_addr().ip(),packet.dst_addr().ip(),packet.payload,&packet.ip,pkt_sender.clone())))?; continue; } diff --git a/src/stream/mod.rs b/src/stream/mod.rs index 4f41e26..9878f99 100644 --- a/src/stream/mod.rs +++ b/src/stream/mod.rs @@ -12,8 +12,8 @@ mod unknown; pub enum IpStackStream { Tcp(IpStackTcpStream), Udp(IpStackUdpStream), - UnknownTransport(IpStackUnknownTransport), // todo: fix lint error - UnknownNetwork(Vec), // todo: fix lint errorP + UnknownTransport(IpStackUnknownTransport), + UnknownNetwork(Vec), } impl IpStackStream { diff --git a/src/stream/unknown.rs b/src/stream/unknown.rs index bf3e66a..5b0ce49 100644 --- a/src/stream/unknown.rs +++ b/src/stream/unknown.rs @@ -9,7 +9,7 @@ pub struct IpStackUnknownTransport { src_addr: IpAddr, dst_addr: IpAddr, payload: Vec, - ip: IpHeader, + protocol: u8, // packet_sender: UnboundedSender, } @@ -18,14 +18,18 @@ impl IpStackUnknownTransport { src_addr: IpAddr, dst_addr: IpAddr, payload: Vec, - ip: IpHeader, + ip: &IpHeader, _packet_sender: UnboundedSender, ) -> Self { + let protocol = match ip { + IpHeader::Version4(ip, _) => ip.protocol, + IpHeader::Version6(ip, _) => ip.next_header, + }; IpStackUnknownTransport { src_addr, dst_addr, payload, - ip, + protocol, // packet_sender, } } @@ -39,10 +43,7 @@ impl IpStackUnknownTransport { &self.payload } pub fn ip_protocol(&self) -> u8 { - match &self.ip { - IpHeader::Version4(ip, _) => ip.protocol, - IpHeader::Version6(ip, _) => ip.next_header, - } + self.protocol } // pub fn send(&self, payload: Vec) { // let packet = NetworkPacket::new(self.ip.clone(), payload); From 71c55333c4c1f26c693386045aa1b4041958de38 Mon Sep 17 00:00:00 2001 From: SajjadPourali Date: Sat, 20 Jan 2024 20:04:07 -0500 Subject: [PATCH 3/3] Implement UnknownTransport and UnknownNetwork --- examples/tun.rs | 28 +++++++++++++-- src/lib.rs | 2 +- src/packet.rs | 8 +++-- src/stream/unknown.rs | 80 ++++++++++++++++++++++++++++++++++++------- 4 files changed, 101 insertions(+), 17 deletions(-) diff --git a/examples/tun.rs b/examples/tun.rs index be5b6a0..8a5dfa5 100644 --- a/examples/tun.rs +++ b/examples/tun.rs @@ -26,6 +26,7 @@ //! use clap::Parser; +use etherparse::{IcmpEchoHeader, Icmpv4Header}; use ipstack::stream::IpStackStream; use std::net::{Ipv4Addr, SocketAddr}; use tokio::{join, net::TcpStream}; @@ -52,7 +53,7 @@ async fn main() -> Result<(), Box> { let mut config = tun2::Configuration::default(); config.address(ipv4).netmask(netmask).mtu(MTU as i32).up(); - config.destination(gateway).name("utun3"); + config.destination(gateway); #[cfg(target_os = "linux")] config.platform(|config| { @@ -109,7 +110,30 @@ async fn main() -> Result<(), Box> { println!("==== end UDP connection ===="); }); } - _ => { + IpStackStream::UnknownTransport(u) => { + if u.src_addr().is_ipv4() && u.ip_protocol() == 1 { + let (icmp_header, req_payload) = Icmpv4Header::from_slice(u.payload())?; + if let etherparse::Icmpv4Type::EchoRequest(req) = icmp_header.icmp_type { + println!("ICMPv4 echo"); + let echo = IcmpEchoHeader { + id: req.id, + seq: req.seq, + }; + let mut resp = Icmpv4Header::new(etherparse::Icmpv4Type::EchoReply(echo)); + resp.update_checksum(req_payload); + let mut payload = resp.to_bytes().to_vec(); + payload.extend_from_slice(req_payload); + u.send(payload).await?; + } else { + println!("ICMPv4"); + } + continue; + } + println!("unknown transport - Ip Protocol {}", u.ip_protocol()); + continue; + } + IpStackStream::UnknownNetwork(payload) => { + println!("unknown transport - {} bytes", payload.len()); continue; } }; diff --git a/src/lib.rs b/src/lib.rs index c1d4468..9139097 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,7 +104,7 @@ impl IpStack { continue; }; if let IpStackPacketProtocol::Unknown = packet.transport_protocol() { - accept_sender.send(IpStackStream::UnknownTransport(IpStackUnknownTransport::new(packet.src_addr().ip(),packet.dst_addr().ip(),packet.payload,&packet.ip,pkt_sender.clone())))?; + accept_sender.send(IpStackStream::UnknownTransport(IpStackUnknownTransport::new(packet.src_addr().ip(),packet.dst_addr().ip(),packet.payload,&packet.ip,config.mtu,pkt_sender.clone())))?; continue; } diff --git a/src/packet.rs b/src/packet.rs index c54cd29..a89ca78 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -43,14 +43,18 @@ impl NetworkPacket { pub fn parse(buf: &[u8]) -> Result { let p = PacketHeaders::from_ip_slice(buf).map_err(|_| IpStackError::InvalidPacket)?; let ip = p.ip.ok_or(IpStackError::InvalidPacket)?; - // p.payload; let transport = match p.transport { Some(etherparse::TransportHeader::Tcp(h)) => TransportHeader::Tcp(h), Some(etherparse::TransportHeader::Udp(u)) => TransportHeader::Udp(u), _ => TransportHeader::Unknown, }; - let payload = p.payload.to_vec(); + let payload = if let TransportHeader::Unknown = transport { + buf[ip.header_len()..].to_vec() + } else { + p.payload.to_vec() + }; + Ok(NetworkPacket { ip, transport, diff --git a/src/stream/unknown.rs b/src/stream/unknown.rs index 5b0ce49..4f5fae3 100644 --- a/src/stream/unknown.rs +++ b/src/stream/unknown.rs @@ -1,16 +1,20 @@ -use std::net::IpAddr; +use std::{io::Error, mem, net::IpAddr}; -use etherparse::IpHeader; +use etherparse::{IpHeader, Ipv4Extensions, Ipv4Header, Ipv6Extensions, Ipv6Header}; use tokio::sync::mpsc::UnboundedSender; -use crate::packet::NetworkPacket; +use crate::{ + packet::{NetworkPacket, TransportHeader}, + TTL, +}; pub struct IpStackUnknownTransport { src_addr: IpAddr, dst_addr: IpAddr, payload: Vec, protocol: u8, - // packet_sender: UnboundedSender, + mtu: u16, + packet_sender: UnboundedSender, } impl IpStackUnknownTransport { @@ -19,7 +23,8 @@ impl IpStackUnknownTransport { dst_addr: IpAddr, payload: Vec, ip: &IpHeader, - _packet_sender: UnboundedSender, + mtu: u16, + packet_sender: UnboundedSender, ) -> Self { let protocol = match ip { IpHeader::Version4(ip, _) => ip.protocol, @@ -30,7 +35,8 @@ impl IpStackUnknownTransport { dst_addr, payload, protocol, - // packet_sender, + mtu, + packet_sender, } } pub fn src_addr(&self) -> IpAddr { @@ -45,11 +51,61 @@ impl IpStackUnknownTransport { pub fn ip_protocol(&self) -> u8 { self.protocol } - // pub fn send(&self, payload: Vec) { - // let packet = NetworkPacket::new(self.ip.clone(), payload); - // self.packet_sender.send(packet).unwrap(); - // // } - // pub fn create_rev_packet(&self, mut payload: Vec)-> Result{ + pub async fn send(&self, mut payload: Vec) -> Result<(), Error> { + loop { + let packet = self.create_rev_packet(&mut payload)?; + self.packet_sender + .send(packet) + .map_err(|_| Error::new(std::io::ErrorKind::Other, "send error"))?; + if payload.is_empty() { + return Ok(()); + } + } + } + + pub fn create_rev_packet(&self, payload: &mut Vec) -> Result { + match (self.dst_addr, self.src_addr) { + (std::net::IpAddr::V4(dst), std::net::IpAddr::V4(src)) => { + let mut ip_h = Ipv4Header::new(0, TTL, self.protocol, dst.octets(), src.octets()); + let line_buffer = self.mtu.saturating_sub(ip_h.header_len() as u16); - // } + let p = if payload.len() > line_buffer as usize { + payload.drain(0..line_buffer as usize).collect::>() + } else { + mem::take(payload) + }; + ip_h.payload_len = p.len() as u16; + Ok(NetworkPacket { + ip: etherparse::IpHeader::Version4(ip_h, Ipv4Extensions::default()), + transport: TransportHeader::Unknown, + payload: p, + }) + } + (std::net::IpAddr::V6(dst), std::net::IpAddr::V6(src)) => { + let mut ip_h = Ipv6Header { + traffic_class: 0, + flow_label: 0, + payload_length: 0, + next_header: 17, + hop_limit: TTL, + source: dst.octets(), + destination: src.octets(), + }; + let line_buffer = self.mtu.saturating_sub(ip_h.header_len() as u16); + payload.truncate(line_buffer as usize); + ip_h.payload_length = payload.len() as u16; + let p = if payload.len() > line_buffer as usize { + payload.drain(0..line_buffer as usize).collect::>() + } else { + mem::take(payload) + }; + Ok(NetworkPacket { + ip: etherparse::IpHeader::Version6(ip_h, Ipv6Extensions::default()), + transport: TransportHeader::Unknown, + payload: p, + }) + } + _ => unreachable!(), + } + } }