I have this code for a reverse shell with tcp in rust
fn pipe_thread<R, W>(mut r: R, mut w: W) -> std::thread::JoinHandle<()>
where
R: std::io::Read + Send + 'static,
W: std::io::Write + Send + 'static,
{
std::thread::spawn(move || {
let mut buffer = [0; 1024];
loop {
let len = r.read(&mut buffer).unwrap();
if len == 0 {
println!("Connection lost");
std::process::exit(0x0100);
}
w.write(&buffer[..len]).unwrap();
w.flush().unwrap();
}
})
}
fn listen() -> std::io::Result<()> {
let listener = std::net::TcpListener::bind(format!("{}:{}", "0.0.0.0", "55100"))?;
println!("Started listener");
let (stream, _) = listener.accept()?;
let t1 = pipe_thread(std::io::stdin(), stream.try_clone()?);
println!("Connection recieved");
let t2 = pipe_thread(stream, std::io::stdout());
t1.join().unwrap();
t2.join().unwrap();
return Ok(());
}
How would but would I do the exact same thing but with udp instead of tcp?
Netcat example:
netcat -ul 55100
The following code will listen for udp on port 55100. When it is sent a packet, it will save the address of the sender in the addr variable. Then when the user inputs a command, a udp packet is sent to the addr address.
To test it, first send it a udp packet from port 55101 nc -u localhost 55100 -p 55101, this sets addr to localhost:55101. Then listen on port 55101 with nc -ul localhost 55101 and send a command from the rust program so that the nc listener knows where to send its packets to. Now you should be able to send udp messages back and forth between net cat and the rust program.
fn main() {
let socket = std::net::UdpSocket::bind(format!("{}:{}", "0.0.0.0", "55100"))?;
println!("Started listener");
// Addr is the last address that send me a udp packet or None if I have never received a udp packet
use std::sync::{Arc, Mutex};
let addr: Arc<Mutex<Option<std::net::SocketAddr>>> = Arc::from(Mutex::new(None));
// Clone addr so it can be moved into the closure
let addr_clone = addr.clone();
let socket_clone = socket.try_clone().unwrap();
// Spawn listening loop
std::thread::spawn(move || loop {
let mut buffer = [0; 1024];
let (len, src_addr) = socket_clone.recv_from(&mut buffer).unwrap();
*addr_clone.lock().unwrap() = Some(src_addr);
print!("{}", std::str::from_utf8(&buffer).unwrap());
});
loop {
// Get user input
let mut buffer = String::new();
std::io::stdin().read_line(&mut buffer).unwrap();
// Send the command to the last address that send me a udp packet or if I have never received a udp packet, panic
let addr_option = *addr.lock().unwrap();
if let Some(addr) = addr_option {
socket.send_to(buffer.as_bytes(), addr).unwrap();
} else {
panic!("Cant send udp because I dont know where to send it.");
}
}
}
Related
I currently am attempting to write a server and client using Tokio and the broadcast channel. I have a loop that essentially listens for connections and, after reading the TcpStream, I send through the channel.
Here is the code that I have attempted:
What I end up getting is a print each time I connect to the server and bytes are read.. , but I never get a 'Received'
use dbjade::serverops::ServerOp;
use tokio::io::{BufReader};
use tokio::net::TcpStream;
use tokio::{net::TcpListener, io::AsyncReadExt};
use tokio::sync::broadcast;
const ADDR: &str = "localhost:7676"; // Your own address : TODO change to be configured
const CHANNEL_NUM: usize = 100;
use std::io;
use std::net::{SocketAddr};
use bincode;
#[tokio::main]
async fn main() {
// Create listener instance that bounds to certain address
let listener = TcpListener::bind(ADDR).await.map_err(|err| panic!("Failed to bind: {err}")).unwrap();
let (tx, mut rx) = broadcast::channel::<(ServerOp, SocketAddr)>(CHANNEL_NUM);
loop {
if let Ok((mut socket, addr)) = listener.accept().await {
let tx = tx.clone();
let mut rx = tx.subscribe();
println!("Receieved stream from: {}", addr);
let mut buf = vec![0, 255];
tokio::select! {
result = socket.read(&mut buf) => {
match result {
Ok(res) => println!("Bytes Read: {res}"),
Err(_) => println!(""),
}
tx.send((ServerOp::Dummy, addr)).unwrap();
}
result = rx.recv() =>{
let (msg, addr) = result.unwrap();
println!("Receieved: {msg}");
}
}
}
}
}
The main problem in your code are these lines
let tx = tx.clone();
let mut rx = tx.subscribe();
You are redefining tx and rx. and you do it in the loop, so next iteration there is never same tx and rx so they can not be connected between iterations. And so when you do rx.recv() it is not the rx that you expect that is on the other end of the channel. The rx that you define in the beginning is unused. Variable shadowing is a common problem in Rust. The general way to solve it is to read all warnings of the compiler and resolve all "unused" variables, imports, etc. I would argue that turning these warnings into errors by default won't harm either. So that's what I did: I removed all unused stuff and connected the correct channel ends. I also removed dbjade as I've no idea where to get it and for the sake of the example replaced it with "Dummy" string.
use tokio::{net::TcpListener, io::AsyncReadExt};
use tokio::sync::broadcast;
const ADDR: &str = "localhost:7676"; // Your own address : TODO change to be configured
const CHANNEL_NUM: usize = 100;
use std::net::{SocketAddr};
#[tokio::main]
async fn main() {
// Create listener instance that bounds to certain address
let listener = TcpListener::bind(ADDR).await.map_err(|err| panic!("Failed to bind: {err}")).unwrap();
let (tx, mut rx) = broadcast::channel::<(String, SocketAddr)>(CHANNEL_NUM);
loop {
if let Ok((mut socket, addr)) = listener.accept().await {
println!("Receieved stream from: {}", addr);
let mut buf = vec![0, 255];
tokio::select! {
result = socket.read(&mut buf) => {
match result {
Ok(res) => println!("Bytes Read: {res}"),
Err(_) => println!("Err"),
}
tx.send(("Dummy".to_string(), addr)).unwrap();
}
result = rx.recv() =>{
let (msg, _) = result.unwrap();
println!("Receieved: {msg}");
}
}
}
}
}
I'm making a simple chat using Tokio for learning. I've made a server with TcpListener that works fine when I use telnets conexions. For example, if I open 2 terminals with telnet and send data, the server receives the conexion and send the data to the address that is not the sender.
The problem I have is with the TcpStream. For some reason (I think is some type of blocking problem) the stream is not sending the data until I stop the app.
I'd tried multiple configurations, but I think that the simple requiered that is close to "work" is the next one.
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let mut stream = TcpStream::connect("127.0.0.1:8080").await?;
println!("INFO: Socket Address: {:?}", stream.local_addr().unwrap());
let (read, mut writer) = stream.split();
let (sender, receiver) = channel();
thread::spawn(move || loop {
let mut line_buf = String::new();
stdin().read_line(&mut line_buf);
let line = line_buf.trim_end().to_string();
if line.len() > 0 {
sender.send(line_buf.trim_end().to_string()).unwrap();
}
});
loop {
let line = receiver.recv().unwrap();
println!("DEBUG User Input {line}");
writer.write_all(line.as_bytes()).await?;
}
P.D: this code doesn't have anything for receive the messages sended by the server. For manage that, I had something like:
tokio::spawn(async move {
let (read, mut writer) = socket.split();
let mut reader = BufReader::new(read);
let mut line = String::new();
loop {
tokio::select! {
result = reader.read_line(&mut line) => {
if result.unwrap() == 0 {
break;
}
print!("DEBUG: Message Received: {line}");
tx.send((line.clone(), addr)).unwrap();
line.clear();
}
result = rx.recv() => {
let (msg, other_addr) = result.unwrap();
println!("INFO: Message Address: {addr}\n\n");
if addr != other_addr {
writer.write_all(msg.as_bytes()).await.unwrap();
}
}
}
}
});
I am attempting to have a tokio::select! loop where I want an Interval to tick() every second and listen for Udp messages to come in on a UdpFramed Stream
When there are no messages, the Interval ticks just fine, but when a message is received, it seems like the loop is blocking on f.next() but I don't understand why.
Shouldn't next() call poll_next() on the Stream and only wait for the next item if it is available? And thus shouldn't it skip this select! arm and just keep on ticking?
use futures::StreamExt;
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
use std::io;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::time::Duration;
use tokio::net::UdpSocket;
use tokio::select;
use tokio::time::interval;
use tokio_util::codec::BytesCodec;
use tokio_util::udp::UdpFramed;
//MULTICAST Constants
const IP_ANY: [u8; 4] = [0, 0, 0, 0];
#[tokio::main]
async fn main() -> io::Result<()> {
pretty_env_logger::init();
info!("Tokio Select Example");
//Create a udp ip4 socket
let socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?;
//Allow this port to be reused by other sockets
socket.set_reuse_address(true)?;
socket.set_reuse_port(true)?;
//Create IPV4 any adress
let address = SocketAddrV4::new(IP_ANY.into(), 5353);
println!("Created Address");
//Bind to wildcard 0.0.0.0
socket.bind(&SockAddr::from(address))?;
println!("Bound Socket");
//Join multicast group
socket.join_multicast_v4(&Ipv4Addr::new(224, 0, 0, 251), address.ip())?;
println!("Joined Multicast");
//Convert to std::net udp socket
let udp_std_socket: std::net::UdpSocket = socket.into();
//Convert to tokio udp socket
let udp_socket = UdpSocket::from_std(udp_std_socket)?;
println!(
"Created a UDP Socket at {}, {}",
address.ip().to_string(),
address.port().to_string()
);
let mut f = UdpFramed::new(udp_socket, BytesCodec::new());
let mut interval = interval(Duration::from_secs(1));
loop {
select! {
result = tokio::time::timeout(Duration::from_millis(200), f.next()) => {
println!("{:?}", result);
}
default = interval.tick() => {
println!("Tick!");
}
}
}
}
Quote from the documentation of UdpSocket::from_std():
This function is intended to be used to wrap a UDP socket from the standard library in the Tokio equivalent. The conversion assumes nothing about the underlying socket; it is left up to the user to set it in non-blocking mode.
You are not setting the underlying socket in non-blocking mode.
This works:
use futures::StreamExt;
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
use std::io;
use std::net::SocketAddrV4;
use std::time::Duration;
use tokio::net::UdpSocket;
use tokio::select;
use tokio::time::interval;
use tokio_util::codec::BytesCodec;
use tokio_util::udp::UdpFramed;
//MULTICAST Constants
const IP_ANY: [u8; 4] = [0, 0, 0, 0];
#[tokio::main]
async fn main() -> io::Result<()> {
println!("Tokio Select Example");
//Create a udp ip4 socket
let socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?;
//Allow this port to be reused by other sockets
socket.set_reuse_address(true)?;
socket.set_reuse_port(true)?;
socket.set_nonblocking(true)?;
//Create IPV4 any adress
let address = SocketAddrV4::new(IP_ANY.into(), 15253);
println!("Created Address");
//Bind to wildcard 0.0.0.0
socket.bind(&SockAddr::from(address))?;
println!("Bound Socket");
//Convert to tokio udp socket
let udp_socket = UdpSocket::from_std(socket.into())?;
println!(
"Created a UDP Socket at {}, {}",
address.ip().to_string(),
address.port().to_string()
);
let mut f = UdpFramed::new(udp_socket, BytesCodec::new());
let mut interval = interval(Duration::from_secs(1));
loop {
println!("A");
select! {
result = tokio::time::timeout(Duration::from_millis(200), f.next()) => {
println!("{:?}", result);
}
_ = interval.tick() => {
println!("Tick!");
}
}
println!("Z");
}
}
I have the following client IPMI ping program:
pub fn ping(host: &String) -> Result<(), String> {
let socket = UdpSocket::bind("0.0.0.0:0").expect("Unable to bind to host");
let mut udp_payload: Vec<u8> = vec![];
// WRITE RMCP header
// WRITE ASF Ping header
let mut retry_count = 3;
while retry_count > 0 {
match socket.send_to(udp_payload.as_slice(), host) {
Ok(_) => trace!("Successfully sent ping packet"),
Err(_) => {
trace!("Unable to send ping packet retrying");
retry_count -= 1;
continue;
}
}
trace!("Sent ping pkt");
let mut buffer = [0u8; 1500];
match socket.recv_from(&mut buffer) {
Ok((amt, source)) => {
trace!("Got {} a pong response from {}", amt, source);
// Verify RMCP and ASF Pong headers
return Ok(());
}
Err(err) => {
trace!("Did not receive a Pong response, so retrying {}", err);
retry_count = retry_count - 1;
continue;
}
}
}
Err(format!("IPMI ping failed"))
}
I took a packet capture while running the above function. I see the ping packet being sent and a pong response being received from the server, but the recv_from function never returns.
I was running the above program on Mac along with Proxifier that was messing up the UDP traffic. Once I stopped running proxifier my program start working without any issues.
I don't know....
But I would guess that "Proxifier" changes the firewall settings, and those changes make disrupt your UDP. You might want to read up on iptables, and its replacement nftables.
I have a UDP server example, which is working:
let mut socket = UdpSocket::bind("127.0.0.1:12345")?;
let mut buf = [0; 4096];
loop {
let sock = socket.try_clone()?;
match socket.recv_from(&mut buf) {
Ok((amt, src)) => {
thread::spawn(move || {
println!("Handling connection from {}", &src);
let buf = &mut buf[..amt];
buf.reverse();
sock.send_to(&buf, &src).expect("error sending");
});
},
Err(err) => {
eprintln!("Err: {}", err);
}
}
}
It looks like all incoming UDP packets are sharing the same buffer.
If two UDP packets arrive at the same time, won't the second packet overwrite the first in buf, leading to the second packet's (reversed) content being sent back to both senders?
How does Rust prevent this?
No, the buffer is not shared among threads but implicitly copied before starting a new one. From the array doc:
Arrays of any size are Copy if the element type is Copy
Therefore a move keyword forces a buffer movement, which leads to a copy since the same buffer can be used at the next iteration of the loop.