288 lines
8.1 KiB
Rust
288 lines
8.1 KiB
Rust
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<u8>,
|
|
rx_buffer: VecDeque<u8>,
|
|
local_seq_no: u32,
|
|
remote_seq_no: u32,
|
|
remote_last_ack: Option<u32>,
|
|
remote_last_win: u16,
|
|
local_rx_last_seq: Option<u32>,
|
|
local_rx_last_ack: Option<u32>,
|
|
state: TcpState,
|
|
peer_info: Option<PeerInfo>,
|
|
ack_timeout: Option<Duration>,
|
|
}
|
|
|
|
#[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<u8> {
|
|
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<u8>)>, Option<Vec<u8>>)> {
|
|
match socket.state {
|
|
TcpState::SynSent if packet.ack() && packet.syn() => {}
|
|
_ => {}
|
|
}
|
|
Ok((None, None))
|
|
}
|
|
|
|
fn send_data(
|
|
socket: &mut TcpSocket,
|
|
data: Vec<u8>,
|
|
) -> anyhow::Result<Option<(TCPPacketBuilder, Vec<u8>)>> {
|
|
Ok(None)
|
|
}
|
|
|
|
struct TcpSocketHandle {
|
|
send_channel: mpsc::Sender<Vec<u8>>,
|
|
receiver_channel: mpsc::Receiver<Vec<u8>>,
|
|
}
|
|
|
|
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::<Ipv4Addr>()?;
|
|
|
|
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::<pcap_sys::DevDisabled>::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());
|
|
}
|
|
}
|