use std::{ collections::VecDeque, net::{Ipv4Addr, SocketAddr}, time::Duration, }; use anyhow::{anyhow, bail}; use log::{debug, error, info, trace}; use nl_sys::{netlink, route}; use packets::{ self, ARPMode, ARPPacket, ARPProto, 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, remote_port: u16, local_addr: Ipv4Addr, local_port: u16, } #[derive(Default)] struct TcpSocket { tx_buffer: VecDeque, rx_buffer: VecDeque, local_seq_no: u32, remote_seq_no: u32, remote_last_ack: Option, remote_last_win: u16, local_rx_last_seq: Option, local_rx_last_ack: Option, state: TcpState, peer_info: Option, ack_timeout: Option, } #[derive(Default)] enum TcpState { Listen, SynSent, SynReceived, Established, FinWait1, FinWait2, CloseWait, Closing, LastAck, TimeWait, #[default] 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() && peer.remote_addr == ip.source_ip() && peer.local_port == tcp.dstport() && peer.remote_port == tcp.srcport() } else { false } } fn connect( socket: &mut TcpSocket, remote_addr: Ipv4Addr, remote_port: u16, local_addr: Ipv4Addr, ) -> (u16, TCPPacket) { socket.state = TcpState::SynSent; let local_port: u16 = loop { let port = rand::random(); if port > 40000 { break port; } }; socket.peer_info = Some(PeerInfo { remote_addr, remote_port, local_addr, local_port, }); socket.local_seq_no = rand::random(); let packet = TCPPacketBuilder::default() .srcport(local_port) .dstport(remote_port) .syn(true) .window(64240) .seqnumber(socket.local_seq_no) //.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<(Option<(TCPPacketBuilder, Vec)>, Option>)> { match socket.state { TcpState::SynSent if packet.ack() && packet.syn() => {} _ => {} } Ok((None, None)) } fn send_data( socket: &mut TcpSocket, data: Vec, ) -> anyhow::Result)>> { Ok(None) } 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] async fn main() -> anyhow::Result<()> { simple_logger::SimpleLogger::new() .with_level(log::LevelFilter::Trace) .with_module_level("tcp_test", log::LevelFilter::Trace) .init()?; let ip = std::env::args() .skip(1) .next() .ok_or(anyhow!("could not get target IP"))? .parse::()?; let (ifname, _, srcip, src_mac, dst_mac, _) = { let socket = netlink::Socket::new()?; let routes = socket.get_routes()?; let neighs = socket.get_neigh()?; let links = socket.get_links()?; let addrs = socket.get_addrs()?; route::get_macs_and_src_for_ip(&addrs, &routes, &neighs, &links, ip) .ok_or(anyhow!("unable to find a route to the IP"))? }; let mut socket = TcpSocket::default(); let mut interface = pcap_sys::Interface::::new(&ifname)?; let srcip: u32 = srcip.into(); let srcip = srcip + 10; let srcip: Ipv4Addr = srcip.into(); dbg!(srcip, src_mac, dst_mac); let dst_mac = [0x00, 0x16, 0x3e, 0xde, 0xa9, 0x93]; 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 ippkt = IPv4Packet::construct(srcip, ip, &Layer4Packet::TCP($tcp_packet)); EthernetPacket::construct(src_mac, dst_mac, &Layer3Packet::IPv4(ippkt)) }}; } let (port, packet) = connect(&mut socket, ip, 54248, srcip); interface.set_filter(&format!("arp or (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(packet) = tokio::select! { Some(Ok(bytes)) = packets.next() => { let pkt = bytes.pkt(); match pkt.get_layer3_pkt() { Ok(Layer3Pkt::IPv4Pkt(ip_pkt)) => { let Ok(Layer4Pkt::TCP(tcp_pkt)) = ip_pkt.get_layer4_packet() else { continue; }; if !socket_accepts_packet(&socket, &ip_pkt, &tcp_pkt) { 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.map(|(b, d)| format_packet!(b.build(srcip, ip, d, None))) }, Ok(Layer3Pkt::ARP(arp)) => { if arp.opcode() != 1 || arp.plen() != 4 || arp.hwlen() != 6 { continue; } let senderip: [u8; 4] = arp.srcprotoaddr().try_into().unwrap(); let sendermac: &[u8] = arp.srchwaddr(); let queryip: [u8; 4] = arp.targetprotoaddr().try_into().unwrap(); let queryip: Ipv4Addr = queryip.into(); if queryip != srcip { continue; } let response = ARPPacket::construct(ARPMode::Reply, ARPProto::IPv4, &src_mac, &sendermac, &queryip.octets(), &senderip); Some(EthernetPacket::construct(src_mac, sendermac.try_into().unwrap(), &Layer3Packet::ARP(response))) }, _ => continue } }, Some(to_send) = send_packet.recv() => { match send_data(&mut socket, to_send) { Ok(v) => v.map(|(b, d)| format_packet!(b.build(srcip, ip, d, None))), Err(_) => continue } }, else => { continue; } } else { continue; }; _ = packets.sendpacket(packet.pkt()); } }