While searching the internet for existing solutions I bounced over the so called "Nat Holepunch".
See the article on wikipedia .This actually made that much sense to me, I started developing my own proof of concept.
Details
At first I will describe the Server, as it is the basic component. This is the so called "Relay Server".
RelayServer.java
package de.boehme.app.natholepunch;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.HashSet;
import java.util.Set;
import de.boehme.app.natholepunch.dto.NATDevice;
public class RelayServer {
private Set<NATDevice> inquiredComputers = new HashSet<NATDevice>();
public static void main(String[] args) {
RelayServer rs = new RelayServer();
try {
rs.startServer();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void startServer() throws IOException, InterruptedException {
DatagramSocket serverSocket = new DatagramSocket(12345);
byte[] receiveData = new byte[50];
while (true) {
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
System.out.println("Listening...");
serverSocket.receive(receivePacket);
String data = new String(receivePacket.getData());
//NAT Device 1
InetAddress incomingIPAddress = receivePacket.getAddress();
int port = receivePacket.getPort();
NATDevice startComp = new NATDevice();
startComp.setPortOfNAT(port);
startComp.setPublicIpOfNAT(incomingIPAddress);
//NAT Device 2
String accordingIP = data.substring(0, data.indexOf(0));
// String accordingPort = data.substring(data.indexOf(':')+1, data.indexOf(0));
NATDevice destinationComp = new NATDevice();
// destinationComp.setPortOfNAT(Integer.valueOf(accordingPort));
destinationComp.setPublicIpOfNAT(InetAddress.getByName(accordingIP));
System.out.println("Checking: "+startComp.getPublicIpOfNAT()+":"+startComp.getPortOfNAT()+" TO: "+destinationComp.getPublicIpOfNAT());
//check here if a matching entry is already present
NATDevice matchComp = checkMatchingNATDevice(destinationComp);
if(matchComp != null){
System.out.println("Already present.. now sending packets to both of them...");
//send to the socket from previously saved first NAT Device infos from the second NAT Device
sendPacket(serverSocket, matchComp, startComp);
Thread.sleep(1000);
sendPacket(serverSocket, startComp, matchComp);
inquiredComputers.remove(startComp);
inquiredComputers.remove(matchComp);
} else{
System.out.println("Adding "+startComp.getPublicIpOfNAT()+":"+startComp.getPortOfNAT()+" AND "+destinationComp.getPublicIpOfNAT()+" for later matching");
inquiredComputers.add(startComp);
}
}
// serverSocket.close();
}
private synchronized NATDevice checkMatchingNATDevice(NATDevice comp){
for(NATDevice c : inquiredComputers){
if(c.getPublicIpOfNAT().equals(comp.getPublicIpOfNAT())){
return c;
}
}
return null;
}
private synchronized void sendPacket(DatagramSocket socket, NATDevice natDeviceHome, NATDevice natDeviceRemote) throws IOException{
byte[] sendData = new byte[50];
InetAddress homeIPAddress = natDeviceHome.getPublicIpOfNAT();
int homePort = natDeviceHome.getPortOfNAT();
//now the remote destination
InetAddress destIPAddress = natDeviceRemote.getPublicIpOfNAT();
int destPort = natDeviceRemote.getPortOfNAT();
String data = destIPAddress.getHostAddress()+":"+destPort+"-"+homePort;
sendData = data.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, homeIPAddress, homePort);
socket.send(sendPacket);
}
}
Explanation of the code:
The server should be run on a machine that can accept connections on port 12345. This is because the server listens on this specific port number.
Note: As this is only for development purposes the port number was hardcoded, i.e. when in production systems you would create it dynamically.
Going onwards to the most important method: startServer();
In the while loop we can see that on every connection attempt we differentiate between NAT Device 1 and NAT Device 2. How does this work? From the received packet we get a port number and an IP Adress. Both are needed to create a new object "NatDevice". In the data part of the packet we can extract the information we need to get the according second NAT Device.
The combination of NAT Device 1 to NAT Device 2 will be then added to an internal HashSet. That means when now NAT Device 2 connects to the server and the according NAT Device 1 is already present both NAT Devices get informed with the connection credentials of their connection peer.
How does the Client Side look like?
ClientBehindNAT.java
package de.boehme.app.natholepunch;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
public class ClientBehindNAT {
private String relayServerIP;
private String destinationIP;
private InetAddress clientIP;
private int socketTimeout;
public static void main(String[] args) {
ClientBehindNAT c = new ClientBehindNAT();
boolean result = c.parseInput(args);
if(result == true){
try {
c.createHole(true);
} catch (SocketTimeoutException e) {
System.out.println("Timeout occured... Try again?");
} catch (IOException e) {
e.printStackTrace();
}
} else{
System.err.println("Usage: <Relay Server IP> (e.g. 192.168.40.1) <Destination IP> (e.g. 192.168.40.128) <Timeout> (in milliseconds)");
}
}
/**
* Main method used for outer access
* @param standAlone
* @return the free NAT port of the Firewall
* @throws IOException
*/
public synchronized int createConnectionToPeer(String relayServerIP, String destinationIP, int socketTimeout) throws SocketTimeoutException, IOException{
this.relayServerIP = relayServerIP;
this.destinationIP = destinationIP;
this.socketTimeout = socketTimeout;
return createHole(false);
}
private boolean parseInput(String[] args){
if(args.length < 3){
return false;
} else if(args[0].equals("") || args[1].equals("") || args[2].equals("")){
return false;
}else{
relayServerIP = args[0];
destinationIP = args[1];
socketTimeout = Integer.valueOf(args[2]);
return true;
}
}
private int createHole(boolean standAlone) throws SocketTimeoutException, IOException{
// InetAddress serverIPAddress = InetAddress.getByName("192.168.40.1");
clientIP = InetAddress.getLocalHost();
byte[] addrInByte = createInternetAddressFromString(relayServerIP);//{(byte) 192, (byte) 168, 40, 1};
InetAddress serverIPAddress = InetAddress.getByAddress(addrInByte);
int port = 12345;
String data = destinationIP;
System.out.println("Try to send: "+data+" TO: "+serverIPAddress+" ON PORT: "+port);
//first send UDP packet to the relay server
DatagramSocket clientSocket = new DatagramSocket();
clientSocket.setSoTimeout(socketTimeout);
sendPacket(clientSocket, serverIPAddress, port, data);
//now wait for the answer of the server
String peer = receivePacket(clientSocket);
clientSocket.close();
//need to make sure all had the chance to receive packets with infos
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return initPeerConnection(peer, standAlone);
}
private byte[] createInternetAddressFromString(String address){
byte[] inetAddressBytes = new byte[4];
int index = address.indexOf('.');
int i=0;
while((index = address.indexOf('.')) != -1){
int part = Integer.valueOf(address.substring(0, index));
inetAddressBytes[i] = (byte) part;
address = address.substring(index+1);
i++;
}
inetAddressBytes[i] = (byte) Integer.valueOf(address).intValue();
return inetAddressBytes;
}
private synchronized void sendPacket(DatagramSocket socket, InetAddress destIPAddress, int port, String data) throws IOException{
byte[] sendData = new byte[data.length()];
sendData = data.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData,
sendData.length, destIPAddress, port);
socket.send(sendPacket);
}
private synchronized String receivePacket(DatagramSocket socket) throws SocketTimeoutException, IOException{
byte[] receiveData = new byte[50];
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
socket.receive(receivePacket);
String answerFromServer = new String(receivePacket.getData());
answerFromServer = answerFromServer.substring(0, answerFromServer.indexOf(0));
System.out.println(clientIP+" GOT FROM SERVER:" + answerFromServer);
return answerFromServer;
}
private synchronized int initPeerConnection(String peer, boolean standAlone) throws IOException{
String accordingIP = peer.substring(0, peer.indexOf(':'));
String accordingPort = peer.substring(peer.indexOf(':')+1, peer.indexOf('-'));
InetAddress destIPAddress = InetAddress.getByName(accordingIP);
int remotePort = Integer.valueOf(accordingPort);
int natPort = Integer.valueOf(peer.substring(peer.indexOf('-')+1));
//this only applies in stand-alone mode
if(standAlone){
Thread receiver = new Thread(new PeerReceiveThread(natPort));
receiver.start();
Thread sender = new Thread(new PeerSendThread(destIPAddress, remotePort));
sender.start();
}
return natPort;
}
private class PeerReceiveThread implements Runnable{
int natPort;
public PeerReceiveThread(int port){
this.natPort = port;
}
public void run() {
try {
DatagramSocket serverSocket = new DatagramSocket(natPort);
byte[] receiveData = new byte[50];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
System.out.println(clientIP+" listening on port: "+natPort);
while(true){
serverSocket.receive(receivePacket);
String data = new String(receivePacket.getData());
System.out.println(clientIP+" FROM "+destinationIP+" WITH "+data);
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private class PeerSendThread implements Runnable{
InetAddress destIPAddress;
int port;
public PeerSendThread(InetAddress destIPAddress, int port) throws UnknownHostException{
this.destIPAddress = destIPAddress;
this.port = port;
}
public void run() {
try {
DatagramSocket clientSocket = new DatagramSocket();
while(true){
sendPacket(clientSocket, destIPAddress, port, "Hello from "+clientIP);
Thread.sleep(2000);
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
The basic principle works like this: (code taken from own videochat application)
ClientBehindNAT c = new ClientBehindNAT();
dataPort = c.createConnectionToPeer(relayServerIP, destAddress, 15000);
controlPort = c.createConnectionToPeer(relayServerIP, destAddress, 15000);
At first we create a new ClientBehindNAT object and then calling createConnectionToPeer() method. This leads to a connection attempt to the listening RelayServer. As we have defined a timeout of 15 seconds the Client won't wait for too long, in case the other peer didn't get connected to the server or any other unforeseen problem occured.
The most important part is the createHole() method. Inside of this method we define the set up to the relay server by sending an initial packet to it. After that we wait until a packet comes back or the timeout occurs.
When everything went well, we extract the valid port number from the data part of the received message and return it back to the method caller.
Download Source Code:
complete Maven Project
natholepunch.zip
i'm not sure this is a udp hole punching implementation. I think the relay server should only give ip:port of client1 to client2 (and vice versa) so they can communicate without any relay server, by "punching" the nat with udp packets ip1:port1 <-> ip2:port2. On Client1, by punching paquets to ip2:port2 of client2, he can receive response from client2 because the client1's nat thinks that these packets are response from client1 paquets (same behaviour for client2's nat). So i think your code is only a kind of udp proxy : paquets are always sent to the relay server.
ReplyDeleteCorrect me if i'm wrong. Sorry for my english, i'm french.
Hi, Download link is down ? any chances of getting natholepunch.zip ?
ReplyDeleteLink is down! Please email file on vitrag007@gmail.com
ReplyDeletePlease email me source on phanthai.uit@gmail.com thanks!
ReplyDeleteLink is down... :( i need natholepunch.zip file
ReplyDeletePlease email on 0verman2ya@gmail.com
Thanks all !!!
Interesting Article
ReplyDeleteOnline Java Training | Core Java Online Training
Interesting Article
Online Java Training | Java EE Online Training
Link is down... :( i need natholepunch.zip file
ReplyDeletePlease email on msshin@iges.kr
Thanks all !!!
Link is down... :( i need natholepunch.zip file
ReplyDeletePlease email on msshin@iges.kr
Thanks all !!!
organic cold pressed oils
ReplyDeletenatural cold pressed oils
organic oil
organic oil in jaipur
organic cold pressed oil in jaipur
natural oil
natural oil shop in jaipur
pure herbal oil
ayurvedic oil store in jaipur
ayurvedic oil
Hey Your site is awesome and full of information. I have read you posts they are so informative. Keep Posting wonderful content.
ReplyDeleteAni international provide the security solutions for all kind of secruity system and other equipment.
Home security system in jaipur
Wireless Home Security System in jaipur
Realtime attendance machine in jaipur
CCTV Camera dealer in jaipur
Hikvision DVR in jaipur at Rajasthan
security system solutions in jaipur
website design in jaipur
website development company in jaipur
seo company in jaipur
Thanks for sharing this unique information with us. Your post is really awesome. Your blog is really helpful for me..
ReplyDeletehospital equipment
sarthak maditech
hospital equipment suppliers
hospital equipment manufacturers
medical equipment manufacturers in jaipur
operation theater lights
hospital suction machine
alcohol breath tester
hospital furniture manufacturer
ReplyDeleteI have read your blog its very attractive and impressive. Nice information. It helped me alot.
Government vacancy
Govt Jobs
Sarkari nokri
latest sarkari vacancy
Online Form
latest govt jobs
I have read your blog its very attractive and impressive. Nice information. It helped me alot.
ReplyDeletebest smartphone
best smartphone in india
best android phone
best mobiles phones 2020
best smartphone in india under 15000
I have read your blog its very attractive and impressive. Nice information. It helped me alot.
ReplyDeleteGovernment vacancy
govt jobs
latest govt jobs
Sarkari nokri
govt jobs Adda
govt recruitment
latest sarkari vacancy
youtube abone satın al
ReplyDeletetrendyol indirim kodu
cami avizesi
cami avizeleri
avize cami
no deposit bonus forex 2021
takipçi satın al
takipçi satın al
takipçi satın al
takipcialdim.com/tiktok-takipci-satin-al/
instagram beğeni satın al
instagram beğeni satın al
btcturk
tiktok izlenme satın al
sms onay
youtube izlenme satın al
no deposit bonus forex 2021
tiktok jeton hilesi
tiktok beğeni satın al
binance
takipçi satın al
uc satın al
sms onay
sms onay
tiktok takipçi satın al
tiktok beğeni satın al
twitter takipçi satın al
trend topic satın al
youtube abone satın al
instagram beğeni satın al
tiktok beğeni satın al
twitter takipçi satın al
trend topic satın al
youtube abone satın al
takipcialdim.com/instagram-begeni-satin-al/
perde modelleri
instagram takipçi satın al
instagram takipçi satın al
takipçi satın al
instagram takipçi satın al
betboo
marsbahis
sultanbet
takipçi satın al
ReplyDeletetakipçi satın al
takipçi satın al
marsbahis
ReplyDeletebetboo
sultanbet
marsbahis
betboo
sultanbet
swrv coin hangi borsada
ReplyDeleterose coin hangi borsada
ray coin hangi borsada
cover coin hangi borsada
xec coin hangi borsada
tiktok jeton hilesi
tiktok jeton hilesi
tiktok jeton hilesi
tiktok jeton hilesi
tiktok jeton hilesi
ReplyDeletetiktok jeton hilesi
referans kimliği nedir
gate güvenilir mi
tiktok jeton hilesi
paribu
btcturk
bitcoin nasıl alınır
yurtdışı kargo
seo fiyatları
ReplyDeletesaç ekimi
dedektör
instagram takipçi satın al
ankara evden eve nakliyat
fantezi iç giyim
sosyal medya yönetimi
mobil ödeme bozdurma
kripto para nasıl alınır
instagram beğeni satın al
ReplyDeleteyurtdışı kargo
seo fiyatları
saç ekimi
dedektör
fantazi iç giyim
sosyal medya yönetimi
farmasi üyelik
mobil ödeme bozdurma
bitcoin nasıl alınır
ReplyDeletetiktok jeton hilesi
youtube abone satın al
gate io güvenilir mi
binance referans kimliği nedir
tiktok takipçi satın al
bitcoin nasıl alınır
mobil ödeme bozdurma
mobil ödeme bozdurma
smm panel
ReplyDeletesmm panel
İsilanlariblog.com
İnstagram takipçi satın al
hirdavatci burada
Www.beyazesyateknikservisi.com.tr
servis
tiktok jeton hilesi
pendik toshiba klima servisi
ReplyDeletependik beko klima servisi
ataşehir beko klima servisi
maltepe lg klima servisi
beykoz lg klima servisi
üsküdar lg klima servisi
tuzla lg klima servisi
tuzla daikin klima servisi
ümraniye toshiba klima servisi
Good content. You write beautiful things.
ReplyDeletesportsbet
sportsbet
hacklink
vbet
mrbahis
korsan taksi
taksi
vbet
hacklink
Success Write content success. Thanks.
ReplyDeletedeneme bonusu
betmatik
canlı slot siteleri
canlı poker siteleri
betpark
betturkey
kralbet