Skip to content

Commit

Permalink
Merge pull request #17 from narrowlink/UnknownPackets
Browse files Browse the repository at this point in the history
Implement UnknownTransport and UnknownNetwork
  • Loading branch information
SajjadPourali authored Jan 21, 2024
2 parents 0d76b50 + 71c5533 commit 4819292
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 39 deletions.
29 changes: 28 additions & 1 deletion examples/tun.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -52,7 +53,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

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| {
Expand Down Expand Up @@ -109,6 +110,32 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
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;
}
};
}
}
35 changes: 22 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use tracing::{error, trace};

use crate::{
packet::IpStackPacketProtocol,
stream::{IpStackTcpStream, IpStackUdpStream},
stream::{IpStackTcpStream, IpStackUdpStream, IpStackUnknownTransport},
};
mod error;
mod packet;
Expand Down Expand Up @@ -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");
// }
// }

}
}
Expand All @@ -141,6 +147,9 @@ impl IpStack {
entry.insert(stream.stream_sender());
accept_sender.send(IpStackStream::Udp(stream))?;
}
IpStackPacketProtocol::Unknown => {
unreachable!()
}
}
}
}
Expand Down
57 changes: 40 additions & 17 deletions src/packet.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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<u8>,
pub(crate) ip: IpHeader,
pub(crate) transport: TransportHeader,
pub(crate) payload: Vec<u8>,
}

impl NetworkPacket {
pub fn parse(buf: &[u8]) -> Result<Self, IpStackError> {
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,
Expand All @@ -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, _) => {
Expand All @@ -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, _) => {
Expand Down Expand Up @@ -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)
}
Expand Down
20 changes: 19 additions & 1 deletion src/stream/mod.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,46 @@
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<u8>),
}

impl IpStackStream {
pub fn local_addr(&self) -> SocketAddr {
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)),
},
}
}
}
4 changes: 2 additions & 2 deletions src/stream/tcp.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
11 changes: 6 additions & 5 deletions src/stream/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading

0 comments on commit 4819292

Please sign in to comment.