UDP socket multicast - java

I will start by saying that I'm not absolutely a network expert.
I'm trying to create a UDP multicast socket system with four RaspBerry Pi model B.
Into each Rpi is running a listening script (I will call it "listen.py") socket client.
Case 1 - I'm perfectly able to send datagram if I run the socket server (I will call it "server.py") directly inside of the Rpi (by SSH, with my laptop as well).
I have:
-listen.py on boot of the Rpi (here I create a socket client);
-I run the server.py (the server.py is obviously into the Rpi)
In this case I receive answer from all 4 Rpi that joined the multicast group (224.1.1.1)
Case 2 - I created a socket server java and a socket client python in my laptop and everything works perfectly (same code, same multicast group, same multicast port).I tried also without multicast using just 'localhost' and everything works as well. With netstat I can see multicast group and port.
netstat -lu
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
udp 0 0 224.1.1.1:21581 *:* //MulticastGroupIp:Port
udp 0 0 192.168.1.103:ntp *:* //Static ip of one Rpi
udp 0 0 *:ntp *:*
My problem is that if I run the server.py from my laptop (no SSH) I have no answer from the listen.py, socket client, which is running into the Rpi. I absolutely need to send datagram from my laptop (I want a java class) to the 4 Rpi.
I have excluded the possibilities of bad code, wrong multicast ip group, wrong multicast port group. Firewall is off in my laptop and in the router as well.
The parameter net.ipv4.ip_forward on the Rpi is 1.
I know that UDP is unreliable but here I'm speaking about 100% of the datagram lost.
IGMP is enabled on my D-Link router.
I have the same problem with Ethernet and WiFi configuration.
I really need other ideas.....So I tried to write here.
Sorry, this is my first post and I'm newbie a bit of everything.
I will appreciate any suggestion.
Probably it's something stupid that I can't understand.
Maybe some problems with the routing table???? This is mine:
route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default D-Link.Home 0.0.0.0 UG 0 0 0 wlan0
192.168.1.0 * 255.255.255.0 U 0 0 0 wlan0
Thanks in advance
For me the code works well and the problem is not there but if can be useful to understand better the situation.....
Code of server.py (useless to say that I have python installed in my machine with Windows 7):
import socket
import sys
# import time
print 'message:'
n = sys.stdin.readline()
n = n.strip('\n')
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 21581
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
sock.sendto(n, (MCAST_GRP, MCAST_PORT))
or with java (It's exactly what I want...a server socket java but at the moment it's not the priority):
public class PythonScriptScan {
private static int portMulticasting = 21581;
// private boolean broadcast = true;
private DatagramSocket socket;
private String groupMulticast = "224.1.1.1"; // group address
private int delay = 3000;
public PythonScriptScan() {
try {
socket = new DatagramSocket();
} catch (SocketException e) {
e.printStackTrace();
System.exit(1);
}
}
public void start(String agentName) {
try {
InetAddress group = InetAddress.getByName(groupMulticast);
#SuppressWarnings("resource")
MulticastSocket s = new MulticastSocket(portMulticasting);
s.joinGroup(group);
// while (broadcast) {
byte[] buf = new byte[10240];
buf = agentName.getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, portMulticasting);
System.out.println(packet);
socket.send(packet);
// OK, I'm done talking - leave the group...
s.leaveGroup(group);
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
System.exit(0);
}
// }
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
System.out.println("Insert Message");
#SuppressWarnings("resource")
Scanner sc = new Scanner(System.in);
String agentName = sc.nextLine();
PythonScriptScan agent = new PythonScriptScan();
agent.start(agentName);
}
and listen.py (It's running on boot in each Rpis, the configuration that I want is with Ethernet, each Rpis has a static ip and they are connected properly with my D-link router):
#!/usr/bin/python
import socket
import struct
import fcntl
import subprocess
import sys
import errno
import time
import os
# Create the socket
MCAST_GRP = "224.1.1.1"
MCAST_PORT = 21581
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
except socket.error, msg:
print 'Could not create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Bind to the server address
# sock.bind(('', MCAST_PORT))
sock.bind((MCAST_GRP, MCAST_PORT))
# Tell the operating system to add the socket to the multicast group on all interfaces
mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
# Receive loop
try:
while True:
print >>sys.stderr, '\nWAITING TO RECEIVE MESSAGE'
d = sock.recvfrom(10240)
data = d[0]
addr = d[1]
print data.strip(), addr
finally:
print >>sys.stderr, 'closing socket'
sock.close()

Related

Router does not forward multicast packet across interfaces

My router has three network interfaces:
Ethernet;
2.4GHz antenna;
5GHz antenna;
I have a program that sends and receives packets on a multicast address (I set it to 239.5.6.7) on port 10468.
For my tests I have two devices (one sender and one receiver) that exchange information.
If both devices are connected to the same interface of the router (let's say, both connected to the 5GHz WiFi) then the devices will be able to communicate.
On the other hand, if the devices are on two different interfaces (one 5GHz and one Ethernet), packets will not be exchanged (as if the router does not forward multicast traffic to one interface to the others).
All three interfaces support multicast (examining traffic with WireShark shows that every host is able to join the multicast group), but it seems like the router is blocking this cross-interface exchange.
It really is a shitty router issue? Or I did something wrong on my end?
Both the sender and receiver communicate with the multicast group with all their interfaces (as long as they have a link-local IP address).
getActiveInterfaces() is a method that gathers such interfaces and saves them in an array list.
Sender snippet (getActiveInterfaces() returns only the ethernet connection):
static final int port = 10468;
public static void main(String[] args) {
try {
ArrayList<NetworkInterface> interfaces = getActiveInterfaces();
// Initialize sockets
ArrayList<MulticastSocket> sockets = new ArrayList<>(interfaces.size());
for (NetworkInterface networkInterface : interfaces) {
MulticastSocket socket = new MulticastSocket();
socket.setOption(StandardSocketOptions.IP_MULTICAST_TTL, 1);
socket.setNetworkInterface(networkInterface);
sockets.add(socket);
}
InetSocketAddress group = new InetSocketAddress(InetAddress.getByName("239.5.6.7"), port);
byte[] buf = new byte[128];
String msg = "Hello";
DatagramPacket toSend = new DatagramPacket(msg.getBytes(), msg.getBytes().length, group);
while (true) {
Thread.sleep(1000);
for (MulticastSocket socket : sockets)
socket.send(toSend);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
Receiver snippet (getActiveInterfaces() returns only the 2.4GHz wireless connection):
static final int port = 10468;
public static void main(String[] args) {
try(MulticastSocket s = new MulticastSocket(port)) {
InetSocketAddress group = new InetSocketAddress(InetAddress.getByName("239.5.6.7"), port);
ArrayList<NetworkInterface> activeInterfaces = getActiveInterfaces();
for (NetworkInterface networkInterface : activeInterfaces) {
s.joinGroup(group, networkInterface);
}
DatagramPacket rec = new DatagramPacket(new byte[128], 128);
while(true) {
s.receive(rec);
System.out.println(new String(rec.getData(), StandardCharsets.UTF_8).replaceAll("\0", ""));
}
}catch (Exception e) {
e.printStackTrace();
}
}
After some investigations, I came to a conclusion that this is a router issue.
It seems that there is some sort of whitelisting going on.
For example, packets sent to the reserved Local Control Block multicast addresses (224.0.0.1-224.0.0.255) do not have this issue. Well-known multicast IPs are also whitelisted (like 239.255.255.250, used for SSDP).
Even changing to the next multicast address (239.255.255.249 or 239.255.255.251) leads to the same issue.
The only solution I could come up with is to use one of these whitelisted addresses and to use a different port number (not one linked with the actual address).
you may want to up your ttl to 3,
each time a multicast packet is received by a router the ttl is decremented by 1, when the ttl is 0 the packet is dropped.
Does it work with the sender and receiver on the same machine?
If it does, next as root, run
tcpdump multicast
on both machines
you should see something like
16:26:22.085822 IP debian.attlocal.net.51429 > 239.35.3.5.3535: UDP, length 1316

Pcap4j TCP packets being dropped after showing on Wireshark

For educational purposes I'm trying to perform a SYN flood attack on a Ubuntu 18.04 VM. I have enabled bridge mode in my VM settings and set up a web server (10.0.0.10) I can reach on my host pc (10.0.0.3) and vice versa with pings. Pinging from host to server shows Wireshark traffic on the server (request and response), pinging from server to host also shows Wireshark traffic on the server, but not on the host, even though the ping packets are correctly built.
The way I build my attack is to generate random IPs, construct TCP SYN packet and send it to the web server from my host through port 80 (open), which should send a TCP SYN/ACK packet back (I used iptables to route it back to my host pc).
If I construct a TCP packet through Pcap4J (Pcap library for Java) and subsequently send it through the handler, I see it pop up on the host Wireshark.
However, if I check the Wireshark on my VM, the packets do not arrive. The handler does not give an error and the program exits correctly and I am therefore unsure how to fix this problem.
Where is the packet dropped and what can I do to fix it? I need the packets to reach the web server VM (and the server to send them back).
Code:
Pcaphandle send_handle;
//nif_address is a constant of my ethernet connection defined in the file
try {
PcapNetworkInterface nif = Pcaps.getDevByAddress(nif_address);
if (nif == null) {
System.out.println("Networkinterface is null");
return;
}
// Open the device and get a send_handle
int snapshotLength = 65536; // in bytes
int readTimeout = 50; // in milliseconds
send_handle = nif.openLive(snapshotLength, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, readTimeout);
} catch (PcapNativeException e) {
System.out.println("Cannot bind NIF to variable from localhost");
e.printStackTrace();
return;
}
//Send packets, e.g. 1 packet by 5 different IPs
for (int i = 0; i < 5; i++) {
//generateIP() function not shown here, but is simply a randomizer and format to IP
InetAddress src_ip = generateIP();
Packet tcpPacket = constructSYNPacket(i, src_ip);
try {
send_handle.sendPacket(tcpPacket);
System.out.println(send_handle.getError());
} catch (PcapNativeException | NotOpenException e) {
e.printStackTrace();
}
}
private Packet constructSYNPacket(int packetNr, InetAddress src_address) {
TcpPacket.Builder tcpBuilder = new TcpPacket.Builder();
tcpBuilder
.syn(true)
.ack(false)
.rst(false)
.psh(false)
.urg(false)
.srcAddr(src_address)
.srcPort(TcpPort.getInstance((short) srcPort))
.dstAddr(dst_address)
.dstPort(TcpPort.getInstance((short) dstPort))
.correctLengthAtBuild(true)
.correctChecksumAtBuild(true)
.sequenceNumber(100000 + (packetNr*50));
IpV4Packet.Builder ipv4Builder = new IpV4Packet.Builder();
ipv4Builder
.srcAddr((Inet4Address)src_address)
.dstAddr((Inet4Address)dst_address)
.dontFragmentFlag(true)
.fragmentOffset((short)0)
.ihl((byte)5)
.correctLengthAtBuild(true)
.correctChecksumAtBuild(true)
.protocol(IpNumber.TCP)
.version(IpVersion.IPV4)
.tos((IpV4Packet.IpV4Tos) () -> (byte)0)
.ttl((byte)100)
.payloadBuilder(tcpBuilder);
EthernetPacket.Builder ethBuilder = new EthernetPacket.Builder();
ethBuilder
.srcAddr(nif_mac)
.dstAddr(dst_mac)
.type(EtherType.IPV4)
.payloadBuilder(ipv4Builder)
.paddingAtBuild(true);
Packet p = ethBuilder.build();
Note: I already disabled SYN cookies in the Ubuntu sysctl.
Even though I have not found out why bridging mode did not work, I managed to make it work using a host-only adapter. Pings and packets were received both ways when I used it.

Unable to send anything from Python server to Java client

I've set up a Raspberry Pi 3 and I want to make a program that sends data whenever a button is pushed on my breadboard. I have a Python server running on my RPi, and a Java client running on my Windows laptop. However, whenever I send data to my Java client, it receives the data, and then for some reason, the RPi server closes the program due to "broken pipe". However this cannot be true, because my Java program receives data from the Pi! The Java program then closes due to the Pi server closing. But from what I've read online, Python's "error 32: broken pipe" is triggered when the remote socket closes prematurely!
What's going on here? Why can't I keep my server running?
(PS: The data that my Java program receives is wrong, but it receives data nonetheless. I send "1\n", and I receive null.)
Here is the code for my RPi server program:
import RPi.GPIO as GPIO
from time import sleep
import atexit
import socket
import sys
GPIO.setmode(GPIO.BOARD)
GPIO.setup(5, GPIO.IN)
GPIO.setup(7, GPIO.OUT)
def cleanup():
print("Goodbye.")
s.close()
GPIO.cleanup()
atexit.register(cleanup)
THRESHOLD= 0.3
host= sys.argv[1]
port= 42844
length= 0
def displayDot():
GPIO.output(7,True)
sleep(0.2)
GPIO.output(7,False)
def displayDash():
GPIO.output(7,True)
sleep(0.5)
GPIO.output(7,False)
try:
print("Initializing connection...")
s= socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverAddress= (host, 42844)
s.bind(serverAddress)
print("Connection initialized!")
print("Waiting for client...")
s.listen(1) #Puts the server socket into server mode
client, address= s.accept()
print(address)
while True:
if not GPIO.input(5):
length+= 0.1
GPIO.output(7,True)
s.sendall('1\n')
print("HELLO??")
else:
if length!=0:
if length>=THRESHOLD:
print("Dash") #displayDash()
else:
print("Dot") #displayDot()
s.sendall('0')
length= 0
GPIO.output(7,False)
except KeyboardInterrupt:
print("\nScript Exited.")
cleanup();
Here's the code for the Java client program:
import java.net.*;
import java.io.*;
public class MorseClient{
public static void main(String[] args) throws IOException{
String hostname= null; //Initialize
int portNumber= 0; //Initialize
try {
hostname= args[0];
portNumber= Integer.parseInt(args[1]);
}
catch(ArrayIndexOutOfBoundsException aiobe) {
System.err.println("ERROR. Please specify server address, and port number, respectively");
System.exit(1);
}
Socket redoSocket;
long initTime;
try(
Socket echoSocket= new Socket(hostname, portNumber);
PrintWriter out= new PrintWriter(echoSocket.getOutputStream(), true);
BufferedReader in= new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
BufferedReader stdin= new BufferedReader(new InputStreamReader(System.in));
){
redoSocket= echoSocket;
System.out.println("Connection made!");
String userInput= "";
//Order of priority
//Connection time= 0
//Latency= 0
//Bandwidth= 1
redoSocket.setPerformancePreferences(0,0,1);
//Optimizes reliability
redoSocket.setTrafficClass(0x04);
echoSocket.setKeepAlive(true);
String returned= "";
while(true){
returned= in.readLine();
System.out.println(returned);
if(!(returned.isEmpty())){
System.out.println(returned);
System.out.println("YEP");
}
System.out.println(returned);
if(returned==null){
System.out.println("HAHA");
System.out.println("Attempting to reconnect...");
redoSocket= new Socket(hostname,portNumber);
System.out.println(redoSocket.isConnected());
}
}
}
catch(Exception e){
if(e instanceof ConnectException || e instanceof SocketException || e instanceof NullPointerException)
System.err.println("Connection closed by server");
else
System.err.println(e.toString());
}
}
}
The output for the Pi server is:
python ServerMorse.py 192.168.1.101
Initializing connection...
Connection initialized!
Waiting for client...
('192.168.1.14', 58067)
('192.168.1.14', 58067)
Traceback (most recent call last):
File "ServerMorse.py", in <module>
s.sendall('1\n')
File "/usr/lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 32] Broken pipe
Goodbye.
And the output for the Java client:
java MorseClient 192.168.1.101 42844
Connection made!
null
Connection closed by server
Good lord, why are you writing a server with sockets? Use Flask.
http://flask.pocoo.org/
Also, pretty sure s should not be sending all. It should be like this:
conn, addr = server.accept()
conn.sendall(.... # <- this is what sends
Here is some sample code from a server I wrote with sockets once..might be useful:
def server():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
address = ('127.0.0.1', 5020)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(address)
server.listen(1)
conn, addr = server.accept()
...
...
conn.sendall(response_ok(some_stuff))
...
conn.close()
(response_ok is a function I wrote)

Java: Receiving an UDP datgram packet with multiple DatagramSockets

I am trying to implement a method that sends an UDP packet to multiple receivers. I thought that this should be doable setting setReuseAddress(true) on the receiving DatagramSocket instances.
My problem is that in certain conditions I need to limit the communication to the local computer - hence the localhost interface (useLocalhost=true in the demo code below). In such a case suddenly only the first receiver socket gets the incoming packet, the two other don't see anything.
I tested this on Windows (oracle 64bit) and Linux (OpenJDK 64bit), therefore I only see three possibilities:
This is an intended and known behavior (and I don't understand the whole mechanism - aka "bug in my brain")
There is a bug in the Java JRE
There is a bug in my code.
Does somebody have any experience on that topic and can me help to identify where the problem is located?
See below a minimal working example that demonstrates this. Note that I am using the broadcast address for simulating network packets that come from a real external host.
If everything goes right you should see three lines at the end (in this or a different order):
Thread-0 - packet received
Thread-1 - packet received
Thread-2 - packet received
 
public static void main(String[] args) throws Exception {
boolean useLocalhost = true;
InetSocketAddress addr;
String sendPacketTo = "192.168.1.255"; // we use broadcast so that packet comes from an real external address
if (useLocalhost)
sendPacketTo = "localhost"; // does not work (only listener 1 received packet)
addr = new InetSocketAddress(15002);
new MyThread(addr).start(); // Datagram socket listener 1
new MyThread(addr).start(); // Datagram socket listener 2
new MyThread(addr).start(); // Datagram socket listener 3
DatagramSocket so = new DatagramSocket();
so.setBroadcast(true); // does not change anything
so.connect(new InetSocketAddress(sendPacketTo, 15002));
so.send(new DatagramPacket("test".getBytes(), 4));
Thread.sleep(1000);
System.exit(0);
}
public static class MyThread extends Thread {
DatagramSocket socket;
public MyThread(InetSocketAddress addr) throws SocketException {
super();
setDaemon(true);
socket = new DatagramSocket(null);
socket.setReuseAddress(true);
socket.setBroadcast(true); // does not change anything
socket.bind(addr);
System.out.println("Listener started: " + socket.getLocalAddress());
}
public void run() {
byte[] buf = new byte[10];
DatagramPacket p = new DatagramPacket(buf, buf.length);
try {
socket.receive(p);
System.out.println(Thread.currentThread().getName() + " - packet received");
} catch (IOException e) {
e.printStackTrace();
}
}
}
192.168.1.255 is a broadcast address, so the datagram is broadcast, under the rules for UDP broadcast. 127.0.0.1 is a unicast address, so the packet is unicast. So you get different behaviour.
As #DavidSchwartz commented, your code is a mixture. Connecting to a broadcast address for example doesn't have a lot of meaning, and neither does binding to it. I think what you are looking for is multicast.
You can use multicast on localhost
However, there are several things you need to be careful of to make it work.
example:
lo0 (127.0.0.1)
en0 (192.168.0.111)
en1 (10.1.0.111)
for each interface 2 separate sockets, one for receiving, one for
sending. In the above example this means creating a total of 6
sockets.
Never bind() a socket that will send multicast UDP packets.
Always bind() a socket that will receive multicast UDP packets.
Never try to setsockopt() or reconfigure multicast sockets after you call bind()
Instead, when machine's interfaces change due to cables being unplugged/plugged,
destroy all send/receive multicast sockets and recreate them.
sample code:
iMulticastSocketInterfaceIPAddress would be one of the three interfaces
/* use setsockopt() to request that the kernel join a multicast group */
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr=inet_addr( "239.192.0.133" );
myAddress.sin_addr.s_addr = mreq.imr_multiaddr.s_addr;
mreq.imr_interface.s_addr=( htonl(iMulticastSocketInterfaceIPAddress) );
theErr = setsockopt( CFSocketGetNative( mSocketBroadcast ) ,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));

Add a timeout when creating a new Socket

I have a local network with DHCP and a few PCs. One of these should be my Server and get automatically connected to all others (clients). My idea was this:
First, I create a server on every client (CServer) that is listening for a client programm from the server (SClient). When the SClient connects to a CServer, the SClient sends the CServer his IP, so he knows there will be the server on this IP. Then after trying all IPs in his IP range (e.g. 192.168.1.xxx), he starts the real server and all the clients connect to the known server IP.
But when I try the following, the SClient just freezes at the first IP, when trying to connect to 192.168.1.0. How can i define a timeout or something similar that lets the SClient drop the unsuccessful connection and going on with 192.168.1.1?
import java.lang.*;
import java.io.*;
import java.net.*;
class SClient {
public SClient() {
for(int i = 120; i < 125; i++){
try{
InetAddress addr = InetAddress.getLocalHost();
String addrs = addr+"";
String ip = addrs.substring(addrs.indexOf("/")+1);
Socket s1 = new Socket("192.168.1." + i, 1254);
OutputStream s1out = s1.getOutputStream();
DataOutputStream dos = new DataOutputStream (s1out);
dos.writeUTF(ip);
dos.close();
s1out.close();
s1.close();
}catch(IOException e){}
}
}
}
and
import java.lang.*;
import java.io.*;
import java.net.*;
class CServer {
public CServer() throws IOException{
ServerSocket s = new ServerSocket(1254);
while(true){
Socket s1=s.accept();
InputStream s1In = s1.getInputStream();
DataInputStream dis = new DataInputStream(s1In);
String st = new String (dis.readUTF());
System.out.println(st);
dis.close();
s1In.close();
s1.close();
}
}
}
I've found a solution for my problem. It was just initializing the Socket not with
Socket s1 = new Socket("192.168.1." + i, 1254);
but with
Socket s1 = new Socket();
s1.setSoTimeout(200);
s1.connect(new InetSocketAddress("192.168.1." + i, 1254), 200);
Thanks anyway!
It's much easier to do this with UDP. The general logic would be:
Identify a well known port for 'discovery'
Any machine that starts up sends out a 'Query Master Server' message
If a response is not received to that message within a time frame
you define, then the machine that sent it automatically designates
itself as being the server.
Henceforth, any machine that sends out a 'Query Master Server'
message will get a response back from the master, with its IP
address and a 'communication port'
Connect from the new machine to the server on the communication port
and start sending messages.
You might run into situations where more than one server thinks it is the master in this scenario, and then you would need a conflict resolution process, but the outline should give you a general idea of a process that will work for you.

Categories