feat: added basic structure around packet transfer
This commit is contained in:
parent
867464f673
commit
0bda72491c
@ -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();
|
||||
|
||||
@ -450,6 +450,18 @@ impl<T: Activated> InterfaceStream<T> {
|
||||
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<u32>,
|
||||
) -> error::Result<Box<ffi::BpfProgram>> {
|
||||
self.inner
|
||||
.get_mut()
|
||||
.interface
|
||||
.set_filter(filter, optimize, mask)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Activated> Unpin for InterfaceStream<T> {}
|
||||
|
||||
@ -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<u32>,
|
||||
state: TcpState,
|
||||
peer_info: Option<PeerInfo>,
|
||||
ack_timeout: Option<Duration>
|
||||
ack_timeout: Option<Duration>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@ -49,6 +55,22 @@ enum TcpState {
|
||||
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()
|
||||
@ -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<Option<(TCPPacketBuilder, Vec<u8>)>> {
|
||||
) -> anyhow::Result<(Option<(TCPPacketBuilder, Vec<u8>)>, Option<Vec<u8>>)> {
|
||||
match socket.state {
|
||||
TcpState::SynSent if packet.ack() && packet.syn() => {}
|
||||
_ => {}
|
||||
}
|
||||
Ok(None)
|
||||
Ok((None, None))
|
||||
}
|
||||
|
||||
fn send_data(socket: &mut TcpSocket, data: Vec<u8>) -> anyhow::Result<(TCPPacketBuilder, Vec<u8>)> {
|
||||
Ok(todo!())
|
||||
}
|
||||
|
||||
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]
|
||||
@ -116,7 +167,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
.ok_or(anyhow!("could not get target IP"))?
|
||||
.parse::<Ipv4Addr>()?;
|
||||
|
||||
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::<pcap_sys::DevDisabled>::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());
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user