Android:NAT穿越?

Posted

技术标签:

【中文标题】Android:NAT穿越?【英文标题】:Android: NAT Traversal? 【发布时间】:2012-05-09 05:03:36 【问题描述】:

在我看来,较新的 android 设备在 NAT 之后运行,其中本地地址是内部运营商或 LAN 地址,而公共地址是路由器或运营商分配的外部地址。

尽管如此,较新的手机使用网络接口返回的地址与访问 IP 检测服务时不同。

因此,通过直接 P2P SocketChannels 连接本身就失败了。

针对 Android 平台设计的此问题是否有任何常见的解决方法?谁能澄清导致这种类似 NAT 的安全问题的原因?

任何指向 Java NAT 遍历 tutorialsexamplesNOT 论文或论文)的链接也将被视为有帮助(正如我我不太清楚如何在 Java 中实现它)。

我当然也会接受任何人提供的任何其他解决方案!

【问题讨论】:

Android 设备中没有类似内部 NAT 的东西。一台设备有一个或多个网络interfaces,如果您在正确的网络上收听,您可以从外部获得连接(假设您有互联网许可)。如果您无法检查尝试访问的设备与您的设备之间的网络路径。 NAT 与终端设备无关。设备只分配了一个 IP 地址。这是否是可路由的取决于接入点/DHCP 服务器。 它一定与终端设备有关。在使用移动网络接口地址测试直接 P2P 连接时,它可以正常连接到较旧的 Android 设备 (Epic 4G),但在连接到 Galaxy S2 时却不行。 NetworkInterface.getNetWorkInterfaces 方法返回的 Galaxy 地址与外部 IP 不匹配,而 Epic 4G 则匹配。显然,手机的网络设置发生了一些变化。 是的,我支持 zapi。我认为你正在得出一个结论。我想知道几件事:1)似乎为您设备上的接口分配了哪些地址; 2)当您将数据包从您的设备发送到其他连接的设备时,数据包似乎来自哪个地址。当然,与 DHCP 无关。 【参考方案1】:

几乎您将接触的每部手机或 PC 都没有静态公共 IP 地址,因此需要 NAT 穿越。这不是因为设备;运营商或 ISP 在您的设备和公共互联网之间放置路由器。根据您的应用程序,通常有您可以使用的 NAT 遍历库,例如 ice4j 或 STUNT。

【讨论】:

ice4j 和 STUNT 不是都只支持 UDP 吗?【参考方案2】:

我在自己的项目中这样做,发现这个问题并不复杂。

这是 node.js 中一个非常简单的 UDP 回显服务器

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

Android 客户端只需向该节点服务器发送一条消息

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 客户端 UDP 监听器通过 UDPholepunching 获取通用 msg 和你自己的全局 ip&port

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 客户端 UDP 发送方使用其他客户端的 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();

【讨论】:

目的是回复问题【参考方案3】:

看http://sourceforge.net/projects/jnat-pmplib/ 它是 NAT-PMP 在 java 中的实现。

【讨论】:

这属于 cmets。 我收集了所有PCP/NAT-PMP库的列表en.wikipedia.org/wiki/Port_Control_Protocol#Implementations【参考方案4】:

我已经设法通过转发您在路由器连接期间使用的套接字来建立套接字。它对我有用。

更新

如果您使用的是 Windows (ipconfig),请通过 cmd.exe 查找您的 IP 地址;如果您使用的是 Linux (ifconfig),请通过终端会话查找您的 IP 地址。然后通过浏览器连接到它,应该有一个安全部分。转到端口转发并打开您在建立 ServerSocket 和 Socket 时使用的端口。使用 TCP 作为协议。 请注意,这仅适用于您尝试从 wlan 外部连接时。

【讨论】:

您能否详细说明或提供一个示例?这似乎是一个有趣的概念。 哦,只是端口转发? NAT Traversal 的全部意义在于避免这种情况。

以上是关于Android:NAT穿越?的主要内容,如果未能解决你的问题,请参考以下文章

VOIP NAT穿越之SIP信令穿越

P2P技术详解:P2P中的NAT穿越(打洞)方案详解(进阶分析篇)

P2P技术详解:P2P中的NAT穿越(打洞)方案详解(进阶分析篇)

P2P技术详解:P2P中的NAT穿越(打洞)方案详解(进阶分析篇)

TCP打孔(NAT穿越)库还是啥?

是否有任何浏览器实现了 NAT 穿越?