10
votes

It appears to me that newer Android devices run behind a NAT, where the local address is an internal carrier or LAN address and the public address is the router or carrier assigned external address.

Nevertheless, newer phones don't return the same address using the NetworkInterface as when accessing an IP detection service.

Therefore, connecting via direct P2P SocketChannels inherently fails.

Are there any common workarounds to this problem designed for the Android platform? Can anyone clarify what is causing this NAT-like security issue?

Any links to Java NAT traversal tutorials or examples (NOT essays or theses) would also be appreciated as being helpful (as I'm not quite sure how to implement it in Java).

I will of course also accept any other solutions anyone has to offer!

4
There is no internal NAT like thing in Android devices. A device has one or several network interfaces and if you are listening on the right one you can get connections from outside (assuming you have the internet permission). If you can't check the network path between the one that tries to access and your device.zapl
NAT has nothing to do with the end device. The device is just assigned an IP address. Whether that is a routable one or not depends on the access point / DHCP server.Nick
It must have something to do with the end device. When testing a direct P2P connection with the mobile network interface address, it works fine connecting to an older Android device (Epic 4G) but not when connecting to the Galaxy S2. The Galaxy's address returned by NetworkInterface.getNetWorkInterfaces method does not match the external IP whereas the Epic 4G's does. Clearly something changed with the phones' networking setup.bgroenks
Yeah, I'm with zapi. I think you are leaping to a conclusion. I'd like to know a couple of things: 1) What addresses appear to be assigned to the interfaces on your device; 2) When you send a packet from your device to some other connected device, what address does the packet appear to come from. Nothing to do with DHCP, of course.G. Blake Meike

4 Answers

6
votes

Almost every phone or PC you will ever touch won't have a static public IP address, and therefore will require NAT traversal. It's not because of the device; the carrier or ISP put routers between your device and the public internet. Depending on your application, usually there are NAT-traversal libraries you can use, such as ice4j or STUNT.

3
votes

I do that in my own project and have found this issue is not that complicated.

Here's a very simple UDP echo server in node.js

var dgram = require('dgram');

var socket =
    dgram.createSocket('udp4');

socket
    .on('listening', function()
    {
        var address = socket.address();
        console.log('socket listening ' +
            address.address + ':' + address.port);
    })
    .on('error', function(err)
    {
        console.log('socket error:\n' + err.stack);
        socket.close();
    })
    .on('message', function(message, rinfo)
    {
        console.log('message: ' + message + ' from ' +
            rinfo.address + ':' + rinfo.port);

        var msg = new Buffer(rinfo.address + ':' + rinfo.port);
        socket
            .send(msg, 0, msg.length,
                rinfo.port, rinfo.address,
                function(err, bytes)
                {
                    //socket.close();
                });

    })
    .bind(15000);

An android client simply send a msg to this node server

System.out.println("UDP hole punching=======================");

class IOth extends Thread {
    @Override
    public void run() {

        String sendMsg = "UDP hole punching";
        byte[] buf = sendMsg.getBytes();
        DatagramPacket packet;

        System.out.println(HPremoteHost); // node server IP
        System.out.println(HPremotePort); // 15000
        try {
            packet = new DatagramPacket(buf, buf.length, InetAddress.getByName(HPremoteHost), HPremotePort);
            ds.send(packet);
        } catch (Exception e) {
            System.out.println("error================");
            System.out.println(e);
        }
    }
}
IOth io00 = new IOth();
io00.start();

Android Client UDP listener to obtain general msg and your own Global ip&port via UDPholepunching

class IOLoop extends Thread {
    @Override
    public void run() {
        try {
            String msg = "Native.UDPserver.open";
            SocketAddress sockAddress;
            String address;
            byte[] buf = new byte[1024];
            DatagramPacket packet = new DatagramPacket(buf, buf.length);
            while (true) {
                try {
                    ds.receive(packet);
                    sockAddress = packet.getSocketAddress();
                    address = sockAddress.toString();

                    msg = new String(buf, 0, packet.getLength());

                    System.out.println(msg + "  received !!! by " + address);

                    // this case is UDP HolePunching reaction
                    if (address.equals(HPaddress1)) {
                        System.out.println(msg + "hole punched");

                        // So you can obtain own Global ip& port here.
                        // exchange this information
                        // `remoteHost` `remotePort` to another client
                        // with some method (signaling server)
                    }
                } catch (IOException e) {
                }
            }
        } catch (Exception e) {
        }
    }
}
IOLoop io00 = new IOLoop();
io00.start();

Android Client UDP sender using other client's IP remoteHost remotePort

class IOth extends Thread {
    @Override
    public void run() {
        String sendMsg = "This is a test message";
        byte[] buf = sendMsg.getBytes();
        DatagramPacket packet;

        try {
            packet = new DatagramPacket(buf, buf.length, InetAddress.getByName(remoteHost), remotePort);
            ds.send(packet);
        } catch (Exception e) {
        }
    }
}
IOth io00 = new IOth();
io00.start();
1
votes

Look at http://sourceforge.net/projects/jnat-pmplib/ It is an implementation of NAT-PMP in java.

0
votes

I've managed to establish sockets just by forwarding the sockets you're using during the connection in your router. It worked for me.

UPDATE

Find out your IP address through cmd.exe if your using Windows (ipconfig) or through a terminal session if your on Linux (ifconfig). Then connect to it through the browser and there should be a security section. Go to port forwarding and open up the ports your using when establishing you're ServerSocket and Socket. Use TCP as the protocol. Please note that this only applies if you're trying to connect from outside your wlan.