From 852e2b7beaf4e340e24b9577f47234cc8ce582fa Mon Sep 17 00:00:00 2001 From: xmh0511 <970252187@qq.com> Date: Fri, 19 Jan 2024 21:09:52 +0800 Subject: [PATCH] support processing other packet from ipstack --- Cargo.toml | 1 + examples/tun.rs | 44 +++++++++++++++++++++++++- src/lib.rs | 78 ++++++++++++++++++++++++++--------------------- src/packet.rs | 53 +++++++++++++++++++++++--------- src/stream/mod.rs | 21 ++++++++++++- src/stream/raw.rs | 38 +++++++++++++++++++++++ 6 files changed, 185 insertions(+), 50 deletions(-) create mode 100644 src/stream/raw.rs diff --git a/Cargo.toml b/Cargo.toml index 58e953a..0356469 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ tun2 = { version = "0.6", features = ["async"] } tokio = { version = "1.35", features = [ "rt-multi-thread", ], default-features = false } +packet = "0.1.4" [profile.release] opt-level = 'z' # Optimize for size. diff --git a/examples/tun.rs b/examples/tun.rs index 2af5e20..f2017c8 100644 --- a/examples/tun.rs +++ b/examples/tun.rs @@ -26,7 +26,7 @@ //! use clap::Parser; -use ipstack::stream::IpStackStream; +use ipstack::stream::{IpStackStream, RawPacket}; use std::net::{Ipv4Addr, SocketAddr}; use tokio::{join, net::TcpStream}; use udp_stream::UdpStream; @@ -70,6 +70,13 @@ async fn main() -> Result<(), Box> { let mut ip_stack = ipstack::IpStack::new(ipstack_config, tun2::create_as_async(&config)?); + #[cfg(target_os = "macos")] + std::process::Command::new("sh") + .arg("-c") + .arg("sudo route -n add -net 10.0.0.0/24 10.0.0.33") + .output() + .unwrap(); + let server_addr = args.server_addr; loop { @@ -108,6 +115,41 @@ async fn main() -> Result<(), Box> { println!("==== end UDP connection ===="); }); } + IpStackStream::RawPacket(_pkt) => { + //println!("{:?}", _pkt); + icmp_reply(_pkt).await; + } }; } } + +async fn icmp_reply(raw_pkt: RawPacket) { + use ::packet::{builder::Builder, Packet}; + let pkt = ::packet::ip::v4::Packet::new(raw_pkt.bytes()).unwrap(); + let icmp = ::packet::icmp::Packet::new(pkt.payload()).unwrap(); + let icmp = icmp.echo().unwrap(); + let reply = ::packet::ip::v4::Builder::default() + .id(0x42) + .unwrap() + .ttl(64) + .unwrap() + .source(pkt.destination()) + .unwrap() + .destination(pkt.source()) + .unwrap() + .icmp() + .unwrap() + .echo() + .unwrap() + .reply() + .unwrap() + .identifier(icmp.identifier()) + .unwrap() + .sequence(icmp.sequence()) + .unwrap() + .payload(icmp.payload()) + .unwrap() + .build() + .unwrap(); + raw_pkt.send(&reply).await.unwrap(); +} diff --git a/src/lib.rs b/src/lib.rs index 6bfc485..ea79279 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub use error::{IpStackError, Result}; +use etherparse::TransportHeader; use packet::{NetworkPacket, NetworkTuple}; use std::{ collections::{ @@ -7,7 +8,7 @@ use std::{ }, time::Duration, }; -use stream::IpStackStream; +use stream::{IpStackStream, RawPacket}; use tokio::{ io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, select, @@ -100,53 +101,62 @@ impl IpStack { 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 { + let Ok(packet) = packet::parse_packet(&buffer[offset..n]) else { #[cfg(feature = "log")] trace!("parse error"); continue; }; - match streams.entry(packet.network_tuple()){ - Occupied(entry) =>{ - 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 packet{ + packet::TunPacket::NetworkPacket(packet)=>{ + let packet = *packet; + match streams.entry(packet.network_tuple()){ + Occupied(entry) =>{ + 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"); + } + } + } } - - } - } - Vacant(entry) => { - match packet.transport_protocol(){ - IpStackPacketProtocol::Tcp(h) => { - match IpStackTcpStream::new(packet.src_addr(),packet.dst_addr(),h, pkt_sender.clone(),config.mtu,config.tcp_timeout).await{ - Ok(stream) => { - entry.insert(stream.stream_sender()); - accept_sender.send(IpStackStream::Tcp(stream))?; + Vacant(entry) => { + match packet.transport_protocol(){ + IpStackPacketProtocol::Tcp(h) => { + match IpStackTcpStream::new(packet.src_addr(),packet.dst_addr(),h, pkt_sender.clone(),config.mtu,config.tcp_timeout).await{ + Ok(stream) => { + entry.insert(stream.stream_sender()); + accept_sender.send(IpStackStream::Tcp(stream))?; + } + Err(_e) => { + #[cfg(feature = "log")] + error!("{}", _e); + } + } } - Err(_e) => { - #[cfg(feature = "log")] - error!("{}", _e); + IpStackPacketProtocol::Udp => { + let stream = IpStackUdpStream::new(packet.src_addr(),packet.dst_addr(),packet.payload, pkt_sender.clone(),config.mtu,config.udp_timeout); + entry.insert(stream.stream_sender()); + accept_sender.send(IpStackStream::Udp(stream))?; } } } - IpStackPacketProtocol::Udp => { - let stream = IpStackUdpStream::new(packet.src_addr(),packet.dst_addr(),packet.payload, pkt_sender.clone(),config.mtu,config.udp_timeout); - entry.insert(stream.stream_sender()); - accept_sender.send(IpStackStream::Udp(stream))?; - } } } + packet::TunPacket::RawPacket=>{ + accept_sender.send(IpStackStream::RawPacket(RawPacket::new(buffer[offset..n].to_vec(), pkt_sender.clone(),config.mtu)))?; + } } } Some(packet) = pkt_receiver.recv() => { - if packet.ttl() == 0{ + let t = packet.transport.clone(); + if (matches!(t, TransportHeader::Tcp(_)) || matches!(t, TransportHeader::Udp(_))) && packet.ttl() == 0{ streams.remove(&packet.reverse_network_tuple()); continue; } @@ -158,7 +168,7 @@ impl IpStack { }; #[cfg(unix)] if config.packet_information { - if packet.src_addr().is_ipv4(){ + if packet.src_ip().is_ipv4(){ packet_byte.splice(0..0, [TUN_FLAGS, TUN_PROTO_IP4].concat()); } else{ packet_byte.splice(0..0, [TUN_FLAGS, TUN_PROTO_IP6].concat()); diff --git a/src/packet.rs b/src/packet.rs index f4e3fe7..19961c7 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -25,20 +25,47 @@ pub(crate) enum IpStackPacketProtocol { Tcp(TcpPacket), Udp, } +#[derive(Debug)] pub struct NetworkPacket { pub ip: IpHeader, pub transport: TransportHeader, pub payload: Vec, } +pub enum TunPacket { + NetworkPacket(Box), + RawPacket, +} + +pub(crate) fn parse_packet(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 + .ok_or(IpStackError::UnsupportedTransportProtocol)?; + match transport { + TransportHeader::Tcp(_) | TransportHeader::Udp(_) => { + Ok(TunPacket::NetworkPacket(Box::new(NetworkPacket { + ip, + transport, + payload: p.payload.to_vec(), + }))) + } + TransportHeader::Icmpv4(_) | TransportHeader::Icmpv6(_) => Ok(TunPacket::RawPacket), + } +} + impl NetworkPacket { - pub fn parse(buf: &[u8]) -> Result { + pub fn parse_from(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(_))) + (matches!(t, TransportHeader::Tcp(_)) + || matches!(t, TransportHeader::Udp(_)) + || matches!(t, TransportHeader::Icmpv4(_)) + || matches!(t, TransportHeader::Icmpv6(_))) }) .ok_or(IpStackError::UnsupportedTransportProtocol)?; let payload = p.payload.to_vec(); @@ -61,13 +88,12 @@ impl NetworkPacket { TransportHeader::Tcp(tcp) => tcp.source_port, _ => unreachable!(), }; + SocketAddr::new(self.src_ip(), port) + } + pub fn src_ip(&self) -> IpAddr { match &self.ip { - IpHeader::Version4(ip, _) => { - SocketAddr::new(IpAddr::V4(Ipv4Addr::from(ip.source)), port) - } - IpHeader::Version6(ip, _) => { - SocketAddr::new(IpAddr::V6(Ipv6Addr::from(ip.source)), port) - } + IpHeader::Version4(ip, _) => IpAddr::V4(Ipv4Addr::from(ip.source)), + IpHeader::Version6(ip, _) => IpAddr::V6(Ipv6Addr::from(ip.source)), } } pub fn dst_addr(&self) -> SocketAddr { @@ -76,13 +102,12 @@ impl NetworkPacket { TransportHeader::Tcp(tcp) => tcp.destination_port, _ => unreachable!(), }; + SocketAddr::new(self.dst_ip(), port) + } + pub fn dst_ip(&self) -> IpAddr { match &self.ip { - IpHeader::Version4(ip, _) => { - SocketAddr::new(IpAddr::V4(Ipv4Addr::from(ip.destination)), port) - } - IpHeader::Version6(ip, _) => { - SocketAddr::new(IpAddr::V6(Ipv6Addr::from(ip.destination)), port) - } + IpHeader::Version4(ip, _) => IpAddr::V4(Ipv4Addr::from(ip.destination)), + IpHeader::Version6(ip, _) => IpAddr::V6(Ipv6Addr::from(ip.destination)), } } pub fn network_tuple(&self) -> NetworkTuple { diff --git a/src/stream/mod.rs b/src/stream/mod.rs index 4a134bb..7d22034 100644 --- a/src/stream/mod.rs +++ b/src/stream/mod.rs @@ -1,8 +1,10 @@ -use std::net::SocketAddr; +use std::net::{IpAddr, SocketAddr}; +pub use self::raw::RawPacket; pub use self::tcp::IpStackTcpStream; pub use self::udp::IpStackUdpStream; +mod raw; mod tcb; mod tcp; mod udp; @@ -10,6 +12,7 @@ mod udp; pub enum IpStackStream { Tcp(IpStackTcpStream), Udp(IpStackUdpStream), + RawPacket(RawPacket), } impl IpStackStream { @@ -17,12 +20,28 @@ impl IpStackStream { match self { IpStackStream::Tcp(tcp) => tcp.local_addr(), IpStackStream::Udp(udp) => udp.local_addr(), + IpStackStream::RawPacket(_) => unreachable!(), + } + } + pub fn local_ip(&self) -> IpAddr { + match self { + IpStackStream::Tcp(tcp) => tcp.local_addr().ip(), + IpStackStream::Udp(udp) => udp.local_addr().ip(), + IpStackStream::RawPacket(_) => unreachable!(), } } pub fn peer_addr(&self) -> SocketAddr { match self { IpStackStream::Tcp(tcp) => tcp.peer_addr(), IpStackStream::Udp(udp) => udp.peer_addr(), + IpStackStream::RawPacket(_) => unreachable!(), + } + } + pub fn peer_ip(&self) -> IpAddr { + match self { + IpStackStream::Tcp(tcp) => tcp.peer_addr().ip(), + IpStackStream::Udp(udp) => udp.peer_addr().ip(), + IpStackStream::RawPacket(_) => unreachable!(), } } } diff --git a/src/stream/raw.rs b/src/stream/raw.rs new file mode 100644 index 0000000..de391ed --- /dev/null +++ b/src/stream/raw.rs @@ -0,0 +1,38 @@ +use crate::IpStackError; +use etherparse::WriteError; +use tokio::sync::mpsc::UnboundedSender; + +use crate::packet::NetworkPacket; + +#[derive(Debug)] +pub struct RawPacket { + packet: Vec, + pkt_sender: UnboundedSender, + mtu: u16, +} +impl RawPacket { + pub fn new(packet: Vec, pkt_sender: UnboundedSender, mtu: u16) -> Self { + Self { + packet, + pkt_sender, + mtu, + } + } + pub fn bytes(&self) -> &[u8] { + &self.packet + } + pub fn mtu(&self) -> u16 { + self.mtu + } + pub async fn send(self, pkt: &[u8]) -> Result<(), IpStackError> { + self.pkt_sender + .send(NetworkPacket::parse_from(pkt)?) + .map_err(|_| { + IpStackError::PacketWriteError(WriteError::IoError(std::io::Error::new( + std::io::ErrorKind::Other, + "", + ))) + })?; + Ok(()) + } +}