Closed tomDev5 closed 1 month ago
you probably want to feed the packets to smoltcp via a custom fake Device
implementation, not loopback + raw socket. Set the TCP socket to listen, then call .poll() on the interface.
However, if you want to "offline" decode packet captures, Interface is probably not the right tool for the job. Interface
is designed for interactively participating in a network. Maybe use wire
, or perhaps reuse chunks of TcpSocket code.
I will describe my problem better, the API is preferably two sided (raw to tcp and vice versa), and it is not offline
Won't a fake device cause the same problem where there is no tcp socket on the other side?
Even if it somehow works, a fake device seems to me like a one-sided solution
If I've correctly understood @Dirbaio's suggestion, the idea is that you only create one socket (the server in your example above) for which your custom device generates the packets (from whatever source): therefore you don't have/need any raw sockets at all.
I don't think that would prevent the reset packet. It is sent because only one tcp socket exists for smoltcp Having no raw socket would still cause that issue
Edit: nvm worked. Thanks!
@tomDev5 could you share the final implementation on this, I'm after something similar, can can't wrap my head around a "fake" Device
implementation
sure, here is a sample device:
use std::collections::VecDeque;
use smoltcp::phy::{self, Device, DeviceCapabilities, Medium};
use smoltcp::time::Instant;
#[derive(Debug)]
pub struct VecDevice {
to_smoltcp: VecDeque<Vec<u8>>,
from_smoltcp: VecDeque<Vec<u8>>,
medium: Medium,
}
impl VecDevice {
pub fn new(medium: Medium) -> VecDevice {
VecDevice {
to_smoltcp: VecDeque::new(),
from_smoltcp: VecDeque::new(),
medium,
}
}
pub fn send_raw(&mut self, packet: Vec<u8>) {
self.to_smoltcp.push_back(packet);
}
pub fn recv_raw(&mut self) -> Option<Vec<u8>> {
self.from_smoltcp.pop_front()
}
}
impl Device for VecDevice {
type RxToken<'a> = RxToken;
type TxToken<'a> = TxToken<'a>;
fn capabilities(&self) -> DeviceCapabilities {
let mut d = DeviceCapabilities::default();
d.medium = self.medium;
d.max_transmission_unit = 65535;
d
}
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
self.to_smoltcp.pop_front().map(move |buffer| {
let rx = RxToken { buffer };
let tx = TxToken {
queue: &mut self.from_smoltcp,
};
(rx, tx)
})
}
fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
Some(TxToken {
queue: &mut self.from_smoltcp,
})
}
}
pub struct RxToken {
buffer: Vec<u8>,
}
impl phy::RxToken for RxToken {
fn consume<R, F>(mut self, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
f(&mut self.buffer)
}
}
pub struct TxToken<'a> {
queue: &'a mut VecDeque<Vec<u8>>,
}
impl<'a> phy::TxToken for TxToken<'a> {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let mut buffer = Vec::new();
buffer.resize(len, 0);
let result = f(&mut buffer);
self.queue.push_back(buffer);
result
}
}
It is worth mentioning that inserting raw traffic is not done via a smolTCP raw socket, but through the api in the device send_raw
and recv_raw
I am trying to convert a list of (IP) packets into a tcp stream. I have been trying to modify the loopback example like so, to get an initial POC:
The problem is that the logs show that a RST packet from the client to the server is sent after the synack (after adding logs for the packets transmitted):
Looking at how the interface processes IPv4 packets, it appears that it expects a TCP socket to handle the incoming SYN ACK, or else an RST response will be sent (thanks to eggyal on GitHub for figuring this out) So - is there a better way to achieve this?