1

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)
        }
    }
}

}
shmosel
  • 49,289
  • 6
  • 73
  • 138
Pavel Vlasov
  • 4,206
  • 6
  • 41
  • 54

2 Answers2

0

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.

0

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.

slipperyseal
  • 2,728
  • 1
  • 13
  • 15