diff --git a/examples/tun.rs b/examples/tun.rs index bfafc9e..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,6 +110,32 @@ 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 d48e103..9139097 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,config.mtu,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..a89ca78 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,25 +23,38 @@ 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)?; - let payload = p.payload.to_vec(); + 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 = if let TransportHeader::Unknown = transport { + buf[ip.header_len()..].to_vec() + } else { + p.payload.to_vec() + }; + Ok(NetworkPacket { ip, transport, @@ -52,14 +65,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 +87,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 +117,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..9878f99 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), + UnknownNetwork(Vec), } 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..4f5fae3 --- /dev/null +++ b/src/stream/unknown.rs @@ -0,0 +1,111 @@ +use std::{io::Error, mem, net::IpAddr}; + +use etherparse::{IpHeader, Ipv4Extensions, Ipv4Header, Ipv6Extensions, Ipv6Header}; +use tokio::sync::mpsc::UnboundedSender; + +use crate::{ + packet::{NetworkPacket, TransportHeader}, + TTL, +}; + +pub struct IpStackUnknownTransport { + src_addr: IpAddr, + dst_addr: IpAddr, + payload: Vec, + protocol: u8, + mtu: u16, + packet_sender: UnboundedSender, +} + +impl IpStackUnknownTransport { + pub fn new( + src_addr: IpAddr, + dst_addr: IpAddr, + payload: Vec, + ip: &IpHeader, + mtu: u16, + 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, + protocol, + mtu, + 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 { + self.protocol + } + 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!(), + } + } +}