feat: trying out smoltcp
This commit is contained in:
parent
35bcf5352b
commit
f5b31954d4
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -697,9 +697,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.147"
|
version = "0.2.148"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
@ -1257,6 +1257,7 @@ dependencies = [
|
|||||||
"defmt",
|
"defmt",
|
||||||
"heapless",
|
"heapless",
|
||||||
"libc",
|
"libc",
|
||||||
|
"log",
|
||||||
"managed",
|
"managed",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1417,6 +1418,7 @@ name = "tcp-test"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"libc",
|
||||||
"nl-sys",
|
"nl-sys",
|
||||||
"packets",
|
"packets",
|
||||||
"pcap-sys",
|
"pcap-sys",
|
||||||
|
|||||||
@ -146,7 +146,7 @@ pub fn get_macs_and_src_for_ip(
|
|||||||
neighs: &Cache<Neigh>,
|
neighs: &Cache<Neigh>,
|
||||||
links: &Cache<Link>,
|
links: &Cache<Link>,
|
||||||
addr: Ipv4Addr,
|
addr: Ipv4Addr,
|
||||||
) -> Option<(String, Ipv4Addr, [u8; 6], [u8; 6])> {
|
) -> Option<(String, i32, Ipv4Addr, [u8; 6], [u8; 6], u8)> {
|
||||||
let mut sorted_routes = routes.iter().collect::<Vec<_>>();
|
let mut sorted_routes = routes.iter().collect::<Vec<_>>();
|
||||||
|
|
||||||
sorted_routes.sort_by(|r1, r2| {
|
sorted_routes.sort_by(|r1, r2| {
|
||||||
@ -182,6 +182,7 @@ pub fn get_macs_and_src_for_ip(
|
|||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
|
println!("Link index: {link_ind}\n");
|
||||||
for link in links.iter() {
|
for link in links.iter() {
|
||||||
println!(
|
println!(
|
||||||
"Link {}: {:?} ({})",
|
"Link {}: {:?} ({})",
|
||||||
@ -202,7 +203,6 @@ pub fn get_macs_and_src_for_ip(
|
|||||||
.iter()
|
.iter()
|
||||||
.filter(|neigh| neigh.ifindex() == link.ifindex())
|
.filter(|neigh| neigh.ifindex() == link.ifindex())
|
||||||
{
|
{
|
||||||
println!("\t\ttest {:?}, {:?}", neigh.ifindex(), neigh.dst());
|
|
||||||
println!("\t\t{:?}, {:?}", neigh.dst(), neigh.lladdr());
|
println!("\t\t{:?}, {:?}", neigh.dst(), neigh.lladdr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,9 +221,11 @@ pub fn get_macs_and_src_for_ip(
|
|||||||
|
|
||||||
Some((
|
Some((
|
||||||
link.name(),
|
link.name(),
|
||||||
|
link_ind,
|
||||||
(&srcip.local()?).try_into().ok()?,
|
(&srcip.local()?).try_into().ok()?,
|
||||||
link.addr().hw_address().try_into().ok()?,
|
link.addr().hw_address().try_into().ok()?,
|
||||||
neigh,
|
neigh,
|
||||||
|
route.dst().unwrap().cidrlen() as u8,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,4 +13,5 @@ rand = "0.8.5"
|
|||||||
tokio = { version = "1.32.0", features = ["full"] }
|
tokio = { version = "1.32.0", features = ["full"] }
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.75"
|
||||||
tokio-stream = { version = "0.1.14", features = ["full"] }
|
tokio-stream = { version = "0.1.14", features = ["full"] }
|
||||||
smoltcp = { version = "0.10.0", default-features = false, features = ["socket-tcp", "phy-raw_socket", "std", "async", "medium-ethernet"] }
|
smoltcp = { version = "0.10.0", features = ["socket-tcp", "phy-raw_socket", "std", "async", "medium-ethernet", "proto-ipv4", "reassembly-buffer-size-65536", "fragmentation-buffer-size-65536", "proto-ipv4-fragmentation"] }
|
||||||
|
libc = "0.2.148"
|
||||||
|
|||||||
@ -1,11 +1,17 @@
|
|||||||
use std::{net::Ipv4Addr, sync::Arc};
|
use std::{net::Ipv4Addr, os::fd::AsRawFd, sync::Arc};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
|
||||||
use nl_sys::{netlink, route};
|
use nl_sys::{netlink, route};
|
||||||
use packets::{
|
|
||||||
EthernetPacket, IPv4Packet, Layer3Packet, Layer4Packet, TCPPacketBuilder, UDPPacket,
|
use smoltcp::{
|
||||||
|
iface::{Config, Interface, Route, SocketSet},
|
||||||
|
phy::{wait as phy_wait, Medium, RawSocket},
|
||||||
|
socket::tcp,
|
||||||
|
time::Instant,
|
||||||
|
wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address},
|
||||||
};
|
};
|
||||||
|
use tokio::io::{unix::AsyncFd, Interest};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
@ -15,7 +21,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
.ok_or(anyhow!("could not get target IP"))?
|
.ok_or(anyhow!("could not get target IP"))?
|
||||||
.parse::<Ipv4Addr>()?;
|
.parse::<Ipv4Addr>()?;
|
||||||
|
|
||||||
let (ifname, srcip, src_mac, dst_mac) = {
|
let (routes, (ifname, ifindex, srcip, src_mac, _, src_snmask)) = {
|
||||||
let socket = netlink::Socket::new()?;
|
let socket = netlink::Socket::new()?;
|
||||||
|
|
||||||
let routes = socket.get_routes()?;
|
let routes = socket.get_routes()?;
|
||||||
@ -23,51 +29,136 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
let links = socket.get_links()?;
|
let links = socket.get_links()?;
|
||||||
let addrs = socket.get_addrs()?;
|
let addrs = socket.get_addrs()?;
|
||||||
|
|
||||||
route::get_macs_and_src_for_ip(&addrs, &routes, &neighs, &links, ip)
|
let res = route::get_macs_and_src_for_ip(&addrs, &routes, &neighs, &links, ip)
|
||||||
.ok_or(anyhow!("unable to find a route to the IP"))?
|
.ok_or(anyhow!("unable to find a route to the IP"))?;
|
||||||
|
|
||||||
|
(routes, res)
|
||||||
};
|
};
|
||||||
|
|
||||||
dbg!((&ifname, srcip, src_mac, dst_mac));
|
// dbg!((&ifname, srcip, src_mac, dst_mac));
|
||||||
|
|
||||||
let mut interface = pcap_sys::Interface::<pcap_sys::DevDisabled>::new(&ifname)?;
|
let mut device = RawSocket::new(&ifname, Medium::Ethernet)?;
|
||||||
|
|
||||||
interface.set_buffer_size(8192)?;
|
let mut config = Config::new(EthernetAddress(src_mac).into());
|
||||||
interface.set_non_blocking(true)?;
|
config.random_seed = rand::random();
|
||||||
interface.set_promisc(false)?;
|
|
||||||
interface.set_timeout(10)?;
|
|
||||||
|
|
||||||
let interface = Arc::new(interface.activate()?);
|
let mut iface = Interface::new(config, &mut device, Instant::now());
|
||||||
|
iface.update_ip_addrs(|ip_addrs| {
|
||||||
|
let o = srcip.octets();
|
||||||
|
ip_addrs
|
||||||
|
.push(IpCidr::new(
|
||||||
|
IpAddress::v4(o[0], o[1], o[2], o[3]),
|
||||||
|
src_snmask,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
let port: u16 = loop {
|
for route in routes.iter() {
|
||||||
let port = rand::random();
|
let Some(dst) = route.dst() else {
|
||||||
if port > 30_000 {
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(hop) = route.hop_iter().next() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if hop.ifindex() != ifindex {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Some(laddr) = hop.gateway() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if laddr.atype() != Some(libc::AF_INET) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Some(raddr) = route.dst() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if raddr.atype() != Some(libc::AF_INET) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if dst.cidrlen() == 0 {
|
||||||
|
iface
|
||||||
|
.routes_mut()
|
||||||
|
.add_default_ipv4_route(Ipv4Address::from_bytes(&laddr.hw_address()))?;
|
||||||
|
} else {
|
||||||
|
iface.routes_mut().update(|routes| {
|
||||||
|
let lip = laddr.hw_address();
|
||||||
|
let rip = raddr.hw_address();
|
||||||
|
|
||||||
|
_ = routes.push(Route {
|
||||||
|
cidr: IpCidr::new(
|
||||||
|
IpAddress::v4(rip[0], rip[1], rip[2], rip[3]),
|
||||||
|
dst.cidrlen() as u8,
|
||||||
|
),
|
||||||
|
via_router: IpAddress::v4(lip[0], lip[1], lip[2], lip[3]),
|
||||||
|
expires_at: None,
|
||||||
|
preferred_until: None,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 1500]);
|
||||||
|
let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 1500]);
|
||||||
|
let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
|
||||||
|
let mut sockets = SocketSet::new(vec![]);
|
||||||
|
let tcp_handle = sockets.add(tcp_socket);
|
||||||
|
|
||||||
|
let port = loop {
|
||||||
|
let port = rand::random::<u16>();
|
||||||
|
|
||||||
|
if port > 40_000 {
|
||||||
break port;
|
break port;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let packets_to_ack: Vec<EthernetPacket> = vec![];
|
let socket = sockets.get_mut::<tcp::Socket>(tcp_handle);
|
||||||
|
socket.connect(iface.context(), (ip, 54248), port)?;
|
||||||
|
|
||||||
interface.set_filter(&format!("inbound and tcp port {}", port), true, None)?;
|
let fd = device.as_raw_fd();
|
||||||
|
let interest = Interest::WRITABLE
|
||||||
|
.add(Interest::READABLE)
|
||||||
|
.add(Interest::ERROR)
|
||||||
|
.add(Interest::PRIORITY);
|
||||||
|
let afd = AsyncFd::with_interest(fd, interest)?;
|
||||||
|
|
||||||
let seq: u32 = rand::random();
|
let mut tcp_active = false;
|
||||||
|
let mut tcp_data_sent = false;
|
||||||
|
let mut tcp_data_recvd = false;
|
||||||
|
|
||||||
let udppacket = UDPPacket::construct(port, 54248, vec![]);
|
loop {
|
||||||
|
let timestamp = Instant::now();
|
||||||
|
iface.poll(timestamp, &mut device, &mut sockets);
|
||||||
|
|
||||||
let tcppacket = TCPPacketBuilder::default()
|
let socket = sockets.get_mut::<tcp::Socket>(tcp_handle);
|
||||||
.srcport(port)
|
if socket.is_active() && !tcp_active {
|
||||||
.dstport(54248)
|
println!("connected!");
|
||||||
.seqnumber(seq)
|
} else if !socket.is_active() && tcp_active {
|
||||||
.acknumber(0)
|
println!("disconnected");
|
||||||
.syn(true)
|
break Ok(());
|
||||||
.window(65495)
|
}
|
||||||
.build(srcip.clone(), ip.clone(), vec![]);
|
tcp_active = socket.is_active();
|
||||||
|
|
||||||
let ippacket = IPv4Packet::construct(srcip, ip, &Layer4Packet::UDP(udppacket));
|
if !tcp_data_sent && socket.can_send() {
|
||||||
let ethpacket = EthernetPacket::construct(src_mac, dst_mac, &Layer3Packet::IPv4(ippacket));
|
socket.send_slice(b"ping")?;
|
||||||
|
tcp_data_sent = true;
|
||||||
|
}
|
||||||
|
if !tcp_data_recvd && socket.may_recv() {
|
||||||
|
socket.recv(|data| {
|
||||||
|
if !data.is_empty() {
|
||||||
|
match std::str::from_utf8(&data) {
|
||||||
|
Ok(s) => println!("Data received: {}", s),
|
||||||
|
Err(_) => println!("Data received: {:?}", data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(data.len(), data)
|
||||||
|
})?;
|
||||||
|
tcp_data_recvd = true;
|
||||||
|
}
|
||||||
|
|
||||||
println!("sending packet...");
|
// phy_wait(fd, iface.poll_delay(timestamp, &sockets))?;
|
||||||
|
|
||||||
interface.sendpacket(ethpacket.pkt())?;
|
drop(afd.ready(interest).await?);
|
||||||
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,9 @@ import socket
|
|||||||
|
|
||||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
||||||
|
server.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1500)
|
||||||
|
server.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1500)
|
||||||
|
|
||||||
server.bind(("0.0.0.0", 54248))
|
server.bind(("0.0.0.0", 54248))
|
||||||
server.listen(32)
|
server.listen(32)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user