diff --git a/packets/src/lib.rs b/packets/src/lib.rs index 8aee8ec..dac53ba 100644 --- a/packets/src/lib.rs +++ b/packets/src/lib.rs @@ -600,7 +600,12 @@ impl TCPPacketBuilder { let seqnumber = self.seqnumber.unwrap(); let window = self.window.unwrap(); - let len: u8 = (self.options.len() / 4 + 5).try_into().unwrap(); + let mut options = self.options; + while options.len() % 4 != 0 { + options.push(0); + } + + let len: u8 = (options.len() / 4 + 5).try_into().unwrap(); let len = len << 4; let mut bytes = [ @@ -617,7 +622,7 @@ impl TCPPacketBuilder { &window.to_be_bytes(), &[0, 0], &self.urgent_ptr.to_be_bytes(), - &self.options, + &options, &data, ] .concat(); diff --git a/pcap-sys/src/lib.rs b/pcap-sys/src/lib.rs index 60cb4f1..02b5c1e 100644 --- a/pcap-sys/src/lib.rs +++ b/pcap-sys/src/lib.rs @@ -450,6 +450,18 @@ impl InterfaceStream { pub fn sendpacket(&mut self, packet: packets::EthernetPkt) -> error::Result<()> { self.inner.get_mut().interface.sendpacket(packet) } + + pub fn set_filter( + &mut self, + filter: &str, + optimize: bool, + mask: Option, + ) -> error::Result> { + self.inner + .get_mut() + .interface + .set_filter(filter, optimize, mask) + } } impl Unpin for InterfaceStream {} diff --git a/tcp-test/client/src/main.rs b/tcp-test/client/src/main.rs index 0c97ada..627fe03 100644 --- a/tcp-test/client/src/main.rs +++ b/tcp-test/client/src/main.rs @@ -1,15 +1,21 @@ use std::{ collections::VecDeque, - net::{Ipv4Addr, SocketAddr}, time::Duration, + net::{Ipv4Addr, SocketAddr}, + time::Duration, }; -use anyhow::anyhow; +use anyhow::{anyhow, bail}; -use log::{debug, info, trace}; +use log::{debug, error, info, trace}; use nl_sys::{netlink, route}; -use packets::{self, EthernetPacket, IPv4Pkt, TCPPacket, TCPPacketBuilder, TCPPkt}; +use packets::{ + self, EthernetPacket, IPv4Packet, IPv4Pkt, Layer3Packet, Layer3Pkt, Layer4Packet, Layer4Pkt, + TCPPacket, TCPPacketBuilder, TCPPkt, +}; use pcap_sys; +use tokio::{sync::mpsc, task}; +use tokio_stream::StreamExt; struct PeerInfo { remote_addr: Ipv4Addr, @@ -30,7 +36,7 @@ struct TcpSocket { local_rx_last_ack: Option, state: TcpState, peer_info: Option, - ack_timeout: Option + ack_timeout: Option, } #[derive(Default)] @@ -49,6 +55,22 @@ enum TcpState { Closed, } +enum TcpOptions { + EndOfList, + NoOp, + MaxSegmentSize(u16), +} + +impl TcpOptions { + fn get_bytes(&self) -> Vec { + match self { + Self::EndOfList => vec![0x00], + Self::NoOp => vec![0x01], + Self::MaxSegmentSize(size) => [&[0x02, 0x04][..], &size.to_be_bytes()].concat(), + } + } +} + fn socket_accepts_packet(socket: &TcpSocket, ip: IPv4Pkt<'_>, tcp: TCPPkt<'_>) -> bool { if let Some(peer) = &socket.peer_info { peer.local_addr == ip.dest_ip() @@ -65,7 +87,7 @@ fn connect( remote_addr: Ipv4Addr, remote_port: u16, local_addr: Ipv4Addr, -) -> TCPPacket { +) -> (u16, TCPPacket) { socket.state = TcpState::SynSent; let local_port: u16 = loop { let port = rand::random(); @@ -82,25 +104,54 @@ fn connect( socket.local_seq_no = rand::random(); - TCPPacketBuilder::default() + let packet = TCPPacketBuilder::default() .srcport(local_port) .dstport(remote_port) - . .syn(true) .window(64240) .seqnumber(socket.local_seq_no) - .build(local_addr, remote_addr, vec![], None) + .options([TcpOptions::MaxSegmentSize(64240).get_bytes()].concat()) + .build(local_addr, remote_addr, vec![], None); + + (local_port, packet) } fn process_packet( socket: &mut TcpSocket, packet: TCPPkt<'_>, -) -> anyhow::Result)>> { +) -> anyhow::Result<(Option<(TCPPacketBuilder, Vec)>, Option>)> { match socket.state { TcpState::SynSent if packet.ack() && packet.syn() => {} _ => {} } - Ok(None) + Ok((None, None)) +} + +fn send_data(socket: &mut TcpSocket, data: Vec) -> anyhow::Result<(TCPPacketBuilder, Vec)> { + Ok(todo!()) +} + +struct TcpSocketHandle { + send_channel: mpsc::Sender>, + receiver_channel: mpsc::Receiver>, +} + +async fn use_socket(mut socket_handle: TcpSocketHandle) { + _ = socket_handle.send_channel.send(b"ping".to_vec()).await; + + match socket_handle.receiver_channel.recv().await { + Some(bytes) => match std::str::from_utf8(&bytes) { + Ok(string) => { + log::info!("received packet: {string}") + } + Err(_) => { + log::info!("received packet: {bytes:?}"); + } + }, + None => { + log::error!("could not get packets from server") + } + } } #[tokio::main] @@ -116,7 +167,7 @@ async fn main() -> anyhow::Result<()> { .ok_or(anyhow!("could not get target IP"))? .parse::()?; - let (routes, (ifname, ifindex, srcip, src_mac, _, src_snmask)) = { + let (routes, (ifname, ifindex, srcip, src_mac, dst_mac, src_snmask)) = { let socket = netlink::Socket::new()?; let routes = socket.get_routes()?; @@ -130,7 +181,77 @@ async fn main() -> anyhow::Result<()> { (routes, res) }; - let socket = TcpSocket::default(); + let mut socket = TcpSocket::default(); - Ok(()) + let mut interface = pcap_sys::Interface::::new(&ifname)?; + + interface.set_buffer_size(8192)?; + interface.set_non_blocking(true)?; + interface.set_promisc(false)?; + interface.set_timeout(10)?; + + let interface = interface.activate()?; + + macro_rules! format_packet { + ($tcp_packet:expr) => {{ + let layer3pkt = Layer3Packet::IPv4(IPv4Packet::construct( + srcip, + ip, + &Layer4Packet::TCP($tcp_packet), + )); + EthernetPacket::construct(src_mac, dst_mac, &layer3pkt) + }}; + } + + let (port, packet) = connect(&mut socket, ip, 54248, srcip); + + interface.set_filter(&format!("inbound and tcp port {port}"), true, None)?; + + if interface.datalink() != pcap_sys::consts::DLT_EN10MB { + bail!("interface does not support ethernet"); + } + + let mut packets = interface.stream()?; + + packets.sendpacket(format_packet!(packet).pkt())?; + + let (send_channel, mut send_packet) = mpsc::channel(1024); + let (receive_packet, receiver_channel) = mpsc::channel(1024); + + let socket_handle = TcpSocketHandle { + receiver_channel, + send_channel, + }; + + task::spawn(async move { use_socket(socket_handle) }); + + loop { + let Some((builder, data)) = tokio::select! { + Some(Ok(bytes)) = packets.next() => { + let pkt = bytes.pkt(); + let Ok(Layer3Pkt::IPv4Pkt(ip_pkt)) = pkt.get_layer3_pkt() else { continue; }; + let Ok(Layer4Pkt::TCP(tcp_pkt)) = ip_pkt.get_layer4_packet() else { continue; }; + + let Ok((to_send, received)) = process_packet(&mut socket, tcp_pkt) else { continue; }; + + if let Some(received) = received { + _ = receive_packet.send(received).await; + } + + to_send + }, + Some(to_send) = send_packet.recv() => { + match send_data(&mut socket, to_send) { + Ok(v) => Some(v), + Err(_) => continue + } + }, + else => { continue; } + } else { + continue; + }; + + let packet = builder.build(srcip, ip, data, None); + _ = packets.sendpacket(format_packet!(packet).pkt()); + } }