I'm trying to send a UDP broadcast on IP address "255.255.255.255" for device discovery in my network. The program executes, but I don't see anything in Wireshark. when I'm changing the IP address to a known IP in my network, I can see the packets in Wireshark. what's going on ?
This is my code:
public static void main(String args[]) throws Exception
{
String Broadcastaddress = new String("255.255.255.255");
int port = 9876;
DatagramSocket serverSocket = new DatagramSocket();
serverSocket.setBroadcast(true);
InetAddress IPAddress = InetAddress.getByName(Broadcastaddress);
System.out.println("Sending Discovery message to " + IPAddress + "Via UDP port " + port);
byte[] sendData = new byte[4];
sendData[0] = 'F';
sendData[1] = 'I';
sendData[2] = 'N';
sendData[3] = 'D';
DatagramPacket sendPacket = new DatagramPacket(sendData,sendData.length,IPAddress,port);
while (true)
{
serverSocket.send(sendPacket);
System.out.println("Packet sent");
}
}
OK, I found an answer. Windows 7 doesn't support 255.255.255.255 broadcasts anymore, apparently it was an opening to various threats. To broadcast, one needs to use a different approach.
This is a small explenation from Wikipedia:
The broadcast address for an IPv4 host can be obtained by performing a bitwise logical OR operation between the bit complement of the subnet mask and the host's IP address.
Example: to broadcast a packet to an entire IPv4 subnet using the private IP address space 100.16.0.0/12, which has the subnet mask 255.240.0.0, the broadcast address is: 100.16.0.0 | 0.15.255.255 = 100.31.255.255.
A special definition exists for the IP broadcast address 255.255.255.255. It is the broadcast address of the zero network or 0.0.0.0, which in Internet Protocol standards stands for this network, i.e. the local network. Transmission to this address is limited by definition, in that it is never forwarded by the routers connecting the local network to the Internet.
Related
There are two Groovy sub programs below sending messages to each other via plain UDP sockets. They does receive the messages successfully when they are sent to 127.0.0.1. But the messages aren't received when sending them to the public IP address (the machine is behind NAT).
Why the hole is not punched? And how to fix that?
I tried querying a public STUN server via a Java library earlier but it responded with the same public IP address to me, so I use wtfismyip.com here.
class GroovyTest {
static String PUBLIC_IP = new URL('https://wtfismyip.com/text').text.trim()
//static String PUBLIC_IP = '127.0.0.1' // works fine
static void main(String[] args) {
runInstance(11111, 22222)
runInstance(22222, 11111)
}
static void runInstance(int thisPort, int anotherPort) {
def socket = new DatagramSocket(thisPort)
Thread.start {
// message listener
byte[] buf = new byte[1024]
while (true) {
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
InetAddress remoteAddr = packet.getAddress();
int remotePort = packet.getPort();
String sentence = new String(packet.getData(), 0, packet.length);
println("server-$thisPort: received [$sentence] from ${remoteAddr.hostAddress}:${remotePort}")
}
}
Thread.start {
// message sender
while (true) {
println("client-$thisPort: sending to ${PUBLIC_IP}:${anotherPort}...")
byte[] buf = ("Hello " + System.currentTimeMillis()).bytes
DatagramPacket packet = new DatagramPacket(buf, buf.length, InetAddress.getByName(PUBLIC_IP), anotherPort)
socket.send(packet)
Thread.sleep(2000)
}
}
}
}
Your problem stems from the fact that the IP address returned by wtfismyip is the IP address of the router on your network, which is not assigned to your computer. When you try and send a datagram to your router's public IP you'll probably get and ICMP Destination Unreachable error message from your router. If you need this behavior, your router may have some port forwarding capabilities that can forward inbound UDP traffic to your local IP address.
I have been successfully replying to UDP packets behind a NAT router by simply taking the address and port details from the UDP packet I'm responding to...
DatagramSocket socket = new DatagramSocket(port);
DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
socket.receive(receivePacket);
DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length,
receivePacket.getAddress(), receivePacket.getPort());
socket.send(sendPacket);
The code is more robust in that it doesn't matter where the packet came from, or any address translation which occurred along the way. It will always reply to the right place.
I'v also noticed you are using two different port numbers. "thisPort" and "anotherPort". As far as I know, the hole punching will only work if you reply on the same port number. This makes sense for security reasons.
The marine robot on top of my head, pictured in my avatar, uses this UDP hole punching technique.
I have a server with many IP addresses, and a UDP socket bound to 0.0.0.0 so I can receive UDP from any of them. How can I specify the source IP address to use in the UDP packets I am sending? My current implementation is using NIO so maybe using the DatagramChannel to perform the sending is the problem.
I gave up on a clean solution and just use a bound DatagramSocket per IP address on server that can be used to send UDP with the specific source IP for the outbound packets.
The following program demonstrates that your requirement is imaginary. It shows that a datagram packet originated at a DatagramSocket bound to 0.0.0.0 is delivered with a source-address of 127.0.0.1.
public static void main(String[] args) throws IOException
{
DatagramSocket ds1 = new DatagramSocket(0);
int port = ds1.getLocalPort();
System.out.println(ds1.getLocalAddress());
DatagramSocket ds2 = new DatagramSocket();
byte[] bytes = {0x01};
SocketAddress sa = new InetSocketAddress("localhost", port);
DatagramPacket dp = new DatagramPacket(bytes, 0, bytes.length, sa);
ds2.send(dp);
ds1.receive(dp);
ds2.send(dp);
ds2.receive(dp);
System.out.println(dp.getAddress());
}
I have UDP server and client, my code works inside home with internal IPs such as 192.168.0.X. If I put my code inside my online server with external IP (X.X.X.X) server receives and send but Android can only send and doesn't receive. What is the problem?
Android send code :
byte[] sendData = new byte[1024];
try {
DatagramSocket serverSocket = new DatagramSocket(1500);
InetAddress IP = InetAddress.getByName("My server IP");
String invia = "I am Android";
sendData = invia.getBytes();
DatagramPacket send = new DatagramPacket(sendData, sendData.length, IP, 1500);
serverSocket.send(send);
}
Android receive code :
byte[] receiveData = new byte[1024];
try {
DatagramSocket serverSocket = new DatagramSocket(1600);
while (true) {
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData());
Log.i("FROM SERVER:", "" + sentence);
}
} catch (Exception e) {
}
Server code :
DatagramSocket serverSocket = new DatagramSocket(1500);
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
while(true)
{
/** receive **/
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData());
System.out.println("RECEIVED: " + sentence);
/** send **/
InetAddress IPAddress = receivePacket.getAddress();
int port = receivePacket.getPort();
sentence = "I am PC";
sendData = sentence.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 1600);
serverSocket.send(sendPacket);
}
Why does it not work externally, yet it does locally ?
You have to understand NATPAT.
Even running a webserver on your home pc will not work.
When you browse with your browser, you are taking initiative and send a GET to a server using its IP# and port. Your local IP# behind the NATPAT router is not unique across the internet, it is unique only behind your router. So your local ip# of your pc cannot be used to talk to the server. So your router is going to build an internal table based on your local ip# and local port and a port he allocates himself, he then forwards your request to the webserver you want to talk to but using your public ip# and that allocated port. when the server replies he is going to reply to your public ip# and that allocated port. Your NATPAT router sees the reply and know ah it is a reply on that allocated port, it looks in his internal table and forwards to the local ip# and local port that he remembered in his lookup table.
If you host a server behind a NAT PAT router, you cannot get any incoming messages to your webserver because the table is empty.
And that is the problem with your android listening on port 1600. He never sent anything on that port and ip# so your router does not know for whom it is.
It works locally because then all your local ip# are used that your DHCP enabled router has assigned to your devices. And there is never any translation needed to the public IP# that your ISP has provided you with.
Read this :
http://searchnetworking.techtarget.com/definition/Port-Address-Translation-PAT
and this :
Following is an illustration. Let's say the ISP Public IP address is 3.12.62.154. The objective is to run public-accessible web server that run on standard protocol TCP port 80 (the web port). The local network Private Subnet is 10.0.0.0/24 where the server IP address is 10.0.0.10. For the public access, the 10.0.0.10 will be PAT-ed to the 3.12.62.154 on TCP port 80.
When users on the Internet try to connect to the public web server, those users connect to the 3.12.62.154 IP address and not to the 10.0.0.10 IP address. The reason is that on the Internet, the web server is seen as the 3.12.62.154 IP address. The 10.0.0.10 IP address is only seen within local LAN.
from here : http://www.dslreports.com/faq/13449
If you don't understand any of this, stop trying, start reading instead.
I want to do UDP Hole Punching with two clients with the help of a server with a static IP. The server waits for the two clients on port 7070 and 7071. After that it sends the IP address and port to each other. This part is working fine. But I'm not able to establish a communication between the two clients. I tried the code in different Wifi networks and in 3G mobile network. The client program throws the IO-Exception "No route to host".
The client code is used for both clients. Once executed with port 7070 and once with 7071.
Do you think I've implemented the UDP hole punching concept correctly? Any ideas to make it work?
Here's the server code first, followed by the client code.
Thank you for help.
Code of server:
public class UDPHolePunchingServer {
public static void main(String args[]) throws Exception {
// Waiting for Connection of Client1 on Port 7070
// ////////////////////////////////////////////////
// open serverSocket on Port 7070
DatagramSocket serverSocket1 = new DatagramSocket(7070);
System.out.println("Waiting for Client 1 on Port "
+ serverSocket1.getLocalPort());
// receive Data
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
serverSocket1.receive(receivePacket);
// Get IP-Address and Port of Client1
InetAddress IPAddress1 = receivePacket.getAddress();
int port1 = receivePacket.getPort();
String msgInfoOfClient1 = IPAddress1 + "-" + port1 + "-";
System.out.println("Client1: " + msgInfoOfClient1);
// Waiting for Connection of Client2 on Port 7071
// ////////////////////////////////////////////////
// open serverSocket on Port 7071
DatagramSocket serverSocket2 = new DatagramSocket(7071);
System.out.println("Waiting for Client 2 on Port "
+ serverSocket2.getLocalPort());
// receive Data
receivePacket = new DatagramPacket(new byte[1024], 1024);
serverSocket2.receive(receivePacket);
// GetIP-Address and Port of Client1
InetAddress IPAddress2 = receivePacket.getAddress();
int port2 = receivePacket.getPort();
String msgInfoOfClient2 = IPAddress2 + "-" + port2 + "-";
System.out.println("Client2:" + msgInfoOfClient2);
// Send the Information to the other Client
// /////////////////////////////////////////////////
// Send Information of Client2 to Client1
serverSocket1.send(new DatagramPacket(msgInfoOfClient2.getBytes(),
msgInfoOfClient2.getBytes().length, IPAddress1, port1));
// Send Infos of Client1 to Client2
serverSocket2.send(new DatagramPacket(msgInfoOfClient1.getBytes(),
msgInfoOfClient1.getBytes().length, IPAddress2, port2));
//close Sockets
serverSocket1.close();
serverSocket2.close();
}
Code of client
public class UDPHolePunchingClient {
public static void main(String[] args) throws Exception {
// prepare Socket
DatagramSocket clientSocket = new DatagramSocket();
// prepare Data
byte[] sendData = "Hello".getBytes();
// send Data to Server with fix IP (X.X.X.X)
// Client1 uses port 7070, Client2 uses port 7071
DatagramPacket sendPacket = new DatagramPacket(sendData,
sendData.length, InetAddress.getByName("X.X.X.X"), 7070);
clientSocket.send(sendPacket);
// receive Data ==> Format:"<IP of other Client>-<Port of other Client>"
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
clientSocket.receive(receivePacket);
// Convert Response to IP and Port
String response = new String(receivePacket.getData());
String[] splitResponse = response.split("-");
InetAddress ip = InetAddress.getByName(splitResponse[0].substring(1));
int port = Integer.parseInt(splitResponse[1]);
// output converted Data for check
System.out.println("IP: " + ip + " PORT: " + port);
// close socket and open new socket with SAME localport
int localPort = clientSocket.getLocalPort();
clientSocket.close();
clientSocket = new DatagramSocket(localPort);
// set Timeout for receiving Data
clientSocket.setSoTimeout(1000);
// send 5000 Messages for testing
for (int i = 0; i < 5000; i++) {
// send Message to other client
sendData = ("Datapacket(" + i + ")").getBytes();
sendPacket = new DatagramPacket(sendData, sendData.length, ip, port);
clientSocket.send(sendPacket);
// receive Message from other client
try {
receivePacket.setData(new byte[1024]);
clientSocket.receive(receivePacket);
System.out.println("REC: "
+ new String(receivePacket.getData()));
} catch (Exception e) {
System.out.println("SERVER TIMED OUT");
}
}
// close connection
clientSocket.close();
}
UPDATE
The code is generally working. I've tried it in two different home networks now and it's working. But it isn't working in my 3G or university network. In 3G, I verified that the NAT is mapping the two ports (the client port and by the router assigned port) together again, even after closing and opening the clientSocket. Has anyone an idea why it isn't working then?
UDP hole punching can't be achieved with all types of NAT. There is no universal or reliable way defined for all types of NAT. It is even very difficult for symmetric NAT.
Depending on the NAT behaviour, the port mapping could be different for different devices sending the UDP packets.
Like, If A sends a UDP packet to B, it may get some port like 50000. But if A sends a UDP packet to C, then it may get a different mapping like 50002. So, in your case sending a packet to server may give a client some port but sending a packet to other client may give some other port.
You shall read more about NAT behaviour here:
https://www.rfc-editor.org/rfc/rfc4787
https://www.rfc-editor.org/rfc/rfc5128
UDP hole punching not going through on 3G
For symmetric NAT (3G network connecting to a different mobile network), you need to do Multi-UDP hole punching.
See:
https://drive.google.com/file/d/0B1IimJ20gG0SY2NvaE4wRVVMbG8/view?usp=sharing
http://tools.ietf.org/id/draft-takeda-symmetric-nat-traversal-00.txt
https://www.goto.info.waseda.ac.jp/~wei/file/wei-apan-v10.pdf
http://journals.sfu.ca/apan/index.php/apan/article/view/75/pdf_31
Either that or relay all the data through a TURN server.
You rightly use a rendezvous server to inform each node of the others IP / port based on the UDP connection. However using the public IP and port which is the combination which will is obtained by the connection as you have, means that in scenarios where both hosts exist on the same private network hairpin translation is required by the NAT which is sometimes not supported.
To remedy this you can send the IP and port your node believes itself to have in the message to the server (private ip / port) and include this in the information each node receives on the other. Then attempt a connection on both the public combination (the one you are using) and the one I just mentioned and just use the first one which is successfully established.
I need to get the IP address for remote hosts. I tried the following and works fine:
socket = factory.createSocket(hostName, port);
InetAddress remoteIP = socket.getInetAddress();
String[] remoteIPOnly = remoteIP.toString().split("\\/");
System.out.println("Remote IP is: "+remoteIPOnly[1]);
But, I need a way where I don't have to specify a port number. I.e, I need the IP for a remote host despite the port number. Is this possible ? Is it possible to get the IP without creating socket from the first place ?
Try this:
InetAddress inetAddress = InetAddress.getByName("www.google.com");
byte[] raw = inetAddress.getAddress();
The byte array now contains the IP addresses bytes.
Use getHostAddress() as below:
InetAddress inetAddress = InetAddress.getByName("www.google.com");
String ipAddress = inetAddress.getHostAddress();
System.out.println(ipAddress );//prints 66.152.109.61