【问题标题】:Android VpnService forward packetsAndroid VpnService 转发数据包
【发布时间】:2016-09-13 00:31:09
【问题描述】:

我想使用 android 的 VpnService 来捕获数据包,根据 IP 地址过滤它们。我可以从“tun”接口获取数据包,但之后我不知道如何将它们转发到原来的目的地。根据this answer 的 cmets,我似乎只需要:

  1. 为目标 IP 地址和端口创建一个新套接字
  2. 修剪 IP 和 TCP 标头以仅发送数据
  3. 收到响应后重新附加 IP 和 TCP 标头
  4. 将完整的数据包发送到输出流

我尝试过这样发送数据:

Socket socket = new Socket();
socket.bind(new InetSocketAddress(0));
if (protect(socket)){
    Log.e(TAG, "Socket protected");
}else{
    Log.e(TAG, "Socket NOT protected");
}
socket.connect(new InetSocketAddress(ipPacket.getDestinationIp(), ipPacket.getDstPort()));
Log.e(TAG, "Socket connected: " + socket.isConnected());

socket.getOutputStream().write(getTCPHeader(getIpHeader(packet)[1])[1].array());

getTCPHeader(ByteArray packet)getIpHeader(ByteArray packet) 方法只是将数据包分成两个ByteArray,如下所示:

private ByteBuffer[] getIpHeader(ByteBuffer packet){
    packet.position(0);
    ByteBuffer ipHeader = ByteBuffer.allocate(20);
    ByteBuffer data = ByteBuffer.allocate(packet.limit() - 20);
    
    packet.get(ipHeader.array(), 0, 20);
    
    packet.get(data.array(), 0, packet.limit() - 20);
    
    return new ByteBuffer[]{ipHeader, data};
}

private ByteBuffer[] getTCPHeader(ByteBuffer packet){
    packet.position(20);
    ByteBuffer tcpHeader = ByteBuffer.allocate(20);
    ByteBuffer data = ByteBuffer.allocate(packet.limit() - 20);

    packet.get(tcpHeader.array(), 0, 20);

    packet.get(data.array(), 0, packet.limit() - 40);

    return new ByteBuffer[]{tcpHeader, data};
}

现在要从服务器获得响应,我使用以下代码:

ByteBuffer responsePacket = ByteBuffer.allocate(65535);
InputStream socketInputStream = socket.getInputStream();
try{
    int responseLength = socketInputStream.read(responsePacket.array());
    if (responseLength > 20){
        Log.e(TAG, "===Server Response===");
        Log.e(TAG, "Length: " + responseLength);

        ByteBuffer trimmedResponseData = ByteBuffer.allocate(responseLength);
        System.arraycopy(responseData.array(), 0, trimmedResponseData.array(), 0, responseLength);

        String resp = "";
        for (int i = 0; i < responseLength; i++){
            resp += String.valueOf(responseData.get(i) + " ");
        }

        Log.e(TAG, "Response data: " + resp);

        ByteBuffer finalPacket = ByteBuffer.allocate(40 + responseLength);
        ByteBuffer swappedIpHeader = swapSrcDstAddress(getIpHeader(packet)[0]);
        ByteBuffer swappedTcpHeader = swapTCPSrcDst(getTCPHeader(getIpHeader(packet)[1])[0]);

        finalPacket.put(swappedIpHeader.array());
        finalPacket.put(swappedTcpHeader.array());
        finalPacket.put(serverResponseData.array());

        Packet finPack = debugPacket(finalPacket);
        Log.e("VPN", "Final packet --> Packet size: " + finPack.getTotalLength() + " from " + finPack.getSourceIp() + " src port: " + finPack.getSrcPort() + " going to " + finPack.getDestinationIp() + " dst port: " + finPack.getDstPort());

        out.write(finalPacket.array());
    }
}catch (Exception e){
    //Log.e(TAG, "EXCEPTION: " + e);
    e.printStackTrace();
}

此代码似乎运行得非常缓慢,或者根本不运行。有时,如果我去www.google.com,它会加载缓慢,但大多数时候不会。有时我在int responseLength = socketInputStream.read(serverResponse.array()); 行上遇到以下错误

java.net.SocketException:recvfrom 失败:ECONNRESET(对等方重置连接)

是什么导致了这个错误,我怎样才能正确地将这些数据包转发到适当的目的地?非常感谢任何帮助!

【问题讨论】:

    标签: java android sockets tcp packet-capture


    【解决方案1】:

    是什么导致了这个错误?

    recvfrom failed 异常表示服务器已关闭客户端套接字,但客户端仍在读取输入数据(在您的情况下为 serverResponse.array()。有关详细信息,see this

    我怎样才能正确地将这些数据包转发到适当的 目的地?

    来自 google-sources here 的示例代码用于转发可用的数据包。请浏览代码和相关的cmets。根据谷歌来源:

    此应用由一个 Android 客户端和一个示例组成 服务器的实现。它通过 UDP 执行 IP,并且能够 只要能做到不同网络之间的无缝切换 接收相同的 VPN 参数。它显示了如何构建 VPN 客户端 使用 API 级别 14 中引入的 VpnService 类。

    服务器端实现的示例代码是特定于 Linux 的 并且在server 目录中可用。运行服务器或端口 它到另一个平台,请参阅代码中的 cmets 详情。

    另一个有用的应用链接here

    【讨论】:

    • 我已经查看了谷歌的 toyVpn 示例,但该示例使用单独的 VPN 服务器。我正在尝试在手机本身上实现所有这些,而无需连接到另一台服务器。
    • 特定于 linux 的服务器端实现是您必须经历的。如前所述,转到服务器目录。你的手机本身也是基于linux的。
    猜你喜欢
    • 1970-01-01
    • 2013-07-19
    • 2012-07-21
    • 2014-02-19
    • 1970-01-01
    • 2012-06-04
    • 2015-12-23
    • 1970-01-01
    相关资源
    最近更新 更多