GCDAsyncUdpSocket Socket Closes In between sending 255 packets - swift

I have a module where I have to discover by sending a packets to the 255 IP addresses.
eg. Connected IP : 192.188.2.1 then I have to send a packet changing the last value i.e.
var HOST = "192.188.2.1"
var arr = HOST.components(separatedBy: ".")
for i in 1 ..< 254
{
dispatchGroup.enter()
time += 0.005
DispatchQueue.main.asyncAfter(deadline: .now() + time) {
let obj = LPScanPacket()
arr[3] = "\(i)"
let str = arr.joined(separator: ".")
SenderWrapper.sendLPPacket(lpPacket: obj, HOST: str)
dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: .main) {
print("Completed sending 👍")
}
But on sending this many packet it shows me error within udpSocketDidClose delegate method
Error Domain=NSPOSIXErrorDomain Code=65 "No route to host" UserInfo={NSLocalizedDescription=No route to host, NSLocalizedFailureReason=Error in send() function.}
Firstly why do I get this error, is there any alternative way I can achieve this result.
EDIT :
Try running this code, I am trying to get response from the device connected to the same router. To find the device IP I am using the above code. But the socket closes in between sometimes it works and sometime it doesn't I am not able to find the solution why it closes.
Thanks

A broadcast message is sent to all hosts on a network or subnetwork and is created by setting the node part of the IP address to all 1’s.
The error message you received is related to the fact, that broadcasts messages do not go through routers.
To be able to broadcast a datagram, the underlying socket must be in the broadcast mode. Run man setsockopt in your terminal for further reference.

Related

Converting bytes from UDP Server

I am creating a windows UDP tunnel using wintun driver. I have written a code to receive data from the server and send it to the windows tunnel using the function send_packet and allocatesendpacket. The error I get is that I can read data only as bytes from the UDP server but it causes a mismatch when I pass it to the send_packet function. The error is as follows:
mismatched types
expected struct `wintun::Packet`, found `&[u8]`
Code for send_packet and allocatesendpacket
https://github.com/nulldotblack/wintun/blob/main/src/session.rs
Code for packet struct data type
https://github.com/nulldotblack/wintun/blob/main/src/packet.rs
Link for other dependencies
https://github.com/nulldotblack/wintun
How do I convert the bytes (variable buffer below) to Packet struct data type?. The error of mismatch occurs when I declare the value of a variable packet with the value of the received buffer variable, so that packet variable can be sent to tunnel.
My code:
let socket = UdpSocket::bind("6.0.0.1:8000") //create client socket object with ip and port
.expect("Could not bind client socket");
socket.connect("6.0.0.10:8888") //SERVER IP /PORT
let writer_session = session.clone();
let writer =
std::thread::spawn(move || {
info!("Starting writer");
while RUNNING.load(Ordering::Relaxed) {
let mut buffer = [0u8; 20000];
socket.recv_from(&mut buffer) //get message from server
.expect("Could not read into buffer");
let leng1 = buffer.len();
let mut packet = writer_session.allocate_send_packet(leng1.try_into().unwrap()).unwrap();
packet = &buffer[0..leng1]; //ERROR occurs here
writer_session.send_packet(packet);
}
});
You have two errors the first caused by trying to assign a slice to packet directly which is solved by copying the buffer into packet instead:
packet.bytes_mut().copy_from_slice(&buffer);
The second is that you are not using the length returned by recv_from but instead using the length of the whole buffer which may lead to reading past the end of the read data although memory address is valid. You should do this instead:
let mut buffer = [0u8; 20000];
let (leng1, src_addr) = socket.recv_from(&mut buffer) //get message from server
.expect("Could not read into buffer");
let buffer = &mut buffer[..leng1];
To copy the contents of buffer into packet, you can use slice::copy_from_slice:
packet.bytes_mut().copy_from_slice(&buffer);

Multicast UDP packets using Tokio futures

I'm playing around with Tokio and Rust and as an example, I am trying to write a simple UDP proxy that will just accept UDP packets on one socket and send it out to multiple other destinations. However, I stumble over the situation that I need to send the received packet to multiple addresses and am not sure how to do that in a idiomatic way.
Code I have this far:
extern crate bytes;
extern crate futures;
use std::net::SocketAddr;
use tokio::codec::BytesCodec;
use tokio::net::{UdpFramed, UdpSocket};
use tokio::prelude::*;
fn main() {
let listen_address = "127.0.0.1:4711".parse::<SocketAddr>().unwrap();
let forwarder = {
let socket = UdpSocket::bind(&listen_address).unwrap();
let peers = vec![
"192.168.1.136:4711".parse::<SocketAddr>().unwrap(),
"192.168.1.136:4712".parse::<SocketAddr>().unwrap(),
];
UdpFramed::new(UdpSocket::bind(&listen_address).unwrap(), BytesCodec::new()).for_each(
move |(bytes, _from)| {
// These are the problematic lines
for peer in peers.iter() {
socket.send_dgram(&bytes, &peer);
}
Ok(())
},
)
};
tokio::run({
forwarder
.map_err(|err| println!("Error: {}", err))
.map(|_| ())
});
}
The problematic lines are trying to send the received packet to multiple other addresses using a newly bound socket.
The existing examples all forward packets to single destinations, or internally use mpsc channels to communicate between internal tasks. I do not think that this is necessary and that it should be possible to do without having to spawn more than one task per listening socket.
Update: Thanks to #Ömer-erden I got this code that works.
extern crate bytes;
extern crate futures;
use std::net::SocketAddr;
use tokio::codec::BytesCodec;
use tokio::net::{UdpFramed, UdpSocket};
use tokio::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let listen_address = "0.0.0.0:4711".parse::<SocketAddr>()?;
let socket = UdpSocket::bind(&listen_address)?;
let peers: Vec<SocketAddr> = vec!["192.168.1.136:8080".parse()?, "192.168.1.136:8081".parse()?];
let (mut writer, reader) = UdpFramed::new(socket, BytesCodec::new()).split();
let forwarder = reader.for_each(move |(bytes, _from)| {
for peer in peers.iter() {
writer.start_send((bytes.clone().into(), peer.clone()))?;
}
writer.poll_complete()?;
Ok(())
});
tokio::run({
forwarder
.map_err(|err| println!("Error: {}", err))
.map(|_| ())
});
Ok(())
}
Note that:
It is not necessary to call poll_completion for each start_send: it just need to be called after all start_send has been dispatched.
For some reason, the content of the peer is gutted between calls (but there is no compiler error), generating an Error 22 (which is usually because a bad address is given to sendto(2)).
Looking in a debugger, it is quite clear that the second time, the peer address is pointing to invalid memory. I opted to clone the peer instead.
I removed the calls to unwrap() and propagate the Result upwards instead.
Your code has a logical mistake: you are trying to bind the same address twice, as sender and receiver respectively. Instead, you can use a stream and sink. UdpFramed has the functionality to provide that, please see Sink:
A Sink is a value into which other values can be sent, asynchronously.
let listen_address = "127.0.0.1:4711".parse::<SocketAddr>().unwrap();
let forwarder = {
let (mut socket_sink, socket_stream) =
UdpFramed::new(UdpSocket::bind(&listen_address).unwrap(), BytesCodec::new()).split();
let peers = vec![
"192.168.1.136:4711".parse::<SocketAddr>().unwrap(),
"192.168.1.136:4712".parse::<SocketAddr>().unwrap(),
];
socket_stream.for_each(move |(bytes, _from)| {
for peer in peers.iter() {
socket_sink.start_send((bytes.clone().into(), *peer));
socket_sink.poll_complete();
}
Ok(())
})
};
tokio::run({
forwarder
.map_err(|err| println!("Error: {}", err))
.map(|_| ())
});

Bound UDP socket not closed when network becomes unavailable

On Linux, I open an UDP socket and bind it to an address that is currently available. I then listen in a loop for new packets. Then I disable wifi, the interface goes down and the network address is removed from the interface. I would expect the receive call to return an error but this is not the case.
Is this expected behaviour? Is there a way to receive an error from a call to receive when the address the socket is bound to disappears?
Example code in Rust:
use std::net::UdpSocket;
fn main() {
let mut socket = UdpSocket::bind("192.168.2.43:64041").expect("Unable to open socket");
loop {
let mut buf = [0u8; 1500];
match socket.recv_from(&mut buf) {
Ok((n, _addr)) => println!("Received {} bytes", n),
Err(err) => println!("Error receiving bytes: {}", err)
}
}
}

macOS - Use `Process` to telnet to an IP address and pass commands

I'm developing a macOS app where I need to connect using telnet to a device and send commands to it.
(BTW, I'm connecting to a Roku)
This is as far as I got
func telnet(to host: String, port: String) {
let process = Process()
let pipe = Pipe()
process.executableURL = URL(fileURLWithPath: "/usr/local/bin/telnet")
process.arguments = [host, port]
process.standardOutput = pipe
do {
try process.run()
} catch {
return
}
let resultData = pipe.fileHandleForReading.readDataToEndOfFile()
let result = String (data: resultData, encoding: .utf8) ?? ""
print(result)
}
telnet(to: "10.0.1.11", port: "8080")
The problem is that the Process is closed immediately. I need to leave the Process open and somehow send commands to the device and then close the connection.
So those are my questions:
How can I leave the Process running?
How can I send commands to the device through the telnet connection?
Your best bet will be to avoid using Process and make a network connection directly from your application. (This will also free you from your dependency on /usr/local/bin/telnet, which is not present in a clean install of macOS.)
The SwiftSocket pod looks like an excellent way of doing this. The "Client socket example" in the documentation appears to cover most of your questions.

How do I get the broadcast address of my wifi network using Swift?

currently I am using GCDAsyncUdpSocket to send a udp broadcast. Currently, the code sends it to a hardcoded 255.255.255.255 address. Is that the correct broadcast address on all networks? Will it fail on certain networks? What is the correct swift code?
socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main)
socket!.send(ipRequestData!, toHost: "255.255.255.255", port: discoveryPort, withTimeout: 10000, tag: 0)
This question has an answer but it is in Objective-C
Calculating the Broadcast Address in Objective-C
Your broadcast address depends on your host address and the subnet mask. You can find the formula to calculate the broadcast address on Wikipedia:
broadcastAddress = ipAddress | ~subnetMask
You can calculate it with the following function:
func calculateBroadcastAddress(ipAddress: String, subnetMask: String) -> String {
let ipAdressArray = ipAddress.split(separator: ".")
let subnetMaskArray = subnetMask.split(separator: ".")
guard ipAdressArray.count == 4 && subnetMaskArray.count == 4 else {
return "255.255.255.255"
}
var broadcastAddressArray = [String]()
for i in 0..<4 {
let ipAddressByte = UInt8(ipAdressArray[i]) ?? 0
let subnetMaskbyte = UInt8(subnetMaskArray[i]) ?? 0
let broadcastAddressByte = ipAddressByte | ~subnetMaskbyte
broadcastAddressArray.append(String(broadcastAddressByte))
}
return broadcastAddressArray.joined(separator: ".")
}
Example:
let broadcastAddress = calculateBroadcastAddress(ipAddress: "172.16.0.0", subnetMask: "255.240.0.0")
Result:
"172.31.255.255"
In general, you should never choose the main queue for network operations because it will lead to lags in the user interface (which is drawn in the main queue). Better use
let udpSocket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.global())
Do not forget to explicitly enable broadcasts for this socket
do {
try udpSocket?.enableBroadcast(true)
} catch let error {
print(error)
}
Also consider that Apple enforces an iOS app to work with IPv6, which does not support broadcasts but multicasts. So maybe you should switch to multicasts at least if your device is inside a pure IPv6 network.