UDP multicast sending on wrong NIC (Java, Mac OS X) - java

While working on a Java application under Mac OS X (Lion, 10.7.2, Java version "1.6.0_29"), I'm running into a strange problem while trying to send multicast UDP datagrams. The packets are only being sent on one NIC, and I have no control over which one.
The following example code illustrates what I am trying to do:
public class MCast {
public static void main(String[] args) throws IOException {
InetAddress multicastAddr = InetAddress.getByName("224.0.0.1");
int port = 58680;
byte[] data = "test".getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length, multicastAddr, port);
MulticastSocket socket = new MulticastSocket();
socket.joinGroup(multicastAddr);
socket.setNetworkInterface(NetworkInterface.getByName("en0"));
socket.send(packet);
System.out.println("Packet sent.");
}
}
Whilst executing this code, I am using Wireshark to examine all the traffic going out on en0. No packets are sent on the port specified. However, said packets do appear on the trace for en1.
When I disable en1, the packets go out on en0 properly.
I'm at a loss here. Does anyone know what's going on?

Multicast output interface is decided by the current routing table at the time you do the group join. In most cases that means default route, hence the en0. Adding an explicit route would help, but you can just reverse the two lines in your code to be:
socket.setNetworkInterface(NetworkInterface.getByName("en0"));
socket.joinGroup(multicastAddr);
Also, you don't need to join (nor bind()) the group if you are only sending and not listening to that multicast traffic. Instead, connect() to the group address.

You can pass a an address to the constructor of MulticastSocket. You can use it to bind it to the address you want.

Related

Is there a way in java to listen to UDP broadcast msgs AND get the source IP address and Mac that the message was sent from

I need to create a java application that functions similar to WireShark in that it is able to listen to UDP traffic. But I need to know more about the datagram than just the data, I need to know the sender's IP and mac address. It there a way to accomplish this in Java?
Here is a screen shot of what I am talking about from Wireshark
WireShark Image
Notice the Ethernet II stack has the mac and the Internet Protocoal Version 4 has Src Ip.
The use case of this is that there are multiple devices on the network emitting data (as in this msg is STS:ANT:OK:8). But I need to know what the mac and IP is of this sender so I can categorize the msgs by sender and mac. (technically I can have duplicate IPs on the network.) So both are needed. This also allows me to show error cases where this is occurring.
IP protocol is underlying tool for UDP/TCP or other layers. You may need to capture the packets and listen to specific port (filter IP messages for UDP port)
Otherwise you can use external server commands to get it done more efficiently.
Here is an example (from How could I sniff network traffic in Java?):
public static void main(String[] args) throws Exception {
File f = new File("sample.pcap");
EthernetDecoder eth = new EthernetDecoder();
IpDecoder ip = new IpDecoder();
TcpDecoder tcp = new TcpDecoder(new TcpPortProtocolMapper());
UdpDecoder udp = new UdpDecoder(new UdpPortProtocolMapper());
eth.register(EthernetType.IPV4, ip);
ip.register(InternetProtocol.TCP, tcp);
ip.register(InternetProtocol.UDP, udp);
PcapInputStream is = new PcapFileInputStream(f);
while (true) {
// getPacket() will throws EOFException and you should call is.close()
PcapPacket packet = is.getPacket();
eth.decode(packet);
}
}

Can't receive UDP Packets in Java

I'm trying to receive some UDP packets on a Java MulticastSocket.
I can see the packets arriving in wireshark and the code works for other people, but not for me.
I honestly don't know what I'm doing wrong.
I have disabled my firewall and antivirus.
I'm running Windows 10 and IntelliJ 2017.2.5.
I'm creating a MulticastSocket with a portnumber (2000 or 2001) as a parameter.
My JRE is 1.8.0_152 and I'm using the JDK supplied by JetBrains.
This is how I'm creating the MulticastSocket:
this.socket = new MulticastSocket(this.portNum);
//this.socket = new MulticastSocket();
this.socket.setReceiveBufferSize(1 << 17);
this.socket.joinGroup(InetAddress.getByName(this.ip));
And, in a while loop, I try to receive data like this:
while(!this.socket.isClosed())
{
byte[] buffer = new byte[500];
DatagramPacket incomingPacket = new DatagramPacket(buffer, buffer.length);
try
{
this.socket.receive(incomingPacket);
...
Things to check are:
Make sure you bind your UDP socket to the interface you want to receive on. This is different for Windows and for Linux. For Windows: Bind to the IP address of the interface you want to receive on. On Linux bind to 0.0.0.0 to receive on all interfaces. (Receiving just on a specific interface is non-trivial on Linux.)
Make sure your this.ip is your multicast address, e.g. 224.1.2.3.
The problem has been solved, it was an unrelated concurrency issue.

DatagramSocket Broadcast Behavior (Windows vs. Linux)

Backstory:
I have a wireless device which creates it's own SSID, assigns itself an IP address using auto-ip, and begins broadcasting discovery information to 255.255.255.255. (unfortunately, it does not easily support multicast)
What I'm trying to do:
I need to be able to receive the discovery information, then send configuration information to the device. The problem is, with auto-ip, the "IP negotiation" process can take minutes on Windows, etc (during which time I can see the broadcasts and can even send broadcast information back to the device).
So I enumerate all connected network interfaces (can't directly tell which will be used to talk to the device), create a DatagramSocket for each of their addresses, then start listening. If I receive the discovery information via a particular socket, I know I can use that same socket to send data back to the device. This works on Windows.
The problem:
On Linux and OSX, the following code does not receive broadcast packets:
byte[] addr = {(byte)169, (byte)254, (byte)6, (byte)215};
DatagramSocket foo = new DatagramSocket(new InetSocketAddress(InetAddress.getByAddress(addr), PORT_NUM));
while (true)
{
byte[] buf = new byte[256];
DatagramPacket pct = new DatagramPacket(buf, buf.length);
foo.receive(pct);
System.out.println( IoBuffer.wrap(buf).getHexDump() );
}
In order to receive broadcast packets (on Linux/OSX), I need to create my DatagramSocket using:
DatagramSocket foo = new DatagramSocket(PORT_NUM);
However, when I then use this socket to send data back to the device, the packet is routed by the OS (I'm assuming) and since the interface of interest may be in the middle of auto-ip negotiation, fails.
Thoughts on the following?
How to get the "working" Windows behavior to happen on Linux/OSX
A better way to handle this process
Thanks in advance!
I do not think this is the problem with the code. Have you checked if OSX/Linux has correctly allowed those address / port number through their firewalls? I had this simple problem too in the past =P..
FYI, there is a nice technology called Zero-configuration which was built to solve this problem. It is very easy to learn so I recommend you to having a look at that as well.
Good luck.

Sending Java Packets to Python Server?

I'm just starting to learn about sending UDP packets, and I'm running into a problem. I've written a Java client and server which easily communicate with each other, and I've done a Python client/server combo, but I'm not sure how to send a UDP packet from Java and receive it in Python. Here's what I have for the Java client:
import java.io.*;
import java.net.*;
public class testclient {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket();
byte[] buf = new byte[256];
InetAddress address = InetAddress.getLocalHost();
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, Integer.parseInt(args[0]));
System.out.println("Sending...");
socket.send(packet);
System.out.println("Receiving...");
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String received = new String(packet.getData(), 0, packet.getLength());
System.out.println(received);
System.out.println("Done!");
socket.close();
}
}
And the Python server:
from sys import *
from socket import *
host = gethostname()
port = int(argv[1])
address = (host, port)
print "Binding..."
sock = socket(AF_INET, SOCK_DGRAM)
sock.bind(address)
print "Receiving..."
data, client = sock.recvfrom(256)
print "Sending to", client
sock.sendto("Hi", client)
print "Closing..."
sock.close()
print "Done!"
All I'm trying to do here is send a request from the Java client to the Python server, then have the Python server send "Hi" back to the Java client, and have the client print the string. What happens for me is the client sends the packet, and the server waits at the sock.recvfrom(256) and never receives the packet (or that's what it looks like anyway).
Any ideas? I'm guessing it's some difference between how Java and Python handle the packets but, I'm not sure.
EDIT: Just for clarification, the port number is passed in via command-line arguments for both of these applications.
The problem must be within your code, they should be able to communicate: this
is a good example of writing a client server pair in java.
So, to start, I'm on Ubuntu 10.10.
I went into /etc/hosts and it looks like 127.0.0.1 was assigned to localhost.localdomain, while 127.0.1.1 was assigned to my machine's name. So, Python was using the localhost address, while Java was using my machine name address. I changed localhost to my machine name and everything works now.
Thanks everybody for trying to help!
In Java, I see where you create the packet, but I don't see you actually putting any data into the packet using setData before sending it.

Multicast in java

I am trying to write a simple multicast trial.
I used a standard code (sender and reciever).
I tried a few different standard pieces of code. it appears that the receiving code is stuck on receive (as if it's not receving anything).
receive side:
byte[] b = new byte[3];
DatagramPacket dgram = new DatagramPacket(b, b.length);
MulticastSocket socket =
new MulticastSocket(4545); // must bind receive side
socket.joinGroup(InetAddress.getByName("226.100.100.125"));
while(true) {
socket.receive(dgram); // blocks until a datagram is received
System.err.println("Received " + dgram.getLength() +
" bytes from " + dgram.getAddress());
dgram.setLength(b.length); // must reset length field!
}
sending side:
DatagramSocket socket = new DatagramSocket();
byte[] b = new byte[]{(byte)1,(byte)5,(byte)3};
DatagramPacket dgram;
dgram = new DatagramPacket(b, b.length,
InetAddress.getByName("226.100.100.125"), 4545);
System.err.println("Sending " + b.length + " bytes to " +
dgram.getAddress() + ':' + dgram.getPort());
while(true) {
System.err.print(".");
socket.send(dgram);
Thread.sleep(1000);
}
What is wrong with my code?
*I tried alot of different IPs also*
thanks for the help.
Try receiving in from the same IP but sending to localhost. If this works, then it's your router that is the problem as it doesn't support multicasting. If this still doesn't work then it's the IP address. try something in the 233.x.x.x - 239.x.x.x range.
I ran your code on my computer and it works fine as is, and also works if I changed the send address to localhost. Sounds like this is a problem with your router and not your code.
The network 239.0.0.0/8 is designated for administrator multi-cast traffic. If all of your machines are on the same network segment, you can use an ip in this network to play around with multi-casting.
Here is the RFC defining these:
https://www.rfc-editor.org/rfc/rfc2365
As far as sending goes... Your code should look something like this:
DatagramPacket p = ...
MulticastSocket s = new MulticastSocket(LISTENPORT);
InetAddress group = InetAddress.getByName(LISTENIP);
s.joinGroup(group);
s.send(p);
s.leaveGroup(group);
Multicast usually (in a real network) depends on the router's support. From what i know in general you can't really count on it being supported properly. I would try to send packets from a different client (command line or something else) to see if the server side is binding properly or not.
On the other side if you look here: http://www.iana.org/assignments/multicast-addresses/multicast-addresses.xml it sais that the 226 address block is marked as reserved. The referenced RFC sais:
Use of IANA Reserved Addresses
Applications MUST NOT use
addressing in the IANA reserved
blocks.
That might have something to do with it also.
You shall not use same port, try different port and create one socket for receiving and second one for sending.
When this happens on my Linux boxes I check to make sure that
1) there is a route for 224.0.0.0/4 on the correct interfaces
2) the source IP address matches one of the routes for that interface
#2 is the stickiest in my lab. If my eth1 only has a route for 10.77.4.0/24 and some box is transmitting from 10.78.5.15, then linux discards it as a "martian packet".

Categories

Resources