Skip to content

Commit

Permalink
Implement UnknownTransport and UnknownNetwork
Browse files Browse the repository at this point in the history
  • Loading branch information
SajjadPourali committed Jan 21, 2024
1 parent 5bbd543 commit 71c5533
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 17 deletions.
28 changes: 26 additions & 2 deletions 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,7 +110,30 @@ 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;
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
8 changes: 6 additions & 2 deletions src/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,18 @@ 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)?;
// 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,
Expand Down
80 changes: 68 additions & 12 deletions src/stream/unknown.rs
Original file line number Diff line number Diff line change
@@ -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<u8>,
protocol: u8,
// packet_sender: UnboundedSender<NetworkPacket>,
mtu: u16,
packet_sender: UnboundedSender<NetworkPacket>,
}

impl IpStackUnknownTransport {
Expand All @@ -19,7 +23,8 @@ impl IpStackUnknownTransport {
dst_addr: IpAddr,
payload: Vec<u8>,
ip: &IpHeader,
_packet_sender: UnboundedSender<NetworkPacket>,
mtu: u16,
packet_sender: UnboundedSender<NetworkPacket>,
) -> Self {
let protocol = match ip {
IpHeader::Version4(ip, _) => ip.protocol,
Expand All @@ -30,7 +35,8 @@ impl IpStackUnknownTransport {
dst_addr,
payload,
protocol,
// packet_sender,
mtu,
packet_sender,
}
}
pub fn src_addr(&self) -> IpAddr {
Expand All @@ -45,11 +51,61 @@ impl IpStackUnknownTransport {
pub fn ip_protocol(&self) -> u8 {
self.protocol
}
// pub fn send(&self, payload: Vec<u8>) {
// let packet = NetworkPacket::new(self.ip.clone(), payload);
// self.packet_sender.send(packet).unwrap();
// // }
// pub fn create_rev_packet(&self, mut payload: Vec<u8>)-> Result<NetworkPacket, Error>{
pub async fn send(&self, mut payload: Vec<u8>) -> 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<u8>) -> Result<NetworkPacket, Error> {
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::<Vec<u8>>()
} 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::<Vec<u8>>()
} else {
mem::take(payload)
};
Ok(NetworkPacket {
ip: etherparse::IpHeader::Version6(ip_h, Ipv6Extensions::default()),
transport: TransportHeader::Unknown,
payload: p,
})
}
_ => unreachable!(),
}
}
}

0 comments on commit 71c5533

Please sign in to comment.